From afd0922e7478ce3e4ea5812835164fe4e2a12896 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 16 Oct 2013 16:45:41 +0300 Subject: ath10k: prevent starting monitor without a vdev This fixes issue with interface bridging. Linux bridging sets promiscuous mode for all interfaces that are in a bridge. This translates to configure_filter() being called in a mac80211 driver. Before the patch operational interface would be started and upped again when promiscuous mode was enabled causing all sorts of strange issues: * no HTT RX happening (i.e. no traffic) * FW crash upon driver reload/unload Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 0b1cc516e77..527343de573 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2265,8 +2265,14 @@ static void ath10k_configure_filter(struct ieee80211_hw *hw, *total_flags &= SUPPORTED_FILTERS; ar->filter_flags = *total_flags; + /* Monitor must not be started if it wasn't created first. + * Promiscuous mode may be started on a non-monitor interface - in + * such case the monitor vdev is not created so starting the + * monitor makes no sense. Since ath10k uses no special RX filters + * (only BSS filter in STA mode) there's no need for any special + * action here. */ if ((ar->filter_flags & FIF_PROMISC_IN_BSS) && - !ar->monitor_enabled) { + !ar->monitor_enabled && ar->monitor_present) { ath10k_dbg(ATH10K_DBG_MAC, "mac monitor %d start\n", ar->monitor_vdev_id); @@ -2274,7 +2280,7 @@ static void ath10k_configure_filter(struct ieee80211_hw *hw, if (ret) ath10k_warn("Unable to start monitor mode\n"); } else if (!(ar->filter_flags & FIF_PROMISC_IN_BSS) && - ar->monitor_enabled) { + ar->monitor_enabled && ar->monitor_present) { ath10k_dbg(ATH10K_DBG_MAC, "mac monitor %d stop\n", ar->monitor_vdev_id); -- cgit v1.2.3-70-g09d2 From 0ed00eea0961db3a007cbca727e3dd54e4bfd05f Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 16 Oct 2013 16:45:48 +0300 Subject: ath10k: add sanity checks for monitor management Add a few checks and warnings to make it easier to track any kind of monitor vdev mismanagement. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 527343de573..da23c3faaf5 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -516,6 +516,11 @@ static int ath10k_monitor_start(struct ath10k *ar, int vdev_id) lockdep_assert_held(&ar->conf_mutex); + if (!ar->monitor_present) { + ath10k_warn("mac montor stop -- monitor is not present\n"); + return -EINVAL; + } + arg.vdev_id = vdev_id; arg.channel.freq = channel->center_freq; arg.channel.band_center_freq1 = ar->hw->conf.chandef.center_freq1; @@ -566,6 +571,16 @@ static int ath10k_monitor_stop(struct ath10k *ar) lockdep_assert_held(&ar->conf_mutex); + if (!ar->monitor_present) { + ath10k_warn("mac montor stop -- monitor is not present\n"); + return -EINVAL; + } + + if (!ar->monitor_enabled) { + ath10k_warn("mac montor stop -- monitor is not enabled\n"); + return -EINVAL; + } + ret = ath10k_wmi_vdev_down(ar, ar->monitor_vdev_id); if (ret) ath10k_warn("Monitor vdev down failed: %d\n", ret); -- cgit v1.2.3-70-g09d2 From 5c54a7bf48650a8d38f2e0b1748885f5c044f45f Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 16 Oct 2013 16:45:53 +0300 Subject: ath10k: fix endianess in prints This fixes incorrect values being printed on big-endian hosts. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 77238afbed7..a796d0b9a13 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -2211,7 +2211,7 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar) } ath10k_dbg(ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n", - __cpu_to_le32(ar->wmi.num_mem_chunks)); + ar->wmi.num_mem_chunks); cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks); @@ -2224,10 +2224,10 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar) __cpu_to_le32(ar->wmi.mem_chunks[i].req_id); ath10k_dbg(ATH10K_DBG_WMI, - "wmi chunk %d len %d requested, addr 0x%x\n", + "wmi chunk %d len %d requested, addr 0x%llx\n", i, - cmd->host_mem_chunks[i].size, - cmd->host_mem_chunks[i].ptr); + ar->wmi.mem_chunks[i].len, + (unsigned long long)ar->wmi.mem_chunks[i].paddr); } out: memcpy(&cmd->resource_config, &config, sizeof(config)); @@ -2302,7 +2302,7 @@ static int ath10k_wmi_10x_cmd_init(struct ath10k *ar) } ath10k_dbg(ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n", - __cpu_to_le32(ar->wmi.num_mem_chunks)); + ar->wmi.num_mem_chunks); cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks); @@ -2315,10 +2315,10 @@ static int ath10k_wmi_10x_cmd_init(struct ath10k *ar) __cpu_to_le32(ar->wmi.mem_chunks[i].req_id); ath10k_dbg(ATH10K_DBG_WMI, - "wmi chunk %d len %d requested, addr 0x%x\n", + "wmi chunk %d len %d requested, addr 0x%llx\n", i, - cmd->host_mem_chunks[i].size, - cmd->host_mem_chunks[i].ptr); + ar->wmi.mem_chunks[i].len, + (unsigned long long)ar->wmi.mem_chunks[i].paddr); } out: memcpy(&cmd->resource_config, &config, sizeof(config)); -- cgit v1.2.3-70-g09d2 From c4340c26d63550eaedcc3440f6ba78d6d4c451d4 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 16 Oct 2013 16:45:59 +0300 Subject: ath10k: fix NSS reporting in RX NSTS values reported in the VHT-SIG-A1 are 0 through 7 but they actually describe number of streams 1 through 8. 1SS frames were dropped. This patch fixes this. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/txrx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index 5ae373a1e29..c511f919d54 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -183,7 +183,7 @@ static void process_rx_rates(struct ath10k *ar, struct htt_rx_info *info, /* VHT-SIG-A1 in info 1, VHT-SIG-A2 in info2 TODO check this */ mcs = (info2 >> 4) & 0x0F; - nss = (info1 >> 10) & 0x07; + nss = ((info1 >> 10) & 0x07) + 1; bw = info1 & 3; sgi = info2 & 1; -- cgit v1.2.3-70-g09d2 From 5e90de860bc2d82dcb73caef86c05cb49c2b5792 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 16 Oct 2013 16:46:05 +0300 Subject: ath10k: fix NULL deref upon early FW crash If firmware crashes during FW probing it would try to perform FW recovery which uses mac80211 workqueue before registering to mac80211. Using internal workqueue solves the problem. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 3 ++- drivers/net/wireless/ath/ath10k/pci.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 1129994fb10..2a360cac4ce 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -664,7 +664,8 @@ static void ath10k_core_restart(struct work_struct *work) ieee80211_restart_hw(ar->hw); break; case ATH10K_STATE_OFF: - /* this can happen if driver is being unloaded */ + /* this can happen if driver is being unloaded + * or if the crash happens during FW probing */ ath10k_warn("cannot restart a device that hasn't been started\n"); break; case ATH10K_STATE_RESTARTING: diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index f8d59c7b908..d09f8a2861b 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -777,7 +777,7 @@ static void ath10k_pci_hif_dump_area(struct ath10k *ar) reg_dump_values[i + 2], reg_dump_values[i + 3]); - ieee80211_queue_work(ar->hw, &ar->restart_work); + queue_work(ar->workqueue, &ar->restart_work); } static void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe, -- cgit v1.2.3-70-g09d2 From 233eb97fc9d0f44f2ea99fe48118aa3d2dc25d64 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Wed, 16 Oct 2013 16:46:11 +0300 Subject: ath10k: implement ath10k_pci_soc_read/write32() To make it easier to access SOC registers. No functional changes. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 3 +-- drivers/net/wireless/ath/ath10k/pci.h | 10 ++++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index d09f8a2861b..5c7838398e9 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -2454,8 +2454,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, return ret; } - chip_id = ath10k_pci_read32(ar, - RTC_SOC_BASE_ADDRESS + SOC_CHIP_ID_ADDRESS); + chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS); ath10k_do_pci_sleep(ar); diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index 52fb7b97357..a304c338490 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -318,6 +318,16 @@ static inline u32 ath10k_pci_read32(struct ath10k *ar, u32 offset) return ioread32(ar_pci->mem + offset); } +static inline u32 ath10k_pci_soc_read32(struct ath10k *ar, u32 addr) +{ + return ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + addr); +} + +static inline void ath10k_pci_soc_write32(struct ath10k *ar, u32 addr, u32 val) +{ + ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + addr, val); +} + int ath10k_do_pci_wake(struct ath10k *ar); void ath10k_do_pci_sleep(struct ath10k *ar); -- cgit v1.2.3-70-g09d2 From 60f85bea25d5e9915da8b0c87275143b317cec3b Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 16 Oct 2013 16:46:24 +0300 Subject: ath10k: fix FW crashes on heavy TX on 10.1.389 AP FW 10.1.389 firmware has some differences in calculation of number of outstanding HTT TX completions. This led to FW crashes of 10.1.389 while main firmware branch was unnaffected. The patch makes sure ath10k doesn't queue up more MSDUs than it should. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.c | 11 +++++++++++ drivers/net/wireless/ath/ath10k/htt_tx.c | 11 ++++------- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index e46951b8fb9..d243f287fae 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -1050,6 +1050,17 @@ struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar, u32 ctrl_addr = ath10k_ce_base_address(ce_id); int ret; + /* + * Make sure there's enough CE ringbuffer entries for HTT TX to avoid + * additional TX locking checks. + * + * For the lack of a better place do the check here. + */ + BUILD_BUG_ON(TARGET_NUM_MSDU_DESC > + (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); + BUILD_BUG_ON(TARGET_10X_NUM_MSDU_DESC > + (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); + ret = ath10k_pci_wake(ar); if (ret) return NULL; diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index d9335e9d0d0..f1d36d2d272 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -85,16 +85,13 @@ void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id) int ath10k_htt_tx_attach(struct ath10k_htt *htt) { - u8 pipe; - spin_lock_init(&htt->tx_lock); init_waitqueue_head(&htt->empty_tx_wq); - /* At the beginning free queue number should hint us the maximum - * queue length */ - pipe = htt->ar->htc.endpoint[htt->eid].ul_pipe_id; - htt->max_num_pending_tx = ath10k_hif_get_free_queue_number(htt->ar, - pipe); + if (test_bit(ATH10K_FW_FEATURE_WMI_10X, htt->ar->fw_features)) + htt->max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC; + else + htt->max_num_pending_tx = TARGET_NUM_MSDU_DESC; ath10k_dbg(ATH10K_DBG_BOOT, "htt tx max num pending tx %d\n", htt->max_num_pending_tx); -- cgit v1.2.3-70-g09d2 From f3782744c9b50edf94d28e37a937ff84f267dfab Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Thu, 17 Oct 2013 11:36:15 +0300 Subject: ath10k: add error handling to ath10k_pci_wait() ath10k_pci_wait() didn't notify any errors to callers, it just printed a warning so add proper error handling. This fixes a crash Ben reported: ath10k: MSI-X interrupt handling (8 intrs) ath10k: Unable to wakeup target ath10k: target took longer 5000 us to wake up (awake count 1) ath10k: Failed to get pcie state addr: -16 ath10k: early firmware event indicated BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: [] ath10k_ce_completed_send_next+0x47/0x122 [ath10k_pci] Reported-by: Ben Greear Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 5c7838398e9..42d2473b56b 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -526,15 +526,19 @@ static bool ath10k_pci_target_is_awake(struct ath10k *ar) return (RTC_STATE_V_GET(val) == RTC_STATE_V_ON); } -static void ath10k_pci_wait(struct ath10k *ar) +static int ath10k_pci_wait(struct ath10k *ar) { int n = 100; while (n-- && !ath10k_pci_target_is_awake(ar)) msleep(10); - if (n < 0) + if (n < 0) { ath10k_warn("Unable to wakeup target\n"); + return -ETIMEDOUT; + } + + return 0; } int ath10k_do_pci_wake(struct ath10k *ar) @@ -2155,7 +2159,13 @@ static int ath10k_pci_start_intr_legacy(struct ath10k *ar) ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + PCIE_SOC_WAKE_ADDRESS); - ath10k_pci_wait(ar); + ret = ath10k_pci_wait(ar); + if (ret) { + ath10k_warn("Failed to enable legacy interrupt, target did not wake up: %d\n", + ret); + free_irq(ar_pci->pdev->irq, ar); + return ret; + } /* * A potential race occurs here: The CORE_BASE write @@ -2218,6 +2228,10 @@ static int ath10k_pci_start_intr(struct ath10k *ar) } ret = ath10k_pci_start_intr_legacy(ar); + if (ret) { + ath10k_warn("Failed to start legacy interrupts: %d\n", ret); + return ret; + } exit: ar_pci->num_msi_intrs = num; @@ -2243,13 +2257,19 @@ static int ath10k_pci_reset_target(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int wait_limit = 300; /* 3 sec */ + int ret; /* Wait for Target to finish initialization before we proceed. */ iowrite32(PCIE_SOC_WAKE_V_MASK, ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + PCIE_SOC_WAKE_ADDRESS); - ath10k_pci_wait(ar); + ret = ath10k_pci_wait(ar); + if (ret) { + ath10k_warn("Failed to reset target, target did not wake up: %d\n", + ret); + return ret; + } while (wait_limit-- && !(ioread32(ar_pci->mem + FW_INDICATOR_ADDRESS) & -- cgit v1.2.3-70-g09d2 From e63b33f3d059bda08ab7634a435024a6e7b82e1f Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Tue, 22 Oct 2013 14:54:14 -0700 Subject: ath10k: Initialize list-head on vif creation. If the creation fails, this keeps us from crashing later when trying to do a list_del(arvif->list). Signed-off-by: Ben Greear Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index da23c3faaf5..908e90dc238 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2064,6 +2064,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, arvif->vif = vif; INIT_WORK(&arvif->wep_key_work, ath10k_tx_wep_key_work); + INIT_LIST_HEAD(&arvif->list); if ((vif->type == NL80211_IFTYPE_MONITOR) && ar->monitor_present) { ath10k_warn("Only one monitor interface allowed\n"); -- cgit v1.2.3-70-g09d2 From 89c5c843110b7faee9d132826d574924c4f4c056 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 23 Oct 2013 04:02:13 -0700 Subject: ath10k: setup min channel power to a reasonable value This will be needed for proper support of (user) configurable tx power level. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 908e90dc238..8eb84fbd2d3 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -450,7 +450,7 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif) arg.channel.mode = chan_to_phymode(&conf->chandef); - arg.channel.min_power = channel->max_power * 3; + arg.channel.min_power = 0; arg.channel.max_power = channel->max_power * 4; arg.channel.max_reg_power = channel->max_reg_power * 4; arg.channel.max_antenna_gain = channel->max_antenna_gain; @@ -529,7 +529,7 @@ static int ath10k_monitor_start(struct ath10k *ar, int vdev_id) don't have any vifs? */ arg.channel.mode = chan_to_phymode(&ar->hw->conf.chandef); - arg.channel.min_power = channel->max_power * 3; + arg.channel.min_power = 0; arg.channel.max_power = channel->max_power * 4; arg.channel.max_reg_power = channel->max_reg_power * 4; arg.channel.max_antenna_gain = channel->max_antenna_gain; @@ -1375,7 +1375,7 @@ static int ath10k_update_channel_list(struct ath10k *ar) ch->passive = passive; ch->freq = channel->center_freq; - ch->min_power = channel->max_power * 3; + ch->min_power = 0; ch->max_power = channel->max_power * 4; ch->max_reg_power = channel->max_reg_power * 4; ch->max_antenna_gain = channel->max_antenna_gain; -- cgit v1.2.3-70-g09d2 From 02256930d9b80c3c8ada90ea36fd0488a91735d0 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 23 Oct 2013 04:02:14 -0700 Subject: ath10k: use proper tx power unit It was previously thought that FW expects tx power in quarters of dBm. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 18 +++++++++--------- drivers/net/wireless/ath/ath10k/wmi.h | 3 ++- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 8eb84fbd2d3..03ef162d34d 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -451,9 +451,9 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif) arg.channel.mode = chan_to_phymode(&conf->chandef); arg.channel.min_power = 0; - arg.channel.max_power = channel->max_power * 4; - arg.channel.max_reg_power = channel->max_reg_power * 4; - arg.channel.max_antenna_gain = channel->max_antenna_gain; + arg.channel.max_power = channel->max_power * 2; + arg.channel.max_reg_power = channel->max_reg_power * 2; + arg.channel.max_antenna_gain = channel->max_antenna_gain * 2; if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { arg.ssid = arvif->u.ap.ssid; @@ -530,9 +530,9 @@ static int ath10k_monitor_start(struct ath10k *ar, int vdev_id) arg.channel.mode = chan_to_phymode(&ar->hw->conf.chandef); arg.channel.min_power = 0; - arg.channel.max_power = channel->max_power * 4; - arg.channel.max_reg_power = channel->max_reg_power * 4; - arg.channel.max_antenna_gain = channel->max_antenna_gain; + arg.channel.max_power = channel->max_power * 2; + arg.channel.max_reg_power = channel->max_reg_power * 2; + arg.channel.max_antenna_gain = channel->max_antenna_gain * 2; ret = ath10k_wmi_vdev_start(ar, &arg); if (ret) { @@ -1376,9 +1376,9 @@ static int ath10k_update_channel_list(struct ath10k *ar) ch->freq = channel->center_freq; ch->min_power = 0; - ch->max_power = channel->max_power * 4; - ch->max_reg_power = channel->max_reg_power * 4; - ch->max_antenna_gain = channel->max_antenna_gain; + ch->max_power = channel->max_power * 2; + ch->max_reg_power = channel->max_reg_power * 2; + ch->max_antenna_gain = channel->max_antenna_gain * 2; ch->reg_class_id = 0; /* FIXME */ /* FIXME: why use only legacy modes, why not any diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 78c991aec7f..81e33a7dbaf 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -893,6 +893,7 @@ struct wmi_channel { union { __le32 reginfo0; struct { + /* note: power unit is 0.5 dBm */ u8 min_power; u8 max_power; u8 reg_power; @@ -915,7 +916,7 @@ struct wmi_channel_arg { bool allow_ht; bool allow_vht; bool ht40plus; - /* note: power unit is 1/4th of dBm */ + /* note: power unit is 0.5 dBm */ u32 min_power; u32 max_power; u32 max_reg_power; -- cgit v1.2.3-70-g09d2 From 5474efe802faf84b1db1ae172f1754cca390ee45 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 23 Oct 2013 04:02:15 -0700 Subject: ath10k: respect power_level values This allows txpower limits other than regulatory to be applied (e.g. user txpower limit provided via iw/nl80211). Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 03ef162d34d..bbb0efacfaf 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2013,6 +2013,7 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed) struct ath10k *ar = hw->priv; struct ieee80211_conf *conf = &hw->conf; int ret = 0; + u32 param; mutex_lock(&ar->conf_mutex); @@ -2024,6 +2025,25 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed) spin_unlock_bh(&ar->data_lock); } + if (changed & IEEE80211_CONF_CHANGE_POWER) { + ath10k_dbg(ATH10K_DBG_MAC, "mac config power %d\n", + hw->conf.power_level); + + param = ar->wmi.pdev_param->txpower_limit2g; + ret = ath10k_wmi_pdev_set_param(ar, param, + hw->conf.power_level * 2); + if (ret) + ath10k_warn("mac failed to set 2g txpower %d (%d)\n", + hw->conf.power_level, ret); + + param = ar->wmi.pdev_param->txpower_limit5g; + ret = ath10k_wmi_pdev_set_param(ar, param, + hw->conf.power_level * 2); + if (ret) + ath10k_warn("mac failed to set 5g txpower %d (%d)\n", + hw->conf.power_level, ret); + } + if (changed & IEEE80211_CONF_CHANGE_PS) ath10k_config_ps(ar); -- cgit v1.2.3-70-g09d2 From 5fb5e41f424ad970f3bda645b8234dc71fcc8e59 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 28 Oct 2013 07:18:13 +0100 Subject: ath10k: plug memory leak in wmi mgmt tx worker sk_buff was not freed in some cases. The patch unifies the msdu freeing. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 4 +++- drivers/net/wireless/ath/ath10k/wmi.c | 4 +--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index bbb0efacfaf..f45eca0b7a4 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1729,8 +1729,10 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work) break; ret = ath10k_wmi_mgmt_tx(ar, skb); - if (ret) + if (ret) { ath10k_warn("wmi mgmt_tx failed (%d)\n", ret); + ieee80211_free_txskb(ar->hw, skb); + } } } diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index a796d0b9a13..8db9db2db94 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -674,10 +674,8 @@ int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb) /* Send the management frame buffer to the target */ ret = ath10k_wmi_cmd_send(ar, wmi_skb, ar->wmi.cmd->mgmt_tx_cmdid); - if (ret) { - dev_kfree_skb_any(skb); + if (ret) return ret; - } /* TODO: report tx status to mac80211 - temporary just ACK */ info->flags |= IEEE80211_TX_STAT_ACK; -- cgit v1.2.3-70-g09d2 From e204548101732849dadd8d9f229cd1c83ae9236a Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 28 Oct 2013 07:18:14 +0100 Subject: ath10k: plug memory leak on beacon tx If beacon tx command failed the wmi command buffer was not freed. This led to OOM in the long run. This became aparent when stress testing multi-BSSID. Reported-By: Tomasz Skapski Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 8db9db2db94..f79f17ce5dc 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3092,6 +3092,7 @@ int ath10k_wmi_beacon_send_nowait(struct ath10k *ar, { struct wmi_bcn_tx_cmd *cmd; struct sk_buff *skb; + int ret; skb = ath10k_wmi_alloc_skb(sizeof(*cmd) + arg->bcn_len); if (!skb) @@ -3104,7 +3105,11 @@ int ath10k_wmi_beacon_send_nowait(struct ath10k *ar, cmd->hdr.bcn_len = __cpu_to_le32(arg->bcn_len); memcpy(cmd->bcn, arg->bcn, arg->bcn_len); - return ath10k_wmi_cmd_send_nowait(ar, skb, ar->wmi.cmd->bcn_tx_cmdid); + ret = ath10k_wmi_cmd_send_nowait(ar, skb, ar->wmi.cmd->bcn_tx_cmdid); + if (ret) + dev_kfree_skb(skb); + + return ret; } static void ath10k_wmi_pdev_set_wmm_param(struct wmi_wmm_params *params, -- cgit v1.2.3-70-g09d2 From 12eb087939d11af6b5a8228807d1428535aedb3b Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 30 Oct 2013 13:24:39 +0800 Subject: ath10k: fix possible memory leak in ath10k_pci_probe() memory is malloced in ath10k_pci_probe() and should be freed before leaving from the error handling cases, otherwise it will cause memory leak. Signed-off-by: Wei Yongjun Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 42d2473b56b..25ed07b96a1 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -2471,7 +2471,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ret = ath10k_do_pci_wake(ar); if (ret) { ath10k_err("Failed to get chip id: %d\n", ret); - return ret; + goto err_iomap; } chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS); -- cgit v1.2.3-70-g09d2 From 6f1f56ea43223dd80e238564d31bbc31c65234dd Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Mon, 4 Nov 2013 09:18:16 -0800 Subject: ath10k: Fix un-initialized debug objects. If the 'ar' registration fails early, the debug objects were not initialized, and trouble ensued when the object was later destroyed and the un-initialized objects were accessed. Per Kalle's suggestion, move the debug_destroy to the core_unregister method. Signed-off-by: Ben Greear Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 2a360cac4ce..7d868769436 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -738,8 +738,6 @@ EXPORT_SYMBOL(ath10k_core_create); void ath10k_core_destroy(struct ath10k *ar) { - ath10k_debug_destroy(ar); - flush_workqueue(ar->workqueue); destroy_workqueue(ar->workqueue); @@ -986,6 +984,8 @@ void ath10k_core_unregister(struct ath10k *ar) ath10k_mac_unregister(ar); ath10k_core_free_firmware_files(ar); + + ath10k_debug_destroy(ar); } EXPORT_SYMBOL(ath10k_core_unregister); -- cgit v1.2.3-70-g09d2 From 479398b07048342c7fdca89fd3a6cdb739e48a86 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Mon, 4 Nov 2013 09:19:34 -0800 Subject: ath10k: add logging to better determine some VIF/STA creation failures Not all errors were properly notified, fix that. kvalo: use ath10k_warn() for all messages, cosmetic changes to some of the messages Signed-off-by: Ben Greear Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index f45eca0b7a4..56f030ed357 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -322,12 +322,16 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr) lockdep_assert_held(&ar->conf_mutex); ret = ath10k_wmi_peer_create(ar, vdev_id, addr); - if (ret) + if (ret) { + ath10k_warn("Failed to create wmi peer: %i\n", ret); return ret; + } ret = ath10k_wait_for_peer_created(ar, vdev_id, addr); - if (ret) + if (ret) { + ath10k_warn("Failed to wait for created wmi peer: %i\n", ret); return ret; + } return 0; } @@ -2404,8 +2408,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, ret = ath10k_peer_create(ar, arvif->vdev_id, info->bssid); if (ret) - ath10k_warn("Failed to add peer: %pM for VDEV: %d\n", - info->bssid, arvif->vdev_id); + ath10k_warn("Failed to add peer %pM for vdev %d when changin bssid: %i\n", + info->bssid, arvif->vdev_id, ret); if (vif->type == NL80211_IFTYPE_STATION) { /* @@ -2687,8 +2691,8 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr); if (ret) - ath10k_warn("Failed to add peer: %pM for VDEV: %d\n", - sta->addr, arvif->vdev_id); + ath10k_warn("Failed to add peer %pM for vdev %d when adding a new sta: %i\n", + sta->addr, arvif->vdev_id, ret); } else if ((old_state == IEEE80211_STA_NONE && new_state == IEEE80211_STA_NOTEXIST)) { /* -- cgit v1.2.3-70-g09d2 From fad6ed7867f41b2a9a7fc6cd01db37f33a29da1e Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 8 Nov 2013 08:01:23 +0100 Subject: ath10k: remove ar_pci->ce_count It wasn't really useful to have it to begin with. This makes it a little simpler to re-arrange PCI init code as some function depended on ar_pci->ce_count being set. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.c | 9 +++------ drivers/net/wireless/ath/ath10k/pci.c | 18 ++++++++---------- drivers/net/wireless/ath/ath10k/pci.h | 3 --- 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index d243f287fae..2b99bd41dde 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -731,7 +731,6 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id) void ath10k_ce_per_engine_service_any(struct ath10k *ar) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ce_id, ret; u32 intr_summary; @@ -741,7 +740,7 @@ void ath10k_ce_per_engine_service_any(struct ath10k *ar) intr_summary = CE_INTERRUPT_SUMMARY(ar); - for (ce_id = 0; intr_summary && (ce_id < ar_pci->ce_count); ce_id++) { + for (ce_id = 0; intr_summary && (ce_id < CE_COUNT); ce_id++) { if (intr_summary & (1 << ce_id)) intr_summary &= ~(1 << ce_id); else @@ -785,16 +784,14 @@ static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state, void ath10k_ce_disable_interrupts(struct ath10k *ar) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ce_id, ret; ret = ath10k_pci_wake(ar); if (ret) return; - for (ce_id = 0; ce_id < ar_pci->ce_count; ce_id++) { - struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; - u32 ctrl_addr = ce_state->ctrl_addr; + for (ce_id = 0; ce_id < CE_COUNT; ce_id++) { + u32 ctrl_addr = ath10k_ce_base_address(ce_id); ath10k_ce_copy_complete_intr_disable(ar, ctrl_addr); } diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 25ed07b96a1..f054d4c3024 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -831,7 +831,7 @@ static int ath10k_pci_start_ce(struct ath10k *ar) spin_lock_init(&ar_pci->compl_lock); INIT_LIST_HEAD(&ar_pci->compl_process); - for (pipe_num = 0; pipe_num < ar_pci->ce_count; pipe_num++) { + for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) { pipe_info = &ar_pci->pipe_info[pipe_num]; spin_lock_init(&pipe_info->pipe_lock); @@ -924,7 +924,7 @@ static void ath10k_pci_cleanup_ce(struct ath10k *ar) spin_unlock_bh(&ar_pci->compl_lock); /* Free unused completions for each pipe. */ - for (pipe_num = 0; pipe_num < ar_pci->ce_count; pipe_num++) { + for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) { pipe_info = &ar_pci->pipe_info[pipe_num]; spin_lock_bh(&pipe_info->pipe_lock); @@ -1166,7 +1166,7 @@ static int ath10k_pci_post_rx(struct ath10k *ar) const struct ce_attr *attr; int pipe_num, ret = 0; - for (pipe_num = 0; pipe_num < ar_pci->ce_count; pipe_num++) { + for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) { pipe_info = &ar_pci->pipe_info[pipe_num]; attr = &host_ce_config_wlan[pipe_num]; @@ -1295,7 +1295,7 @@ static void ath10k_pci_buffer_cleanup(struct ath10k *ar) struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int pipe_num; - for (pipe_num = 0; pipe_num < ar_pci->ce_count; pipe_num++) { + for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) { struct ath10k_pci_pipe *pipe_info; pipe_info = &ar_pci->pipe_info[pipe_num]; @@ -1310,7 +1310,7 @@ static void ath10k_pci_ce_deinit(struct ath10k *ar) struct ath10k_pci_pipe *pipe_info; int pipe_num; - for (pipe_num = 0; pipe_num < ar_pci->ce_count; pipe_num++) { + for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) { pipe_info = &ar_pci->pipe_info[pipe_num]; if (pipe_info->ce_hdl) { ath10k_ce_deinit(pipe_info->ce_hdl); @@ -1755,7 +1755,7 @@ static int ath10k_pci_ce_init(struct ath10k *ar) const struct ce_attr *attr; int pipe_num; - for (pipe_num = 0; pipe_num < ar_pci->ce_count; pipe_num++) { + for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) { pipe_info = &ar_pci->pipe_info[pipe_num]; pipe_info->pipe_num = pipe_num; pipe_info->hif_ce_state = ar; @@ -1772,13 +1772,12 @@ static int ath10k_pci_ce_init(struct ath10k *ar) return -1; } - if (pipe_num == ar_pci->ce_count - 1) { + if (pipe_num == CE_COUNT - 1) { /* * Reserve the ultimate CE for * diagnostic Window support */ - ar_pci->ce_diag = - ar_pci->pipe_info[ar_pci->ce_count - 1].ce_hdl; + ar_pci->ce_diag = pipe_info->ce_hdl; continue; } @@ -2235,7 +2234,6 @@ static int ath10k_pci_start_intr(struct ath10k *ar) exit: ar_pci->num_msi_intrs = num; - ar_pci->ce_count = CE_COUNT; return ret; } diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index a304c338490..73a3d4ee6eb 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -199,9 +199,6 @@ struct ath10k_pci { struct tasklet_struct intr_tq; struct tasklet_struct msi_fw_err; - /* Number of Copy Engines supported */ - unsigned int ce_count; - int started; atomic_t keep_awake_count; -- cgit v1.2.3-70-g09d2 From 103d4f5ed68b2667c134189749fb48cb7c96aa80 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 8 Nov 2013 08:01:24 +0100 Subject: ath10k: don't forget to kill fw error tasklet It was possible for FW error tasklet to be executed during teardown. This could lead to system crashes and/or memory corruption. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index f054d4c3024..31cdde05562 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -888,6 +888,7 @@ static void ath10k_pci_stop_ce(struct ath10k *ar) /* Cancel the pending tasklet */ tasklet_kill(&ar_pci->intr_tq); + tasklet_kill(&ar_pci->msi_fw_err); for (i = 0; i < CE_COUNT; i++) tasklet_kill(&ar_pci->pipe_info[i].intr); -- cgit v1.2.3-70-g09d2 From 96a9d0dc296b9ee63383549efb683dbf0ae2f0f8 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 8 Nov 2013 08:01:25 +0100 Subject: ath10k: split tasklet killing function The function will soon be called from more than 1 place. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 31cdde05562..a001ff250d3 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -877,21 +877,26 @@ static int ath10k_pci_start_ce(struct ath10k *ar) return 0; } -static void ath10k_pci_stop_ce(struct ath10k *ar) +static void ath10k_pci_kill_tasklet(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_pci_compl *compl; - struct sk_buff *skb; int i; - ath10k_ce_disable_interrupts(ar); - - /* Cancel the pending tasklet */ tasklet_kill(&ar_pci->intr_tq); tasklet_kill(&ar_pci->msi_fw_err); for (i = 0; i < CE_COUNT; i++) tasklet_kill(&ar_pci->pipe_info[i].intr); +} + +static void ath10k_pci_stop_ce(struct ath10k *ar) +{ + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct ath10k_pci_compl *compl; + struct sk_buff *skb; + + ath10k_ce_disable_interrupts(ar); + ath10k_pci_kill_tasklet(ar); /* Mark pending completions as aborted, so that upper layers free up * their associated resources */ -- cgit v1.2.3-70-g09d2 From d7fb47f52ef5538b4eb32856bd8cb580623dd87f Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 8 Nov 2013 08:01:26 +0100 Subject: ath10k: rename ath10k_pci_reset_target() What the function does is to actually wait for the firmware indication bit to be set. Prerequisite for this is having interrupts registered. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index a001ff250d3..4aa7992f1a3 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -53,7 +53,7 @@ static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info, static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info); static void ath10k_pci_stop_ce(struct ath10k *ar); static void ath10k_pci_device_reset(struct ath10k *ar); -static int ath10k_pci_reset_target(struct ath10k *ar); +static int ath10k_pci_wait_for_target_init(struct ath10k *ar); static int ath10k_pci_start_intr(struct ath10k *ar); static void ath10k_pci_stop_intr(struct ath10k *ar); @@ -1857,7 +1857,7 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) */ ath10k_pci_device_reset(ar); - ret = ath10k_pci_reset_target(ar); + ret = ath10k_pci_wait_for_target_init(ar); if (ret) goto err_irq; @@ -2257,7 +2257,7 @@ static void ath10k_pci_stop_intr(struct ath10k *ar) pci_disable_msi(ar_pci->pdev); } -static int ath10k_pci_reset_target(struct ath10k *ar) +static int ath10k_pci_wait_for_target_init(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int wait_limit = 300; /* 3 sec */ -- cgit v1.2.3-70-g09d2 From 93e0daa0ee3ef53a45293e60b2eaf770d7bb1d53 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 8 Nov 2013 08:01:27 +0100 Subject: ath10k: make sure to mask all CE irqs CE error interrupts were not disabled. This could lead to invalid memory accesses / memory corruption. Also make sure CE watermark interrupts are also disabled. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index 2b99bd41dde..7a49cde9c61 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -243,6 +243,16 @@ static inline void ath10k_ce_error_intr_enable(struct ath10k *ar, misc_ie_addr | CE_ERROR_MASK); } +static inline void ath10k_ce_error_intr_disable(struct ath10k *ar, + u32 ce_ctrl_addr) +{ + u32 misc_ie_addr = ath10k_pci_read32(ar, + ce_ctrl_addr + MISC_IE_ADDRESS); + + ath10k_pci_write32(ar, ce_ctrl_addr + MISC_IE_ADDRESS, + misc_ie_addr & ~CE_ERROR_MASK); +} + static inline void ath10k_ce_engine_int_status_clear(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int mask) @@ -794,6 +804,8 @@ void ath10k_ce_disable_interrupts(struct ath10k *ar) u32 ctrl_addr = ath10k_ce_base_address(ce_id); ath10k_ce_copy_complete_intr_disable(ar, ctrl_addr); + ath10k_ce_error_intr_disable(ar, ctrl_addr); + ath10k_ce_watermark_intr_disable(ar, ctrl_addr); } ath10k_pci_sleep(ar); } -- cgit v1.2.3-70-g09d2 From 1d34902192bf31741729184dd459eccdba5dbc83 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 8 Nov 2013 08:01:28 +0100 Subject: ath10k: fix ath10k_ce_init() failpath Make sure to put target back to sleep. This was a minor issue as it didn't really matter if we put target back to sleep at this point. It just looked wrong. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index 7a49cde9c61..657e8f2ee98 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -1077,7 +1077,7 @@ struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar, ce_state = ath10k_ce_init_state(ar, ce_id, attr); if (!ce_state) { ath10k_err("Failed to initialize CE state for ID: %d\n", ce_id); - return NULL; + goto out; } if (attr->src_nentries) { @@ -1086,7 +1086,8 @@ struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar, ath10k_err("Failed to initialize CE src ring for ID: %d (%d)\n", ce_id, ret); ath10k_ce_deinit(ce_state); - return NULL; + ce_state = NULL; + goto out; } } @@ -1096,15 +1097,16 @@ struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar, ath10k_err("Failed to initialize CE dest ring for ID: %d (%d)\n", ce_id, ret); ath10k_ce_deinit(ce_state); - return NULL; + ce_state = NULL; + goto out; } } /* Enable CE error interrupts */ ath10k_ce_error_intr_enable(ar, ctrl_addr); +out: ath10k_pci_sleep(ar); - return ce_state; } -- cgit v1.2.3-70-g09d2 From 8630e3ad92e76c1b9e4cbd90eaf2eb6d58f1dd31 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 8 Nov 2013 08:01:29 +0100 Subject: ath10k: remove meaningless check The check doesn't make much sense. If the address were to be 0x0000 the check would fail. In this case a 0 address isn't wrong. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 4aa7992f1a3..62df0ddd323 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -2307,9 +2307,6 @@ static void ath10k_pci_device_reset(struct ath10k *ar) int i; u32 val; - if (!SOC_GLOBAL_RESET_ADDRESS) - return; - ath10k_pci_reg_write32(ar, PCIE_SOC_WAKE_ADDRESS, PCIE_SOC_WAKE_V_MASK); for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) { -- cgit v1.2.3-70-g09d2 From 5b2589fcfff1def576314f9e89d61eeb23bac5ac Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 8 Nov 2013 08:01:30 +0100 Subject: ath10k: use ath10k_do_pci_wake/sleep This removes some remaining direct use of the wake register which could interfere with power state tracking of the target device. This will allow initialization code reordering. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 84 +++++++++++------------------------ 1 file changed, 26 insertions(+), 58 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 62df0ddd323..2b4f7d3969e 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -52,7 +52,7 @@ static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info, int num); static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info); static void ath10k_pci_stop_ce(struct ath10k *ar); -static void ath10k_pci_device_reset(struct ath10k *ar); +static int ath10k_pci_device_reset(struct ath10k *ar); static int ath10k_pci_wait_for_target_init(struct ath10k *ar); static int ath10k_pci_start_intr(struct ath10k *ar); static void ath10k_pci_stop_intr(struct ath10k *ar); @@ -526,21 +526,6 @@ static bool ath10k_pci_target_is_awake(struct ath10k *ar) return (RTC_STATE_V_GET(val) == RTC_STATE_V_ON); } -static int ath10k_pci_wait(struct ath10k *ar) -{ - int n = 100; - - while (n-- && !ath10k_pci_target_is_awake(ar)) - msleep(10); - - if (n < 0) { - ath10k_warn("Unable to wakeup target\n"); - return -ETIMEDOUT; - } - - return 0; -} - int ath10k_do_pci_wake(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); @@ -1855,7 +1840,11 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) * is in an unexpected state. We try to catch that here in order to * reset the Target and retry the probe. */ - ath10k_pci_device_reset(ar); + ret = ath10k_pci_device_reset(ar); + if (ret) { + ath10k_err("failed to reset target: %d\n", ret); + goto err_irq; + } ret = ath10k_pci_wait_for_target_init(ar); if (ret) @@ -2156,19 +2145,10 @@ static int ath10k_pci_start_intr_legacy(struct ath10k *ar) if (ret < 0) return ret; - /* - * Make sure to wake the Target before enabling Legacy - * Interrupt. - */ - iowrite32(PCIE_SOC_WAKE_V_MASK, - ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + - PCIE_SOC_WAKE_ADDRESS); - - ret = ath10k_pci_wait(ar); + ret = ath10k_do_pci_wake(ar); if (ret) { - ath10k_warn("Failed to enable legacy interrupt, target did not wake up: %d\n", - ret); free_irq(ar_pci->pdev->irq, ar); + ath10k_err("failed to wake up target: %d\n", ret); return ret; } @@ -2184,10 +2164,8 @@ static int ath10k_pci_start_intr_legacy(struct ath10k *ar) PCIE_INTR_CE_MASK_ALL, ar_pci->mem + (SOC_CORE_BASE_ADDRESS | PCIE_INTR_ENABLE_ADDRESS)); - iowrite32(PCIE_SOC_WAKE_RESET, - ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + - PCIE_SOC_WAKE_ADDRESS); + ath10k_do_pci_sleep(ar); ath10k_info("legacy interrupt handling\n"); return 0; } @@ -2263,15 +2241,9 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar) int wait_limit = 300; /* 3 sec */ int ret; - /* Wait for Target to finish initialization before we proceed. */ - iowrite32(PCIE_SOC_WAKE_V_MASK, - ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + - PCIE_SOC_WAKE_ADDRESS); - - ret = ath10k_pci_wait(ar); + ret = ath10k_do_pci_wake(ar); if (ret) { - ath10k_warn("Failed to reset target, target did not wake up: %d\n", - ret); + ath10k_err("failed to wake up target: %d\n", ret); return ret; } @@ -2288,31 +2260,26 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar) } if (wait_limit < 0) { - ath10k_err("Target stalled\n"); - iowrite32(PCIE_SOC_WAKE_RESET, - ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + - PCIE_SOC_WAKE_ADDRESS); - return -EIO; + ath10k_err("target stalled\n"); + ret = -EIO; + goto out; } - iowrite32(PCIE_SOC_WAKE_RESET, - ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + - PCIE_SOC_WAKE_ADDRESS); - - return 0; +out: + ath10k_do_pci_sleep(ar); + return ret; } -static void ath10k_pci_device_reset(struct ath10k *ar) +static int ath10k_pci_device_reset(struct ath10k *ar) { - int i; + int i, ret; u32 val; - ath10k_pci_reg_write32(ar, PCIE_SOC_WAKE_ADDRESS, - PCIE_SOC_WAKE_V_MASK); - for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) { - if (ath10k_pci_target_is_awake(ar)) - break; - msleep(1); + ret = ath10k_do_pci_wake(ar); + if (ret) { + ath10k_err("failed to wake up target: %d\n", + ret); + return ret; } /* Put Target, including PCIe, into RESET. */ @@ -2338,7 +2305,8 @@ static void ath10k_pci_device_reset(struct ath10k *ar) msleep(1); } - ath10k_pci_reg_write32(ar, PCIE_SOC_WAKE_ADDRESS, PCIE_SOC_WAKE_RESET); + ath10k_do_pci_sleep(ar); + return 0; } static void ath10k_pci_dump_features(struct ath10k_pci *ar_pci) -- cgit v1.2.3-70-g09d2 From 28642f428100fa602d08714d0005b6a5a4e47e9b Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 8 Nov 2013 08:01:31 +0100 Subject: ath10k: propagate ath10k_ce_disable_interrupts() errors This shouldn't be silenced. This will be necessary for PCI init code reordering. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.c | 7 +++++-- drivers/net/wireless/ath/ath10k/ce.h | 2 +- drivers/net/wireless/ath/ath10k/pci.c | 6 +++++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index 657e8f2ee98..ab22d14f456 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -792,13 +792,13 @@ static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state, ath10k_pci_sleep(ar); } -void ath10k_ce_disable_interrupts(struct ath10k *ar) +int ath10k_ce_disable_interrupts(struct ath10k *ar) { int ce_id, ret; ret = ath10k_pci_wake(ar); if (ret) - return; + return ret; for (ce_id = 0; ce_id < CE_COUNT; ce_id++) { u32 ctrl_addr = ath10k_ce_base_address(ce_id); @@ -807,7 +807,10 @@ void ath10k_ce_disable_interrupts(struct ath10k *ar) ath10k_ce_error_intr_disable(ar, ctrl_addr); ath10k_ce_watermark_intr_disable(ar, ctrl_addr); } + ath10k_pci_sleep(ar); + + return 0; } void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state, diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index 15d45b5b761..67dbde6a5c7 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -234,7 +234,7 @@ void ath10k_ce_deinit(struct ath10k_ce_pipe *ce_state); /*==================CE Interrupt Handlers====================*/ void ath10k_ce_per_engine_service_any(struct ath10k *ar); void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id); -void ath10k_ce_disable_interrupts(struct ath10k *ar); +int ath10k_ce_disable_interrupts(struct ath10k *ar); /* ce_attr.flags values */ /* Use NonSnooping PCIe accesses? */ diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 2b4f7d3969e..e41665f7eb8 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -879,8 +879,12 @@ static void ath10k_pci_stop_ce(struct ath10k *ar) struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_pci_compl *compl; struct sk_buff *skb; + int ret; + + ret = ath10k_ce_disable_interrupts(ar); + if (ret) + ath10k_warn("failed to disable CE interrupts: %d\n", ret); - ath10k_ce_disable_interrupts(ar); ath10k_pci_kill_tasklet(ar); /* Mark pending completions as aborted, so that upper layers free up -- cgit v1.2.3-70-g09d2 From 2415fc16391af204170f5478072fb1a2c66b87f3 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 8 Nov 2013 08:01:32 +0100 Subject: ath10k: guard against CE corruption from firmware In case firmware crashes it may report CE completions for entries that were never submitted/filled with meaningful data. This in turn led to NULL dereferences. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htc.c | 5 +++++ drivers/net/wireless/ath/ath10k/pci.c | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index 3118d750673..6d7a72eb11a 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -191,6 +191,11 @@ static int ath10k_htc_tx_completion_handler(struct ath10k *ar, struct ath10k_htc *htc = &ar->htc; struct ath10k_htc_ep *ep = &htc->endpoint[eid]; + if (!skb) { + ath10k_warn("invalid sk_buff completion - NULL pointer. firmware crashed?\n"); + return 0; + } + ath10k_htc_notify_tx_completion(ep, skb); /* the skb now belongs to the completion handler */ diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index e41665f7eb8..0b897269f12 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -1270,6 +1270,13 @@ static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info) * Indicate the completion to higer layer to free * the buffer */ + + if (!netbuf) { + ath10k_warn("invalid sk_buff on CE %d - NULL pointer. firmware crashed?\n", + ce_hdl->id); + continue; + } + ATH10K_SKB_CB(netbuf)->is_aborted = true; ar_pci->msg_callbacks_current.tx_completion(ar, netbuf, -- cgit v1.2.3-70-g09d2 From 98563d5aafa45498f8c2f6885b2bd03eab648f19 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 8 Nov 2013 08:01:33 +0100 Subject: ath10k: re-arrange PCI init code This patch moves irq registering after necessary structures have been allocated and initialized. This should prevent interrupts from causing tasklet access invalid memory pointers. Reported-By: Ben Greear Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.c | 19 ++++++-- drivers/net/wireless/ath/ath10k/ce.h | 1 + drivers/net/wireless/ath/ath10k/pci.c | 87 ++++++++++++++++++++++------------- 3 files changed, 71 insertions(+), 36 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index ab22d14f456..476928f2dad 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -792,6 +792,21 @@ static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state, ath10k_pci_sleep(ar); } +int ath10k_ce_enable_err_irq(struct ath10k *ar) +{ + int i, ret; + + ret = ath10k_pci_wake(ar); + if (ret) + return ret; + + for (i = 0; i < CE_COUNT; i++) + ath10k_ce_error_intr_enable(ar, ath10k_ce_base_address(i)); + + ath10k_pci_sleep(ar); + return 0; +} + int ath10k_ce_disable_interrupts(struct ath10k *ar) { int ce_id, ret; @@ -1059,7 +1074,6 @@ struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar, const struct ce_attr *attr) { struct ath10k_ce_pipe *ce_state; - u32 ctrl_addr = ath10k_ce_base_address(ce_id); int ret; /* @@ -1105,9 +1119,6 @@ struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar, } } - /* Enable CE error interrupts */ - ath10k_ce_error_intr_enable(ar, ctrl_addr); - out: ath10k_pci_sleep(ar); return ce_state; diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index 67dbde6a5c7..8a58bac958a 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -235,6 +235,7 @@ void ath10k_ce_deinit(struct ath10k_ce_pipe *ce_state); void ath10k_ce_per_engine_service_any(struct ath10k *ar); void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id); int ath10k_ce_disable_interrupts(struct ath10k *ar); +int ath10k_ce_enable_err_irq(struct ath10k *ar); /* ce_attr.flags values */ /* Use NonSnooping PCIe accesses? */ diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 0b897269f12..e552770a9e6 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -1786,18 +1786,6 @@ static int ath10k_pci_ce_init(struct ath10k *ar) pipe_info->buf_sz = (size_t) (attr->src_sz_max); } - /* - * Initially, establish CE completion handlers for use with BMI. - * These are overwritten with generic handlers after we exit BMI phase. - */ - pipe_info = &ar_pci->pipe_info[BMI_CE_NUM_TO_TARG]; - ath10k_ce_send_cb_register(pipe_info->ce_hdl, - ath10k_pci_bmi_send_done, 0); - - pipe_info = &ar_pci->pipe_info[BMI_CE_NUM_TO_HOST]; - ath10k_ce_recv_cb_register(pipe_info->ce_hdl, - ath10k_pci_bmi_recv_data); - return 0; } @@ -1830,17 +1818,27 @@ static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar) ath10k_pci_sleep(ar); } +static void ath10k_pci_start_bmi(struct ath10k *ar) +{ + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct ath10k_pci_pipe *pipe; + + /* + * Initially, establish CE completion handlers for use with BMI. + * These are overwritten with generic handlers after we exit BMI phase. + */ + pipe = &ar_pci->pipe_info[BMI_CE_NUM_TO_TARG]; + ath10k_ce_send_cb_register(pipe->ce_hdl, ath10k_pci_bmi_send_done, 0); + + pipe = &ar_pci->pipe_info[BMI_CE_NUM_TO_HOST]; + ath10k_ce_recv_cb_register(pipe->ce_hdl, ath10k_pci_bmi_recv_data); +} + static int ath10k_pci_hif_power_up(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ret; - ret = ath10k_pci_start_intr(ar); - if (ret) { - ath10k_err("could not start interrupt handling (%d)\n", ret); - goto err; - } - /* * Bring the target up cleanly. * @@ -1854,13 +1852,9 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) ret = ath10k_pci_device_reset(ar); if (ret) { ath10k_err("failed to reset target: %d\n", ret); - goto err_irq; + goto err; } - ret = ath10k_pci_wait_for_target_init(ar); - if (ret) - goto err_irq; - if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features)) /* Force AWAKE forever */ ath10k_do_pci_wake(ar); @@ -1869,25 +1863,54 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) if (ret) goto err_ps; - ret = ath10k_pci_init_config(ar); - if (ret) + ret = ath10k_ce_disable_interrupts(ar); + if (ret) { + ath10k_err("failed to disable CE interrupts: %d\n", ret); + goto err_ce; + } + + ret = ath10k_pci_start_intr(ar); + if (ret) { + ath10k_err("failed to start interrupt handling: %d\n", ret); goto err_ce; + } + + ret = ath10k_pci_wait_for_target_init(ar); + if (ret) { + ath10k_err("failed to wait for target to init: %d\n", ret); + goto err_irq; + } + + ret = ath10k_ce_enable_err_irq(ar); + if (ret) { + ath10k_err("failed to enable CE error irq: %d\n", ret); + goto err_irq; + } + + ret = ath10k_pci_init_config(ar); + if (ret) { + ath10k_err("failed to setup init config: %d\n", ret); + goto err_irq; + } ret = ath10k_pci_wake_target_cpu(ar); if (ret) { ath10k_err("could not wake up target CPU (%d)\n", ret); - goto err_ce; + goto err_irq; } + ath10k_pci_start_bmi(ar); return 0; +err_irq: + ath10k_ce_disable_interrupts(ar); + ath10k_pci_stop_intr(ar); + ath10k_pci_kill_tasklet(ar); err_ce: ath10k_pci_ce_deinit(ar); err_ps: if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features)) ath10k_do_pci_sleep(ar); -err_irq: - ath10k_pci_stop_intr(ar); err: return ret; } @@ -2156,7 +2179,7 @@ static int ath10k_pci_start_intr_legacy(struct ath10k *ar) if (ret < 0) return ret; - ret = ath10k_do_pci_wake(ar); + ret = ath10k_pci_wake(ar); if (ret) { free_irq(ar_pci->pdev->irq, ar); ath10k_err("failed to wake up target: %d\n", ret); @@ -2176,7 +2199,7 @@ static int ath10k_pci_start_intr_legacy(struct ath10k *ar) ar_pci->mem + (SOC_CORE_BASE_ADDRESS | PCIE_INTR_ENABLE_ADDRESS)); - ath10k_do_pci_sleep(ar); + ath10k_pci_sleep(ar); ath10k_info("legacy interrupt handling\n"); return 0; } @@ -2252,7 +2275,7 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar) int wait_limit = 300; /* 3 sec */ int ret; - ret = ath10k_do_pci_wake(ar); + ret = ath10k_pci_wake(ar); if (ret) { ath10k_err("failed to wake up target: %d\n", ret); return ret; @@ -2277,7 +2300,7 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar) } out: - ath10k_do_pci_sleep(ar); + ath10k_pci_sleep(ar); return ret; } -- cgit v1.2.3-70-g09d2 From 1d2b48d6174efb216012ec7cae7ddc653871543f Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 8 Nov 2013 08:01:34 +0100 Subject: ath10k: add and fix some PCI prints Add missing error reporting and adjust other prints to make everything more consistent. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 69 ++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 30 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index e552770a9e6..eaa99561dab 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -712,7 +712,7 @@ static int ath10k_pci_hif_send_head(struct ath10k *ar, u8 pipe_id, ret = ath10k_ce_send(ce_hdl, nbuf, skb_cb->paddr, len, transfer_id, flags); if (ret) - ath10k_warn("CE send failed: %p\n", nbuf); + ath10k_warn("failed to send sk_buff to CE: %p\n", nbuf); return ret; } @@ -739,9 +739,10 @@ static void ath10k_pci_hif_dump_area(struct ath10k *ar) ar->fw_version_build); host_addr = host_interest_item_address(HI_ITEM(hi_failure_state)); - if (ath10k_pci_diag_read_mem(ar, host_addr, - ®_dump_area, sizeof(u32)) != 0) { - ath10k_warn("could not read hi_failure_state\n"); + ret = ath10k_pci_diag_read_mem(ar, host_addr, + ®_dump_area, sizeof(u32)); + if (ret) { + ath10k_err("failed to read FW dump area address: %d\n", ret); return; } @@ -751,7 +752,7 @@ static void ath10k_pci_hif_dump_area(struct ath10k *ar) ®_dump_values[0], REG_DUMP_COUNT_QCA988X * sizeof(u32)); if (ret != 0) { - ath10k_err("could not dump FW Dump Area\n"); + ath10k_err("failed to read FW dump area: %d\n", ret); return; } @@ -973,8 +974,8 @@ static void ath10k_pci_process_ce(struct ath10k *ar) case ATH10K_PCI_COMPL_RECV: ret = ath10k_pci_post_rx_pipe(compl->pipe_info, 1); if (ret) { - ath10k_warn("Unable to post recv buffer for pipe: %d\n", - compl->pipe_info->pipe_num); + ath10k_warn("failed to post RX buffer for pipe %d: %d\n", + compl->pipe_info->pipe_num, ret); break; } @@ -1113,7 +1114,7 @@ static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info, for (i = 0; i < num; i++) { skb = dev_alloc_skb(pipe_info->buf_sz); if (!skb) { - ath10k_warn("could not allocate skbuff for pipe %d\n", + ath10k_warn("failed to allocate skbuff for pipe %d\n", num); ret = -ENOMEM; goto err; @@ -1126,7 +1127,7 @@ static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info, DMA_FROM_DEVICE); if (unlikely(dma_mapping_error(ar->dev, ce_data))) { - ath10k_warn("could not dma map skbuff\n"); + ath10k_warn("failed to DMA map sk_buff\n"); dev_kfree_skb_any(skb); ret = -EIO; goto err; @@ -1141,7 +1142,7 @@ static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info, ret = ath10k_ce_recv_buf_enqueue(ce_state, (void *)skb, ce_data); if (ret) { - ath10k_warn("could not enqueue to pipe %d (%d)\n", + ath10k_warn("failed to enqueue to pipe %d: %d\n", num, ret); goto err; } @@ -1171,8 +1172,8 @@ static int ath10k_pci_post_rx(struct ath10k *ar) ret = ath10k_pci_post_rx_pipe(pipe_info, attr->dest_nentries - 1); if (ret) { - ath10k_warn("Unable to replenish recv buffers for pipe: %d\n", - pipe_num); + ath10k_warn("failed to post RX buffer for pipe %d: %d\n", + pipe_num, ret); for (; pipe_num >= 0; pipe_num--) { pipe_info = &ar_pci->pipe_info[pipe_num]; @@ -1192,14 +1193,15 @@ static int ath10k_pci_hif_start(struct ath10k *ar) ret = ath10k_pci_start_ce(ar); if (ret) { - ath10k_warn("could not start CE (%d)\n", ret); + ath10k_warn("failed to start CE: %d\n", ret); return ret; } /* Post buffers once to start things off. */ ret = ath10k_pci_post_rx(ar); if (ret) { - ath10k_warn("could not post rx pipes (%d)\n", ret); + ath10k_warn("failed to post RX buffers for all pipes: %d\n", + ret); return ret; } @@ -1593,7 +1595,7 @@ static int ath10k_pci_wake_target_cpu(struct ath10k *ar) CORE_CTRL_ADDRESS, &core_ctrl); if (ret) { - ath10k_warn("Unable to read core ctrl\n"); + ath10k_warn("failed to read core_ctrl: %d\n", ret); return ret; } @@ -1603,10 +1605,13 @@ static int ath10k_pci_wake_target_cpu(struct ath10k *ar) ret = ath10k_pci_diag_write_access(ar, SOC_CORE_BASE_ADDRESS | CORE_CTRL_ADDRESS, core_ctrl); - if (ret) - ath10k_warn("Unable to set interrupt mask\n"); + if (ret) { + ath10k_warn("failed to set target CPU interrupt mask: %d\n", + ret); + return ret; + } - return ret; + return 0; } static int ath10k_pci_init_config(struct ath10k *ar) @@ -1765,7 +1770,7 @@ static int ath10k_pci_ce_init(struct ath10k *ar) pipe_info->ce_hdl = ath10k_ce_init(ar, pipe_num, attr); if (pipe_info->ce_hdl == NULL) { - ath10k_err("Unable to initialize CE for pipe: %d\n", + ath10k_err("failed to initialize CE for pipe: %d\n", pipe_num); /* It is safe to call it here. It checks if ce_hdl is @@ -1832,6 +1837,8 @@ static void ath10k_pci_start_bmi(struct ath10k *ar) pipe = &ar_pci->pipe_info[BMI_CE_NUM_TO_HOST]; ath10k_ce_recv_cb_register(pipe->ce_hdl, ath10k_pci_bmi_recv_data); + + ath10k_dbg(ATH10K_DBG_BOOT, "boot start bmi\n"); } static int ath10k_pci_hif_power_up(struct ath10k *ar) @@ -1860,8 +1867,10 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) ath10k_do_pci_wake(ar); ret = ath10k_pci_ce_init(ar); - if (ret) + if (ret) { + ath10k_err("failed to initialize CE: %d\n", ret); goto err_ps; + } ret = ath10k_ce_disable_interrupts(ar); if (ret) { @@ -1895,7 +1904,7 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) ret = ath10k_pci_wake_target_cpu(ar); if (ret) { - ath10k_err("could not wake up target CPU (%d)\n", ret); + ath10k_err("could not wake up target CPU: %d\n", ret); goto err_irq; } @@ -2397,7 +2406,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ar = ath10k_core_create(ar_pci, ar_pci->dev, &ath10k_pci_hif_ops); if (!ar) { - ath10k_err("ath10k_core_create failed!\n"); + ath10k_err("failed to create driver core\n"); ret = -EINVAL; goto err_ar_pci; } @@ -2416,20 +2425,20 @@ static int ath10k_pci_probe(struct pci_dev *pdev, */ ret = pci_assign_resource(pdev, BAR_NUM); if (ret) { - ath10k_err("cannot assign PCI space: %d\n", ret); + ath10k_err("failed to assign PCI space: %d\n", ret); goto err_ar; } ret = pci_enable_device(pdev); if (ret) { - ath10k_err("cannot enable PCI device: %d\n", ret); + ath10k_err("failed to enable PCI device: %d\n", ret); goto err_ar; } /* Request MMIO resources */ ret = pci_request_region(pdev, BAR_NUM, "ath"); if (ret) { - ath10k_err("PCI MMIO reservation error: %d\n", ret); + ath10k_err("failed to request MMIO region: %d\n", ret); goto err_device; } @@ -2439,13 +2448,13 @@ static int ath10k_pci_probe(struct pci_dev *pdev, */ ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (ret) { - ath10k_err("32-bit DMA not available: %d\n", ret); + ath10k_err("failed to set DMA mask to 32-bit: %d\n", ret); goto err_region; } ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); if (ret) { - ath10k_err("cannot enable 32-bit consistent DMA\n"); + ath10k_err("failed to set consistent DMA mask to 32-bit\n"); goto err_region; } @@ -2462,7 +2471,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, /* Arrange for access to Target SoC registers. */ mem = pci_iomap(pdev, BAR_NUM, 0); if (!mem) { - ath10k_err("PCI iomap error\n"); + ath10k_err("failed to perform IOMAP for BAR%d\n", BAR_NUM); ret = -EIO; goto err_master; } @@ -2485,7 +2494,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ret = ath10k_core_register(ar, chip_id); if (ret) { - ath10k_err("could not register driver core (%d)\n", ret); + ath10k_err("failed to register driver core: %d\n", ret); goto err_iomap; } @@ -2551,7 +2560,7 @@ static int __init ath10k_pci_init(void) ret = pci_register_driver(&ath10k_pci_driver); if (ret) - ath10k_err("pci_register_driver failed [%d]\n", ret); + ath10k_err("failed to register PCI driver: %d\n", ret); return ret; } -- cgit v1.2.3-70-g09d2 From 6a42a47e23acdcbc97aac925b5a14d1b187606cf Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 8 Nov 2013 08:01:35 +0100 Subject: ath10k: reset device upon stopping/power down This should make sure the device won't issue any interrupts nor access any memory after the driver is stopped/freed thus avoid memory corruption in some cases. Reported-By: Ben Greear Reported-By: Janusz Dziedzic Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index eaa99561dab..46c94ce58f9 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -1353,6 +1353,13 @@ static void ath10k_pci_hif_stop(struct ath10k *ar) ath10k_pci_cleanup_ce(ar); ath10k_pci_buffer_cleanup(ar); + /* Make the sure the device won't access any structures on the host by + * resetting it. The device was fed with PCI CE ringbuffer + * configuration during init. If ringbuffers are freed and the device + * were to access them this could lead to memory corruption on the + * host. */ + ath10k_pci_device_reset(ar); + ar_pci->started = 0; } @@ -1915,6 +1922,7 @@ err_irq: ath10k_ce_disable_interrupts(ar); ath10k_pci_stop_intr(ar); ath10k_pci_kill_tasklet(ar); + ath10k_pci_device_reset(ar); err_ce: ath10k_pci_ce_deinit(ar); err_ps: @@ -1929,6 +1937,7 @@ static void ath10k_pci_hif_power_down(struct ath10k *ar) struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); ath10k_pci_stop_intr(ar); + ath10k_pci_device_reset(ar); ath10k_pci_ce_deinit(ar); if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features)) -- cgit v1.2.3-70-g09d2 From 67e3c63fef6041f41e22335852de9d3924cff7a1 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 8 Nov 2013 08:05:18 +0100 Subject: ath10k: fix core init failpath HIF was not stopped properly in ath10k_core_start() upon failure. This could cause memory leaks of CE completions entries and possibly other issues as well. Move the HIF start/stop out of ath10k_htc_wait_target(). The ctl_resp completion is already prepared in ath10k_htc_init. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 16 +++++++++++++--- drivers/net/wireless/ath/ath10k/htc.c | 26 +++++--------------------- 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 7d868769436..be5b17e8990 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -785,14 +785,22 @@ int ath10k_core_start(struct ath10k *ar) goto err; } - status = ath10k_htc_wait_target(&ar->htc); - if (status) + status = ath10k_hif_start(ar); + if (status) { + ath10k_err("could not start HIF: %d\n", status); goto err_wmi_detach; + } + + status = ath10k_htc_wait_target(&ar->htc); + if (status) { + ath10k_err("failed to connect to HTC: %d\n", status); + goto err_hif_stop; + } status = ath10k_htt_attach(ar); if (status) { ath10k_err("could not attach htt (%d)\n", status); - goto err_wmi_detach; + goto err_hif_stop; } status = ath10k_init_connect_htc(ar); @@ -831,6 +839,8 @@ err_disconnect_htc: ath10k_htc_stop(&ar->htc); err_htt_detach: ath10k_htt_detach(&ar->htt); +err_hif_stop: + ath10k_hif_stop(ar); err_wmi_detach: ath10k_wmi_detach(ar); err: diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index 6d7a72eb11a..b068ae04cf6 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -539,14 +539,6 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc) u16 credit_count; u16 credit_size; - INIT_COMPLETION(htc->ctl_resp); - - status = ath10k_hif_start(htc->ar); - if (status) { - ath10k_err("could not start HIF (%d)\n", status); - goto err_start; - } - status = wait_for_completion_timeout(&htc->ctl_resp, ATH10K_HTC_WAIT_TIMEOUT_HZ); if (status <= 0) { @@ -554,15 +546,13 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc) status = -ETIMEDOUT; ath10k_err("ctl_resp never came in (%d)\n", status); - goto err_target; + return status; } if (htc->control_resp_len < sizeof(msg->hdr) + sizeof(msg->ready)) { ath10k_err("Invalid HTC ready msg len:%d\n", htc->control_resp_len); - - status = -ECOMM; - goto err_target; + return -ECOMM; } msg = (struct ath10k_htc_msg *)htc->control_resp_buffer; @@ -572,8 +562,7 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc) if (message_id != ATH10K_HTC_MSG_READY_ID) { ath10k_err("Invalid HTC ready msg: 0x%x\n", message_id); - status = -ECOMM; - goto err_target; + return -ECOMM; } htc->total_transmit_credits = credit_count; @@ -586,9 +575,8 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc) if ((htc->total_transmit_credits == 0) || (htc->target_credit_size == 0)) { - status = -ECOMM; ath10k_err("Invalid credit size received\n"); - goto err_target; + return -ECOMM; } ath10k_htc_setup_target_buffer_assignments(htc); @@ -605,14 +593,10 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc) status = ath10k_htc_connect_service(htc, &conn_req, &conn_resp); if (status) { ath10k_err("could not connect to htc service (%d)\n", status); - goto err_target; + return status; } return 0; -err_target: - ath10k_hif_stop(htc->ar); -err_start: - return status; } int ath10k_htc_connect_service(struct ath10k_htc *htc, -- cgit v1.2.3-70-g09d2 From c4dd0d01da8979bd5c7f4367661115617bc389ea Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 13 Nov 2013 11:05:10 +0100 Subject: ath10k: allow dynamic bandwidth in hw rate control Frames were never retransmitted with different/lower bandwidths, e.g. only 80MHz bandwidth was used when dealing with a VHT80 peer. Allow HW rate control to try out different bandwidths when retransmitting. This increases robustness. Also, document the parameter properly. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 2 +- drivers/net/wireless/ath/ath10k/wmi.h | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 56f030ed357..db819429134 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1964,7 +1964,7 @@ static int ath10k_start(struct ieee80211_hw *hw) ath10k_warn("could not enable WMI_PDEV_PARAM_PMF_QOS (%d)\n", ret); - ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->dynamic_bw, 0); + ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->dynamic_bw, 1); if (ret) ath10k_warn("could not init WMI_PDEV_PARAM_DYNAMIC_BW (%d)\n", ret); diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 81e33a7dbaf..8b824f9c2f1 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -2234,7 +2234,12 @@ enum wmi_pdev_param { * 0: no protection 1:use CTS-to-self 2: use RTS/CTS */ WMI_PDEV_PARAM_PROTECTION_MODE, - /* Dynamic bandwidth 0: disable 1: enable */ + /* + * Dynamic bandwidth - 0: disable, 1: enable + * + * When enabled HW rate control tries different bandwidths when + * retransmitting frames. + */ WMI_PDEV_PARAM_DYNAMIC_BW, /* Non aggregrate/ 11g sw retry threshold.0-disable */ WMI_PDEV_PARAM_NON_AGG_SW_RETRY_TH, -- cgit v1.2.3-70-g09d2 From 652de35e86da3e206fbfa40bca254b028b6403b6 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Wed, 13 Nov 2013 15:23:30 +0200 Subject: ath10k: remove htt rx amsdu clear retry bit hack With commit 0cfcefef1 ("mac80211: support reporting A-MSDU subframes individually") there's no need to have the hack to clear the retry bit in ath10k_htt_rx_amsdu(), mac80211 can handle this properly now. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt.h | 1 + drivers/net/wireless/ath/ath10k/htt_rx.c | 20 +++----------------- drivers/net/wireless/ath/ath10k/txrx.c | 3 +++ 3 files changed, 7 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 1a337e93b7e..7fc7919ea5f 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -1182,6 +1182,7 @@ struct htt_rx_info { u32 info2; } rate; bool fcs_err; + bool amsdu_more; }; struct ath10k_htt { diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 90d4f74c28d..0335218ad57 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -659,23 +659,6 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt, memcpy(hdr_buf, hdr, hdr_len); hdr = (struct ieee80211_hdr *)hdr_buf; - /* FIXME: Hopefully this is a temporary measure. - * - * Reporting individual A-MSDU subframes means each reported frame - * shares the same sequence number. - * - * mac80211 drops frames it recognizes as duplicates, i.e. - * retransmission flag is set and sequence number matches sequence - * number from a previous frame (as per IEEE 802.11-2012: 9.3.2.10 - * "Duplicate detection and recovery") - * - * To avoid frames being dropped clear retransmission flag for all - * received A-MSDUs. - * - * Worst case: actual duplicate frames will be reported but this should - * still be handled gracefully by other OSI/ISO layers. */ - hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_RETRY); - first = skb; while (skb) { void *decap_hdr; @@ -746,6 +729,9 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt, skb = skb->next; info->skb->next = NULL; + if (skb) + info->amsdu_more = true; + ath10k_process_rx(htt->ar, info); } diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index c511f919d54..df279a31e18 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -236,6 +236,9 @@ void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info) if (info->fcs_err) status->flag |= RX_FLAG_FAILED_FCS_CRC; + if (info->amsdu_more) + status->flag |= RX_FLAG_AMSDU_MORE; + status->signal = info->signal; spin_lock_bh(&ar->data_lock); -- cgit v1.2.3-70-g09d2 From 71098615730f01cd5e70c7777b691572ee2bafb0 Mon Sep 17 00:00:00 2001 From: Bartosz Markowski Date: Thu, 14 Nov 2013 09:01:15 +0100 Subject: ath10k: expand the wmi mgmt queue limit to 128 It was obseverd many times the short queue limit can be easily exceeded in case of AP multiple BSSID scenarios. "ath10k: wmi mgmt_tx queue limit reached." This was leading to TX packets drops. This patch expands the queue limit to 128. After many stress experiments (high traffic and lot of management frames in the air) the new value seems to fix the problem on platforms with limited resources. Reported-By: Tomasz Skapski Signed-off-by: Bartosz Markowski Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 0934f7633de..be35df2902c 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -43,7 +43,7 @@ /* Antenna noise floor */ #define ATH10K_DEFAULT_NOISE_FLOOR -95 -#define ATH10K_MAX_NUM_MGMT_PENDING 16 +#define ATH10K_MAX_NUM_MGMT_PENDING 128 struct ath10k; -- cgit v1.2.3-70-g09d2 From 5d04e4120a6ef2eac3a3a80bda6a16bb90f2da2c Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 14 Nov 2013 10:34:18 +0100 Subject: ath10k: clear tx status before submitting to mac80211 Garbage was reported in ieee80211_tx_info. This led to a WARN_ON in cfg80211_calculate_bitrate(). This also fixes some random tx bitrate values reported through `iw` command. Reported-By: Kalle Valo Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/txrx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index df279a31e18..d476b2cc9d7 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -75,6 +75,7 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, ath10k_report_offchan_tx(htt->ar, msdu); info = IEEE80211_SKB_CB(msdu); + memset(info, 0, sizeof(*info)); if (tx_done->discard) { ieee80211_free_txskb(htt->ar->hw, msdu); -- cgit v1.2.3-70-g09d2 From e1bd1dc207dae92cdb5b424226f89d1b4e4bb182 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 14 Nov 2013 01:05:58 +0000 Subject: net_tstamp: Improve kernel-doc for struct hwtstamp_config Fix the name of the rx_filter field. Remove text about 32/64-bit compatibility; this works just the same as for most socket ioctls and as the structure is not allowed to grow there is no need to remind anyone how to maintain it. Add explanation about drivers changing the filter mode. Signed-off-by: Ben Hutchings --- include/uapi/linux/net_tstamp.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/uapi/linux/net_tstamp.h b/include/uapi/linux/net_tstamp.h index ae5df122e42..c9a7de2a627 100644 --- a/include/uapi/linux/net_tstamp.h +++ b/include/uapi/linux/net_tstamp.h @@ -30,13 +30,13 @@ enum { * * @flags: no flags defined right now, must be zero * @tx_type: one of HWTSTAMP_TX_* - * @rx_type: one of one of HWTSTAMP_FILTER_* + * @rx_filter: one of HWTSTAMP_FILTER_* * * %SIOCSHWTSTAMP expects a &struct ifreq with a ifr_data pointer to - * this structure. dev_ifsioc() in the kernel takes care of the - * translation between 32 bit userspace and 64 bit kernel. The - * structure is intentionally chosen so that it has the same layout on - * 32 and 64 bit systems, don't break this! + * this structure. If the driver or hardware does not support the + * requested @rx_filter value, the driver may use a more general + * filter mode. In this case @rx_filter will indicate the actual mode + * on return. */ struct hwtstamp_config { int flags; -- cgit v1.2.3-70-g09d2 From 417c3522b3202dacce4873cfb0190459fbce95c5 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 18 Nov 2013 17:04:58 +0000 Subject: net/compat: Fix minor information leak in siocdevprivate_ioctl() We don't need to check that ifr_data itself is a valid user pointer, but we should check &ifr_data is. Thankfully the copy of ifr_name is checked, so this can only leak a few bytes from immediately above the user address limit. Signed-off-by: Ben Hutchings --- net/socket.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/net/socket.c b/net/socket.c index c226aceee65..fbb6ec13b1f 100644 --- a/net/socket.c +++ b/net/socket.c @@ -3015,19 +3015,16 @@ static int siocdevprivate_ioctl(struct net *net, unsigned int cmd, if (copy_from_user(&tmp_buf[0], &(u_ifreq32->ifr_ifrn.ifrn_name[0]), IFNAMSIZ)) return -EFAULT; - if (__get_user(data32, &u_ifreq32->ifr_ifru.ifru_data)) + if (get_user(data32, &u_ifreq32->ifr_ifru.ifru_data)) return -EFAULT; data64 = compat_ptr(data32); u_ifreq64 = compat_alloc_user_space(sizeof(*u_ifreq64)); - /* Don't check these user accesses, just let that get trapped - * in the ioctl handler instead. - */ if (copy_to_user(&u_ifreq64->ifr_ifrn.ifrn_name[0], &tmp_buf[0], IFNAMSIZ)) return -EFAULT; - if (__put_user(data64, &u_ifreq64->ifr_ifru.ifru_data)) + if (put_user(data64, &u_ifreq64->ifr_ifru.ifru_data)) return -EFAULT; return dev_ioctl(net, cmd, u_ifreq64); -- cgit v1.2.3-70-g09d2 From 590d4693fb1c96ce441d11c6d1acb413a90b62e5 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 18 Nov 2013 17:04:13 +0000 Subject: net/compat: Merge multiple implementations of ifreq::ifr_data conversion Signed-off-by: Ben Hutchings --- net/socket.c | 49 ++++++------------------------------------------- 1 file changed, 6 insertions(+), 43 deletions(-) diff --git a/net/socket.c b/net/socket.c index fbb6ec13b1f..7a766ab83ca 100644 --- a/net/socket.c +++ b/net/socket.c @@ -2964,11 +2964,8 @@ static int bond_ioctl(struct net *net, unsigned int cmd, struct compat_ifreq __user *ifr32) { struct ifreq kifr; - struct ifreq __user *uifr; mm_segment_t old_fs; int err; - u32 data; - void __user *datap; switch (cmd) { case SIOCBONDENSLAVE: @@ -2985,26 +2982,13 @@ static int bond_ioctl(struct net *net, unsigned int cmd, set_fs(old_fs); return err; - case SIOCBONDSLAVEINFOQUERY: - case SIOCBONDINFOQUERY: - uifr = compat_alloc_user_space(sizeof(*uifr)); - if (copy_in_user(&uifr->ifr_name, &ifr32->ifr_name, IFNAMSIZ)) - return -EFAULT; - - if (get_user(data, &ifr32->ifr_ifru.ifru_data)) - return -EFAULT; - - datap = compat_ptr(data); - if (put_user(datap, &uifr->ifr_ifru.ifru_data)) - return -EFAULT; - - return dev_ioctl(net, cmd, uifr); default: return -ENOIOCTLCMD; } } -static int siocdevprivate_ioctl(struct net *net, unsigned int cmd, +/* Handle ioctls that use ifreq::ifr_data and just need struct ifreq converted */ +static int compat_ifr_data_ioctl(struct net *net, unsigned int cmd, struct compat_ifreq __user *u_ifreq32) { struct ifreq __user *u_ifreq64; @@ -3104,27 +3088,6 @@ static int compat_sioc_ifmap(struct net *net, unsigned int cmd, return err; } -static int compat_siocshwtstamp(struct net *net, struct compat_ifreq __user *uifr32) -{ - void __user *uptr; - compat_uptr_t uptr32; - struct ifreq __user *uifr; - - uifr = compat_alloc_user_space(sizeof(*uifr)); - if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq))) - return -EFAULT; - - if (get_user(uptr32, &uifr32->ifr_data)) - return -EFAULT; - - uptr = compat_ptr(uptr32); - - if (put_user(uptr, &uifr->ifr_data)) - return -EFAULT; - - return dev_ioctl(net, SIOCSHWTSTAMP, uifr); -} - struct rtentry32 { u32 rt_pad1; struct sockaddr rt_dst; /* target address */ @@ -3236,7 +3199,7 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, struct net *net = sock_net(sk); if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) - return siocdevprivate_ioctl(net, cmd, argp); + return compat_ifr_data_ioctl(net, cmd, argp); switch (cmd) { case SIOCSIFBR: @@ -3256,8 +3219,6 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, case SIOCBONDENSLAVE: case SIOCBONDRELEASE: case SIOCBONDSETHWADDR: - case SIOCBONDSLAVEINFOQUERY: - case SIOCBONDINFOQUERY: case SIOCBONDCHANGEACTIVE: return bond_ioctl(net, cmd, argp); case SIOCADDRT: @@ -3267,8 +3228,10 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, return do_siocgstamp(net, sock, cmd, argp); case SIOCGSTAMPNS: return do_siocgstampns(net, sock, cmd, argp); + case SIOCBONDSLAVEINFOQUERY: + case SIOCBONDINFOQUERY: case SIOCSHWTSTAMP: - return compat_siocshwtstamp(net, argp); + return compat_ifr_data_ioctl(net, cmd, argp); case FIOSETOWN: case SIOCSPGRP: -- cgit v1.2.3-70-g09d2 From fd468c74bd4d6949736810a80d6ca05eb20fba84 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 14 Nov 2013 01:19:29 +0000 Subject: net_tstamp: Add SIOCGHWTSTAMP ioctl to match SIOCSHWTSTAMP SIOCSHWTSTAMP returns the real configuration to the application using it, but there is currently no way for any other application to find out the configuration non-destructively. Add a new ioctl for this, making it unprivileged. Signed-off-by: Ben Hutchings --- Documentation/networking/timestamping.txt | 9 +++++++-- include/uapi/linux/net_tstamp.h | 14 +++++++------- include/uapi/linux/sockios.h | 3 ++- net/core/dev_ioctl.c | 2 ++ net/socket.c | 1 + 5 files changed, 19 insertions(+), 10 deletions(-) diff --git a/Documentation/networking/timestamping.txt b/Documentation/networking/timestamping.txt index 98097d8cb91..661d3c316a1 100644 --- a/Documentation/networking/timestamping.txt +++ b/Documentation/networking/timestamping.txt @@ -85,7 +85,7 @@ Filled in if SOF_TIMESTAMPING_SYS_HARDWARE is set. Requires support by the network device and will be empty without that support. -SIOCSHWTSTAMP: +SIOCSHWTSTAMP, SIOCGHWTSTAMP: Hardware time stamping must also be initialized for each device driver that is expected to do hardware time stamping. The parameter is defined in @@ -115,6 +115,10 @@ Only a processes with admin rights may change the configuration. User space is responsible to ensure that multiple processes don't interfere with each other and that the settings are reset. +Any process can read the actual configuration by passing this +structure to ioctl(SIOCGHWTSTAMP) in the same way. However, this has +not been implemented in all drivers. + /* possible values for hwtstamp_config->tx_type */ enum { /* @@ -157,7 +161,8 @@ DEVICE IMPLEMENTATION A driver which supports hardware time stamping must support the SIOCSHWTSTAMP ioctl and update the supplied struct hwtstamp_config with -the actual values as described in the section on SIOCSHWTSTAMP. +the actual values as described in the section on SIOCSHWTSTAMP. It +should also support SIOCGHWTSTAMP. Time stamps for received packets must be stored in the skb. To get a pointer to the shared time stamp structure of the skb call skb_hwtstamps(). Then diff --git a/include/uapi/linux/net_tstamp.h b/include/uapi/linux/net_tstamp.h index c9a7de2a627..f53879c0f59 100644 --- a/include/uapi/linux/net_tstamp.h +++ b/include/uapi/linux/net_tstamp.h @@ -26,17 +26,17 @@ enum { }; /** - * struct hwtstamp_config - %SIOCSHWTSTAMP parameter + * struct hwtstamp_config - %SIOCGHWTSTAMP and %SIOCSHWTSTAMP parameter * - * @flags: no flags defined right now, must be zero + * @flags: no flags defined right now, must be zero for %SIOCSHWTSTAMP * @tx_type: one of HWTSTAMP_TX_* * @rx_filter: one of HWTSTAMP_FILTER_* * - * %SIOCSHWTSTAMP expects a &struct ifreq with a ifr_data pointer to - * this structure. If the driver or hardware does not support the - * requested @rx_filter value, the driver may use a more general - * filter mode. In this case @rx_filter will indicate the actual mode - * on return. + * %SIOCGHWTSTAMP and %SIOCSHWTSTAMP expect a &struct ifreq with a + * ifr_data pointer to this structure. For %SIOCSHWTSTAMP, if the + * driver or hardware does not support the requested @rx_filter value, + * the driver may use a more general filter mode. In this case + * @rx_filter will indicate the actual mode on return. */ struct hwtstamp_config { int flags; diff --git a/include/uapi/linux/sockios.h b/include/uapi/linux/sockios.h index 7997a506ad4..e888b1aed69 100644 --- a/include/uapi/linux/sockios.h +++ b/include/uapi/linux/sockios.h @@ -125,7 +125,8 @@ #define SIOCBRDELIF 0x89a3 /* remove interface from bridge */ /* hardware time stamping: parameters in linux/net_tstamp.h */ -#define SIOCSHWTSTAMP 0x89b0 +#define SIOCSHWTSTAMP 0x89b0 /* set and get config */ +#define SIOCGHWTSTAMP 0x89b1 /* get config */ /* Device private ioctl calls */ diff --git a/net/core/dev_ioctl.c b/net/core/dev_ioctl.c index 5b7d0e1d066..cf999e09bcd 100644 --- a/net/core/dev_ioctl.c +++ b/net/core/dev_ioctl.c @@ -327,6 +327,7 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd) cmd == SIOCBRADDIF || cmd == SIOCBRDELIF || cmd == SIOCSHWTSTAMP || + cmd == SIOCGHWTSTAMP || cmd == SIOCWANDEV) { err = -EOPNOTSUPP; if (ops->ndo_do_ioctl) { @@ -546,6 +547,7 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg) */ default: if (cmd == SIOCWANDEV || + cmd == SIOCGHWTSTAMP || (cmd >= SIOCDEVPRIVATE && cmd <= SIOCDEVPRIVATE + 15)) { dev_load(net, ifr.ifr_name); diff --git a/net/socket.c b/net/socket.c index 7a766ab83ca..1a548b70ef3 100644 --- a/net/socket.c +++ b/net/socket.c @@ -3231,6 +3231,7 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, case SIOCBONDSLAVEINFOQUERY: case SIOCBONDINFOQUERY: case SIOCSHWTSTAMP: + case SIOCGHWTSTAMP: return compat_ifr_data_ioctl(net, cmd, argp); case FIOSETOWN: -- cgit v1.2.3-70-g09d2 From 433dc9b3d123e72a0f5988c1f0d1c9319a735276 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 14 Nov 2013 01:26:21 +0000 Subject: sfc: Implement the SIOCGHWTSTAMP ioctl Signed-off-by: Ben Hutchings --- drivers/net/ethernet/sfc/efx.c | 4 +++- drivers/net/ethernet/sfc/nic.h | 3 ++- drivers/net/ethernet/sfc/ptp.c | 11 ++++++++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 07c9bc4c61b..22ca5cd3f72 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -1857,7 +1857,9 @@ static int efx_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd) struct mii_ioctl_data *data = if_mii(ifr); if (cmd == SIOCSHWTSTAMP) - return efx_ptp_ioctl(efx, ifr, cmd); + return efx_ptp_set_ts_config(efx, ifr); + if (cmd == SIOCGHWTSTAMP) + return efx_ptp_get_ts_config(efx, ifr); /* Convert phy_id from older PRTAD/DEVAD format */ if ((cmd == SIOCGMIIREG || cmd == SIOCSMIIREG) && diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h index 11b6112d924..33852e824f1 100644 --- a/drivers/net/ethernet/sfc/nic.h +++ b/drivers/net/ethernet/sfc/nic.h @@ -555,7 +555,8 @@ int efx_sriov_set_vf_spoofchk(struct net_device *net_dev, int vf, struct ethtool_ts_info; void efx_ptp_probe(struct efx_nic *efx); -int efx_ptp_ioctl(struct efx_nic *efx, struct ifreq *ifr, int cmd); +int efx_ptp_set_ts_config(struct efx_nic *efx, struct ifreq *ifr); +int efx_ptp_get_ts_config(struct efx_nic *efx, struct ifreq *ifr); void efx_ptp_get_ts_info(struct efx_nic *efx, struct ethtool_ts_info *ts_info); bool efx_ptp_is_ptp_tx(struct efx_nic *efx, struct sk_buff *skb); int efx_ptp_tx(struct efx_nic *efx, struct sk_buff *skb); diff --git a/drivers/net/ethernet/sfc/ptp.c b/drivers/net/ethernet/sfc/ptp.c index 03acf57df04..afd4d3a5046 100644 --- a/drivers/net/ethernet/sfc/ptp.c +++ b/drivers/net/ethernet/sfc/ptp.c @@ -1231,7 +1231,7 @@ void efx_ptp_get_ts_info(struct efx_nic *efx, struct ethtool_ts_info *ts_info) 1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ); } -int efx_ptp_ioctl(struct efx_nic *efx, struct ifreq *ifr, int cmd) +int efx_ptp_set_ts_config(struct efx_nic *efx, struct ifreq *ifr) { struct hwtstamp_config config; int rc; @@ -1251,6 +1251,15 @@ int efx_ptp_ioctl(struct efx_nic *efx, struct ifreq *ifr, int cmd) ? -EFAULT : 0; } +int efx_ptp_get_ts_config(struct efx_nic *efx, struct ifreq *ifr) +{ + if (!efx->ptp_data) + return -EOPNOTSUPP; + + return copy_to_user(ifr->ifr_data, &efx->ptp_data->config, + sizeof(efx->ptp_data->config)) ? -EFAULT : 0; +} + static void ptp_event_failure(struct efx_nic *efx, int expected_frag_len) { struct efx_ptp_data *ptp = efx->ptp_data; -- cgit v1.2.3-70-g09d2 From 9702c686081240bff1f05150c78335152d37ac8d Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Wed, 20 Nov 2013 09:59:41 +0200 Subject: ath10k: add phyerr/dfs handling Handle phyerr, dfs event, radar_report and fft_report. Add also debugfs dfs_simulate_radar and dfs_stats files. Use ath dfs pattern detector. Signed-off-by: Janusz Dziedzic Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 13 ++ drivers/net/wireless/ath/ath10k/debug.c | 90 ++++++++++++ drivers/net/wireless/ath/ath10k/debug.h | 6 + drivers/net/wireless/ath/ath10k/mac.c | 24 ++++ drivers/net/wireless/ath/ath10k/wmi.c | 244 +++++++++++++++++++++++++++++++- drivers/net/wireless/ath/ath10k/wmi.h | 85 +++++++++++ 6 files changed, 461 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index be35df2902c..afbc7449b13 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -30,6 +30,7 @@ #include "wmi.h" #include "../ath.h" #include "../regd.h" +#include "../dfs_pattern_detector.h" #define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB) #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK) @@ -192,6 +193,14 @@ struct ath10k_target_stats { }; +struct ath10k_dfs_stats { + u32 phy_errors; + u32 pulses_total; + u32 pulses_detected; + u32 pulses_discarded; + u32 radar_detected; +}; + #define ATH10K_MAX_NUM_PEER_IDS (1 << 11) /* htt rx_desc limit */ struct ath10k_peer { @@ -261,6 +270,8 @@ struct ath10k_debug { unsigned long htt_stats_mask; struct delayed_work htt_stats_dwork; + struct ath10k_dfs_stats dfs_stats; + struct ath_dfs_pool_stats dfs_pool_stats; }; enum ath10k_state { @@ -428,6 +439,8 @@ struct ath10k { u32 survey_last_cycle_count; struct survey_info survey[ATH10K_NUM_CHANS]; + struct dfs_pattern_detector *dfs_detector; + #ifdef CONFIG_ATH10K_DEBUGFS struct ath10k_debug debug; #endif diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 760ff2289e3..13705d41795 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -639,6 +639,86 @@ void ath10k_debug_stop(struct ath10k *ar) cancel_delayed_work(&ar->debug.htt_stats_dwork); } +static ssize_t ath10k_write_simulate_radar(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath10k *ar = file->private_data; + + ieee80211_radar_detected(ar->hw); + + return count; +} + +static const struct file_operations fops_simulate_radar = { + .write = ath10k_write_simulate_radar, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +#define ATH10K_DFS_STAT(s, p) (\ + len += scnprintf(buf + len, size - len, "%-28s : %10u\n", s, \ + ar->debug.dfs_stats.p)) + +#define ATH10K_DFS_POOL_STAT(s, p) (\ + len += scnprintf(buf + len, size - len, "%-28s : %10u\n", s, \ + ar->debug.dfs_pool_stats.p)) + +static ssize_t ath10k_read_dfs_stats(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + int retval = 0, len = 0; + const int size = 8000; + struct ath10k *ar = file->private_data; + char *buf; + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + if (!ar->dfs_detector) { + len += scnprintf(buf + len, size - len, "DFS not enabled\n"); + goto exit; + } + + ar->debug.dfs_pool_stats = + ar->dfs_detector->get_stats(ar->dfs_detector); + + len += scnprintf(buf + len, size - len, "Pulse detector statistics:\n"); + + ATH10K_DFS_STAT("reported phy errors", phy_errors); + ATH10K_DFS_STAT("pulse events reported", pulses_total); + ATH10K_DFS_STAT("DFS pulses detected", pulses_detected); + ATH10K_DFS_STAT("DFS pulses discarded", pulses_discarded); + ATH10K_DFS_STAT("Radars detected", radar_detected); + + len += scnprintf(buf + len, size - len, "Global Pool statistics:\n"); + ATH10K_DFS_POOL_STAT("Pool references", pool_reference); + ATH10K_DFS_POOL_STAT("Pulses allocated", pulse_allocated); + ATH10K_DFS_POOL_STAT("Pulses alloc error", pulse_alloc_error); + ATH10K_DFS_POOL_STAT("Pulses in use", pulse_used); + ATH10K_DFS_POOL_STAT("Seqs. allocated", pseq_allocated); + ATH10K_DFS_POOL_STAT("Seqs. alloc error", pseq_alloc_error); + ATH10K_DFS_POOL_STAT("Seqs. in use", pseq_used); + +exit: + if (len > size) + len = size; + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; +} + +static const struct file_operations fops_dfs_stats = { + .read = ath10k_read_dfs_stats, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + int ath10k_debug_create(struct ath10k *ar) { ar->debug.debugfs_phy = debugfs_create_dir("ath10k", @@ -667,6 +747,16 @@ int ath10k_debug_create(struct ath10k *ar) debugfs_create_file("htt_stats_mask", S_IRUSR, ar->debug.debugfs_phy, ar, &fops_htt_stats_mask); + if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) { + debugfs_create_file("dfs_simulate_radar", S_IWUSR, + ar->debug.debugfs_phy, ar, + &fops_simulate_radar); + + debugfs_create_file("dfs_stats", S_IRUSR, + ar->debug.debugfs_phy, ar, + &fops_dfs_stats); + } + return 0; } diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h index 46e640a6968..92f1a5e1aa7 100644 --- a/drivers/net/wireless/ath/ath10k/debug.h +++ b/drivers/net/wireless/ath/ath10k/debug.h @@ -33,6 +33,7 @@ enum ath10k_debug_mask { ATH10K_DBG_MGMT = 0x00000100, ATH10K_DBG_DATA = 0x00000200, ATH10K_DBG_BMI = 0x00000400, + ATH10K_DBG_REGULATORY = 0x00000800, ATH10K_DBG_ANY = 0xffffffff, }; @@ -53,6 +54,8 @@ void ath10k_debug_read_service_map(struct ath10k *ar, void ath10k_debug_read_target_stats(struct ath10k *ar, struct wmi_stats_event *ev); +#define ATH10K_DFS_STAT_INC(ar, c) (ar->debug.dfs_stats.c++) + #else static inline int ath10k_debug_start(struct ath10k *ar) { @@ -82,6 +85,9 @@ static inline void ath10k_debug_read_target_stats(struct ath10k *ar, struct wmi_stats_event *ev) { } + +#define ATH10K_DFS_STAT_INC(ar, c) do { } while (0) + #endif /* CONFIG_ATH10K_DEBUGFS */ #ifdef CONFIG_ATH10K_DEBUG diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index db819429134..c95a3985209 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1442,9 +1442,20 @@ static void ath10k_reg_notifier(struct wiphy *wiphy, { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct ath10k *ar = hw->priv; + bool result; ath_reg_notifier_apply(wiphy, request, &ar->ath_common.regulatory); + if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) { + ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs region 0x%x\n", + request->dfs_region); + result = ar->dfs_detector->set_dfs_domain(ar->dfs_detector, + request->dfs_region); + if (!result) + ath10k_warn("dfs region 0x%X not supported, will trigger radar for every pulse\n", + request->dfs_region); + } + mutex_lock(&ar->conf_mutex); if (ar->state == ATH10K_STATE_ON) ath10k_regd_update(ar); @@ -3531,6 +3542,16 @@ int ath10k_mac_register(struct ath10k *ar) ar->hw->netdev_features = NETIF_F_HW_CSUM; + if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) { + /* Init ath dfs pattern detector */ + ar->ath_common.debug_mask = ATH_DBG_DFS; + ar->dfs_detector = dfs_pattern_detector_init(&ar->ath_common, + NL80211_DFS_UNSET); + + if (!ar->dfs_detector) + ath10k_warn("dfs pattern detector init failed\n"); + } + ret = ath_regd_init(&ar->ath_common.regulatory, ar->hw->wiphy, ath10k_reg_notifier); if (ret) { @@ -3566,6 +3587,9 @@ void ath10k_mac_unregister(struct ath10k *ar) { ieee80211_unregister_hw(ar->hw); + if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) + ar->dfs_detector->exit(ar->dfs_detector); + kfree(ar->mac.sbands[IEEE80211_BAND_2GHZ].channels); kfree(ar->mac.sbands[IEEE80211_BAND_5GHZ].channels); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index f79f17ce5dc..f0bc94abbc7 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1381,9 +1381,251 @@ static void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar, ath10k_dbg(ATH10K_DBG_WMI, "WMI_TBTTOFFSET_UPDATE_EVENTID\n"); } +static void ath10k_dfs_radar_report(struct ath10k *ar, + struct wmi_single_phyerr_rx_event *event, + struct phyerr_radar_report *rr, + u64 tsf) +{ + u32 reg0, reg1, tsf32l; + struct pulse_event pe; + u64 tsf64; + u8 rssi, width; + + reg0 = __le32_to_cpu(rr->reg0); + reg1 = __le32_to_cpu(rr->reg1); + + ath10k_dbg(ATH10K_DBG_REGULATORY, + "wmi phyerr radar report chirp %d max_width %d agc_total_gain %d pulse_delta_diff %d\n", + MS(reg0, RADAR_REPORT_REG0_PULSE_IS_CHIRP), + MS(reg0, RADAR_REPORT_REG0_PULSE_IS_MAX_WIDTH), + MS(reg0, RADAR_REPORT_REG0_AGC_TOTAL_GAIN), + MS(reg0, RADAR_REPORT_REG0_PULSE_DELTA_DIFF)); + ath10k_dbg(ATH10K_DBG_REGULATORY, + "wmi phyerr radar report pulse_delta_pean %d pulse_sidx %d fft_valid %d agc_mb_gain %d subchan_mask %d\n", + MS(reg0, RADAR_REPORT_REG0_PULSE_DELTA_PEAK), + MS(reg0, RADAR_REPORT_REG0_PULSE_SIDX), + MS(reg1, RADAR_REPORT_REG1_PULSE_SRCH_FFT_VALID), + MS(reg1, RADAR_REPORT_REG1_PULSE_AGC_MB_GAIN), + MS(reg1, RADAR_REPORT_REG1_PULSE_SUBCHAN_MASK)); + ath10k_dbg(ATH10K_DBG_REGULATORY, + "wmi phyerr radar report pulse_tsf_offset 0x%X pulse_dur: %d\n", + MS(reg1, RADAR_REPORT_REG1_PULSE_TSF_OFFSET), + MS(reg1, RADAR_REPORT_REG1_PULSE_DUR)); + + if (!ar->dfs_detector) + return; + + /* report event to DFS pattern detector */ + tsf32l = __le32_to_cpu(event->hdr.tsf_timestamp); + tsf64 = tsf & (~0xFFFFFFFFULL); + tsf64 |= tsf32l; + + width = MS(reg1, RADAR_REPORT_REG1_PULSE_DUR); + rssi = event->hdr.rssi_combined; + + /* hardware store this as 8 bit signed value, + * set to zero if negative number + */ + if (rssi & 0x80) + rssi = 0; + + pe.ts = tsf64; + pe.freq = ar->hw->conf.chandef.chan->center_freq; + pe.width = width; + pe.rssi = rssi; + + ath10k_dbg(ATH10K_DBG_REGULATORY, + "dfs add pulse freq: %d, width: %d, rssi %d, tsf: %llX\n", + pe.freq, pe.width, pe.rssi, pe.ts); + + ATH10K_DFS_STAT_INC(ar, pulses_detected); + + if (!ar->dfs_detector->add_pulse(ar->dfs_detector, &pe)) { + ath10k_dbg(ATH10K_DBG_REGULATORY, + "dfs no pulse pattern detected, yet\n"); + return; + } + + ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs radar detected\n"); + ATH10K_DFS_STAT_INC(ar, radar_detected); + ieee80211_radar_detected(ar->hw); +} + +static int ath10k_dfs_fft_report(struct ath10k *ar, + struct wmi_single_phyerr_rx_event *event, + struct phyerr_fft_report *fftr, + u64 tsf) +{ + u32 reg0, reg1; + u8 rssi, peak_mag; + + reg0 = __le32_to_cpu(fftr->reg0); + reg1 = __le32_to_cpu(fftr->reg1); + rssi = event->hdr.rssi_combined; + + ath10k_dbg(ATH10K_DBG_REGULATORY, + "wmi phyerr fft report total_gain_db %d base_pwr_db %d fft_chn_idx %d peak_sidx %d\n", + MS(reg0, SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB), + MS(reg0, SEARCH_FFT_REPORT_REG0_BASE_PWR_DB), + MS(reg0, SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX), + MS(reg0, SEARCH_FFT_REPORT_REG0_PEAK_SIDX)); + ath10k_dbg(ATH10K_DBG_REGULATORY, + "wmi phyerr fft report rel_pwr_db %d avgpwr_db %d peak_mag %d num_store_bin %d\n", + MS(reg1, SEARCH_FFT_REPORT_REG1_RELPWR_DB), + MS(reg1, SEARCH_FFT_REPORT_REG1_AVGPWR_DB), + MS(reg1, SEARCH_FFT_REPORT_REG1_PEAK_MAG), + MS(reg1, SEARCH_FFT_REPORT_REG1_NUM_STR_BINS_IB)); + + peak_mag = MS(reg1, SEARCH_FFT_REPORT_REG1_PEAK_MAG); + + /* false event detection */ + if (rssi == DFS_RSSI_POSSIBLY_FALSE && + peak_mag < 2 * DFS_PEAK_MAG_THOLD_POSSIBLY_FALSE) { + ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs false pulse detected\n"); + ATH10K_DFS_STAT_INC(ar, pulses_discarded); + return -EINVAL; + } + + return 0; +} + +static void ath10k_wmi_event_dfs(struct ath10k *ar, + struct wmi_single_phyerr_rx_event *event, + u64 tsf) +{ + int buf_len, tlv_len, res, i = 0; + struct phyerr_tlv *tlv; + struct phyerr_radar_report *rr; + struct phyerr_fft_report *fftr; + u8 *tlv_buf; + + buf_len = __le32_to_cpu(event->hdr.buf_len); + ath10k_dbg(ATH10K_DBG_REGULATORY, + "wmi event dfs err_code %d rssi %d tsfl 0x%X tsf64 0x%llX len %d\n", + event->hdr.phy_err_code, event->hdr.rssi_combined, + __le32_to_cpu(event->hdr.tsf_timestamp), tsf, buf_len); + + /* Skip event if DFS disabled */ + if (!config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) + return; + + ATH10K_DFS_STAT_INC(ar, pulses_total); + + while (i < buf_len) { + if (i + sizeof(*tlv) > buf_len) { + ath10k_warn("too short buf for tlv header (%d)\n", i); + return; + } + + tlv = (struct phyerr_tlv *)&event->bufp[i]; + tlv_len = __le16_to_cpu(tlv->len); + tlv_buf = &event->bufp[i + sizeof(*tlv)]; + ath10k_dbg(ATH10K_DBG_REGULATORY, + "wmi event dfs tlv_len %d tlv_tag 0x%02X tlv_sig 0x%02X\n", + tlv_len, tlv->tag, tlv->sig); + + switch (tlv->tag) { + case PHYERR_TLV_TAG_RADAR_PULSE_SUMMARY: + if (i + sizeof(*tlv) + sizeof(*rr) > buf_len) { + ath10k_warn("too short radar pulse summary (%d)\n", + i); + return; + } + + rr = (struct phyerr_radar_report *)tlv_buf; + ath10k_dfs_radar_report(ar, event, rr, tsf); + break; + case PHYERR_TLV_TAG_SEARCH_FFT_REPORT: + if (i + sizeof(*tlv) + sizeof(*fftr) > buf_len) { + ath10k_warn("too short fft report (%d)\n", i); + return; + } + + fftr = (struct phyerr_fft_report *)tlv_buf; + res = ath10k_dfs_fft_report(ar, event, fftr, tsf); + if (res) + return; + break; + } + + i += sizeof(*tlv) + tlv_len; + } +} + +static void ath10k_wmi_event_spectral_scan(struct ath10k *ar, + struct wmi_single_phyerr_rx_event *event, + u64 tsf) +{ + ath10k_dbg(ATH10K_DBG_WMI, "wmi event spectral scan\n"); +} + static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb) { - ath10k_dbg(ATH10K_DBG_WMI, "WMI_PHYERR_EVENTID\n"); + struct wmi_comb_phyerr_rx_event *comb_event; + struct wmi_single_phyerr_rx_event *event; + u32 count, i, buf_len, phy_err_code; + u64 tsf; + int left_len = skb->len; + + ATH10K_DFS_STAT_INC(ar, phy_errors); + + /* Check if combined event available */ + if (left_len < sizeof(*comb_event)) { + ath10k_warn("wmi phyerr combined event wrong len\n"); + return; + } + + left_len -= sizeof(*comb_event); + + /* Check number of included events */ + comb_event = (struct wmi_comb_phyerr_rx_event *)skb->data; + count = __le32_to_cpu(comb_event->hdr.num_phyerr_events); + + tsf = __le32_to_cpu(comb_event->hdr.tsf_u32); + tsf <<= 32; + tsf |= __le32_to_cpu(comb_event->hdr.tsf_l32); + + ath10k_dbg(ATH10K_DBG_WMI, + "wmi event phyerr count %d tsf64 0x%llX\n", + count, tsf); + + event = (struct wmi_single_phyerr_rx_event *)comb_event->bufp; + for (i = 0; i < count; i++) { + /* Check if we can read event header */ + if (left_len < sizeof(*event)) { + ath10k_warn("single event (%d) wrong head len\n", i); + return; + } + + left_len -= sizeof(*event); + + buf_len = __le32_to_cpu(event->hdr.buf_len); + phy_err_code = event->hdr.phy_err_code; + + if (left_len < buf_len) { + ath10k_warn("single event (%d) wrong buf len\n", i); + return; + } + + left_len -= buf_len; + + switch (phy_err_code) { + case PHY_ERROR_RADAR: + ath10k_wmi_event_dfs(ar, event, tsf); + break; + case PHY_ERROR_SPECTRAL_SCAN: + ath10k_wmi_event_spectral_scan(ar, event, tsf); + break; + case PHY_ERROR_FALSE_RADAR_EXT: + ath10k_wmi_event_dfs(ar, event, tsf); + ath10k_wmi_event_spectral_scan(ar, event, tsf); + break; + default: + break; + } + + event += sizeof(*event) + buf_len; + } } static void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb) diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 8b824f9c2f1..e71273e65c5 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -1978,6 +1978,10 @@ struct wmi_mgmt_rx_event_v2 { #define WMI_RX_STATUS_ERR_MIC 0x10 #define WMI_RX_STATUS_ERR_KEY_CACHE_MISS 0x20 +#define PHY_ERROR_SPECTRAL_SCAN 0x26 +#define PHY_ERROR_FALSE_RADAR_EXT 0x24 +#define PHY_ERROR_RADAR 0x05 + struct wmi_single_phyerr_rx_hdr { /* TSF timestamp */ __le32 tsf_timestamp; @@ -2069,6 +2073,87 @@ struct wmi_comb_phyerr_rx_event { u8 bufp[0]; } __packed; +#define PHYERR_TLV_SIG 0xBB +#define PHYERR_TLV_TAG_SEARCH_FFT_REPORT 0xFB +#define PHYERR_TLV_TAG_RADAR_PULSE_SUMMARY 0xF8 + +struct phyerr_radar_report { + __le32 reg0; /* RADAR_REPORT_REG0_* */ + __le32 reg1; /* REDAR_REPORT_REG1_* */ +} __packed; + +#define RADAR_REPORT_REG0_PULSE_IS_CHIRP_MASK 0x80000000 +#define RADAR_REPORT_REG0_PULSE_IS_CHIRP_LSB 31 + +#define RADAR_REPORT_REG0_PULSE_IS_MAX_WIDTH_MASK 0x40000000 +#define RADAR_REPORT_REG0_PULSE_IS_MAX_WIDTH_LSB 30 + +#define RADAR_REPORT_REG0_AGC_TOTAL_GAIN_MASK 0x3FF00000 +#define RADAR_REPORT_REG0_AGC_TOTAL_GAIN_LSB 20 + +#define RADAR_REPORT_REG0_PULSE_DELTA_DIFF_MASK 0x000F0000 +#define RADAR_REPORT_REG0_PULSE_DELTA_DIFF_LSB 16 + +#define RADAR_REPORT_REG0_PULSE_DELTA_PEAK_MASK 0x0000FC00 +#define RADAR_REPORT_REG0_PULSE_DELTA_PEAK_LSB 10 + +#define RADAR_REPORT_REG0_PULSE_SIDX_MASK 0x000003FF +#define RADAR_REPORT_REG0_PULSE_SIDX_LSB 0 + +#define RADAR_REPORT_REG1_PULSE_SRCH_FFT_VALID_MASK 0x80000000 +#define RADAR_REPORT_REG1_PULSE_SRCH_FFT_VALID_LSB 31 + +#define RADAR_REPORT_REG1_PULSE_AGC_MB_GAIN_MASK 0x7F000000 +#define RADAR_REPORT_REG1_PULSE_AGC_MB_GAIN_LSB 24 + +#define RADAR_REPORT_REG1_PULSE_SUBCHAN_MASK_MASK 0x00FF0000 +#define RADAR_REPORT_REG1_PULSE_SUBCHAN_MASK_LSB 16 + +#define RADAR_REPORT_REG1_PULSE_TSF_OFFSET_MASK 0x0000FF00 +#define RADAR_REPORT_REG1_PULSE_TSF_OFFSET_LSB 8 + +#define RADAR_REPORT_REG1_PULSE_DUR_MASK 0x000000FF +#define RADAR_REPORT_REG1_PULSE_DUR_LSB 0 + +struct phyerr_fft_report { + __le32 reg0; /* SEARCH_FFT_REPORT_REG0_ * */ + __le32 reg1; /* SEARCH_FFT_REPORT_REG1_ * */ +} __packed; + +#define SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB_MASK 0xFF800000 +#define SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB_LSB 23 + +#define SEARCH_FFT_REPORT_REG0_BASE_PWR_DB_MASK 0x007FC000 +#define SEARCH_FFT_REPORT_REG0_BASE_PWR_DB_LSB 14 + +#define SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX_MASK 0x00003000 +#define SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX_LSB 12 + +#define SEARCH_FFT_REPORT_REG0_PEAK_SIDX_MASK 0x00000FFF +#define SEARCH_FFT_REPORT_REG0_PEAK_SIDX_LSB 0 + +#define SEARCH_FFT_REPORT_REG1_RELPWR_DB_MASK 0xFC000000 +#define SEARCH_FFT_REPORT_REG1_RELPWR_DB_LSB 26 + +#define SEARCH_FFT_REPORT_REG1_AVGPWR_DB_MASK 0x03FC0000 +#define SEARCH_FFT_REPORT_REG1_AVGPWR_DB_LSB 18 + +#define SEARCH_FFT_REPORT_REG1_PEAK_MAG_MASK 0x0003FF00 +#define SEARCH_FFT_REPORT_REG1_PEAK_MAG_LSB 8 + +#define SEARCH_FFT_REPORT_REG1_NUM_STR_BINS_IB_MASK 0x000000FF +#define SEARCH_FFT_REPORT_REG1_NUM_STR_BINS_IB_LSB 0 + + +struct phyerr_tlv { + __le16 len; + u8 tag; + u8 sig; +} __packed; + +#define DFS_RSSI_POSSIBLY_FALSE 50 +#define DFS_PEAK_MAG_THOLD_POSSIBLY_FALSE 40 + struct wmi_mgmt_tx_hdr { __le32 vdev_id; struct wmi_mac_addr peer_macaddr; -- cgit v1.2.3-70-g09d2 From e8a50f8ba44b6933b2a39b6a65528b9a4e8ba5f3 Mon Sep 17 00:00:00 2001 From: Marek Puzyniak Date: Wed, 20 Nov 2013 09:59:47 +0200 Subject: ath10k: introduce DFS implementation Configure interface combination for AP running on channels where radar detection is required. It allows only one type of interface - AP on DFS channel and limits number of AP interfaces to 8. Setup WMI channel flags accordingly to mac channel configuration. CAC based on additional monitor vdev is started if required for current channel. kvalo: dropped ATH10K_DFS_CERTIFIED config option as this the DFS still depends on few mac80211 and cfg80211 patches which are on mac80211-next.git right now. The config option will be added later once all dependencies are available. Signed-off-by: Marek Puzyniak Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 6 ++ drivers/net/wireless/ath/ath10k/htt_rx.c | 5 + drivers/net/wireless/ath/ath10k/mac.c | 160 +++++++++++++++++++++++++++++-- drivers/net/wireless/ath/ath10k/wmi.c | 23 ++++- drivers/net/wireless/ath/ath10k/wmi.h | 1 + 5 files changed, 182 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index afbc7449b13..0b88d554f95 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -310,6 +310,11 @@ enum ath10k_fw_features { ATH10K_FW_FEATURE_COUNT, }; +enum ath10k_dev_flags { + /* Indicates that ath10k device is during CAC phase of DFS */ + ATH10K_CAC_RUNNING, +}; + struct ath10k { struct ath_common ath_common; struct ieee80211_hw *hw; @@ -403,6 +408,7 @@ struct ath10k { bool monitor_enabled; bool monitor_present; unsigned int filter_flags; + unsigned long dev_flags; struct wmi_pdev_set_wmm_params_arg wmm_params; struct completion install_key_done; diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 0335218ad57..fcb534f2f28 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -945,6 +945,11 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, continue; } + if (test_bit(ATH10K_CAC_RUNNING, &htt->ar->dev_flags)) { + ath10k_htt_rx_free_msdu_chain(msdu_head); + continue; + } + /* FIXME: we do not support chaining yet. * this needs investigation */ if (msdu_chaining) { diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index c95a3985209..b70a3b2f9f4 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -463,6 +463,10 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif) arg.ssid = arvif->u.ap.ssid; arg.ssid_len = arvif->u.ap.ssid_len; arg.hidden_ssid = arvif->u.ap.hidden_ssid; + + /* For now allow DFS for AP mode */ + arg.channel.chan_radar = + !!(channel->flags & IEEE80211_CHAN_RADAR); } else if (arvif->vdev_type == WMI_VDEV_TYPE_IBSS) { arg.ssid = arvif->vif->bss_conf.ssid; arg.ssid_len = arvif->vif->bss_conf.ssid_len; @@ -532,6 +536,8 @@ static int ath10k_monitor_start(struct ath10k *ar, int vdev_id) /* TODO setup this dynamically, what in case we don't have any vifs? */ arg.channel.mode = chan_to_phymode(&ar->hw->conf.chandef); + arg.channel.chan_radar = + !!(channel->flags & IEEE80211_CHAN_RADAR); arg.channel.min_power = 0; arg.channel.max_power = channel->max_power * 2; @@ -666,6 +672,107 @@ static int ath10k_monitor_destroy(struct ath10k *ar) return ret; } +static int ath10k_start_cac(struct ath10k *ar) +{ + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + set_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); + + ret = ath10k_monitor_create(ar); + if (ret) { + clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); + return ret; + } + + ret = ath10k_monitor_start(ar, ar->monitor_vdev_id); + if (ret) { + clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); + ath10k_monitor_destroy(ar); + return ret; + } + + ath10k_dbg(ATH10K_DBG_MAC, "mac cac start monitor vdev %d\n", + ar->monitor_vdev_id); + + return 0; +} + +static int ath10k_stop_cac(struct ath10k *ar) +{ + lockdep_assert_held(&ar->conf_mutex); + + /* CAC is not running - do nothing */ + if (!test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags)) + return 0; + + ath10k_monitor_stop(ar); + ath10k_monitor_destroy(ar); + clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); + + ath10k_dbg(ATH10K_DBG_MAC, "mac cac finished\n"); + + return 0; +} + +static const char *ath10k_dfs_state(enum nl80211_dfs_state dfs_state) +{ + switch (dfs_state) { + case NL80211_DFS_USABLE: + return "USABLE"; + case NL80211_DFS_UNAVAILABLE: + return "UNAVAILABLE"; + case NL80211_DFS_AVAILABLE: + return "AVAILABLE"; + default: + WARN_ON(1); + return "bug"; + } +} + +static void ath10k_config_radar_detection(struct ath10k *ar) +{ + struct ieee80211_channel *chan = ar->hw->conf.chandef.chan; + bool radar = ar->hw->conf.radar_enabled; + bool chan_radar = !!(chan->flags & IEEE80211_CHAN_RADAR); + enum nl80211_dfs_state dfs_state = chan->dfs_state; + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + ath10k_dbg(ATH10K_DBG_MAC, + "mac radar config update: chan %dMHz radar %d chan radar %d chan state %s\n", + chan->center_freq, radar, chan_radar, + ath10k_dfs_state(dfs_state)); + + /* + * It's safe to call it even if CAC is not started. + * This call here guarantees changing channel, etc. will stop CAC. + */ + ath10k_stop_cac(ar); + + if (!radar) + return; + + if (!chan_radar) + return; + + if (dfs_state != NL80211_DFS_USABLE) + return; + + ret = ath10k_start_cac(ar); + if (ret) { + /* + * Not possible to start CAC on current channel so starting + * radiation is not allowed, make this channel DFS_UNAVAILABLE + * by indicating that radar was detected. + */ + ath10k_warn("failed to start CAC (%d)\n", ret); + ieee80211_radar_detected(ar->hw); + } +} + static void ath10k_control_beaconing(struct ath10k_vif *arvif, struct ieee80211_bss_conf *info) { @@ -1375,6 +1482,9 @@ static int ath10k_update_channel_list(struct ath10k *ar) ch->ht40plus = !(channel->flags & IEEE80211_CHAN_NO_HT40PLUS); + ch->chan_radar = + !!(channel->flags & IEEE80211_CHAN_RADAR); + passive = channel->flags & IEEE80211_CHAN_PASSIVE_SCAN; ch->passive = passive; @@ -1921,6 +2031,7 @@ void ath10k_halt(struct ath10k *ar) { lockdep_assert_held(&ar->conf_mutex); + ath10k_stop_cac(ar); del_timer_sync(&ar->scan.timeout); ath10k_offchan_tx_purge(ar); ath10k_mgmt_over_wmi_tx_purge(ar); @@ -2035,11 +2146,16 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed) mutex_lock(&ar->conf_mutex); if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { - ath10k_dbg(ATH10K_DBG_MAC, "mac config channel %d mhz\n", - conf->chandef.chan->center_freq); + ath10k_dbg(ATH10K_DBG_MAC, + "mac config channel %d mhz flags 0x%x\n", + conf->chandef.chan->center_freq, + conf->chandef.chan->flags); + spin_lock_bh(&ar->data_lock); ar->rx_channel = conf->chandef.chan; spin_unlock_bh(&ar->data_lock); + + ath10k_config_radar_detection(ar); } if (changed & IEEE80211_CONF_CHANGE_POWER) { @@ -3308,12 +3424,36 @@ static const struct ieee80211_iface_limit ath10k_if_limits[] = { }, }; -static const struct ieee80211_iface_combination ath10k_if_comb = { - .limits = ath10k_if_limits, - .n_limits = ARRAY_SIZE(ath10k_if_limits), - .max_interfaces = 8, - .num_different_channels = 1, - .beacon_int_infra_match = true, +#ifdef CONFIG_ATH10K_DFS_CERTIFIED +static const struct ieee80211_iface_limit ath10k_if_dfs_limits[] = { + { + .max = 8, + .types = BIT(NL80211_IFTYPE_AP) + }, +}; +#endif + +static const struct ieee80211_iface_combination ath10k_if_comb[] = { + { + .limits = ath10k_if_limits, + .n_limits = ARRAY_SIZE(ath10k_if_limits), + .max_interfaces = 8, + .num_different_channels = 1, + .beacon_int_infra_match = true, + }, +#ifdef CONFIG_ATH10K_DFS_CERTIFIED + { + .limits = ath10k_if_dfs_limits, + .n_limits = ARRAY_SIZE(ath10k_if_dfs_limits), + .max_interfaces = 8, + .num_different_channels = 1, + .beacon_int_infra_match = true, + .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80), + } +#endif }; static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar) @@ -3537,8 +3677,8 @@ int ath10k_mac_register(struct ath10k *ar) */ ar->hw->queues = 4; - ar->hw->wiphy->iface_combinations = &ath10k_if_comb; - ar->hw->wiphy->n_iface_combinations = 1; + ar->hw->wiphy->iface_combinations = ath10k_if_comb; + ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ath10k_if_comb); ar->hw->netdev_features = NETIF_F_HW_CSUM; diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index f0bc94abbc7..aea81d944d8 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -907,6 +907,11 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) ath10k_dbg(ATH10K_DBG_MGMT, "event mgmt rx status %08x\n", rx_status); + if (test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags)) { + dev_kfree_skb(skb); + return 0; + } + if (rx_status & WMI_RX_STATUS_ERR_DECRYPT) { dev_kfree_skb(skb); return 0; @@ -2302,6 +2307,7 @@ int ath10k_wmi_pdev_set_channel(struct ath10k *ar, { struct wmi_set_channel_cmd *cmd; struct sk_buff *skb; + u32 ch_flags = 0; if (arg->passive) return -EINVAL; @@ -2310,10 +2316,14 @@ int ath10k_wmi_pdev_set_channel(struct ath10k *ar, if (!skb) return -ENOMEM; + if (arg->chan_radar) + ch_flags |= WMI_CHAN_FLAG_DFS; + cmd = (struct wmi_set_channel_cmd *)skb->data; cmd->chan.mhz = __cpu_to_le32(arg->freq); cmd->chan.band_center_freq1 = __cpu_to_le32(arg->freq); cmd->chan.mode = arg->mode; + cmd->chan.flags |= __cpu_to_le32(ch_flags); cmd->chan.min_power = arg->min_power; cmd->chan.max_power = arg->max_power; cmd->chan.reg_power = arg->max_reg_power; @@ -2862,6 +2872,7 @@ static int ath10k_wmi_vdev_start_restart(struct ath10k *ar, struct sk_buff *skb; const char *cmdname; u32 flags = 0; + u32 ch_flags = 0; if (cmd_id != ar->wmi.cmd->vdev_start_request_cmdid && cmd_id != ar->wmi.cmd->vdev_restart_request_cmdid) @@ -2888,6 +2899,8 @@ static int ath10k_wmi_vdev_start_restart(struct ath10k *ar, flags |= WMI_VDEV_START_HIDDEN_SSID; if (arg->pmf_enabled) flags |= WMI_VDEV_START_PMF_ENABLED; + if (arg->channel.chan_radar) + ch_flags |= WMI_CHAN_FLAG_DFS; cmd = (struct wmi_vdev_start_request_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(arg->vdev_id); @@ -2909,6 +2922,7 @@ static int ath10k_wmi_vdev_start_restart(struct ath10k *ar, __cpu_to_le32(arg->channel.band_center_freq1); cmd->chan.mode = arg->channel.mode; + cmd->chan.flags |= __cpu_to_le32(ch_flags); cmd->chan.min_power = arg->channel.min_power; cmd->chan.max_power = arg->channel.max_power; cmd->chan.reg_power = arg->channel.max_reg_power; @@ -2916,9 +2930,10 @@ static int ath10k_wmi_vdev_start_restart(struct ath10k *ar, cmd->chan.antenna_max = arg->channel.max_antenna_gain; ath10k_dbg(ATH10K_DBG_WMI, - "wmi vdev %s id 0x%x freq %d, mode %d, ch_flags: 0x%0X," - "max_power: %d\n", cmdname, arg->vdev_id, arg->channel.freq, - arg->channel.mode, flags, arg->channel.max_power); + "wmi vdev %s id 0x%x flags: 0x%0X, freq %d, mode %d, " + "ch_flags: 0x%0X, max_power: %d\n", cmdname, arg->vdev_id, + flags, arg->channel.freq, arg->channel.mode, + cmd->chan.flags, arg->channel.max_power); return ath10k_wmi_cmd_send(ar, skb, cmd_id); } @@ -3252,6 +3267,8 @@ int ath10k_wmi_scan_chan_list(struct ath10k *ar, flags |= WMI_CHAN_FLAG_ALLOW_VHT; if (ch->ht40plus) flags |= WMI_CHAN_FLAG_HT40_PLUS; + if (ch->chan_radar) + flags |= WMI_CHAN_FLAG_DFS; ci->mhz = __cpu_to_le32(ch->freq); ci->band_center_freq1 = __cpu_to_le32(ch->freq); diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index e71273e65c5..0087d699b85 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -916,6 +916,7 @@ struct wmi_channel_arg { bool allow_ht; bool allow_vht; bool ht40plus; + bool chan_radar; /* note: power unit is 0.5 dBm */ u32 min_power; u32 max_power; -- cgit v1.2.3-70-g09d2 From 7d9b40b4618a1f6fcd69db7056903d5cba835c2e Mon Sep 17 00:00:00 2001 From: Marek Puzyniak Date: Wed, 20 Nov 2013 10:00:28 +0200 Subject: ath10k: add debugfs file to control radar events blocking Sometimes for DFS testing is required to stay on current channel even after radar detected. This patch allows to enable/disable radar detected event to be passed to mac80211. By default radar detected event in not blocked. To block it: echo 1 > /sys/kernel/debug/ieee80211/phyX/ath10k/dfs_block_radar_events To unblock again: echo 0 > /sys/kernel/debug/ieee80211/phyX/ath10k/dfs_block_radar_events Inform about blocking radar detected event even when logs are disabled for throughput/performance reasons. Signed-off-by: Marek Puzyniak Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 1 + drivers/net/wireless/ath/ath10k/debug.c | 4 ++++ drivers/net/wireless/ath/ath10k/wmi.c | 8 ++++++++ 3 files changed, 13 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 0b88d554f95..7721e3b2dd5 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -409,6 +409,7 @@ struct ath10k { bool monitor_present; unsigned int filter_flags; unsigned long dev_flags; + u32 dfs_block_radar_events; struct wmi_pdev_set_wmm_params_arg wmm_params; struct completion install_key_done; diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 13705d41795..6bdfad3144a 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -752,6 +752,10 @@ int ath10k_debug_create(struct ath10k *ar) ar->debug.debugfs_phy, ar, &fops_simulate_radar); + debugfs_create_bool("dfs_block_radar_events", S_IWUSR, + ar->debug.debugfs_phy, + &ar->dfs_block_radar_events); + debugfs_create_file("dfs_stats", S_IRUSR, ar->debug.debugfs_phy, ar, &fops_dfs_stats); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index aea81d944d8..c654137c0cf 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1453,6 +1453,14 @@ static void ath10k_dfs_radar_report(struct ath10k *ar, ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs radar detected\n"); ATH10K_DFS_STAT_INC(ar, radar_detected); + + /* Control radar events reporting in debugfs file + dfs_block_radar_events */ + if (ar->dfs_block_radar_events) { + ath10k_info("DFS Radar detected, but ignored as requested\n"); + return; + } + ieee80211_radar_detected(ar->hw); } -- cgit v1.2.3-70-g09d2 From 95cbb6a8f1baa4118912a7d38cf4eca7583c868a Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Wed, 20 Nov 2013 10:00:35 +0200 Subject: ath10k: don't show MSI registration warnings Convert the MSI failure warnings to a debug message to make them less spammy. Also convert the irq mode printout to a single print to make it easier to show it only once. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 46c94ce58f9..a3cdd72f314 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -1851,6 +1851,7 @@ static void ath10k_pci_start_bmi(struct ath10k *ar) static int ath10k_pci_hif_power_up(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + const char *irq_mode; int ret; /* @@ -1916,6 +1917,16 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) } ath10k_pci_start_bmi(ar); + + if (ar_pci->num_msi_intrs > 1) + irq_mode = "MSI-X"; + else if (ar_pci->num_msi_intrs == 1) + irq_mode = "MSI"; + else + irq_mode = "legacy"; + + ath10k_info("pci irq %s\n", irq_mode); + return 0; err_irq: @@ -2161,7 +2172,8 @@ static int ath10k_pci_start_intr_msix(struct ath10k *ar, int num) } } - ath10k_info("MSI-X interrupt handling (%d intrs)\n", num); + ath10k_dbg(ATH10K_DBG_BOOT, + "MSI-X interrupt handling (%d intrs)\n", num); return 0; } @@ -2182,7 +2194,7 @@ static int ath10k_pci_start_intr_msi(struct ath10k *ar) return ret; } - ath10k_info("MSI interrupt handling\n"); + ath10k_dbg(ATH10K_DBG_BOOT, "MSI interrupt handling\n"); return 0; } @@ -2218,7 +2230,7 @@ static int ath10k_pci_start_intr_legacy(struct ath10k *ar) PCIE_INTR_ENABLE_ADDRESS)); ath10k_pci_sleep(ar); - ath10k_info("legacy interrupt handling\n"); + ath10k_dbg(ATH10K_DBG_BOOT, "legacy interrupt handling\n"); return 0; } @@ -2248,7 +2260,8 @@ static int ath10k_pci_start_intr(struct ath10k *ar) if (ret == 0) goto exit; - ath10k_warn("MSI-X didn't succeed (%d), trying MSI\n", ret); + ath10k_dbg(ATH10K_DBG_BOOT, + "MSI-X didn't succeed (%d), trying MSI\n", ret); num = 1; } @@ -2257,8 +2270,9 @@ static int ath10k_pci_start_intr(struct ath10k *ar) if (ret == 0) goto exit; - ath10k_warn("MSI didn't succeed (%d), trying legacy INTR\n", - ret); + ath10k_dbg(ATH10K_DBG_BOOT, + "MSI didn't succeed (%d), trying legacy INTR\n", + ret); num = 0; } -- cgit v1.2.3-70-g09d2 From c8c39afee20124b29b69a35b78e5081dccb97a9b Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Wed, 20 Nov 2013 10:00:41 +0200 Subject: ath10k: make core boot messages more compact We can show the same amount of information in one line. And then it's easier to show this information only during first firmware boot (see next patch). For UART printouts there's already a message when they are enabled so no need to have a print when they are disabled, that's the default anyway. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 16 ++++++++++------ drivers/net/wireless/ath/ath10k/htt.c | 4 ++-- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index be5b17e8990..e6c468b3ea5 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -597,10 +597,8 @@ static int ath10k_init_uart(struct ath10k *ar) return ret; } - if (!uart_print) { - ath10k_info("UART prints disabled\n"); + if (!uart_print) return 0; - } ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, 7); if (ret) { @@ -645,8 +643,8 @@ static int ath10k_init_hw_params(struct ath10k *ar) ar->hw_params = *hw_params; - ath10k_info("Hardware name %s version 0x%x\n", - ar->hw_params.name, ar->target_version); + ath10k_dbg(ATH10K_DBG_BOOT, "Hardware name %s version 0x%x\n", + ar->hw_params.name, ar->target_version); return 0; } @@ -807,7 +805,8 @@ int ath10k_core_start(struct ath10k *ar) if (status) goto err_htt_detach; - ath10k_info("firmware %s booted\n", ar->hw->wiphy->fw_version); + ath10k_dbg(ATH10K_DBG_BOOT, "firmware %s booted\n", + ar->hw->wiphy->fw_version); status = ath10k_wmi_cmd_init(ar); if (status) { @@ -833,6 +832,11 @@ int ath10k_core_start(struct ath10k *ar) ar->free_vdev_map = (1 << TARGET_NUM_VDEVS) - 1; INIT_LIST_HEAD(&ar->arvifs); + ath10k_info("%s (0x%x) fw %s api %d htt %d.%d\n", + ar->hw_params.name, ar->target_version, + ar->hw->wiphy->fw_version, ar->fw_api, + ar->htt.target_version_major, ar->htt.target_version_minor); + return 0; err_disconnect_htc: diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c index 5f7eeebc543..69697af59ce 100644 --- a/drivers/net/wireless/ath/ath10k/htt.c +++ b/drivers/net/wireless/ath/ath10k/htt.c @@ -104,8 +104,8 @@ err_htc_attach: static int ath10k_htt_verify_version(struct ath10k_htt *htt) { - ath10k_info("htt target version %d.%d\n", - htt->target_version_major, htt->target_version_minor); + ath10k_dbg(ATH10K_DBG_BOOT, "htt target version %d.%d\n", + htt->target_version_major, htt->target_version_minor); if (htt->target_version_major != 2 && htt->target_version_major != 3) { -- cgit v1.2.3-70-g09d2 From 650b91fb09c035a99f2aaeb5de9bfc5215301816 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Wed, 20 Nov 2013 10:00:49 +0200 Subject: ath10k: show hardware and firmware info prints only once This makes ath10k a lot less spammy by default. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 12 ++++++++---- drivers/net/wireless/ath/ath10k/core.h | 1 + drivers/net/wireless/ath/ath10k/pci.c | 4 +++- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index e6c468b3ea5..3b59af3bddf 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -832,10 +832,14 @@ int ath10k_core_start(struct ath10k *ar) ar->free_vdev_map = (1 << TARGET_NUM_VDEVS) - 1; INIT_LIST_HEAD(&ar->arvifs); - ath10k_info("%s (0x%x) fw %s api %d htt %d.%d\n", - ar->hw_params.name, ar->target_version, - ar->hw->wiphy->fw_version, ar->fw_api, - ar->htt.target_version_major, ar->htt.target_version_minor); + if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags)) + ath10k_info("%s (0x%x) fw %s api %d htt %d.%d\n", + ar->hw_params.name, ar->target_version, + ar->hw->wiphy->fw_version, ar->fw_api, + ar->htt.target_version_major, + ar->htt.target_version_minor); + + __set_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags); return 0; diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 7721e3b2dd5..79726e0fe2f 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -313,6 +313,7 @@ enum ath10k_fw_features { enum ath10k_dev_flags { /* Indicates that ath10k device is during CAC phase of DFS */ ATH10K_CAC_RUNNING, + ATH10K_FLAG_FIRST_BOOT_DONE, }; struct ath10k { diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index a3cdd72f314..2457c8ba901 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "core.h" #include "debug.h" @@ -1925,7 +1926,8 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) else irq_mode = "legacy"; - ath10k_info("pci irq %s\n", irq_mode); + if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags)) + ath10k_info("pci irq %s\n", irq_mode); return 0; -- cgit v1.2.3-70-g09d2 From 7575c917cf29824b71c4dff8274fe39fc32bc173 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 18 Nov 2013 22:54:03 +0000 Subject: bfin_mac: Implement the SIOCGHWTSTAMP ioctl Compile-tested only (thanks to the kbuild test robot). Signed-off-by: Ben Hutchings --- drivers/net/ethernet/adi/bfin_mac.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/adi/bfin_mac.c b/drivers/net/ethernet/adi/bfin_mac.c index 75fb1d20d6f..0d4f2957987 100644 --- a/drivers/net/ethernet/adi/bfin_mac.c +++ b/drivers/net/ethernet/adi/bfin_mac.c @@ -667,8 +667,8 @@ static u32 bfin_select_phc_clock(u32 input_clk, unsigned int *shift_result) return 1000000000UL / ppn; } -static int bfin_mac_hwtstamp_ioctl(struct net_device *netdev, - struct ifreq *ifr, int cmd) +static int bfin_mac_hwtstamp_set(struct net_device *netdev, + struct ifreq *ifr) { struct hwtstamp_config config; struct bfin_mac_local *lp = netdev_priv(netdev); @@ -824,6 +824,16 @@ static int bfin_mac_hwtstamp_ioctl(struct net_device *netdev, -EFAULT : 0; } +static int bfin_mac_hwtstamp_get(struct net_device *netdev, + struct ifreq *ifr) +{ + struct bfin_mac_local *lp = netdev_priv(netdev); + + return copy_to_user(ifr->ifr_data, &lp->stamp_cfg, + sizeof(lp->stamp_cfg)) ? + -EFAULT : 0; +} + static void bfin_tx_hwtstamp(struct net_device *netdev, struct sk_buff *skb) { struct bfin_mac_local *lp = netdev_priv(netdev); @@ -1062,7 +1072,8 @@ static void bfin_phc_release(struct bfin_mac_local *lp) #else # define bfin_mac_hwtstamp_is_none(cfg) 0 # define bfin_mac_hwtstamp_init(dev) -# define bfin_mac_hwtstamp_ioctl(dev, ifr, cmd) (-EOPNOTSUPP) +# define bfin_mac_hwtstamp_set(dev, ifr) (-EOPNOTSUPP) +# define bfin_mac_hwtstamp_get(dev, ifr) (-EOPNOTSUPP) # define bfin_rx_hwtstamp(dev, skb) # define bfin_tx_hwtstamp(dev, skb) # define bfin_phc_init(netdev, dev) 0 @@ -1496,7 +1507,9 @@ static int bfin_mac_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) switch (cmd) { case SIOCSHWTSTAMP: - return bfin_mac_hwtstamp_ioctl(netdev, ifr, cmd); + return bfin_mac_hwtstamp_set(netdev, ifr); + case SIOCGHWTSTAMP: + return bfin_mac_hwtstamp_get(netdev, ifr); default: if (lp->phydev) return phy_mii_ioctl(lp->phydev, ifr, cmd); -- cgit v1.2.3-70-g09d2 From 7260899bde50cbe84bdf0a15b5642e2c3b03db32 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 18 Nov 2013 22:59:43 +0000 Subject: tg3: Implement the SIOCGHWTSTAMP ioctl While we're doing this, fix the error code for SIOCSHWTSTAMP ioctl on non-timestamping hardware. Compile-tested only. Signed-off-by: Ben Hutchings --- drivers/net/ethernet/broadcom/tg3.c | 71 ++++++++++++++++++++++++++++++++++--- 1 file changed, 67 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index a9e068423ba..539c6ace170 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -13603,14 +13603,13 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, } -static int tg3_hwtstamp_ioctl(struct net_device *dev, - struct ifreq *ifr, int cmd) +static int tg3_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) { struct tg3 *tp = netdev_priv(dev); struct hwtstamp_config stmpconf; if (!tg3_flag(tp, PTP_CAPABLE)) - return -EINVAL; + return -EOPNOTSUPP; if (copy_from_user(&stmpconf, ifr->ifr_data, sizeof(stmpconf))) return -EFAULT; @@ -13691,6 +13690,67 @@ static int tg3_hwtstamp_ioctl(struct net_device *dev, -EFAULT : 0; } +static int tg3_hwtstamp_get(struct net_device *dev, struct ifreq *ifr) +{ + struct tg3 *tp = netdev_priv(dev); + struct hwtstamp_config stmpconf; + + if (!tg3_flag(tp, PTP_CAPABLE)) + return -EOPNOTSUPP; + + stmpconf.flags = 0; + stmpconf.tx_type = (tg3_flag(tp, TX_TSTAMP_EN) ? + HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF); + + switch (tp->rxptpctl) { + case 0: + stmpconf.rx_filter = HWTSTAMP_FILTER_NONE; + break; + case TG3_RX_PTP_CTL_RX_PTP_V1_EN | TG3_RX_PTP_CTL_ALL_V1_EVENTS: + stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT; + break; + case TG3_RX_PTP_CTL_RX_PTP_V1_EN | TG3_RX_PTP_CTL_SYNC_EVNT: + stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_SYNC; + break; + case TG3_RX_PTP_CTL_RX_PTP_V1_EN | TG3_RX_PTP_CTL_DELAY_REQ: + stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ; + break; + case TG3_RX_PTP_CTL_RX_PTP_V2_EN | TG3_RX_PTP_CTL_ALL_V2_EVENTS: + stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; + break; + case TG3_RX_PTP_CTL_RX_PTP_V2_L2_EN | TG3_RX_PTP_CTL_ALL_V2_EVENTS: + stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT; + break; + case TG3_RX_PTP_CTL_RX_PTP_V2_L4_EN | TG3_RX_PTP_CTL_ALL_V2_EVENTS: + stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT; + break; + case TG3_RX_PTP_CTL_RX_PTP_V2_EN | TG3_RX_PTP_CTL_SYNC_EVNT: + stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_SYNC; + break; + case TG3_RX_PTP_CTL_RX_PTP_V2_L2_EN | TG3_RX_PTP_CTL_SYNC_EVNT: + stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_SYNC; + break; + case TG3_RX_PTP_CTL_RX_PTP_V2_L4_EN | TG3_RX_PTP_CTL_SYNC_EVNT: + stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_SYNC; + break; + case TG3_RX_PTP_CTL_RX_PTP_V2_EN | TG3_RX_PTP_CTL_DELAY_REQ: + stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_DELAY_REQ; + break; + case TG3_RX_PTP_CTL_RX_PTP_V2_L2_EN | TG3_RX_PTP_CTL_DELAY_REQ: + stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ; + break; + case TG3_RX_PTP_CTL_RX_PTP_V2_L4_EN | TG3_RX_PTP_CTL_DELAY_REQ: + stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ; + break; + default: + WARN_ON_ONCE(1); + return -ERANGE; + } + + return copy_to_user(ifr->ifr_data, &stmpconf, sizeof(stmpconf)) ? + -EFAULT : 0; +} + static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct mii_ioctl_data *data = if_mii(ifr); @@ -13744,7 +13804,10 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return err; case SIOCSHWTSTAMP: - return tg3_hwtstamp_ioctl(dev, ifr, cmd); + return tg3_hwtstamp_set(dev, ifr); + + case SIOCGHWTSTAMP: + return tg3_hwtstamp_get(dev, ifr); default: /* do nothing */ -- cgit v1.2.3-70-g09d2 From 1d5244d0e43b70565d3988a52c6461ee42d3927c Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 18 Nov 2013 23:02:44 +0000 Subject: fec: Implement the SIOCGHWTSTAMP ioctl This is untested. Signed-off-by: Ben Hutchings --- drivers/net/ethernet/freescale/fec.h | 3 ++- drivers/net/ethernet/freescale/fec_main.c | 8 ++++++-- drivers/net/ethernet/freescale/fec_ptp.c | 16 +++++++++++++++- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index 0120217a16d..3b8d6d19ff0 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -339,7 +339,8 @@ struct fec_enet_private { void fec_ptp_init(struct platform_device *pdev); void fec_ptp_start_cyclecounter(struct net_device *ndev); -int fec_ptp_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd); +int fec_ptp_set(struct net_device *ndev, struct ifreq *ifr); +int fec_ptp_get(struct net_device *ndev, struct ifreq *ifr); /****************************************************************************/ #endif /* FEC_H */ diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 4cbebf3d80e..40e953e81eb 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -1684,8 +1684,12 @@ static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) if (!phydev) return -ENODEV; - if (cmd == SIOCSHWTSTAMP && fep->bufdesc_ex) - return fec_ptp_ioctl(ndev, rq, cmd); + if (fep->bufdesc_ex) { + if (cmd == SIOCSHWTSTAMP) + return fec_ptp_set(ndev, rq); + if (cmd == SIOCGHWTSTAMP) + return fec_ptp_get(ndev, rq); + } return phy_mii_ioctl(phydev, rq, cmd); } diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c index 5007e4f9fff..3a74ea48fd4 100644 --- a/drivers/net/ethernet/freescale/fec_ptp.c +++ b/drivers/net/ethernet/freescale/fec_ptp.c @@ -274,7 +274,7 @@ static int fec_ptp_enable(struct ptp_clock_info *ptp, * @ifreq: ioctl data * @cmd: particular ioctl requested */ -int fec_ptp_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd) +int fec_ptp_set(struct net_device *ndev, struct ifreq *ifr) { struct fec_enet_private *fep = netdev_priv(ndev); @@ -321,6 +321,20 @@ int fec_ptp_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd) -EFAULT : 0; } +int fec_ptp_get(struct net_device *ndev, struct ifreq *ifr) +{ + struct fec_enet_private *fep = netdev_priv(ndev); + struct hwtstamp_config config; + + config.flags = 0; + config.tx_type = fep->hwts_tx_en ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF; + config.rx_filter = (fep->hwts_rx_en ? + HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE); + + return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? + -EFAULT : 0; +} + /** * fec_time_keep - call timecounter_read every second to avoid timer overrun * because ENET just support 32bit counter, will timeout in 4s -- cgit v1.2.3-70-g09d2 From ca0c88c2897581fa70227d408c43fb4efb7b7631 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 18 Nov 2013 23:05:27 +0000 Subject: gianfar: Implement the SIOCGHWTSTAMP ioctl This is untested. Signed-off-by: Ben Hutchings --- drivers/net/ethernet/freescale/gianfar.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index b14d7904a07..365342d293e 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -795,8 +795,7 @@ err_grp_init: return err; } -static int gfar_hwtstamp_ioctl(struct net_device *netdev, - struct ifreq *ifr, int cmd) +static int gfar_hwtstamp_set(struct net_device *netdev, struct ifreq *ifr) { struct hwtstamp_config config; struct gfar_private *priv = netdev_priv(netdev); @@ -845,7 +844,20 @@ static int gfar_hwtstamp_ioctl(struct net_device *netdev, -EFAULT : 0; } -/* Ioctl MII Interface */ +static int gfar_hwtstamp_get(struct net_device *netdev, struct ifreq *ifr) +{ + struct hwtstamp_config config; + struct gfar_private *priv = netdev_priv(netdev); + + config.flags = 0; + config.tx_type = priv->hwts_tx_en ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF; + config.rx_filter = (priv->hwts_rx_en ? + HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE); + + return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? + -EFAULT : 0; +} + static int gfar_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct gfar_private *priv = netdev_priv(dev); @@ -854,7 +866,9 @@ static int gfar_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return -EINVAL; if (cmd == SIOCSHWTSTAMP) - return gfar_hwtstamp_ioctl(dev, rq, cmd); + return gfar_hwtstamp_set(dev, rq); + if (cmd == SIOCGHWTSTAMP) + return gfar_hwtstamp_get(dev, rq); if (!priv->phydev) return -ENODEV; -- cgit v1.2.3-70-g09d2 From 4e8cff6480932f3ebe865614a1f2274e1983d08c Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 18 Nov 2013 23:07:16 +0000 Subject: e1000e: Implement the SIOCGHWTSTAMP ioctl Compile-tested only. Signed-off-by: Ben Hutchings --- drivers/net/ethernet/intel/e1000e/netdev.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index f0281657536..03e6af736de 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -5790,7 +5790,7 @@ static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, * specified. Matching the kind of event packet is not supported, with the * exception of "all V2 events regardless of level 2 or 4". **/ -static int e1000e_hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr) +static int e1000e_hwtstamp_set(struct net_device *netdev, struct ifreq *ifr) { struct e1000_adapter *adapter = netdev_priv(netdev); struct hwtstamp_config config; @@ -5825,6 +5825,14 @@ static int e1000e_hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr) sizeof(config)) ? -EFAULT : 0; } +static int e1000e_hwtstamp_get(struct net_device *netdev, struct ifreq *ifr) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + return copy_to_user(ifr->ifr_data, &adapter->hwtstamp_config, + sizeof(adapter->hwtstamp_config)) ? -EFAULT : 0; +} + static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) { switch (cmd) { @@ -5833,7 +5841,9 @@ static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) case SIOCSMIIREG: return e1000_mii_ioctl(netdev, ifr, cmd); case SIOCSHWTSTAMP: - return e1000e_hwtstamp_ioctl(netdev, ifr); + return e1000e_hwtstamp_set(netdev, ifr); + case SIOCGHWTSTAMP: + return e1000e_hwtstamp_get(netdev, ifr); default: return -EOPNOTSUPP; } -- cgit v1.2.3-70-g09d2 From 100dbda8e40bf4b537332d909660ddf9945196ff Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 18 Nov 2013 23:13:31 +0000 Subject: mlx4_en: Implement the SIOCGHWTSTAMP ioctl Compile-tested only. Signed-off-by: Ben Hutchings --- drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index e72d8a112a6..709e5ec5ce1 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -2025,7 +2025,7 @@ static int mlx4_en_change_mtu(struct net_device *dev, int new_mtu) return 0; } -static int mlx4_en_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) +static int mlx4_en_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) { struct mlx4_en_priv *priv = netdev_priv(dev); struct mlx4_en_dev *mdev = priv->mdev; @@ -2084,11 +2084,21 @@ static int mlx4_en_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) sizeof(config)) ? -EFAULT : 0; } +static int mlx4_en_hwtstamp_get(struct net_device *dev, struct ifreq *ifr) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + + return copy_to_user(ifr->ifr_data, &priv->hwtstamp_config, + sizeof(priv->hwtstamp_config)) ? -EFAULT : 0; +} + static int mlx4_en_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { switch (cmd) { case SIOCSHWTSTAMP: - return mlx4_en_hwtstamp_ioctl(dev, ifr); + return mlx4_en_hwtstamp_set(dev, ifr); + case SIOCGHWTSTAMP: + return mlx4_en_hwtstamp_get(dev, ifr); default: return -EOPNOTSUPP; } -- cgit v1.2.3-70-g09d2 From 450e55e996e714250baee79e334e879ee659bd11 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 18 Nov 2013 23:16:23 +0000 Subject: vxge: Implement the SIOCGHWTSTAMP ioctl Compile-tested only. Signed-off-by: Ben Hutchings --- drivers/net/ethernet/neterion/vxge/vxge-main.c | 27 ++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/neterion/vxge/vxge-main.c b/drivers/net/ethernet/neterion/vxge/vxge-main.c index 8614eeb7de8..33f98eca5dc 100644 --- a/drivers/net/ethernet/neterion/vxge/vxge-main.c +++ b/drivers/net/ethernet/neterion/vxge/vxge-main.c @@ -3185,7 +3185,7 @@ static enum vxge_hw_status vxge_timestamp_config(struct __vxge_hw_device *devh) return status; } -static int vxge_hwtstamp_ioctl(struct vxgedev *vdev, void __user *data) +static int vxge_hwtstamp_set(struct vxgedev *vdev, void __user *data) { struct hwtstamp_config config; int i; @@ -3246,6 +3246,21 @@ static int vxge_hwtstamp_ioctl(struct vxgedev *vdev, void __user *data) return 0; } +static int vxge_hwtstamp_get(struct vxgedev *vdev, void __user *data) +{ + struct hwtstamp_config config; + + config.flags = 0; + config.tx_type = HWTSTAMP_TX_OFF; + config.rx_filter = (vdev->rx_hwts ? + HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE); + + if (copy_to_user(data, &config, sizeof(config))) + return -EFAULT; + + return 0; +} + /** * vxge_ioctl * @dev: Device pointer. @@ -3259,19 +3274,15 @@ static int vxge_hwtstamp_ioctl(struct vxgedev *vdev, void __user *data) static int vxge_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct vxgedev *vdev = netdev_priv(dev); - int ret; switch (cmd) { case SIOCSHWTSTAMP: - ret = vxge_hwtstamp_ioctl(vdev, rq->ifr_data); - if (ret) - return ret; - break; + return vxge_hwtstamp_set(vdev, rq->ifr_data); + case SIOCGHWTSTAMP: + return vxge_hwtstamp_get(vdev, rq->ifr_data); default: return -EOPNOTSUPP; } - - return 0; } /** -- cgit v1.2.3-70-g09d2 From a5b4145ba937b76dd698ad6fe5c5f37e0edbac43 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 18 Nov 2013 23:23:40 +0000 Subject: ti_cpsw: Implement the SIOCGHWTSTAMP ioctl This is untested. Signed-off-by: Ben Hutchings --- drivers/net/ethernet/ti/cpsw.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 7536a4c0129..bc0cb154fc5 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -1322,7 +1322,7 @@ static void cpsw_hwtstamp_v2(struct cpsw_priv *priv) __raw_writel(ETH_P_1588, &priv->regs->ts_ltype); } -static int cpsw_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) +static int cpsw_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) { struct cpsw_priv *priv = netdev_priv(dev); struct cpts *cpts = priv->cpts; @@ -1383,6 +1383,24 @@ static int cpsw_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; } +static int cpsw_hwtstamp_get(struct net_device *dev, struct ifreq *ifr) +{ + struct cpsw_priv *priv = netdev_priv(dev); + struct cpts *cpts = priv->cpts; + struct hwtstamp_config cfg; + + if (priv->version != CPSW_VERSION_1 && + priv->version != CPSW_VERSION_2) + return -EOPNOTSUPP; + + cfg.flags = 0; + cfg.tx_type = cpts->tx_enable ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF; + cfg.rx_filter = (cpts->rx_enable ? + HWTSTAMP_FILTER_PTP_V2_EVENT : HWTSTAMP_FILTER_NONE); + + return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; +} + #endif /*CONFIG_TI_CPTS*/ static int cpsw_ndo_ioctl(struct net_device *dev, struct ifreq *req, int cmd) @@ -1397,7 +1415,9 @@ static int cpsw_ndo_ioctl(struct net_device *dev, struct ifreq *req, int cmd) switch (cmd) { #ifdef CONFIG_TI_CPTS case SIOCSHWTSTAMP: - return cpsw_hwtstamp_ioctl(dev, req); + return cpsw_hwtstamp_set(dev, req); + case SIOCGHWTSTAMP: + return cpsw_hwtstamp_get(dev, req); #endif case SIOCGMIIPHY: data->phy_id = priv->slaves[slave_no].phy->addr; -- cgit v1.2.3-70-g09d2 From 6ab96d1e06ba1452d583f3e45d6a3a45bb36b1c3 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 18 Nov 2013 23:25:20 +0000 Subject: tile_net: Implement the SIOCGHWTSTAMP ioctl Compile-tested only (thanks to the kbuild test robot). Signed-off-by: Ben Hutchings --- drivers/net/ethernet/tile/tilegx.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/tile/tilegx.c b/drivers/net/ethernet/tile/tilegx.c index 628b736e5ae..858f9a786b8 100644 --- a/drivers/net/ethernet/tile/tilegx.c +++ b/drivers/net/ethernet/tile/tilegx.c @@ -481,8 +481,7 @@ static void tile_tx_timestamp(struct sk_buff *skb, int instance) } /* Use ioctl() to enable or disable TX or RX timestamping. */ -static int tile_hwtstamp_ioctl(struct net_device *dev, struct ifreq *rq, - int cmd) +static int tile_hwtstamp_set(struct net_device *dev, struct ifreq *rq) { #ifdef CONFIG_PTP_1588_CLOCK_TILEGX struct hwtstamp_config config; @@ -535,6 +534,21 @@ static int tile_hwtstamp_ioctl(struct net_device *dev, struct ifreq *rq, #endif } +static int tile_hwtstamp_get(struct net_device *dev, struct ifreq *rq) +{ +#ifdef CONFIG_PTP_1588_CLOCK_TILEGX + struct tile_net_priv *priv = netdev_priv(dev); + + if (copy_to_user(rq->ifr_data, &priv->stamp_cfg, + sizeof(priv->stamp_cfg))) + return -EFAULT; + + return 0; +#else + return -EOPNOTSUPP; +#endif +} + static inline bool filter_packet(struct net_device *dev, void *buf) { /* Filter packets received before we're up. */ @@ -2098,7 +2112,9 @@ static void tile_net_tx_timeout(struct net_device *dev) static int tile_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { if (cmd == SIOCSHWTSTAMP) - return tile_hwtstamp_ioctl(dev, rq, cmd); + return tile_hwtstamp_set(dev, rq); + if (cmd == SIOCGHWTSTAMP) + return tile_hwtstamp_get(dev, rq); return -EOPNOTSUPP; } -- cgit v1.2.3-70-g09d2 From 81fc347a0f0ab460276e3800147aaf2e8b32b466 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 18 Nov 2013 23:28:30 +0000 Subject: ixp4xx_eth: Implement the SIOCGHWTSTAMP ioctl This is untested. Signed-off-by: Ben Hutchings --- drivers/net/ethernet/xscale/ixp4xx_eth.c | 36 +++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/xscale/ixp4xx_eth.c b/drivers/net/ethernet/xscale/ixp4xx_eth.c index bcc224a8373..25283f17d82 100644 --- a/drivers/net/ethernet/xscale/ixp4xx_eth.c +++ b/drivers/net/ethernet/xscale/ixp4xx_eth.c @@ -373,7 +373,7 @@ static void ixp_tx_timestamp(struct port *port, struct sk_buff *skb) __raw_writel(TX_SNAPSHOT_LOCKED, ®s->channel[ch].ch_event); } -static int hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +static int hwtstamp_set(struct net_device *netdev, struct ifreq *ifr) { struct hwtstamp_config cfg; struct ixp46x_ts_regs *regs; @@ -417,6 +417,32 @@ static int hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; } +static int hwtstamp_get(struct net_device *netdev, struct ifreq *ifr) +{ + struct hwtstamp_config cfg; + struct port *port = netdev_priv(netdev); + + cfg.flags = 0; + cfg.tx_type = port->hwts_tx_en ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF; + + switch (port->hwts_rx_en) { + case 0: + cfg.rx_filter = HWTSTAMP_FILTER_NONE; + break; + case PTP_SLAVE_MODE: + cfg.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_SYNC; + break; + case PTP_MASTER_MODE: + cfg.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ; + break; + default: + WARN_ON_ONCE(1); + return -ERANGE; + } + + return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; +} + static int ixp4xx_mdio_cmd(struct mii_bus *bus, int phy_id, int location, int write, u16 cmd) { @@ -959,8 +985,12 @@ static int eth_ioctl(struct net_device *dev, struct ifreq *req, int cmd) if (!netif_running(dev)) return -EINVAL; - if (cpu_is_ixp46x() && cmd == SIOCSHWTSTAMP) - return hwtstamp_ioctl(dev, req, cmd); + if (cpu_is_ixp46x()) { + if (cmd == SIOCSHWTSTAMP) + return hwtstamp_set(dev, req); + if (cmd == SIOCGHWTSTAMP) + return hwtstamp_get(dev, req); + } return phy_mii_ioctl(port->phydev, req, cmd); } -- cgit v1.2.3-70-g09d2 From a4bcc795e9cc84902b86edbfbb755ecb38d11f91 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 22 Nov 2013 20:10:24 +0000 Subject: net_tstamp,doc: Add test program for SIOC{G,S}HWTSTAMP Signed-off-by: Ben Hutchings --- Documentation/networking/timestamping/.gitignore | 1 + Documentation/networking/timestamping/Makefile | 5 +- .../networking/timestamping/hwtstamp_config.c | 134 +++++++++++++++++++++ 3 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 Documentation/networking/timestamping/hwtstamp_config.c diff --git a/Documentation/networking/timestamping/.gitignore b/Documentation/networking/timestamping/.gitignore index 71e81eb2e22..a380159765c 100644 --- a/Documentation/networking/timestamping/.gitignore +++ b/Documentation/networking/timestamping/.gitignore @@ -1 +1,2 @@ timestamping +hwtstamp_config diff --git a/Documentation/networking/timestamping/Makefile b/Documentation/networking/timestamping/Makefile index e79973443e9..d934afc8306 100644 --- a/Documentation/networking/timestamping/Makefile +++ b/Documentation/networking/timestamping/Makefile @@ -2,12 +2,13 @@ obj- := dummy.o # List of programs to build -hostprogs-y := timestamping +hostprogs-y := timestamping hwtstamp_config # Tell kbuild to always build the programs always := $(hostprogs-y) HOSTCFLAGS_timestamping.o += -I$(objtree)/usr/include +HOSTCFLAGS_hwtstamp_config.o += -I$(objtree)/usr/include clean: - rm -f timestamping + rm -f timestamping hwtstamp_config diff --git a/Documentation/networking/timestamping/hwtstamp_config.c b/Documentation/networking/timestamping/hwtstamp_config.c new file mode 100644 index 00000000000..e8b685a7f15 --- /dev/null +++ b/Documentation/networking/timestamping/hwtstamp_config.c @@ -0,0 +1,134 @@ +/* Test program for SIOC{G,S}HWTSTAMP + * Copyright 2013 Solarflare Communications + * Author: Ben Hutchings + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +static int +lookup_value(const char **names, int size, const char *name) +{ + int value; + + for (value = 0; value < size; value++) + if (names[value] && strcasecmp(names[value], name) == 0) + return value; + + return -1; +} + +static const char * +lookup_name(const char **names, int size, int value) +{ + return (value >= 0 && value < size) ? names[value] : NULL; +} + +static void list_names(FILE *f, const char **names, int size) +{ + int value; + + for (value = 0; value < size; value++) + if (names[value]) + fprintf(f, " %s\n", names[value]); +} + +static const char *tx_types[] = { +#define TX_TYPE(name) [HWTSTAMP_TX_ ## name] = #name + TX_TYPE(OFF), + TX_TYPE(ON), + TX_TYPE(ONESTEP_SYNC) +#undef TX_TYPE +}; +#define N_TX_TYPES ((int)(sizeof(tx_types) / sizeof(tx_types[0]))) + +static const char *rx_filters[] = { +#define RX_FILTER(name) [HWTSTAMP_FILTER_ ## name] = #name + RX_FILTER(NONE), + RX_FILTER(ALL), + RX_FILTER(SOME), + RX_FILTER(PTP_V1_L4_EVENT), + RX_FILTER(PTP_V1_L4_SYNC), + RX_FILTER(PTP_V1_L4_DELAY_REQ), + RX_FILTER(PTP_V2_L4_EVENT), + RX_FILTER(PTP_V2_L4_SYNC), + RX_FILTER(PTP_V2_L4_DELAY_REQ), + RX_FILTER(PTP_V2_L2_EVENT), + RX_FILTER(PTP_V2_L2_SYNC), + RX_FILTER(PTP_V2_L2_DELAY_REQ), + RX_FILTER(PTP_V2_EVENT), + RX_FILTER(PTP_V2_SYNC), + RX_FILTER(PTP_V2_DELAY_REQ), +#undef RX_FILTER +}; +#define N_RX_FILTERS ((int)(sizeof(rx_filters) / sizeof(rx_filters[0]))) + +static void usage(void) +{ + fputs("Usage: hwtstamp_config if_name [tx_type rx_filter]\n" + "tx_type is any of (case-insensitive):\n", + stderr); + list_names(stderr, tx_types, N_TX_TYPES); + fputs("rx_filter is any of (case-insensitive):\n", stderr); + list_names(stderr, rx_filters, N_RX_FILTERS); +} + +int main(int argc, char **argv) +{ + struct ifreq ifr; + struct hwtstamp_config config; + const char *name; + int sock; + + if ((argc != 2 && argc != 4) || (strlen(argv[1]) >= IFNAMSIZ)) { + usage(); + return 2; + } + + if (argc == 4) { + config.flags = 0; + config.tx_type = lookup_value(tx_types, N_TX_TYPES, argv[2]); + config.rx_filter = lookup_value(rx_filters, N_RX_FILTERS, argv[3]); + if (config.tx_type < 0 || config.rx_filter < 0) { + usage(); + return 2; + } + } + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock < 0) { + perror("socket"); + return 1; + } + + strcpy(ifr.ifr_name, argv[1]); + ifr.ifr_data = (caddr_t)&config; + + if (ioctl(sock, (argc == 2) ? SIOCGHWTSTAMP : SIOCSHWTSTAMP, &ifr)) { + perror("ioctl"); + return 1; + } + + printf("flags = %#x\n", config.flags); + name = lookup_name(tx_types, N_TX_TYPES, config.tx_type); + if (name) + printf("tx_type = %s\n", name); + else + printf("tx_type = %d\n", config.tx_type); + name = lookup_name(rx_filters, N_RX_FILTERS, config.rx_filter); + if (name) + printf("rx_filter = %s\n", name); + else + printf("rx_filter = %d\n", config.rx_filter); + + return 0; +} -- cgit v1.2.3-70-g09d2 From c17bff87bed4bda1835ee41dc908e926414d8d85 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 31 Oct 2013 14:54:35 +0200 Subject: nl80211: better document NL80211_CMD_TDLS_MGMT This command has different semantics depending on the action code sent. Document this fact and detail the supported action codes. Signed-off-by: Arik Nemtsov Signed-off-by: Johannes Berg --- include/uapi/linux/nl80211.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index f752e9821e7..3d8325bb50c 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -581,7 +581,14 @@ * operation, %NL80211_ATTR_MAC contains the peer MAC address, and * %NL80211_ATTR_REASON_CODE the reason code to be used (only with * %NL80211_TDLS_TEARDOWN). - * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame. + * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame. The + * %NL80211_ATTR_TDLS_ACTION attribute determines the type of frame to be + * sent. Public Action codes (802.11-2012 8.1.5.1) will be sent as + * 802.11 management frames, while TDLS action codes (802.11-2012 + * 8.5.13.1) will be encapsulated and sent as data frames. The currently + * supported Public Action code is %WLAN_PUB_ACTION_TDLS_DISCOVER_RES + * and the currently supported TDLS actions codes are given in + * &enum ieee80211_tdls_actioncode. * * @NL80211_CMD_UNEXPECTED_FRAME: Used by an application controlling an AP * (or GO) interface (i.e. hostapd) to ask for unexpected frames to -- cgit v1.2.3-70-g09d2 From 8fe02e167efa8ed4a4503a5eedc0f49fcb7e3eb9 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 21 Oct 2013 19:22:25 +0200 Subject: cfg80211: consolidate passive-scan and no-ibss flags These two flags are used for the same purpose, just combine them into a no-ir flag to annotate no initiating radiation is allowed. Old userspace sending either flag will have it treated as the no-ir flag. To be considerate to older userspace we also send both the no-ir flag and the old no-ibss flags. Newer userspace will have to be aware of older kernels. Update all places in the tree using these flags with the following semantic patch: @@ @@ -NL80211_RRF_PASSIVE_SCAN +NL80211_RRF_NO_IR @@ @@ -NL80211_RRF_NO_IBSS +NL80211_RRF_NO_IR @@ @@ -IEEE80211_CHAN_PASSIVE_SCAN +IEEE80211_CHAN_NO_IR @@ @@ -IEEE80211_CHAN_NO_IBSS +IEEE80211_CHAN_NO_IR @@ @@ -NL80211_RRF_NO_IR | NL80211_RRF_NO_IR +NL80211_RRF_NO_IR @@ @@ -IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_IR +IEEE80211_CHAN_NO_IR @@ @@ -(NL80211_RRF_NO_IR) +NL80211_RRF_NO_IR @@ @@ -(IEEE80211_CHAN_NO_IR) +IEEE80211_CHAN_NO_IR Along with some hand-optimisations in documentation, to remove duplicates and to fix some indentation. Signed-off-by: Luis R. Rodriguez [do all the driver updates in one go] Signed-off-by: Johannes Berg --- Documentation/networking/regulatory.txt | 4 +- drivers/net/wireless/ath/ath10k/mac.c | 4 +- drivers/net/wireless/ath/regd.c | 47 +++++++-------- drivers/net/wireless/brcm80211/brcmfmac/p2p.c | 2 +- .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 10 ++-- drivers/net/wireless/brcm80211/brcmsmac/channel.c | 31 ++++------ .../net/wireless/brcm80211/brcmsmac/mac80211_if.c | 66 +++++++++++----------- drivers/net/wireless/cw1200/scan.c | 10 ++-- drivers/net/wireless/ipw2x00/ipw2100.c | 4 +- drivers/net/wireless/ipw2x00/ipw2200.c | 8 +-- drivers/net/wireless/iwlegacy/3945-mac.c | 2 +- drivers/net/wireless/iwlegacy/4965-mac.c | 2 +- drivers/net/wireless/iwlegacy/common.c | 4 +- drivers/net/wireless/iwlegacy/debug.c | 8 +-- drivers/net/wireless/iwlwifi/dvm/debugfs.c | 8 +-- drivers/net/wireless/iwlwifi/dvm/scan.c | 2 +- drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c | 4 +- drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 4 +- drivers/net/wireless/iwlwifi/mvm/scan.c | 4 +- drivers/net/wireless/mac80211_hwsim.c | 4 +- drivers/net/wireless/mwifiex/cfg80211.c | 14 ++--- drivers/net/wireless/mwifiex/scan.c | 4 +- drivers/net/wireless/rtlwifi/regd.c | 48 +++++++--------- drivers/net/wireless/ti/wl12xx/scan.c | 2 +- drivers/net/wireless/ti/wlcore/cmd.c | 2 +- drivers/net/wireless/ti/wlcore/main.c | 3 +- drivers/net/wireless/ti/wlcore/scan.c | 12 ++-- include/net/cfg80211.h | 9 ++- include/uapi/linux/nl80211.h | 30 ++++++---- net/mac80211/scan.c | 10 ++-- net/mac80211/tx.c | 3 +- net/wireless/chan.c | 3 +- net/wireless/genregdb.awk | 7 ++- net/wireless/ibss.c | 4 +- net/wireless/mesh.c | 3 +- net/wireless/nl80211.c | 12 ++-- net/wireless/reg.c | 33 ++++------- 37 files changed, 197 insertions(+), 230 deletions(-) diff --git a/Documentation/networking/regulatory.txt b/Documentation/networking/regulatory.txt index 9551622d0a7..356f791af57 100644 --- a/Documentation/networking/regulatory.txt +++ b/Documentation/networking/regulatory.txt @@ -159,10 +159,10 @@ struct ieee80211_regdomain mydriver_jp_regdom = { REG_RULE(2412-20, 2484+20, 40, 6, 20, 0), /* IEEE 802.11a, channels 34..48 */ REG_RULE(5170-20, 5240+20, 40, 6, 20, - NL80211_RRF_PASSIVE_SCAN), + NL80211_RRF_NO_IR), /* IEEE 802.11a, channels 52..64 */ REG_RULE(5260-20, 5320+20, 40, 6, 20, - NL80211_RRF_NO_IBSS | + NL80211_RRF_NO_IR| NL80211_RRF_DFS), } }; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 0b1cc516e77..f23d61fda24 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1351,12 +1351,12 @@ static int ath10k_update_channel_list(struct ath10k *ar) ch->allow_vht = true; ch->allow_ibss = - !(channel->flags & IEEE80211_CHAN_NO_IBSS); + !(channel->flags & IEEE80211_CHAN_NO_IR); ch->ht40plus = !(channel->flags & IEEE80211_CHAN_NO_HT40PLUS); - passive = channel->flags & IEEE80211_CHAN_PASSIVE_SCAN; + passive = channel->flags & IEEE80211_CHAN_NO_IR; ch->passive = passive; ch->freq = channel->center_freq; diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index c00687e0568..e93e517a699 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -37,17 +37,18 @@ static int __ath_regd_init(struct ath_regulatory *reg); /* We enable active scan on these a case by case basis by regulatory domain */ #define ATH9K_2GHZ_CH12_13 REG_RULE(2467-10, 2472+10, 40, 0, 20,\ - NL80211_RRF_PASSIVE_SCAN) + NL80211_RRF_NO_IR) #define ATH9K_2GHZ_CH14 REG_RULE(2484-10, 2484+10, 40, 0, 20,\ - NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_OFDM) + NL80211_RRF_NO_IR | \ + NL80211_RRF_NO_OFDM) /* We allow IBSS on these on a case by case basis by regulatory domain */ #define ATH9K_5GHZ_5150_5350 REG_RULE(5150-10, 5350+10, 80, 0, 30,\ - NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS) + NL80211_RRF_NO_IR) #define ATH9K_5GHZ_5470_5850 REG_RULE(5470-10, 5850+10, 80, 0, 30,\ - NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS) + NL80211_RRF_NO_IR) #define ATH9K_5GHZ_5725_5850 REG_RULE(5725-10, 5850+10, 80, 0, 30,\ - NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS) + NL80211_RRF_NO_IR) #define ATH9K_2GHZ_ALL ATH9K_2GHZ_CH01_11, \ ATH9K_2GHZ_CH12_13, \ @@ -223,18 +224,11 @@ ath_reg_apply_beaconing_flags(struct wiphy *wiphy, * default during init, prior to calling our * regulatory_hint(). */ - if (!(reg_rule->flags & - NL80211_RRF_NO_IBSS)) - ch->flags &= - ~IEEE80211_CHAN_NO_IBSS; - if (!(reg_rule->flags & - NL80211_RRF_PASSIVE_SCAN)) - ch->flags &= - ~IEEE80211_CHAN_PASSIVE_SCAN; + if (!(reg_rule->flags & NL80211_RRF_NO_IR)) + ch->flags &= ~IEEE80211_CHAN_NO_IR; } else { if (ch->beacon_found) - ch->flags &= ~(IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN); + ch->flags &= ~IEEE80211_CHAN_NO_IR; } } } @@ -260,11 +254,11 @@ ath_reg_apply_active_scan_flags(struct wiphy *wiphy, */ if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) { ch = &sband->channels[11]; /* CH 12 */ - if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) - ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; + if (ch->flags & IEEE80211_CHAN_NO_IR) + ch->flags &= ~IEEE80211_CHAN_NO_IR; ch = &sband->channels[12]; /* CH 13 */ - if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) - ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; + if (ch->flags & IEEE80211_CHAN_NO_IR) + ch->flags &= ~IEEE80211_CHAN_NO_IR; return; } @@ -278,17 +272,17 @@ ath_reg_apply_active_scan_flags(struct wiphy *wiphy, ch = &sband->channels[11]; /* CH 12 */ reg_rule = freq_reg_info(wiphy, ch->center_freq); if (!IS_ERR(reg_rule)) { - if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) - if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) - ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; + if (!(reg_rule->flags & NL80211_RRF_NO_IR)) + if (ch->flags & IEEE80211_CHAN_NO_IR) + ch->flags &= ~IEEE80211_CHAN_NO_IR; } ch = &sband->channels[12]; /* CH 13 */ reg_rule = freq_reg_info(wiphy, ch->center_freq); if (!IS_ERR(reg_rule)) { - if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) - if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) - ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; + if (!(reg_rule->flags & NL80211_RRF_NO_IR)) + if (ch->flags & IEEE80211_CHAN_NO_IR) + ch->flags &= ~IEEE80211_CHAN_NO_IR; } } @@ -320,8 +314,7 @@ static void ath_reg_apply_radar_flags(struct wiphy *wiphy) */ if (!(ch->flags & IEEE80211_CHAN_DISABLED)) ch->flags |= IEEE80211_CHAN_RADAR | - IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN; + IEEE80211_CHAN_NO_IR; } } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c index d7a97453290..fd0a4971244 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c @@ -812,7 +812,7 @@ static s32 brcmf_p2p_run_escan(struct brcmf_cfg80211_info *cfg, struct ieee80211_channel *chan = request->channels[i]; if (chan->flags & (IEEE80211_CHAN_RADAR | - IEEE80211_CHAN_PASSIVE_SCAN)) + IEEE80211_CHAN_NO_IR)) continue; chanspecs[i] = channel_to_chanspec(&p2p->cfg->d11inf, diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 571f013cebb..b6a09f97f9a 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -202,9 +202,9 @@ static struct ieee80211_supported_band __wl_band_5ghz_a = { /* This is to override regulatory domains defined in cfg80211 module (reg.c) * By default world regulatory domain defined in reg.c puts the flags - * NL80211_RRF_PASSIVE_SCAN and NL80211_RRF_NO_IBSS for 5GHz channels (for - * 36..48 and 149..165). With respect to these flags, wpa_supplicant doesn't - * start p2p operations on 5GHz channels. All the changes in world regulatory + * NL80211_RRF_NO_IR for 5GHz channels (for * 36..48 and 149..165). + * With respect to these flags, wpa_supplicant doesn't * start p2p + * operations on 5GHz channels. All the changes in world regulatory * domain are to be done here. */ static const struct ieee80211_regdomain brcmf_regdom = { @@ -5197,10 +5197,10 @@ static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap) if (channel & WL_CHAN_RADAR) band_chan_arr[index].flags |= (IEEE80211_CHAN_RADAR | - IEEE80211_CHAN_NO_IBSS); + IEEE80211_CHAN_NO_IR); if (channel & WL_CHAN_PASSIVE) band_chan_arr[index].flags |= - IEEE80211_CHAN_PASSIVE_SCAN; + IEEE80211_CHAN_NO_IR; } } if (!update) diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/brcm80211/brcmsmac/channel.c index cc87926f505..7d8f3fd69a8 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/channel.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.c @@ -59,23 +59,18 @@ #define BRCM_2GHZ_2412_2462 REG_RULE(2412-10, 2462+10, 40, 0, 19, 0) #define BRCM_2GHZ_2467_2472 REG_RULE(2467-10, 2472+10, 20, 0, 19, \ - NL80211_RRF_PASSIVE_SCAN | \ - NL80211_RRF_NO_IBSS) + NL80211_RRF_NO_IR) #define BRCM_5GHZ_5180_5240 REG_RULE(5180-10, 5240+10, 40, 0, 21, \ - NL80211_RRF_PASSIVE_SCAN | \ - NL80211_RRF_NO_IBSS) + NL80211_RRF_NO_IR) #define BRCM_5GHZ_5260_5320 REG_RULE(5260-10, 5320+10, 40, 0, 21, \ - NL80211_RRF_PASSIVE_SCAN | \ NL80211_RRF_DFS | \ - NL80211_RRF_NO_IBSS) + NL80211_RRF_NO_IR) #define BRCM_5GHZ_5500_5700 REG_RULE(5500-10, 5700+10, 40, 0, 21, \ - NL80211_RRF_PASSIVE_SCAN | \ NL80211_RRF_DFS | \ - NL80211_RRF_NO_IBSS) + NL80211_RRF_NO_IR) #define BRCM_5GHZ_5745_5825 REG_RULE(5745-10, 5825+10, 40, 0, 21, \ - NL80211_RRF_PASSIVE_SCAN | \ - NL80211_RRF_NO_IBSS) + NL80211_RRF_NO_IR) static const struct ieee80211_regdomain brcms_regdom_x2 = { .n_reg_rules = 6, @@ -395,7 +390,7 @@ brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec, brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false); brcms_b_set_chanspec(wlc->hw, chanspec, - !!(ch->flags & IEEE80211_CHAN_PASSIVE_SCAN), + !!(ch->flags & IEEE80211_CHAN_NO_IR), &txpwr); } @@ -657,8 +652,8 @@ static void brcms_reg_apply_radar_flags(struct wiphy *wiphy) */ if (!(ch->flags & IEEE80211_CHAN_DISABLED)) ch->flags |= IEEE80211_CHAN_RADAR | - IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN; + IEEE80211_CHAN_NO_IR | + IEEE80211_CHAN_NO_IR; } } @@ -688,14 +683,10 @@ brcms_reg_apply_beaconing_flags(struct wiphy *wiphy, if (IS_ERR(rule)) continue; - if (!(rule->flags & NL80211_RRF_NO_IBSS)) - ch->flags &= ~IEEE80211_CHAN_NO_IBSS; - if (!(rule->flags & NL80211_RRF_PASSIVE_SCAN)) - ch->flags &= - ~IEEE80211_CHAN_PASSIVE_SCAN; + if (!(rule->flags & NL80211_RRF_NO_IR)) + ch->flags &= ~IEEE80211_CHAN_NO_IR; } else if (ch->beacon_found) { - ch->flags &= ~(IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN); + ch->flags &= ~IEEE80211_CHAN_NO_IR; } } } diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index edc5d105ff9..e71ce8c842a 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -125,13 +125,13 @@ static struct ieee80211_channel brcms_2ghz_chantable[] = { CHAN2GHZ(10, 2457, IEEE80211_CHAN_NO_HT40PLUS), CHAN2GHZ(11, 2462, IEEE80211_CHAN_NO_HT40PLUS), CHAN2GHZ(12, 2467, - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS), CHAN2GHZ(13, 2472, - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS), CHAN2GHZ(14, 2484, - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS | IEEE80211_CHAN_NO_OFDM) }; @@ -144,51 +144,51 @@ static struct ieee80211_channel brcms_5ghz_nphy_chantable[] = { CHAN5GHZ(48, IEEE80211_CHAN_NO_HT40PLUS), /* UNII-2 */ CHAN5GHZ(52, - IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), + IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS), CHAN5GHZ(56, - IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), + IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS), CHAN5GHZ(60, - IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), + IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS), CHAN5GHZ(64, - IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), + IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS), /* MID */ CHAN5GHZ(100, - IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), + IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS), CHAN5GHZ(104, - IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), + IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS), CHAN5GHZ(108, - IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), + IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS), CHAN5GHZ(112, - IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), + IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS), CHAN5GHZ(116, - IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), + IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS), CHAN5GHZ(120, - IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), + IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS), CHAN5GHZ(124, - IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), + IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS), CHAN5GHZ(128, - IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), + IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS), CHAN5GHZ(132, - IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), + IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS), CHAN5GHZ(136, - IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), + IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS), CHAN5GHZ(140, - IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS | + IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS), /* UNII-3 */ CHAN5GHZ(149, IEEE80211_CHAN_NO_HT40MINUS), diff --git a/drivers/net/wireless/cw1200/scan.c b/drivers/net/wireless/cw1200/scan.c index ee3c19037aa..8c017bfd2ff 100644 --- a/drivers/net/wireless/cw1200/scan.c +++ b/drivers/net/wireless/cw1200/scan.c @@ -197,9 +197,9 @@ void cw1200_scan_work(struct work_struct *work) if ((*it)->band != first->band) break; if (((*it)->flags ^ first->flags) & - IEEE80211_CHAN_PASSIVE_SCAN) + IEEE80211_CHAN_NO_IR) break; - if (!(first->flags & IEEE80211_CHAN_PASSIVE_SCAN) && + if (!(first->flags & IEEE80211_CHAN_NO_IR) && (*it)->max_power != first->max_power) break; } @@ -210,7 +210,7 @@ void cw1200_scan_work(struct work_struct *work) else scan.max_tx_rate = WSM_TRANSMIT_RATE_1; scan.num_probes = - (first->flags & IEEE80211_CHAN_PASSIVE_SCAN) ? 0 : 2; + (first->flags & IEEE80211_CHAN_NO_IR) ? 0 : 2; scan.num_ssids = priv->scan.n_ssids; scan.ssids = &priv->scan.ssids[0]; scan.num_channels = it - priv->scan.curr; @@ -233,7 +233,7 @@ void cw1200_scan_work(struct work_struct *work) } for (i = 0; i < scan.num_channels; ++i) { scan.ch[i].number = priv->scan.curr[i]->hw_value; - if (priv->scan.curr[i]->flags & IEEE80211_CHAN_PASSIVE_SCAN) { + if (priv->scan.curr[i]->flags & IEEE80211_CHAN_NO_IR) { scan.ch[i].min_chan_time = 50; scan.ch[i].max_chan_time = 100; } else { @@ -241,7 +241,7 @@ void cw1200_scan_work(struct work_struct *work) scan.ch[i].max_chan_time = 25; } } - if (!(first->flags & IEEE80211_CHAN_PASSIVE_SCAN) && + if (!(first->flags & IEEE80211_CHAN_NO_IR) && priv->scan.output_power != first->max_power) { priv->scan.output_power = first->max_power; wsm_set_output_power(priv, diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index f8ab193009c..813c9af0ebd 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -1930,10 +1930,10 @@ static int ipw2100_wdev_init(struct net_device *dev) bg_band->channels[i].max_power = geo->bg[i].max_power; if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY) bg_band->channels[i].flags |= - IEEE80211_CHAN_PASSIVE_SCAN; + IEEE80211_CHAN_NO_IR; if (geo->bg[i].flags & LIBIPW_CH_NO_IBSS) bg_band->channels[i].flags |= - IEEE80211_CHAN_NO_IBSS; + IEEE80211_CHAN_NO_IR; if (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT) bg_band->channels[i].flags |= IEEE80211_CHAN_RADAR; diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index f394af777cf..4eca9e20ade 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -11472,10 +11472,10 @@ static int ipw_wdev_init(struct net_device *dev) bg_band->channels[i].max_power = geo->bg[i].max_power; if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY) bg_band->channels[i].flags |= - IEEE80211_CHAN_PASSIVE_SCAN; + IEEE80211_CHAN_NO_IR; if (geo->bg[i].flags & LIBIPW_CH_NO_IBSS) bg_band->channels[i].flags |= - IEEE80211_CHAN_NO_IBSS; + IEEE80211_CHAN_NO_IR; if (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT) bg_band->channels[i].flags |= IEEE80211_CHAN_RADAR; @@ -11511,10 +11511,10 @@ static int ipw_wdev_init(struct net_device *dev) a_band->channels[i].max_power = geo->a[i].max_power; if (geo->a[i].flags & LIBIPW_CH_PASSIVE_ONLY) a_band->channels[i].flags |= - IEEE80211_CHAN_PASSIVE_SCAN; + IEEE80211_CHAN_NO_IR; if (geo->a[i].flags & LIBIPW_CH_NO_IBSS) a_band->channels[i].flags |= - IEEE80211_CHAN_NO_IBSS; + IEEE80211_CHAN_NO_IR; if (geo->a[i].flags & LIBIPW_CH_RADAR_DETECT) a_band->channels[i].flags |= IEEE80211_CHAN_RADAR; diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c index dea3b50d68b..5a66595b0fa 100644 --- a/drivers/net/wireless/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/iwlegacy/3945-mac.c @@ -1595,7 +1595,7 @@ il3945_get_channels_for_scan(struct il_priv *il, enum ieee80211_band band, * and use long active_dwell time. */ if (!is_active || il_is_channel_passive(ch_info) || - (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)) { + (chan->flags & IEEE80211_CHAN_NO_IR)) { scan_ch->type = 0; /* passive */ if (IL_UCODE_API(il->ucode_ver) == 1) scan_ch->active_dwell = diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c index 3982ab76f37..1c5f8cdbd3a 100644 --- a/drivers/net/wireless/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/iwlegacy/4965-mac.c @@ -805,7 +805,7 @@ il4965_get_channels_for_scan(struct il_priv *il, struct ieee80211_vif *vif, } if (!is_active || il_is_channel_passive(ch_info) || - (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)) + (chan->flags & IEEE80211_CHAN_NO_IR)) scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE; else scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE; diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c index b03e22ef546..a27b14cfeae 100644 --- a/drivers/net/wireless/iwlegacy/common.c +++ b/drivers/net/wireless/iwlegacy/common.c @@ -3445,10 +3445,10 @@ il_init_geos(struct il_priv *il) if (il_is_channel_valid(ch)) { if (!(ch->flags & EEPROM_CHANNEL_IBSS)) - geo_ch->flags |= IEEE80211_CHAN_NO_IBSS; + geo_ch->flags |= IEEE80211_CHAN_NO_IR; if (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) - geo_ch->flags |= IEEE80211_CHAN_PASSIVE_SCAN; + geo_ch->flags |= IEEE80211_CHAN_NO_IR; if (ch->flags & EEPROM_CHANNEL_RADAR) geo_ch->flags |= IEEE80211_CHAN_RADAR; diff --git a/drivers/net/wireless/iwlegacy/debug.c b/drivers/net/wireless/iwlegacy/debug.c index eff26501d60..3a487a3bb5d 100644 --- a/drivers/net/wireless/iwlegacy/debug.c +++ b/drivers/net/wireless/iwlegacy/debug.c @@ -567,12 +567,12 @@ il_dbgfs_channels_read(struct file *file, char __user *user_buf, size_t count, flags & IEEE80211_CHAN_RADAR ? " (IEEE 802.11h required)" : "", ((channels[i]. - flags & IEEE80211_CHAN_NO_IBSS) || + flags & IEEE80211_CHAN_NO_IR) || (channels[i]. flags & IEEE80211_CHAN_RADAR)) ? "" : ", IBSS", channels[i]. - flags & IEEE80211_CHAN_PASSIVE_SCAN ? + flags & IEEE80211_CHAN_NO_IR ? "passive only" : "active/passive"); } supp_band = il_get_hw_mode(il, IEEE80211_BAND_5GHZ); @@ -594,12 +594,12 @@ il_dbgfs_channels_read(struct file *file, char __user *user_buf, size_t count, flags & IEEE80211_CHAN_RADAR ? " (IEEE 802.11h required)" : "", ((channels[i]. - flags & IEEE80211_CHAN_NO_IBSS) || + flags & IEEE80211_CHAN_NO_IR) || (channels[i]. flags & IEEE80211_CHAN_RADAR)) ? "" : ", IBSS", channels[i]. - flags & IEEE80211_CHAN_PASSIVE_SCAN ? + flags & IEEE80211_CHAN_NO_IR ? "passive only" : "active/passive"); } ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); diff --git a/drivers/net/wireless/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/iwlwifi/dvm/debugfs.c index d94f8ab1500..f69301e505e 100644 --- a/drivers/net/wireless/iwlwifi/dvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/dvm/debugfs.c @@ -352,12 +352,12 @@ static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf, channels[i].max_power, channels[i].flags & IEEE80211_CHAN_RADAR ? " (IEEE 802.11h required)" : "", - ((channels[i].flags & IEEE80211_CHAN_NO_IBSS) + ((channels[i].flags & IEEE80211_CHAN_NO_IR) || (channels[i].flags & IEEE80211_CHAN_RADAR)) ? "" : ", IBSS", channels[i].flags & - IEEE80211_CHAN_PASSIVE_SCAN ? + IEEE80211_CHAN_NO_IR ? "passive only" : "active/passive"); } supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ); @@ -375,12 +375,12 @@ static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf, channels[i].max_power, channels[i].flags & IEEE80211_CHAN_RADAR ? " (IEEE 802.11h required)" : "", - ((channels[i].flags & IEEE80211_CHAN_NO_IBSS) + ((channels[i].flags & IEEE80211_CHAN_NO_IR) || (channels[i].flags & IEEE80211_CHAN_RADAR)) ? "" : ", IBSS", channels[i].flags & - IEEE80211_CHAN_PASSIVE_SCAN ? + IEEE80211_CHAN_NO_IR ? "passive only" : "active/passive"); } ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); diff --git a/drivers/net/wireless/iwlwifi/dvm/scan.c b/drivers/net/wireless/iwlwifi/dvm/scan.c index 35e0ee8b4e5..928f8640a0a 100644 --- a/drivers/net/wireless/iwlwifi/dvm/scan.c +++ b/drivers/net/wireless/iwlwifi/dvm/scan.c @@ -544,7 +544,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, channel = chan->hw_value; scan_ch->channel = cpu_to_le16(channel); - if (!is_active || (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)) + if (!is_active || (chan->flags & IEEE80211_CHAN_NO_IR)) scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE; else scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE; diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c index 4c887f36590..f4a6d317a02 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c @@ -614,10 +614,10 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, channel->flags = IEEE80211_CHAN_NO_HT40; if (!(eeprom_ch->flags & EEPROM_CHANNEL_IBSS)) - channel->flags |= IEEE80211_CHAN_NO_IBSS; + channel->flags |= IEEE80211_CHAN_NO_IR; if (!(eeprom_ch->flags & EEPROM_CHANNEL_ACTIVE)) - channel->flags |= IEEE80211_CHAN_PASSIVE_SCAN; + channel->flags |= IEEE80211_CHAN_NO_IR; if (eeprom_ch->flags & EEPROM_CHANNEL_RADAR) channel->flags |= IEEE80211_CHAN_RADAR; diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index b76a9a8fc0b..2fab203d302 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -223,10 +223,10 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, channel->flags |= IEEE80211_CHAN_NO_160MHZ; if (!(ch_flags & NVM_CHANNEL_IBSS)) - channel->flags |= IEEE80211_CHAN_NO_IBSS; + channel->flags |= IEEE80211_CHAN_NO_IR; if (!(ch_flags & NVM_CHANNEL_ACTIVE)) - channel->flags |= IEEE80211_CHAN_PASSIVE_SCAN; + channel->flags |= IEEE80211_CHAN_NO_IR; if (ch_flags & NVM_CHANNEL_RADAR) channel->flags |= IEEE80211_CHAN_RADAR; diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index dff7592e1ff..e0cd100b40c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -192,7 +192,7 @@ static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd, for (i = 0; i < cmd->channel_count; i++) { chan->channel = cpu_to_le16(req->channels[i]->hw_value); chan->type = cpu_to_le32(type); - if (req->channels[i]->flags & IEEE80211_CHAN_PASSIVE_SCAN) + if (req->channels[i]->flags & IEEE80211_CHAN_NO_IR) chan->type &= cpu_to_le32(~SCAN_CHANNEL_TYPE_ACTIVE); chan->active_dwell = cpu_to_le16(active_dwell); chan->passive_dwell = cpu_to_le16(passive_dwell); @@ -642,7 +642,7 @@ static void iwl_build_channel_cfg(struct iwl_mvm *mvm, channels->iter_count[index] = cpu_to_le16(1); channels->iter_interval[index] = 0; - if (!(s_band->channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN)) + if (!(s_band->channels[i].flags & IEEE80211_CHAN_NO_IR)) channels->type[index] |= cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_ACTIVE); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index de0df86704e..33d4b31995d 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -159,7 +159,7 @@ static const struct ieee80211_regdomain hwsim_world_regdom_custom_02 = { .reg_rules = { REG_RULE(2412-10, 2462+10, 40, 0, 20, 0), REG_RULE(5725-10, 5850+10, 40, 0, 30, - NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS), + NL80211_RRF_NO_IR), } }; @@ -1485,7 +1485,7 @@ static void hw_scan_work(struct work_struct *work) req->channels[hwsim->scan_chan_idx]->center_freq); hwsim->tmp_chan = req->channels[hwsim->scan_chan_idx]; - if (hwsim->tmp_chan->flags & IEEE80211_CHAN_PASSIVE_SCAN || + if (hwsim->tmp_chan->flags & IEEE80211_CHAN_NO_IR || !req->n_ssids) { dwell = 120; } else { diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index fbad00a5abc..7f68943f02c 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -50,24 +50,24 @@ static const struct ieee80211_regdomain mwifiex_world_regdom_custom = { REG_RULE(2412-10, 2462+10, 40, 3, 20, 0), /* Channel 12 - 13 */ REG_RULE(2467-10, 2472+10, 20, 3, 20, - NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS), + NL80211_RRF_NO_IR), /* Channel 14 */ REG_RULE(2484-10, 2484+10, 20, 3, 20, - NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS | + NL80211_RRF_NO_IR | NL80211_RRF_NO_OFDM), /* Channel 36 - 48 */ REG_RULE(5180-10, 5240+10, 40, 3, 20, - NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS), + NL80211_RRF_NO_IR), /* Channel 149 - 165 */ REG_RULE(5745-10, 5825+10, 40, 3, 20, - NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS), + NL80211_RRF_NO_IR), /* Channel 52 - 64 */ REG_RULE(5260-10, 5320+10, 40, 3, 30, - NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS | + NL80211_RRF_NO_IR | NL80211_RRF_DFS), /* Channel 100 - 140 */ REG_RULE(5500-10, 5700+10, 40, 3, 30, - NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS | + NL80211_RRF_NO_IR | NL80211_RRF_DFS), } }; @@ -1968,7 +1968,7 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, user_scan_cfg->chan_list[i].chan_number = chan->hw_value; user_scan_cfg->chan_list[i].radio_type = chan->band; - if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) + if (chan->flags & IEEE80211_CHAN_NO_IR) user_scan_cfg->chan_list[i].scan_type = MWIFIEX_SCAN_TYPE_PASSIVE; else diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 8cf7d50a760..0ed06646f19 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -515,14 +515,14 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv, scan_chan_list[chan_idx].max_scan_time = cpu_to_le16((u16) user_scan_in-> chan_list[0].scan_time); - else if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) + else if (ch->flags & IEEE80211_CHAN_NO_IR) scan_chan_list[chan_idx].max_scan_time = cpu_to_le16(adapter->passive_scan_time); else scan_chan_list[chan_idx].max_scan_time = cpu_to_le16(adapter->active_scan_time); - if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) + if (ch->flags & IEEE80211_CHAN_NO_IR) scan_chan_list[chan_idx].chan_scan_mode_bitmap |= MWIFIEX_PASSIVE_SCAN; else diff --git a/drivers/net/wireless/rtlwifi/regd.c b/drivers/net/wireless/rtlwifi/regd.c index d7d0d4948b0..8453c53143f 100644 --- a/drivers/net/wireless/rtlwifi/regd.c +++ b/drivers/net/wireless/rtlwifi/regd.c @@ -59,30 +59,26 @@ static struct country_code_to_enum_rd allCountries[] = { */ #define RTL819x_2GHZ_CH12_13 \ REG_RULE(2467-10, 2472+10, 40, 0, 20,\ - NL80211_RRF_PASSIVE_SCAN) + NL80211_RRF_NO_IR) #define RTL819x_2GHZ_CH14 \ REG_RULE(2484-10, 2484+10, 40, 0, 20, \ - NL80211_RRF_PASSIVE_SCAN | \ - NL80211_RRF_NO_OFDM) + NL80211_RRF_NO_IR | NL80211_RRF_NO_OFDM) /* 5G chan 36 - chan 64*/ #define RTL819x_5GHZ_5150_5350 \ REG_RULE(5150-10, 5350+10, 40, 0, 30, \ - NL80211_RRF_PASSIVE_SCAN | \ - NL80211_RRF_NO_IBSS) + NL80211_RRF_NO_IR) /* 5G chan 100 - chan 165*/ #define RTL819x_5GHZ_5470_5850 \ REG_RULE(5470-10, 5850+10, 40, 0, 30, \ - NL80211_RRF_PASSIVE_SCAN | \ - NL80211_RRF_NO_IBSS) + NL80211_RRF_NO_IR) /* 5G chan 149 - chan 165*/ #define RTL819x_5GHZ_5725_5850 \ REG_RULE(5725-10, 5850+10, 40, 0, 30, \ - NL80211_RRF_PASSIVE_SCAN | \ - NL80211_RRF_NO_IBSS) + NL80211_RRF_NO_IR) #define RTL819x_5GHZ_ALL \ (RTL819x_5GHZ_5150_5350, RTL819x_5GHZ_5470_5850) @@ -185,16 +181,11 @@ static void _rtl_reg_apply_beaconing_flags(struct wiphy *wiphy, *regulatory_hint(). */ - if (!(reg_rule->flags & NL80211_RRF_NO_IBSS)) - ch->flags &= ~IEEE80211_CHAN_NO_IBSS; - if (!(reg_rule-> - flags & NL80211_RRF_PASSIVE_SCAN)) - ch->flags &= - ~IEEE80211_CHAN_PASSIVE_SCAN; + if (!(reg_rule->flags & NL80211_RRF_NO_IR)) + ch->flags &= ~IEEE80211_CHAN_NO_IR; } else { if (ch->beacon_found) - ch->flags &= ~(IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN); + ch->flags &= ~IEEE80211_CHAN_NO_IR; } } } @@ -219,11 +210,11 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy, */ if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) { ch = &sband->channels[11]; /* CH 12 */ - if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) - ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; + if (ch->flags & IEEE80211_CHAN_NO_IR) + ch->flags &= ~IEEE80211_CHAN_NO_IR; ch = &sband->channels[12]; /* CH 13 */ - if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) - ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; + if (ch->flags & IEEE80211_CHAN_NO_IR) + ch->flags &= ~IEEE80211_CHAN_NO_IR; return; } @@ -237,17 +228,17 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy, ch = &sband->channels[11]; /* CH 12 */ reg_rule = freq_reg_info(wiphy, ch->center_freq); if (!IS_ERR(reg_rule)) { - if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) - if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) - ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; + if (!(reg_rule->flags & NL80211_RRF_NO_IR)) + if (ch->flags & IEEE80211_CHAN_NO_IR) + ch->flags &= ~IEEE80211_CHAN_NO_IR; } ch = &sband->channels[12]; /* CH 13 */ reg_rule = freq_reg_info(wiphy, ch->center_freq); if (!IS_ERR(reg_rule)) { - if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) - if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) - ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; + if (!(reg_rule->flags & NL80211_RRF_NO_IR)) + if (ch->flags & IEEE80211_CHAN_NO_IR) + ch->flags &= ~IEEE80211_CHAN_NO_IR; } } @@ -284,8 +275,7 @@ static void _rtl_reg_apply_radar_flags(struct wiphy *wiphy) */ if (!(ch->flags & IEEE80211_CHAN_DISABLED)) ch->flags |= IEEE80211_CHAN_RADAR | - IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN; + IEEE80211_CHAN_NO_IR; } } diff --git a/drivers/net/wireless/ti/wl12xx/scan.c b/drivers/net/wireless/ti/wl12xx/scan.c index 4a0bbb13806..7541bd1a4a4 100644 --- a/drivers/net/wireless/ti/wl12xx/scan.c +++ b/drivers/net/wireless/ti/wl12xx/scan.c @@ -47,7 +47,7 @@ static int wl1271_get_scan_channels(struct wl1271 *wl, * In active scans, we only scan channels not * marked as passive. */ - (passive || !(flags & IEEE80211_CHAN_PASSIVE_SCAN))) { + (passive || !(flags & IEEE80211_CHAN_NO_IR))) { wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ", req->channels[i]->band, req->channels[i]->center_freq); diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index 34d9dfff2ad..9b2ecf52449 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -1688,7 +1688,7 @@ int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl) if (channel->flags & (IEEE80211_CHAN_DISABLED | IEEE80211_CHAN_RADAR | - IEEE80211_CHAN_PASSIVE_SCAN)) + IEEE80211_CHAN_NO_IR)) continue; ch_bit_idx = wlcore_get_reg_conf_ch_idx(b, ch); diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 0368b9cbfb8..e9da47cead5 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -91,8 +91,7 @@ static void wl1271_reg_notify(struct wiphy *wiphy, continue; if (ch->flags & IEEE80211_CHAN_RADAR) - ch->flags |= IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN; + ch->flags |= IEEE80211_CHAN_NO_IR; } diff --git a/drivers/net/wireless/ti/wlcore/scan.c b/drivers/net/wireless/ti/wlcore/scan.c index 7ed86203304..1e3d51cd673 100644 --- a/drivers/net/wireless/ti/wlcore/scan.c +++ b/drivers/net/wireless/ti/wlcore/scan.c @@ -188,16 +188,14 @@ wlcore_scan_get_channels(struct wl1271 *wl, flags = req_channels[i]->flags; if (force_passive) - flags |= IEEE80211_CHAN_PASSIVE_SCAN; + flags |= IEEE80211_CHAN_NO_IR; if ((req_channels[i]->band == band) && !(flags & IEEE80211_CHAN_DISABLED) && (!!(flags & IEEE80211_CHAN_RADAR) == radar) && /* if radar is set, we ignore the passive flag */ (radar || - !!(flags & IEEE80211_CHAN_PASSIVE_SCAN) == passive)) { - - + !!(flags & IEEE80211_CHAN_NO_IR) == passive)) { if (flags & IEEE80211_CHAN_RADAR) { channels[j].flags |= SCAN_CHANNEL_FLAGS_DFS; @@ -220,7 +218,7 @@ wlcore_scan_get_channels(struct wl1271 *wl, (band == IEEE80211_BAND_2GHZ) && (channels[j].channel >= 12) && (channels[j].channel <= 14) && - (flags & IEEE80211_CHAN_PASSIVE_SCAN) && + (flags & IEEE80211_CHAN_NO_IR) && !force_passive) { /* pactive channels treated as DFS */ channels[j].flags = SCAN_CHANNEL_FLAGS_DFS; @@ -243,8 +241,8 @@ wlcore_scan_get_channels(struct wl1271 *wl, max_dwell_time_active, flags & IEEE80211_CHAN_RADAR ? ", DFS" : "", - flags & IEEE80211_CHAN_PASSIVE_SCAN ? - ", PASSIVE" : ""); + flags & IEEE80211_CHAN_NO_IR ? + ", NO-IR" : ""); j++; } } diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 3eae46cb1ac..c1b88741323 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -91,9 +91,8 @@ enum ieee80211_band { * Channel flags set by the regulatory control code. * * @IEEE80211_CHAN_DISABLED: This channel is disabled. - * @IEEE80211_CHAN_PASSIVE_SCAN: Only passive scanning is permitted - * on this channel. - * @IEEE80211_CHAN_NO_IBSS: IBSS is not allowed on this channel. + * @IEEE80211_CHAN_NO_IR: do not initiate radiation, this includes + * sending probe requests or beaconing. * @IEEE80211_CHAN_RADAR: Radar detection is required on this channel. * @IEEE80211_CHAN_NO_HT40PLUS: extension channel above this channel * is not permitted. @@ -113,8 +112,8 @@ enum ieee80211_band { */ enum ieee80211_channel_flags { IEEE80211_CHAN_DISABLED = 1<<0, - IEEE80211_CHAN_PASSIVE_SCAN = 1<<1, - IEEE80211_CHAN_NO_IBSS = 1<<2, + IEEE80211_CHAN_NO_IR = 1<<1, + /* hole at 1<<2 */ IEEE80211_CHAN_RADAR = 1<<3, IEEE80211_CHAN_NO_HT40PLUS = 1<<4, IEEE80211_CHAN_NO_HT40MINUS = 1<<5, diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 3d8325bb50c..7e25164adfe 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -2231,10 +2231,9 @@ enum nl80211_band_attr { * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz * @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current * regulatory domain. - * @NL80211_FREQUENCY_ATTR_PASSIVE_SCAN: Only passive scanning is - * permitted on this channel in current regulatory domain. - * @NL80211_FREQUENCY_ATTR_NO_IBSS: IBSS networks are not permitted - * on this channel in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_NO_IR: no mechanisms that initiate radiation + * are permitted on this channel, this includes sending probe + * requests, or modes of operation that require beaconing. * @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory * on this channel in current regulatory domain. * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm @@ -2261,8 +2260,8 @@ enum nl80211_frequency_attr { __NL80211_FREQUENCY_ATTR_INVALID, NL80211_FREQUENCY_ATTR_FREQ, NL80211_FREQUENCY_ATTR_DISABLED, - NL80211_FREQUENCY_ATTR_PASSIVE_SCAN, - NL80211_FREQUENCY_ATTR_NO_IBSS, + NL80211_FREQUENCY_ATTR_NO_IR, + __NL80211_FREQUENCY_ATTR_NO_IBSS, NL80211_FREQUENCY_ATTR_RADAR, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, NL80211_FREQUENCY_ATTR_DFS_STATE, @@ -2278,6 +2277,9 @@ enum nl80211_frequency_attr { }; #define NL80211_FREQUENCY_ATTR_MAX_TX_POWER NL80211_FREQUENCY_ATTR_MAX_TX_POWER +#define NL80211_FREQUENCY_ATTR_PASSIVE_SCAN NL80211_FREQUENCY_ATTR_NO_IR +#define NL80211_FREQUENCY_ATTR_NO_IBSS NL80211_FREQUENCY_ATTR_NO_IR +#define NL80211_FREQUENCY_ATTR_NO_IR NL80211_FREQUENCY_ATTR_NO_IR /** * enum nl80211_bitrate_attr - bitrate attributes @@ -2420,8 +2422,9 @@ enum nl80211_sched_scan_match_attr { * @NL80211_RRF_DFS: DFS support is required to be used * @NL80211_RRF_PTP_ONLY: this is only for Point To Point links * @NL80211_RRF_PTMP_ONLY: this is only for Point To Multi Point links - * @NL80211_RRF_PASSIVE_SCAN: passive scan is required - * @NL80211_RRF_NO_IBSS: no IBSS is allowed + * @NL80211_RRF_NO_IR: no mechanisms that initiate radiation are allowed, + * this includes probe requests or modes of operation that require + * beaconing. */ enum nl80211_reg_rule_flags { NL80211_RRF_NO_OFDM = 1<<0, @@ -2431,10 +2434,17 @@ enum nl80211_reg_rule_flags { NL80211_RRF_DFS = 1<<4, NL80211_RRF_PTP_ONLY = 1<<5, NL80211_RRF_PTMP_ONLY = 1<<6, - NL80211_RRF_PASSIVE_SCAN = 1<<7, - NL80211_RRF_NO_IBSS = 1<<8, + NL80211_RRF_NO_IR = 1<<7, + __NL80211_RRF_NO_IBSS = 1<<8, }; +#define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR +#define NL80211_RRF_NO_IBSS NL80211_RRF_NO_IR +#define NL80211_RRF_NO_IR NL80211_RRF_NO_IR + +/* For backport compatibility with older userspace */ +#define NL80211_RRF_NO_IR_ALL (NL80211_RRF_NO_IR | __NL80211_RRF_NO_IBSS) + /** * enum nl80211_dfs_regions - regulatory DFS regions * diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 5ad66a83ef7..c22cbb57b49 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -526,7 +526,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, ieee80211_hw_config(local, 0); if ((req->channels[0]->flags & - IEEE80211_CHAN_PASSIVE_SCAN) || + IEEE80211_CHAN_NO_IR) || !local->scan_req->n_ssids) { next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; } else { @@ -572,7 +572,7 @@ ieee80211_scan_get_channel_time(struct ieee80211_channel *chan) * TODO: channel switching also consumes quite some time, * add that delay as well to get a better estimation */ - if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) + if (chan->flags & IEEE80211_CHAN_NO_IR) return IEEE80211_PASSIVE_CHANNEL_TIME; return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME; } @@ -696,7 +696,7 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, * * In any case, it is not necessary for a passive scan. */ - if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN || + if (chan->flags & IEEE80211_CHAN_NO_IR || !local->scan_req->n_ssids) { *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; local->next_scan_state = SCAN_DECISION; @@ -881,7 +881,7 @@ int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, struct ieee80211_channel *tmp_ch = &local->hw.wiphy->bands[band]->channels[i]; - if (tmp_ch->flags & (IEEE80211_CHAN_NO_IBSS | + if (tmp_ch->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_DISABLED)) continue; @@ -895,7 +895,7 @@ int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, local->int_scan_req->n_channels = n_ch; } else { - if (WARN_ON_ONCE(chan->flags & (IEEE80211_CHAN_NO_IBSS | + if (WARN_ON_ONCE(chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_DISABLED))) goto unlock; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index c558b246ef0..5ad2e8b1f92 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1724,8 +1724,7 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, * radar detection by itself. We can do that later by adding a * monitor flag interfaces used for AP support. */ - if ((chan->flags & (IEEE80211_CHAN_NO_IBSS | IEEE80211_CHAN_RADAR | - IEEE80211_CHAN_PASSIVE_SCAN))) + if ((chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR))) goto fail_rcu; ieee80211_xmit(sdata, skb, chan->band); diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 9b8cc877eb1..344966496b7 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -467,8 +467,7 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy, res = cfg80211_chandef_usable(wiphy, chandef, IEEE80211_CHAN_DISABLED | - IEEE80211_CHAN_PASSIVE_SCAN | - IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR); trace_cfg80211_return_bool(res); diff --git a/net/wireless/genregdb.awk b/net/wireless/genregdb.awk index 42ed274e81f..c808619ac9c 100644 --- a/net/wireless/genregdb.awk +++ b/net/wireless/genregdb.awk @@ -107,10 +107,13 @@ active && /^[ \t]*\(/ { } else if (flagarray[arg] == "PTMP-ONLY") { flags = flags "\n\t\t\tNL80211_RRF_PTMP_ONLY | " } else if (flagarray[arg] == "PASSIVE-SCAN") { - flags = flags "\n\t\t\tNL80211_RRF_PASSIVE_SCAN | " + flags = flags "\n\t\t\tNL80211_RRF_NO_IR | " } else if (flagarray[arg] == "NO-IBSS") { - flags = flags "\n\t\t\tNL80211_RRF_NO_IBSS | " + flags = flags "\n\t\t\tNL80211_RRF_NO_IR | " + } else if (flagarray[arg] == "NO-IR") { + flags = flags "\n\t\t\tNL80211_RRF_NO_IR | " } + } flags = flags "0" printf "\t\tREG_RULE(%d, %d, %d, %d, %d, %s),\n", start, end, bw, gain, power, flags diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 9d797df5664..f7910571294 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -274,7 +274,7 @@ int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, for (i = 0; i < sband->n_channels; i++) { chan = &sband->channels[i]; - if (chan->flags & IEEE80211_CHAN_NO_IBSS) + if (chan->flags & IEEE80211_CHAN_NO_IR) continue; if (chan->flags & IEEE80211_CHAN_DISABLED) continue; @@ -345,7 +345,7 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev, chan = ieee80211_get_channel(wdev->wiphy, freq); if (!chan) return -EINVAL; - if (chan->flags & IEEE80211_CHAN_NO_IBSS || + if (chan->flags & IEEE80211_CHAN_NO_IR || chan->flags & IEEE80211_CHAN_DISABLED) return -EINVAL; } diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index 0553fd4d85a..b0e1869de7d 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c @@ -141,8 +141,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, for (i = 0; i < sband->n_channels; i++) { chan = &sband->channels[i]; - if (chan->flags & (IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN | + if (chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_DISABLED | IEEE80211_CHAN_RADAR)) continue; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index a7f4e790210..41af3a0e996 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -545,12 +545,12 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, if ((chan->flags & IEEE80211_CHAN_DISABLED) && nla_put_flag(msg, NL80211_FREQUENCY_ATTR_DISABLED)) goto nla_put_failure; - if ((chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) && - nla_put_flag(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN)) - goto nla_put_failure; - if ((chan->flags & IEEE80211_CHAN_NO_IBSS) && - nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IBSS)) - goto nla_put_failure; + if (chan->flags & IEEE80211_CHAN_NO_IR) { + if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IR)) + goto nla_put_failure; + if (nla_put_flag(msg, __NL80211_FREQUENCY_ATTR_NO_IBSS)) + goto nla_put_failure; + } if (chan->flags & IEEE80211_CHAN_RADAR) { if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR)) goto nla_put_failure; diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 7da67fd0b41..e4e3337ba29 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -163,35 +163,29 @@ static const struct ieee80211_regdomain world_regdom = { REG_RULE(2412-10, 2462+10, 40, 6, 20, 0), /* IEEE 802.11b/g, channels 12..13. */ REG_RULE(2467-10, 2472+10, 40, 6, 20, - NL80211_RRF_PASSIVE_SCAN | - NL80211_RRF_NO_IBSS), + NL80211_RRF_NO_IR), /* IEEE 802.11 channel 14 - Only JP enables * this and for 802.11b only */ REG_RULE(2484-10, 2484+10, 20, 6, 20, - NL80211_RRF_PASSIVE_SCAN | - NL80211_RRF_NO_IBSS | + NL80211_RRF_NO_IR | NL80211_RRF_NO_OFDM), /* IEEE 802.11a, channel 36..48 */ REG_RULE(5180-10, 5240+10, 160, 6, 20, - NL80211_RRF_PASSIVE_SCAN | - NL80211_RRF_NO_IBSS), + NL80211_RRF_NO_IR), /* IEEE 802.11a, channel 52..64 - DFS required */ REG_RULE(5260-10, 5320+10, 160, 6, 20, - NL80211_RRF_PASSIVE_SCAN | - NL80211_RRF_NO_IBSS | + NL80211_RRF_NO_IR | NL80211_RRF_DFS), /* IEEE 802.11a, channel 100..144 - DFS required */ REG_RULE(5500-10, 5720+10, 160, 6, 20, - NL80211_RRF_PASSIVE_SCAN | - NL80211_RRF_NO_IBSS | + NL80211_RRF_NO_IR | NL80211_RRF_DFS), /* IEEE 802.11a, channel 149..165 */ REG_RULE(5745-10, 5825+10, 80, 6, 20, - NL80211_RRF_PASSIVE_SCAN | - NL80211_RRF_NO_IBSS), + NL80211_RRF_NO_IR), /* IEEE 802.11ad (60gHz), channels 1..3 */ REG_RULE(56160+2160*1-1080, 56160+2160*3+1080, 2160, 0, 0, 0), @@ -698,10 +692,8 @@ regdom_intersect(const struct ieee80211_regdomain *rd1, static u32 map_regdom_flags(u32 rd_flags) { u32 channel_flags = 0; - if (rd_flags & NL80211_RRF_PASSIVE_SCAN) - channel_flags |= IEEE80211_CHAN_PASSIVE_SCAN; - if (rd_flags & NL80211_RRF_NO_IBSS) - channel_flags |= IEEE80211_CHAN_NO_IBSS; + if (rd_flags & NL80211_RRF_NO_IR_ALL) + channel_flags |= IEEE80211_CHAN_NO_IR; if (rd_flags & NL80211_RRF_DFS) channel_flags |= IEEE80211_CHAN_RADAR; if (rd_flags & NL80211_RRF_NO_OFDM) @@ -1066,13 +1058,8 @@ static void handle_reg_beacon(struct wiphy *wiphy, unsigned int chan_idx, chan_before.center_freq = chan->center_freq; chan_before.flags = chan->flags; - if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) { - chan->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; - channel_changed = true; - } - - if (chan->flags & IEEE80211_CHAN_NO_IBSS) { - chan->flags &= ~IEEE80211_CHAN_NO_IBSS; + if (chan->flags & IEEE80211_CHAN_NO_IR) { + chan->flags &= ~IEEE80211_CHAN_NO_IR; channel_changed = true; } -- cgit v1.2.3-70-g09d2 From 2e3049b79cb98018abc83383f9b737508240dd54 Mon Sep 17 00:00:00 2001 From: Karl Beldan Date: Thu, 24 Oct 2013 15:53:32 +0200 Subject: mac80211: do not compute offset from ssn in Rx AMPDU reordering buffer Currently, frames that go into the reordering buffer are stored at index ieee80211_sn_sub(sn, tid_rx->ssn) % tid_rx->buf_size. The offset calculation to the starting sequence number (SSN) is useless and just adds overhead so simply use sn % tid_rx->buf_size. This means the reordering buffer will start to be filled somewhere in the middle (at SSN % buf_size) and continue to get used from there, but there's no reason to start from the beginning. Signed-off-by: Karl Beldan [rewrite commit message] Signed-off-by: Johannes Berg --- net/mac80211/rx.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index caecef870c0..401f3c26e70 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -729,9 +729,7 @@ static void ieee80211_release_reorder_frames(struct ieee80211_sub_if_data *sdata lockdep_assert_held(&tid_agg_rx->reorder_lock); while (ieee80211_sn_less(tid_agg_rx->head_seq_num, head_seq_num)) { - index = ieee80211_sn_sub(tid_agg_rx->head_seq_num, - tid_agg_rx->ssn) % - tid_agg_rx->buf_size; + index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size; ieee80211_release_reorder_frame(sdata, tid_agg_rx, index, frames); } @@ -757,8 +755,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, lockdep_assert_held(&tid_agg_rx->reorder_lock); /* release the buffer until next missing frame */ - index = ieee80211_sn_sub(tid_agg_rx->head_seq_num, - tid_agg_rx->ssn) % tid_agg_rx->buf_size; + index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size; if (!tid_agg_rx->reorder_buf[index] && tid_agg_rx->stored_mpdu_num) { /* @@ -793,15 +790,11 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, } else while (tid_agg_rx->reorder_buf[index]) { ieee80211_release_reorder_frame(sdata, tid_agg_rx, index, frames); - index = ieee80211_sn_sub(tid_agg_rx->head_seq_num, - tid_agg_rx->ssn) % - tid_agg_rx->buf_size; + index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size; } if (tid_agg_rx->stored_mpdu_num) { - j = index = ieee80211_sn_sub(tid_agg_rx->head_seq_num, - tid_agg_rx->ssn) % - tid_agg_rx->buf_size; + j = index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size; for (; j != (index - 1) % tid_agg_rx->buf_size; j = (j + 1) % tid_agg_rx->buf_size) { @@ -861,8 +854,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata /* Now the new frame is always in the range of the reordering buffer */ - index = ieee80211_sn_sub(mpdu_seq_num, - tid_agg_rx->ssn) % tid_agg_rx->buf_size; + index = mpdu_seq_num % tid_agg_rx->buf_size; /* check if we already stored this frame */ if (tid_agg_rx->reorder_buf[index]) { -- cgit v1.2.3-70-g09d2 From 70526e543c8087b7fa136fd5e6be98332d609848 Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Fri, 1 Nov 2013 20:35:58 +0100 Subject: mac80211_hwsim: use debugfs_remove_recursive Use debugfs_remove_recursive. That avoids the need for the new dentry pointers and extra debugfs_remove calls. Signed-off-by: Janusz Dziedzic Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 33d4b31995d..76b362ed76b 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -353,7 +353,6 @@ struct mac80211_hwsim_data { } ps; bool ps_poll_pending; struct dentry *debugfs; - struct dentry *debugfs_ps; struct sk_buff_head pending; /* packets pending */ /* @@ -362,7 +361,6 @@ struct mac80211_hwsim_data { * radio can be in more then one group. */ u64 group; - struct dentry *debugfs_group; int power_level; @@ -1734,9 +1732,7 @@ static void mac80211_hwsim_free(void) spin_unlock_bh(&hwsim_radio_lock); list_for_each_entry_safe(data, tmpdata, &tmplist, list) { - debugfs_remove(data->debugfs_group); - debugfs_remove(data->debugfs_ps); - debugfs_remove(data->debugfs); + debugfs_remove_recursive(data->debugfs); ieee80211_unregister_hw(data->hw); device_release_driver(data->dev); device_unregister(data->dev); @@ -2534,12 +2530,10 @@ static int __init init_mac80211_hwsim(void) data->debugfs = debugfs_create_dir("hwsim", hw->wiphy->debugfsdir); - data->debugfs_ps = debugfs_create_file("ps", 0666, - data->debugfs, data, - &hwsim_fops_ps); - data->debugfs_group = debugfs_create_file("group", 0666, - data->debugfs, data, - &hwsim_fops_group); + debugfs_create_file("ps", 0666, data->debugfs, data, + &hwsim_fops_ps); + debugfs_create_file("group", 0666, data->debugfs, data, + &hwsim_fops_group); tasklet_hrtimer_init(&data->beacon_timer, mac80211_hwsim_beacon, -- cgit v1.2.3-70-g09d2 From bba05e3d5afb6ed31c00068f12418a9dacb42328 Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Tue, 5 Nov 2013 13:03:53 +0100 Subject: mac80211_hwsim: Add iface comb for DFS Add iface combination that will allow DFS support. Add also debugfs dfs_simulate_radar file that can be used to simulate radar event. This could be useful for mac80211/cfg80211/ regulatory/hostap code testing without real HW. Signed-off-by: Janusz Dziedzic Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 50 +++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 76b362ed76b..bad66e3cdd1 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -1889,6 +1889,17 @@ static int hwsim_fops_ps_write(void *dat, u64 val) DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_ps, hwsim_fops_ps_read, hwsim_fops_ps_write, "%llu\n"); +static int hwsim_write_simulate_radar(void *dat, u64 val) +{ + struct mac80211_hwsim_data *data = dat; + + ieee80211_radar_detected(data->hw); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(hwsim_simulate_radar, NULL, + hwsim_write_simulate_radar, "%llu\n"); static int hwsim_fops_group_read(void *dat, u64 *val) { @@ -2190,11 +2201,28 @@ static const struct ieee80211_iface_limit hwsim_if_limits[] = { { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) }, }; -static struct ieee80211_iface_combination hwsim_if_comb = { - .limits = hwsim_if_limits, - .n_limits = ARRAY_SIZE(hwsim_if_limits), - .max_interfaces = 2048, - .num_different_channels = 1, +static const struct ieee80211_iface_limit hwsim_if_dfs_limits[] = { + { .max = 8, .types = BIT(NL80211_IFTYPE_AP) }, +}; + +static struct ieee80211_iface_combination hwsim_if_comb[] = { + { + .limits = hwsim_if_limits, + .n_limits = ARRAY_SIZE(hwsim_if_limits), + .max_interfaces = 2048, + .num_different_channels = 1, + }, + { + .limits = hwsim_if_dfs_limits, + .n_limits = ARRAY_SIZE(hwsim_if_dfs_limits), + .max_interfaces = 8, + .num_different_channels = 1, + .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80) | + BIT(NL80211_CHAN_WIDTH_160), + } }; static int __init init_mac80211_hwsim(void) @@ -2212,7 +2240,7 @@ static int __init init_mac80211_hwsim(void) return -EINVAL; if (channels > 1) { - hwsim_if_comb.num_different_channels = channels; + hwsim_if_comb[0].num_different_channels = channels; mac80211_hwsim_ops.hw_scan = mac80211_hwsim_hw_scan; mac80211_hwsim_ops.cancel_hw_scan = mac80211_hwsim_cancel_hw_scan; @@ -2292,13 +2320,15 @@ static int __init init_mac80211_hwsim(void) hw->wiphy->n_addresses = 2; hw->wiphy->addresses = data->addresses; - hw->wiphy->iface_combinations = &hwsim_if_comb; - hw->wiphy->n_iface_combinations = 1; + hw->wiphy->iface_combinations = hwsim_if_comb; + hw->wiphy->n_iface_combinations = ARRAY_SIZE(hwsim_if_comb); if (channels > 1) { hw->wiphy->max_scan_ssids = 255; hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; hw->wiphy->max_remain_on_channel_duration = 1000; + /* For channels > 1 DFS is not allowed */ + hw->wiphy->n_iface_combinations = 1; } INIT_DELAYED_WORK(&data->roc_done, hw_roc_done); @@ -2534,6 +2564,10 @@ static int __init init_mac80211_hwsim(void) &hwsim_fops_ps); debugfs_create_file("group", 0666, data->debugfs, data, &hwsim_fops_group); + if (channels == 1) + debugfs_create_file("dfs_simulate_radar", 0222, + data->debugfs, + data, &hwsim_simulate_radar); tasklet_hrtimer_init(&data->beacon_timer, mac80211_hwsim_beacon, -- cgit v1.2.3-70-g09d2 From c17aa52c5bf571533cc8561292f7316b9216eddc Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Tue, 5 Nov 2013 13:03:54 +0100 Subject: mac80211_hwsim: VHT add 160MHz width support Add 160MHz width support. This could be usefull for testing VHT160 DFS functionality. This could be also usefull in the future when DFS and non-DFS channels could be mixed. Signed-off-by: Janusz Dziedzic Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index bad66e3cdd1..bd7dd0d242d 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2412,6 +2412,7 @@ static int __init init_mac80211_hwsim(void) sband->vht_cap.cap = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ | + IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ | IEEE80211_VHT_CAP_RXLDPC | IEEE80211_VHT_CAP_SHORT_GI_80 | IEEE80211_VHT_CAP_SHORT_GI_160 | -- cgit v1.2.3-70-g09d2 From 40d1ba63ff4ae1a73b0042202b54b688ada469be Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Tue, 5 Nov 2013 14:48:47 +0100 Subject: cfg80211: add helper functions for start/end freq Add helper fuctions for start/end freq. Signed-off-by: Janusz Dziedzic Reviewed-by: Luis R. Rodriguez Signed-off-by: Johannes Berg --- net/wireless/chan.c | 44 ++++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 344966496b7..1d25a462b14 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -277,6 +277,32 @@ void cfg80211_set_dfs_state(struct wiphy *wiphy, width, dfs_state); } +static u32 cfg80211_get_start_freq(u32 center_freq, + u32 bandwidth) +{ + u32 start_freq; + + if (bandwidth <= 20) + start_freq = center_freq; + else + start_freq = center_freq - bandwidth/2 + 10; + + return start_freq; +} + +static u32 cfg80211_get_end_freq(u32 center_freq, + u32 bandwidth) +{ + u32 end_freq; + + if (bandwidth <= 20) + end_freq = center_freq; + else + end_freq = center_freq + bandwidth/2 - 10; + + return end_freq; +} + static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy, u32 center_freq, u32 bandwidth) @@ -284,13 +310,8 @@ static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy, struct ieee80211_channel *c; u32 freq, start_freq, end_freq; - if (bandwidth <= 20) { - start_freq = center_freq; - end_freq = center_freq; - } else { - start_freq = center_freq - bandwidth/2 + 10; - end_freq = center_freq + bandwidth/2 - 10; - } + start_freq = cfg80211_get_start_freq(center_freq, bandwidth); + end_freq = cfg80211_get_end_freq(center_freq, bandwidth); for (freq = start_freq; freq <= end_freq; freq += 20) { c = ieee80211_get_channel(wiphy, freq); @@ -337,13 +358,8 @@ static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, struct ieee80211_channel *c; u32 freq, start_freq, end_freq; - if (bandwidth <= 20) { - start_freq = center_freq; - end_freq = center_freq; - } else { - start_freq = center_freq - bandwidth/2 + 10; - end_freq = center_freq + bandwidth/2 - 10; - } + start_freq = cfg80211_get_start_freq(center_freq, bandwidth); + end_freq = cfg80211_get_end_freq(center_freq, bandwidth); for (freq = start_freq; freq <= end_freq; freq += 20) { c = ieee80211_get_channel(wiphy, freq); -- cgit v1.2.3-70-g09d2 From fe7c3a1f20a419d86d3f90316d8efc2d04f3f0ed Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Tue, 5 Nov 2013 14:48:48 +0100 Subject: cfg80211: DFS check chandef usable before CAC Check chandef we get in CAC request is usable for CAC. All channels have to be DFS channels. Allow DFS_USABLE and DFS_AVAILABLE channels mix. At least one channel has to be DFS_USABLE (require CAC). Signed-off-by: Janusz Dziedzic Reviewed-by: Luis R. Rodriguez Signed-off-by: Johannes Berg --- net/wireless/chan.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++ net/wireless/core.h | 13 +++++++++ net/wireless/nl80211.c | 2 +- 3 files changed, 88 insertions(+), 1 deletion(-) diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 1d25a462b14..96c97800e24 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -351,6 +351,80 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy, } EXPORT_SYMBOL(cfg80211_chandef_dfs_required); +static int cfg80211_get_chans_dfs_usable(struct wiphy *wiphy, + u32 center_freq, + u32 bandwidth) +{ + struct ieee80211_channel *c; + u32 freq, start_freq, end_freq; + int count = 0; + + start_freq = cfg80211_get_start_freq(center_freq, bandwidth); + end_freq = cfg80211_get_end_freq(center_freq, bandwidth); + + /* + * Check entire range of channels for the bandwidth. + * Check all channels are DFS channels (DFS_USABLE or + * DFS_AVAILABLE). Return number of usable channels + * (require CAC). Allow DFS and non-DFS channel mix. + */ + for (freq = start_freq; freq <= end_freq; freq += 20) { + c = ieee80211_get_channel(wiphy, freq); + if (!c) + return -EINVAL; + + if (c->flags & IEEE80211_CHAN_DISABLED) + return -EINVAL; + + if (c->flags & IEEE80211_CHAN_RADAR) { + if (c->dfs_state == NL80211_DFS_UNAVAILABLE) + return -EINVAL; + + if (c->dfs_state == NL80211_DFS_USABLE) + count++; + } + } + + return count; +} + +bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy, + const struct cfg80211_chan_def *chandef) +{ + int width; + int r1, r2 = 0; + + if (WARN_ON(!cfg80211_chandef_valid(chandef))) + return false; + + width = cfg80211_chandef_get_width(chandef); + if (width < 0) + return false; + + r1 = cfg80211_get_chans_dfs_usable(wiphy, chandef->center_freq1, + width); + + if (r1 < 0) + return false; + + switch (chandef->width) { + case NL80211_CHAN_WIDTH_80P80: + WARN_ON(!chandef->center_freq2); + r2 = cfg80211_get_chans_dfs_usable(wiphy, + chandef->center_freq2, + width); + if (r2 < 0) + return false; + break; + default: + WARN_ON(chandef->center_freq2); + break; + } + + return (r1 + r2 > 0); +} + + static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, u32 center_freq, u32 bandwidth, u32 prohibited_flags) diff --git a/net/wireless/core.h b/net/wireless/core.h index eb0f7a3a25a..2888867ee7c 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -382,6 +382,19 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, enum cfg80211_chan_mode chanmode, u8 radar_detect); +/** + * cfg80211_chandef_dfs_usable - checks if chandef is DFS usable + * @wiphy: the wiphy to validate against + * @chandef: the channel definition to check + * + * Checks if chandef is usable and we can/need start CAC on such channel. + * + * Return: Return true if all channels available and at least + * one channel require CAC (NL80211_DFS_USABLE) + */ +bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy, + const struct cfg80211_chan_def *chandef); + void cfg80211_set_dfs_state(struct wiphy *wiphy, const struct cfg80211_chan_def *chandef, enum nl80211_dfs_state dfs_state); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 41af3a0e996..e2bb4276af1 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -5651,7 +5651,7 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, if (err == 0) return -EINVAL; - if (chandef.chan->dfs_state != NL80211_DFS_USABLE) + if (!cfg80211_chandef_dfs_usable(wdev->wiphy, &chandef)) return -EINVAL; if (!rdev->ops->start_radar_detection) -- cgit v1.2.3-70-g09d2 From 222ea5819901ed174db4df2e26aa5e982f857845 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 5 Nov 2013 09:18:00 -0800 Subject: cfg80211: force WIPHY_FLAG_CUSTOM_REGULATORY on wiphy_apply_custom_regulatory() wiphy_apply_custom_regulatory() implies WIPHY_FLAG_CUSTOM_REGULATORY but we never enforced it, do that now and warn if the driver didn't set it. All drivers should be following this today already. Having WIPHY_FLAG_CUSTOM_REGULATORY does not however mean you will use wiphy_apply_custom_regulatory() though, you may have your own _orig value set up tools / helpers. The intel drivers are examples of this type of driver. Signed-off-by: Luis R. Rodriguez Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 7 ++++++- net/wireless/reg.c | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index c1b88741323..b7a825ecff5 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2441,7 +2441,9 @@ struct cfg80211_ops { * has its own custom regulatory domain and cannot identify the * ISO / IEC 3166 alpha2 it belongs to. When this is enabled * we will disregard the first regulatory hint (when the - * initiator is %REGDOM_SET_BY_CORE). + * initiator is %REGDOM_SET_BY_CORE). Drivers that use + * wiphy_apply_custom_regulatory() should have this flag set + * or the regulatory core will set it for wiphy. * @WIPHY_FLAG_STRICT_REGULATORY: tells us the driver for this device will * ignore regulatory domain settings until it gets its own regulatory * domain via its regulatory_hint() unless the regulatory hint is @@ -3471,6 +3473,9 @@ int regulatory_hint(struct wiphy *wiphy, const char *alpha2); * custom regulatory domain will be trusted completely and as such previous * default channel settings will be disregarded. If no rule is found for a * channel on the regulatory domain the channel will be disabled. + * Drivers using this for a wiphy should also set the wiphy flag + * WIPHY_FLAG_CUSTOM_REGULATORY or cfg80211 will set it for the wiphy + * that called this helper. */ void wiphy_apply_custom_regulatory(struct wiphy *wiphy, const struct ieee80211_regdomain *regd); diff --git a/net/wireless/reg.c b/net/wireless/reg.c index e4e3337ba29..04b6fe4b765 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1292,6 +1292,10 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy, enum ieee80211_band band; unsigned int bands_set = 0; + WARN(!(wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY), + "wiphy should have WIPHY_FLAG_CUSTOM_REGULATORY\n"); + wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { if (!wiphy->bands[band]) continue; -- cgit v1.2.3-70-g09d2 From 1daa37c7ba01bd788148d6a9dc5d6fb491a20931 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 5 Nov 2013 09:18:02 -0800 Subject: cfg80211: remove second argument from reg_process_hint() The iniator is already available to us, so use it. Signed-off-by: Luis R. Rodriguez Signed-off-by: Johannes Berg --- net/wireless/reg.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 04b6fe4b765..dccdfe36a31 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1526,8 +1526,7 @@ new_request: } /* This processes *all* regulatory hints */ -static void reg_process_hint(struct regulatory_request *reg_request, - enum nl80211_reg_initiator reg_initiator) +static void reg_process_hint(struct regulatory_request *reg_request) { struct wiphy *wiphy = NULL; @@ -1537,7 +1536,7 @@ static void reg_process_hint(struct regulatory_request *reg_request, if (reg_request->wiphy_idx != WIPHY_IDX_INVALID) wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx); - if (reg_initiator == NL80211_REGDOM_SET_BY_DRIVER && !wiphy) { + if (reg_request->initiator == NL80211_REGDOM_SET_BY_DRIVER && !wiphy) { kfree(reg_request); return; } @@ -1546,10 +1545,10 @@ static void reg_process_hint(struct regulatory_request *reg_request, case REG_REQ_ALREADY_SET: /* This is required so that the orig_* parameters are saved */ if (wiphy && wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) - wiphy_update_regulatory(wiphy, reg_initiator); + wiphy_update_regulatory(wiphy, reg_request->initiator); break; default: - if (reg_initiator == NL80211_REGDOM_SET_BY_USER) + if (reg_request->initiator == NL80211_REGDOM_SET_BY_USER) schedule_delayed_work(®_timeout, msecs_to_jiffies(3142)); break; @@ -1587,7 +1586,7 @@ static void reg_process_pending_hints(void) spin_unlock(®_requests_lock); - reg_process_hint(reg_request, reg_request->initiator); + reg_process_hint(reg_request); } /* Processes beacon hints -- this has nothing to do with country IEs */ -- cgit v1.2.3-70-g09d2 From 3cde38e7f3491ea62429556149713b7a875c9ac2 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Tue, 5 Nov 2013 11:16:49 -0800 Subject: mac80211: fix off-by-one in llid check. According to IEEE 802.11-2012 (8.4.2.104), no peering management element exists with length 7. This code is checking to see if llid is present to ignore close frames with different llid, which would be IEs with length 8. Signed-off-by: Bob Copeland Signed-off-by: Johannes Berg --- net/mac80211/mesh_plink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 4301aa5aa22..a8c75c1c66b 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -825,7 +825,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, event = CLS_ACPT; else if (sta->plid != plid) event = CLS_IGNR; - else if (ie_len == 7 && sta->llid != llid) + else if (ie_len == 8 && sta->llid != llid) event = CLS_IGNR; else event = CLS_ACPT; -- cgit v1.2.3-70-g09d2 From 4efec45134d82fa73826cc24d41274beb5097d64 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Tue, 5 Nov 2013 11:16:50 -0800 Subject: mac80211: consolidate calls to plink_frame_tx Do all frame transfers in one place at the end of the big switch statements. sta->plid and sta->reason can be passed in any case, since they are only used for the frames that need them. Remove assignments to locals for values already stored in the sta structure. Signed-off-by: Thomas Pedersen Signed-off-by: Bob Copeland Signed-off-by: Johannes Berg --- net/mac80211/mesh_plink.c | 72 +++++++++++++++++++---------------------------- 1 file changed, 29 insertions(+), 43 deletions(-) diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index a8c75c1c66b..d45826e347e 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -533,6 +533,7 @@ static void mesh_plink_timer(unsigned long data) __le16 llid, plid, reason; struct ieee80211_sub_if_data *sdata; struct mesh_config *mshcfg; + enum ieee80211_self_protected_actioncode action = 0; /* * This STA is valid because sta_info_destroy() will @@ -575,8 +576,7 @@ static void mesh_plink_timer(unsigned long data) ++sta->plink_retries; mod_plink_timer(sta, sta->plink_timeout); spin_unlock_bh(&sta->lock); - mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN, - sta->sta.addr, llid, 0, 0); + action = WLAN_SP_MESH_PEERING_OPEN; break; } reason = cpu_to_le16(WLAN_REASON_MESH_MAX_RETRIES); @@ -588,8 +588,7 @@ static void mesh_plink_timer(unsigned long data) sta->plink_state = NL80211_PLINK_HOLDING; mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout); spin_unlock_bh(&sta->lock); - mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, - sta->sta.addr, llid, plid, reason); + action = WLAN_SP_MESH_PEERING_CLOSE; break; case NL80211_PLINK_HOLDING: /* holding timer */ @@ -601,6 +600,9 @@ static void mesh_plink_timer(unsigned long data) spin_unlock_bh(&sta->lock); break; } + if (action) + mesh_plink_frame_tx(sdata, action, sta->sta.addr, + llid, plid, reason); } static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout) @@ -662,6 +664,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_rx_status *rx_status) { struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg; + enum ieee80211_self_protected_actioncode action = 0; struct ieee802_11_elems elems; struct sta_info *sta; enum plink_event event; @@ -872,12 +875,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, changed |= ieee80211_mps_local_status_update(sdata); spin_unlock_bh(&sta->lock); - mesh_plink_frame_tx(sdata, - WLAN_SP_MESH_PEERING_OPEN, - sta->sta.addr, llid, 0, 0); - mesh_plink_frame_tx(sdata, - WLAN_SP_MESH_PEERING_CONFIRM, - sta->sta.addr, llid, plid, 0); + action = WLAN_SP_MESH_PEERING_OPEN; break; default: spin_unlock_bh(&sta->lock); @@ -899,21 +897,15 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, mshcfg->dot11MeshHoldingTimeout)) sta->ignore_plink_timer = true; - llid = sta->llid; spin_unlock_bh(&sta->lock); - mesh_plink_frame_tx(sdata, - WLAN_SP_MESH_PEERING_CLOSE, - sta->sta.addr, llid, plid, reason); + action = WLAN_SP_MESH_PEERING_CLOSE; break; case OPN_ACPT: /* retry timer is left untouched */ sta->plink_state = NL80211_PLINK_OPN_RCVD; sta->plid = plid; - llid = sta->llid; spin_unlock_bh(&sta->lock); - mesh_plink_frame_tx(sdata, - WLAN_SP_MESH_PEERING_CONFIRM, - sta->sta.addr, llid, plid, 0); + action = WLAN_SP_MESH_PEERING_CONFIRM; break; case CNF_ACPT: sta->plink_state = NL80211_PLINK_CNF_RCVD; @@ -943,17 +935,12 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, mshcfg->dot11MeshHoldingTimeout)) sta->ignore_plink_timer = true; - llid = sta->llid; spin_unlock_bh(&sta->lock); - mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, - sta->sta.addr, llid, plid, reason); + action = WLAN_SP_MESH_PEERING_CLOSE; break; case OPN_ACPT: - llid = sta->llid; spin_unlock_bh(&sta->lock); - mesh_plink_frame_tx(sdata, - WLAN_SP_MESH_PEERING_CONFIRM, - sta->sta.addr, llid, plid, 0); + action = WLAN_SP_MESH_PEERING_CONFIRM; break; case CNF_ACPT: del_timer(&sta->plink_timer); @@ -988,11 +975,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, mshcfg->dot11MeshHoldingTimeout)) sta->ignore_plink_timer = true; - llid = sta->llid; spin_unlock_bh(&sta->lock); - mesh_plink_frame_tx(sdata, - WLAN_SP_MESH_PEERING_CLOSE, - sta->sta.addr, llid, plid, reason); + action = WLAN_SP_MESH_PEERING_CLOSE; break; case OPN_ACPT: del_timer(&sta->plink_timer); @@ -1003,9 +987,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, changed |= mesh_set_short_slot_time(sdata); mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n", sta->sta.addr); - mesh_plink_frame_tx(sdata, - WLAN_SP_MESH_PEERING_CONFIRM, - sta->sta.addr, llid, plid, 0); + action = WLAN_SP_MESH_PEERING_CONFIRM; ieee80211_mps_sta_status_update(sta); changed |= ieee80211_mps_set_sta_local_pm(sta, mshcfg->power_mode); @@ -1023,20 +1005,15 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, sta->reason = reason; changed |= __mesh_plink_deactivate(sta); sta->plink_state = NL80211_PLINK_HOLDING; - llid = sta->llid; mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout); spin_unlock_bh(&sta->lock); changed |= mesh_set_ht_prot_mode(sdata); changed |= mesh_set_short_slot_time(sdata); - mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, - sta->sta.addr, llid, plid, reason); + action = WLAN_SP_MESH_PEERING_CLOSE; break; case OPN_ACPT: - llid = sta->llid; spin_unlock_bh(&sta->lock); - mesh_plink_frame_tx(sdata, - WLAN_SP_MESH_PEERING_CONFIRM, - sta->sta.addr, llid, plid, 0); + action = WLAN_SP_MESH_PEERING_CONFIRM; break; default: spin_unlock_bh(&sta->lock); @@ -1055,11 +1032,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, case CNF_ACPT: case OPN_RJCT: case CNF_RJCT: - llid = sta->llid; - reason = sta->reason; spin_unlock_bh(&sta->lock); - mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, - sta->sta.addr, llid, plid, reason); + action = WLAN_SP_MESH_PEERING_CLOSE; break; default: spin_unlock_bh(&sta->lock); @@ -1072,6 +1046,18 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, spin_unlock_bh(&sta->lock); break; } + if (action) { + mesh_plink_frame_tx(sdata, action, sta->sta.addr, + sta->llid, sta->plid, sta->reason); + + /* also send confirm in open case */ + if (action == WLAN_SP_MESH_PEERING_OPEN) { + mesh_plink_frame_tx(sdata, + WLAN_SP_MESH_PEERING_CONFIRM, + sta->sta.addr, sta->llid, + sta->plid, 0); + } + } rcu_read_unlock(); -- cgit v1.2.3-70-g09d2 From 0f5ffd24fb732fb4d653a8ee97faea767a0e7172 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Tue, 5 Nov 2013 11:16:51 -0800 Subject: mac80211: hold sta->lock across plink switch statements Rather than unlock at the end of each case, do it once after all is said and done. Signed-off-by: Bob Copeland Signed-off-by: Johannes Berg --- net/mac80211/mesh_plink.c | 29 +++-------------------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index d45826e347e..c3a3faf9b31 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -575,7 +575,6 @@ static void mesh_plink_timer(unsigned long data) rand % sta->plink_timeout; ++sta->plink_retries; mod_plink_timer(sta, sta->plink_timeout); - spin_unlock_bh(&sta->lock); action = WLAN_SP_MESH_PEERING_OPEN; break; } @@ -587,19 +586,17 @@ static void mesh_plink_timer(unsigned long data) reason = cpu_to_le16(WLAN_REASON_MESH_CONFIRM_TIMEOUT); sta->plink_state = NL80211_PLINK_HOLDING; mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout); - spin_unlock_bh(&sta->lock); action = WLAN_SP_MESH_PEERING_CLOSE; break; case NL80211_PLINK_HOLDING: /* holding timer */ del_timer(&sta->plink_timer); mesh_plink_fsm_restart(sta); - spin_unlock_bh(&sta->lock); break; default: - spin_unlock_bh(&sta->lock); break; } + spin_unlock_bh(&sta->lock); if (action) mesh_plink_frame_tx(sdata, action, sta->sta.addr, llid, plid, reason); @@ -856,12 +853,10 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, reason = 0; spin_lock_bh(&sta->lock); switch (sta->plink_state) { - /* spin_unlock as soon as state is updated at each case */ case NL80211_PLINK_LISTEN: switch (event) { case CLS_ACPT: mesh_plink_fsm_restart(sta); - spin_unlock_bh(&sta->lock); break; case OPN_ACPT: sta->plink_state = NL80211_PLINK_OPN_RCVD; @@ -874,11 +869,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, /* set the non-peer mode to active during peering */ changed |= ieee80211_mps_local_status_update(sdata); - spin_unlock_bh(&sta->lock); action = WLAN_SP_MESH_PEERING_OPEN; break; default: - spin_unlock_bh(&sta->lock); break; } break; @@ -897,14 +890,12 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, mshcfg->dot11MeshHoldingTimeout)) sta->ignore_plink_timer = true; - spin_unlock_bh(&sta->lock); action = WLAN_SP_MESH_PEERING_CLOSE; break; case OPN_ACPT: /* retry timer is left untouched */ sta->plink_state = NL80211_PLINK_OPN_RCVD; sta->plid = plid; - spin_unlock_bh(&sta->lock); action = WLAN_SP_MESH_PEERING_CONFIRM; break; case CNF_ACPT: @@ -913,10 +904,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, mshcfg->dot11MeshConfirmTimeout)) sta->ignore_plink_timer = true; - spin_unlock_bh(&sta->lock); break; default: - spin_unlock_bh(&sta->lock); break; } break; @@ -935,17 +924,14 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, mshcfg->dot11MeshHoldingTimeout)) sta->ignore_plink_timer = true; - spin_unlock_bh(&sta->lock); action = WLAN_SP_MESH_PEERING_CLOSE; break; case OPN_ACPT: - spin_unlock_bh(&sta->lock); action = WLAN_SP_MESH_PEERING_CONFIRM; break; case CNF_ACPT: del_timer(&sta->plink_timer); sta->plink_state = NL80211_PLINK_ESTAB; - spin_unlock_bh(&sta->lock); changed |= mesh_plink_inc_estab_count(sdata); changed |= mesh_set_ht_prot_mode(sdata); changed |= mesh_set_short_slot_time(sdata); @@ -956,7 +942,6 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, mshcfg->power_mode); break; default: - spin_unlock_bh(&sta->lock); break; } break; @@ -975,13 +960,11 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, mshcfg->dot11MeshHoldingTimeout)) sta->ignore_plink_timer = true; - spin_unlock_bh(&sta->lock); action = WLAN_SP_MESH_PEERING_CLOSE; break; case OPN_ACPT: del_timer(&sta->plink_timer); sta->plink_state = NL80211_PLINK_ESTAB; - spin_unlock_bh(&sta->lock); changed |= mesh_plink_inc_estab_count(sdata); changed |= mesh_set_ht_prot_mode(sdata); changed |= mesh_set_short_slot_time(sdata); @@ -993,7 +976,6 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, mshcfg->power_mode); break; default: - spin_unlock_bh(&sta->lock); break; } break; @@ -1006,17 +988,14 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, changed |= __mesh_plink_deactivate(sta); sta->plink_state = NL80211_PLINK_HOLDING; mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout); - spin_unlock_bh(&sta->lock); changed |= mesh_set_ht_prot_mode(sdata); changed |= mesh_set_short_slot_time(sdata); action = WLAN_SP_MESH_PEERING_CLOSE; break; case OPN_ACPT: - spin_unlock_bh(&sta->lock); action = WLAN_SP_MESH_PEERING_CONFIRM; break; default: - spin_unlock_bh(&sta->lock); break; } break; @@ -1026,26 +1005,24 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, if (del_timer(&sta->plink_timer)) sta->ignore_plink_timer = 1; mesh_plink_fsm_restart(sta); - spin_unlock_bh(&sta->lock); break; case OPN_ACPT: case CNF_ACPT: case OPN_RJCT: case CNF_RJCT: - spin_unlock_bh(&sta->lock); action = WLAN_SP_MESH_PEERING_CLOSE; break; default: - spin_unlock_bh(&sta->lock); + break; } break; default: /* should not get here, PLINK_BLOCKED is dealt with at the * beginning of the function */ - spin_unlock_bh(&sta->lock); break; } + spin_unlock_bh(&sta->lock); if (action) { mesh_plink_frame_tx(sdata, action, sta->sta.addr, sta->llid, sta->plid, sta->reason); -- cgit v1.2.3-70-g09d2 From e76d67f035649f1cc40603ab06ebcc1d2eb49253 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Tue, 5 Nov 2013 11:16:52 -0800 Subject: mac80211: mesh: factor out common plink close/estab code Reject and accepted close events always put the host in the holding state and compute a reason code based only on the current state. Likewise on establish we always do the same setup. Put these in functions to save some duplicated code. Signed-off-by: Bob Copeland Signed-off-by: Johannes Berg --- net/mac80211/mesh_plink.c | 98 +++++++++++++++++++++-------------------------- 1 file changed, 43 insertions(+), 55 deletions(-) diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index c3a3faf9b31..3bab76f4f3b 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -655,6 +655,39 @@ u32 mesh_plink_block(struct sta_info *sta) return changed; } +static void mesh_plink_close(struct ieee80211_sub_if_data *sdata, + struct sta_info *sta, + enum plink_event event) +{ + struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg; + + __le16 reason = (event == CLS_ACPT) ? + cpu_to_le16(WLAN_REASON_MESH_CLOSE) : + cpu_to_le16(WLAN_REASON_MESH_CONFIG); + + sta->reason = reason; + sta->plink_state = NL80211_PLINK_HOLDING; + if (!mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout)) + sta->ignore_plink_timer = true; +} + +static u32 mesh_plink_establish(struct ieee80211_sub_if_data *sdata, + struct sta_info *sta) +{ + struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg; + u32 changed = 0; + + del_timer(&sta->plink_timer); + sta->plink_state = NL80211_PLINK_ESTAB; + changed |= mesh_plink_inc_estab_count(sdata); + changed |= mesh_set_ht_prot_mode(sdata); + changed |= mesh_set_short_slot_time(sdata); + mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n", sta->sta.addr); + ieee80211_mps_sta_status_update(sta); + changed |= ieee80211_mps_set_sta_local_pm(sta, mshcfg->power_mode); + return changed; +} + void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len, @@ -671,7 +704,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, u8 ie_len; u8 *baseaddr; u32 changed = 0; - __le16 plid, llid, reason; + __le16 plid, llid; /* need action_code, aux */ if (len < IEEE80211_MIN_ACTION_SIZE + 3) @@ -782,10 +815,10 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, if (!sta && !matches_local) { rcu_read_unlock(); - reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG); llid = 0; mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, - mgmt->sa, llid, plid, reason); + mgmt->sa, llid, plid, + cpu_to_le16(WLAN_REASON_MESH_CONFIG)); return; } else if (!sta) { /* ftype == WLAN_SP_MESH_PEERING_OPEN */ @@ -850,7 +883,6 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, mpl_dbg(sdata, "peer %pM in state %s got event %s\n", mgmt->sa, mplstates[sta->plink_state], mplevents[event]); - reason = 0; spin_lock_bh(&sta->lock); switch (sta->plink_state) { case NL80211_PLINK_LISTEN: @@ -880,18 +912,11 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, switch (event) { case OPN_RJCT: case CNF_RJCT: - reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG); case CLS_ACPT: - if (!reason) - reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE); - sta->reason = reason; - sta->plink_state = NL80211_PLINK_HOLDING; - if (!mod_plink_timer(sta, - mshcfg->dot11MeshHoldingTimeout)) - sta->ignore_plink_timer = true; - + mesh_plink_close(sdata, sta, event); action = WLAN_SP_MESH_PEERING_CLOSE; break; + case OPN_ACPT: /* retry timer is left untouched */ sta->plink_state = NL80211_PLINK_OPN_RCVD; @@ -914,32 +939,15 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, switch (event) { case OPN_RJCT: case CNF_RJCT: - reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG); case CLS_ACPT: - if (!reason) - reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE); - sta->reason = reason; - sta->plink_state = NL80211_PLINK_HOLDING; - if (!mod_plink_timer(sta, - mshcfg->dot11MeshHoldingTimeout)) - sta->ignore_plink_timer = true; - + mesh_plink_close(sdata, sta, event); action = WLAN_SP_MESH_PEERING_CLOSE; break; case OPN_ACPT: action = WLAN_SP_MESH_PEERING_CONFIRM; break; case CNF_ACPT: - del_timer(&sta->plink_timer); - sta->plink_state = NL80211_PLINK_ESTAB; - changed |= mesh_plink_inc_estab_count(sdata); - changed |= mesh_set_ht_prot_mode(sdata); - changed |= mesh_set_short_slot_time(sdata); - mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n", - sta->sta.addr); - ieee80211_mps_sta_status_update(sta); - changed |= ieee80211_mps_set_sta_local_pm(sta, - mshcfg->power_mode); + changed |= mesh_plink_establish(sdata, sta); break; default: break; @@ -950,30 +958,13 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, switch (event) { case OPN_RJCT: case CNF_RJCT: - reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG); case CLS_ACPT: - if (!reason) - reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE); - sta->reason = reason; - sta->plink_state = NL80211_PLINK_HOLDING; - if (!mod_plink_timer(sta, - mshcfg->dot11MeshHoldingTimeout)) - sta->ignore_plink_timer = true; - + mesh_plink_close(sdata, sta, event); action = WLAN_SP_MESH_PEERING_CLOSE; break; case OPN_ACPT: - del_timer(&sta->plink_timer); - sta->plink_state = NL80211_PLINK_ESTAB; - changed |= mesh_plink_inc_estab_count(sdata); - changed |= mesh_set_ht_prot_mode(sdata); - changed |= mesh_set_short_slot_time(sdata); - mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n", - sta->sta.addr); + changed |= mesh_plink_establish(sdata, sta); action = WLAN_SP_MESH_PEERING_CONFIRM; - ieee80211_mps_sta_status_update(sta); - changed |= ieee80211_mps_set_sta_local_pm(sta, - mshcfg->power_mode); break; default: break; @@ -983,13 +974,10 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, case NL80211_PLINK_ESTAB: switch (event) { case CLS_ACPT: - reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE); - sta->reason = reason; changed |= __mesh_plink_deactivate(sta); - sta->plink_state = NL80211_PLINK_HOLDING; - mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout); changed |= mesh_set_ht_prot_mode(sdata); changed |= mesh_set_short_slot_time(sdata); + mesh_plink_close(sdata, sta, event); action = WLAN_SP_MESH_PEERING_CLOSE; break; case OPN_ACPT: -- cgit v1.2.3-70-g09d2 From 32cb05bfe81ed00676a21d914db5729abe3f326f Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Tue, 5 Nov 2013 11:16:53 -0800 Subject: mac80211: mesh_plink: group basic fitness checks The initial frame checks differ depending on whether this is a new peer or not, but they were all intermixed with sta checks as necessary. Group them together so the two cases are clearer. Signed-off-by: Bob Copeland Signed-off-by: Johannes Berg --- net/mac80211/mesh_plink.c | 70 +++++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 3bab76f4f3b..5048658709d 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -700,7 +700,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, enum plink_event event; enum ieee80211_self_protected_actioncode ftype; size_t baselen; - bool matches_local = true; + bool matches_local; u8 ie_len; u8 *baseaddr; u32 changed = 0; @@ -771,11 +771,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, rcu_read_lock(); sta = sta_info_get(sdata, mgmt->sa); - if (!sta && ftype != WLAN_SP_MESH_PEERING_OPEN) { - mpl_dbg(sdata, "Mesh plink: cls or cnf from unknown peer\n"); - rcu_read_unlock(); - return; - } + + matches_local = ftype == WLAN_SP_MESH_PEERING_CLOSE || + mesh_matches_local(sdata, &elems); if (ftype == WLAN_SP_MESH_PEERING_OPEN && !rssi_threshold_check(sta, sdata)) { @@ -785,22 +783,41 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, return; } - if (sta && !test_sta_flag(sta, WLAN_STA_AUTH)) { - mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n"); - rcu_read_unlock(); - return; - } - - if (sta && sta->plink_state == NL80211_PLINK_BLOCKED) { - rcu_read_unlock(); - return; + if (!sta) { + if (ftype != WLAN_SP_MESH_PEERING_OPEN) { + mpl_dbg(sdata, "Mesh plink: cls or cnf from unknown peer\n"); + rcu_read_unlock(); + return; + } + /* ftype == WLAN_SP_MESH_PEERING_OPEN */ + if (!mesh_plink_free_count(sdata)) { + mpl_dbg(sdata, "Mesh plink error: no more free plinks\n"); + rcu_read_unlock(); + return; + } + /* deny open request from non-matching peer */ + if (!matches_local) { + rcu_read_unlock(); + mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, + mgmt->sa, 0, plid, + cpu_to_le16(WLAN_REASON_MESH_CONFIG)); + return; + } + } else { + if (!test_sta_flag(sta, WLAN_STA_AUTH)) { + mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n"); + rcu_read_unlock(); + return; + } + if (sta->plink_state == NL80211_PLINK_BLOCKED) { + rcu_read_unlock(); + return; + } } /* Now we will figure out the appropriate event... */ event = PLINK_UNDEFINED; - if (ftype != WLAN_SP_MESH_PEERING_CLOSE && - !mesh_matches_local(sdata, &elems)) { - matches_local = false; + if (!matches_local) { switch (ftype) { case WLAN_SP_MESH_PEERING_OPEN: event = OPN_RJCT; @@ -813,22 +830,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, } } - if (!sta && !matches_local) { - rcu_read_unlock(); - llid = 0; - mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, - mgmt->sa, llid, plid, - cpu_to_le16(WLAN_REASON_MESH_CONFIG)); - return; - } else if (!sta) { - /* ftype == WLAN_SP_MESH_PEERING_OPEN */ - if (!mesh_plink_free_count(sdata)) { - mpl_dbg(sdata, "Mesh plink error: no more free plinks\n"); - rcu_read_unlock(); - return; - } + if (!sta) event = OPN_ACPT; - } else if (matches_local) { + else if (matches_local) { switch (ftype) { case WLAN_SP_MESH_PEERING_OPEN: if (!mesh_plink_free_count(sdata) || -- cgit v1.2.3-70-g09d2 From 36c9bb29bfad5c43327aa7b8b912ff8dca68416c Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Tue, 5 Nov 2013 11:16:54 -0800 Subject: mac80211: mesh: rewrite rssi_threshold_check in C Use C instead of cpp for type checking. Also swap the arguments into the usual sdata -> sta order. Signed-off-by: Bob Copeland Signed-off-by: Johannes Berg --- net/mac80211/mesh_plink.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 5048658709d..36b6cfffa6f 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -19,12 +19,6 @@ #define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \ jiffies + HZ * t / 1000)) -/* We only need a valid sta if user configured a minimum rssi_threshold. */ -#define rssi_threshold_check(sta, sdata) \ - (sdata->u.mesh.mshcfg.rssi_threshold == 0 ||\ - (sta && (s8) -ewma_read(&sta->avg_signal) > \ - sdata->u.mesh.mshcfg.rssi_threshold)) - enum plink_event { PLINK_UNDEFINED, OPN_ACPT, @@ -63,6 +57,16 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, enum ieee80211_self_protected_actioncode action, u8 *da, __le16 llid, __le16 plid, __le16 reason); + +/* We only need a valid sta if user configured a minimum rssi_threshold. */ +static bool rssi_threshold_check(struct ieee80211_sub_if_data *sdata, + struct sta_info *sta) +{ + s32 rssi_threshold = sdata->u.mesh.mshcfg.rssi_threshold; + return rssi_threshold == 0 || + (sta && (s8) -ewma_read(&sta->avg_signal) > rssi_threshold); +} + /** * mesh_plink_fsm_restart - restart a mesh peer link finite state machine * @@ -518,7 +522,7 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata, sta->plink_state == NL80211_PLINK_LISTEN && sdata->u.mesh.accepting_plinks && sdata->u.mesh.mshcfg.auto_open_plinks && - rssi_threshold_check(sta, sdata)) + rssi_threshold_check(sdata, sta)) changed = mesh_plink_open(sta); ieee80211_mps_frame_release(sta, elems); @@ -776,7 +780,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, mesh_matches_local(sdata, &elems); if (ftype == WLAN_SP_MESH_PEERING_OPEN && - !rssi_threshold_check(sta, sdata)) { + !rssi_threshold_check(sdata, sta)) { mpl_dbg(sdata, "Mesh plink: %pM does not meet rssi threshold\n", mgmt->sa); rcu_read_unlock(); -- cgit v1.2.3-70-g09d2 From 58506eba784a0944e4c92876b18aacbaad178be3 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Tue, 5 Nov 2013 11:16:55 -0800 Subject: mac80211: mesh_plink: collapse the two switch statements together The matches_local check can just be done when looking at the individual action types. Signed-off-by: Bob Copeland Signed-off-by: Johannes Berg --- net/mac80211/mesh_plink.c | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 36b6cfffa6f..8e233951467 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -821,33 +821,25 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, /* Now we will figure out the appropriate event... */ event = PLINK_UNDEFINED; - if (!matches_local) { - switch (ftype) { - case WLAN_SP_MESH_PEERING_OPEN: - event = OPN_RJCT; - break; - case WLAN_SP_MESH_PEERING_CONFIRM: - event = CNF_RJCT; - break; - default: - break; - } - } if (!sta) event = OPN_ACPT; - else if (matches_local) { + else { switch (ftype) { case WLAN_SP_MESH_PEERING_OPEN: - if (!mesh_plink_free_count(sdata) || - (sta->plid && sta->plid != plid)) + if (!matches_local) + event = OPN_RJCT; + else if (!mesh_plink_free_count(sdata) || + (sta->plid && sta->plid != plid)) event = OPN_IGNR; else event = OPN_ACPT; break; case WLAN_SP_MESH_PEERING_CONFIRM: - if (!mesh_plink_free_count(sdata) || - (sta->llid != llid || sta->plid != plid)) + if (!matches_local) + event = CNF_RJCT; + else if (!mesh_plink_free_count(sdata) || + (sta->llid != llid || sta->plid != plid)) event = CNF_IGNR; else event = CNF_ACPT; -- cgit v1.2.3-70-g09d2 From 272a9e2614bf3b93f47f95ef9507d4ceec6bec27 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Tue, 5 Nov 2013 11:16:56 -0800 Subject: mac80211: mesh_plink: don't ignore holding timer The ignore_plink_timer flag is set when doing mod_timer() if the timer was not previously active. This is to avoid executing the timeout if del_timer() was subsequently called. However, del_timer() only happens if we are moving to ESTAB state or get a close frame while in HOLDING. We cannot leave HOLDING and re-enter ESTAB unless we receive a close frame (in which case ignore_plink_timer is already set) or if the timeout expires, so there actually isn't a case where this is needed on mod_timer(). Signed-off-by: Bob Copeland Signed-off-by: Johannes Berg --- net/mac80211/mesh_plink.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 8e233951467..550ebc1463c 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -671,8 +671,7 @@ static void mesh_plink_close(struct ieee80211_sub_if_data *sdata, sta->reason = reason; sta->plink_state = NL80211_PLINK_HOLDING; - if (!mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout)) - sta->ignore_plink_timer = true; + mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout); } static u32 mesh_plink_establish(struct ieee80211_sub_if_data *sdata, -- cgit v1.2.3-70-g09d2 From 87d84c452a7603e4f4aaa806ec1a798d6eacfc99 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Tue, 5 Nov 2013 11:16:57 -0800 Subject: mac80211: return -ENOMEM in mesh_plink_frame_tx All other paths return an error code, do the same here. Signed-off-by: Bob Copeland Signed-off-by: Johannes Berg --- net/mac80211/mesh_plink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 550ebc1463c..429f69278d1 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -283,7 +283,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, 2 + 8 + /* peering IE */ sdata->u.mesh.ie_len); if (!skb) - return -1; + return err; info = IEEE80211_SKB_CB(skb); skb_reserve(skb, local->tx_headroom); mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len); -- cgit v1.2.3-70-g09d2 From 2d7f65d6f1842e96286464bc3acb12b7e92c7359 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Tue, 5 Nov 2013 11:16:58 -0800 Subject: mac80211: remove unused mesh_mgmt_ies_add() prototype Said function was removed some time ago. Signed-off-by: Bob Copeland Signed-off-by: Johannes Berg --- net/mac80211/mesh.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 2bc7fd2f787..3f867e52c33 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -215,8 +215,6 @@ int mesh_rmc_check(struct ieee80211_sub_if_data *sdata, bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, struct ieee802_11_elems *ie); void mesh_ids_set_default(struct ieee80211_if_mesh *mesh); -void mesh_mgmt_ies_add(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb); int mesh_add_meshconf_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); int mesh_add_meshid_ie(struct ieee80211_sub_if_data *sdata, -- cgit v1.2.3-70-g09d2 From 05a23ae927d1eb0491064fddaa8b1531a84def6f Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Tue, 5 Nov 2013 11:16:59 -0800 Subject: mac80211: factor peering frame processing into own function Signed-off-by: Thomas Pedersen Signed-off-by: Johannes Berg --- net/mac80211/mesh_plink.c | 88 ++++++++++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 40 deletions(-) diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 429f69278d1..c234ddbbf62 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -691,54 +691,29 @@ static u32 mesh_plink_establish(struct ieee80211_sub_if_data *sdata, return changed; } - -void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, - struct ieee80211_mgmt *mgmt, size_t len, - struct ieee80211_rx_status *rx_status) +static void +mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgmt *mgmt, + struct ieee802_11_elems *elems) { + struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg; enum ieee80211_self_protected_actioncode action = 0; - struct ieee802_11_elems elems; struct sta_info *sta; enum plink_event event; enum ieee80211_self_protected_actioncode ftype; - size_t baselen; bool matches_local; - u8 ie_len; - u8 *baseaddr; u32 changed = 0; + u8 ie_len; __le16 plid, llid; - /* need action_code, aux */ - if (len < IEEE80211_MIN_ACTION_SIZE + 3) - return; - - if (sdata->u.mesh.user_mpm) - /* userspace must register for these */ - return; - - if (is_multicast_ether_addr(mgmt->da)) { - mpl_dbg(sdata, - "Mesh plink: ignore frame from multicast address\n"); - return; - } - - baseaddr = mgmt->u.action.u.self_prot.variable; - baselen = (u8 *) mgmt->u.action.u.self_prot.variable - (u8 *) mgmt; - if (mgmt->u.action.u.self_prot.action_code == - WLAN_SP_MESH_PEERING_CONFIRM) { - baseaddr += 4; - baselen += 4; - } - ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems); - - if (!elems.peering) { + if (!elems->peering) { mpl_dbg(sdata, "Mesh plink: missing necessary peer link ie\n"); return; } - if (elems.rsn_len && + if (elems->rsn_len && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) { mpl_dbg(sdata, "Mesh plink: can't establish link with secure peer\n"); @@ -746,7 +721,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, } ftype = mgmt->u.action.u.self_prot.action_code; - ie_len = elems.peering_len; + ie_len = elems->peering_len; if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 4) || (ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) || (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6 @@ -758,25 +733,25 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, } if (ftype != WLAN_SP_MESH_PEERING_CLOSE && - (!elems.mesh_id || !elems.mesh_config)) { + (!elems->mesh_id || !elems->mesh_config)) { mpl_dbg(sdata, "Mesh plink: missing necessary ie\n"); return; } /* Note the lines below are correct, the llid in the frame is the plid * from the point of view of this host. */ - memcpy(&plid, PLINK_GET_LLID(elems.peering), 2); + memcpy(&plid, PLINK_GET_LLID(elems->peering), 2); if (ftype == WLAN_SP_MESH_PEERING_CONFIRM || (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8)) - memcpy(&llid, PLINK_GET_PLID(elems.peering), 2); + memcpy(&llid, PLINK_GET_PLID(elems->peering), 2); /* WARNING: Only for sta pointer, is dropped & re-acquired */ rcu_read_lock(); sta = sta_info_get(sdata, mgmt->sa); - matches_local = ftype == WLAN_SP_MESH_PEERING_CLOSE || - mesh_matches_local(sdata, &elems); + matches_local = (ftype == WLAN_SP_MESH_PEERING_CLOSE || + mesh_matches_local(sdata, elems)); if (ftype == WLAN_SP_MESH_PEERING_OPEN && !rssi_threshold_check(sdata, sta)) { @@ -872,7 +847,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, if (event == OPN_ACPT) { rcu_read_unlock(); /* allocate sta entry if necessary and update info */ - sta = mesh_sta_info_get(sdata, mgmt->sa, &elems); + sta = mesh_sta_info_get(sdata, mgmt->sa, elems); if (!sta) { mpl_dbg(sdata, "Mesh plink: failed to init peer!\n"); rcu_read_unlock(); @@ -1028,3 +1003,36 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, if (changed) ieee80211_mbss_info_change_notify(sdata, changed); } + +void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgmt *mgmt, size_t len, + struct ieee80211_rx_status *rx_status) +{ + struct ieee802_11_elems elems; + size_t baselen; + u8 *baseaddr; + + /* need action_code, aux */ + if (len < IEEE80211_MIN_ACTION_SIZE + 3) + return; + + if (sdata->u.mesh.user_mpm) + /* userspace must register for these */ + return; + + if (is_multicast_ether_addr(mgmt->da)) { + mpl_dbg(sdata, + "Mesh plink: ignore frame from multicast address\n"); + return; + } + + baseaddr = mgmt->u.action.u.self_prot.variable; + baselen = (u8 *) mgmt->u.action.u.self_prot.variable - (u8 *) mgmt; + if (mgmt->u.action.u.self_prot.action_code == + WLAN_SP_MESH_PEERING_CONFIRM) { + baseaddr += 4; + baselen += 4; + } + ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems); + mesh_process_plink_frame(sdata, mgmt, &elems); +} -- cgit v1.2.3-70-g09d2 From fc10302ef1d22ec559b94a22c3b6b1fc7180240e Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Tue, 5 Nov 2013 11:17:00 -0800 Subject: mac80211: consolidate rcu unlocks in plink frame rx Signed-off-by: Thomas Pedersen Signed-off-by: Johannes Berg --- net/mac80211/mesh_plink.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index c234ddbbf62..e70f4901885 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -757,40 +757,33 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, !rssi_threshold_check(sdata, sta)) { mpl_dbg(sdata, "Mesh plink: %pM does not meet rssi threshold\n", mgmt->sa); - rcu_read_unlock(); - return; + goto unlock_rcu; } if (!sta) { if (ftype != WLAN_SP_MESH_PEERING_OPEN) { mpl_dbg(sdata, "Mesh plink: cls or cnf from unknown peer\n"); - rcu_read_unlock(); - return; + goto unlock_rcu; } /* ftype == WLAN_SP_MESH_PEERING_OPEN */ if (!mesh_plink_free_count(sdata)) { mpl_dbg(sdata, "Mesh plink error: no more free plinks\n"); - rcu_read_unlock(); - return; + goto unlock_rcu; } /* deny open request from non-matching peer */ if (!matches_local) { - rcu_read_unlock(); mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, mgmt->sa, 0, plid, cpu_to_le16(WLAN_REASON_MESH_CONFIG)); - return; + goto unlock_rcu; } } else { if (!test_sta_flag(sta, WLAN_STA_AUTH)) { mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n"); - rcu_read_unlock(); - return; - } - if (sta->plink_state == NL80211_PLINK_BLOCKED) { - rcu_read_unlock(); - return; + goto unlock_rcu; } + if (sta->plink_state == NL80211_PLINK_BLOCKED) + goto unlock_rcu; } /* Now we will figure out the appropriate event... */ @@ -839,8 +832,7 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, break; default: mpl_dbg(sdata, "Mesh plink: unknown frame subtype\n"); - rcu_read_unlock(); - return; + goto unlock_rcu; } } @@ -850,8 +842,7 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, sta = mesh_sta_info_get(sdata, mgmt->sa, elems); if (!sta) { mpl_dbg(sdata, "Mesh plink: failed to init peer!\n"); - rcu_read_unlock(); - return; + goto unlock_rcu; } } @@ -998,6 +989,7 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, } } +unlock_rcu: rcu_read_unlock(); if (changed) -- cgit v1.2.3-70-g09d2 From 5bbdd6c646547046e6c4e0fc9eef78d29a7c3984 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Tue, 5 Nov 2013 11:17:01 -0800 Subject: mac80211: assign sta plid early If we store the peer link ID right after initializing a new neighbor, there is no need to do it later in the peering FSM. Signed-off-by: Thomas Pedersen Signed-off-by: Johannes Berg --- net/mac80211/mesh_plink.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index e70f4901885..fa86d354f62 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -844,6 +844,7 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, mpl_dbg(sdata, "Mesh plink: failed to init peer!\n"); goto unlock_rcu; } + sta->plid = plid; } mpl_dbg(sdata, "peer %pM in state %s got event %s\n", mgmt->sa, @@ -857,7 +858,6 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, break; case OPN_ACPT: sta->plink_state = NL80211_PLINK_OPN_RCVD; - sta->plid = plid; get_random_bytes(&llid, 2); sta->llid = llid; mesh_plink_timer_set(sta, @@ -885,7 +885,6 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, case OPN_ACPT: /* retry timer is left untouched */ sta->plink_state = NL80211_PLINK_OPN_RCVD; - sta->plid = plid; action = WLAN_SP_MESH_PEERING_CONFIRM; break; case CNF_ACPT: -- cgit v1.2.3-70-g09d2 From c7e678115a2693782a9950d33b1a2e602e2c6b70 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Tue, 5 Nov 2013 11:17:02 -0800 Subject: mac80211: factor out peering FSM Signed-off-by: Thomas Pedersen [fix some indentation, squash llid assignment] Signed-off-by: Johannes Berg --- net/mac80211/mesh_plink.c | 298 ++++++++++++++++++++++++---------------------- 1 file changed, 155 insertions(+), 143 deletions(-) diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index fa86d354f62..4311d4571ec 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -691,21 +691,172 @@ static u32 mesh_plink_establish(struct ieee80211_sub_if_data *sdata, return changed; } +/** + * mesh_plink_fsm - step @sta MPM based on @event + * + * @sdata: interface + * @sta: mesh neighbor + * @event: peering event + * + * Return: changed MBSS flags + */ +static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata, + struct sta_info *sta, enum plink_event event) +{ + struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg; + enum ieee80211_self_protected_actioncode action = 0; + u32 changed = 0; + + mpl_dbg(sdata, "peer %pM in state %s got event %s\n", sta->sta.addr, + mplstates[sta->plink_state], mplevents[event]); + + spin_lock_bh(&sta->lock); + switch (sta->plink_state) { + case NL80211_PLINK_LISTEN: + switch (event) { + case CLS_ACPT: + mesh_plink_fsm_restart(sta); + break; + case OPN_ACPT: + sta->plink_state = NL80211_PLINK_OPN_RCVD; + get_random_bytes(&sta->llid, 2); + mesh_plink_timer_set(sta, + mshcfg->dot11MeshRetryTimeout); + + /* set the non-peer mode to active during peering */ + changed |= ieee80211_mps_local_status_update(sdata); + action = WLAN_SP_MESH_PEERING_OPEN; + break; + default: + break; + } + break; + case NL80211_PLINK_OPN_SNT: + switch (event) { + case OPN_RJCT: + case CNF_RJCT: + case CLS_ACPT: + mesh_plink_close(sdata, sta, event); + action = WLAN_SP_MESH_PEERING_CLOSE; + break; + case OPN_ACPT: + /* retry timer is left untouched */ + sta->plink_state = NL80211_PLINK_OPN_RCVD; + action = WLAN_SP_MESH_PEERING_CONFIRM; + break; + case CNF_ACPT: + sta->plink_state = NL80211_PLINK_CNF_RCVD; + if (!mod_plink_timer(sta, + mshcfg->dot11MeshConfirmTimeout)) + sta->ignore_plink_timer = true; + break; + default: + break; + } + break; + case NL80211_PLINK_OPN_RCVD: + switch (event) { + case OPN_RJCT: + case CNF_RJCT: + case CLS_ACPT: + mesh_plink_close(sdata, sta, event); + action = WLAN_SP_MESH_PEERING_CLOSE; + break; + case OPN_ACPT: + action = WLAN_SP_MESH_PEERING_CONFIRM; + break; + case CNF_ACPT: + changed |= mesh_plink_establish(sdata, sta); + break; + default: + break; + } + break; + case NL80211_PLINK_CNF_RCVD: + switch (event) { + case OPN_RJCT: + case CNF_RJCT: + case CLS_ACPT: + mesh_plink_close(sdata, sta, event); + action = WLAN_SP_MESH_PEERING_CLOSE; + break; + case OPN_ACPT: + changed |= mesh_plink_establish(sdata, sta); + action = WLAN_SP_MESH_PEERING_CONFIRM; + break; + default: + break; + } + break; + case NL80211_PLINK_ESTAB: + switch (event) { + case CLS_ACPT: + changed |= __mesh_plink_deactivate(sta); + changed |= mesh_set_ht_prot_mode(sdata); + changed |= mesh_set_short_slot_time(sdata); + mesh_plink_close(sdata, sta, event); + action = WLAN_SP_MESH_PEERING_CLOSE; + break; + case OPN_ACPT: + action = WLAN_SP_MESH_PEERING_CONFIRM; + break; + default: + break; + } + break; + case NL80211_PLINK_HOLDING: + switch (event) { + case CLS_ACPT: + if (del_timer(&sta->plink_timer)) + sta->ignore_plink_timer = 1; + mesh_plink_fsm_restart(sta); + break; + case OPN_ACPT: + case CNF_ACPT: + case OPN_RJCT: + case CNF_RJCT: + action = WLAN_SP_MESH_PEERING_CLOSE; + break; + default: + break; + } + break; + default: + /* should not get here, PLINK_BLOCKED is dealt with at the + * beginning of the function + */ + break; + } + spin_unlock_bh(&sta->lock); + if (action) { + mesh_plink_frame_tx(sdata, action, sta->sta.addr, + sta->llid, sta->plid, sta->reason); + + /* also send confirm in open case */ + if (action == WLAN_SP_MESH_PEERING_OPEN) { + mesh_plink_frame_tx(sdata, + WLAN_SP_MESH_PEERING_CONFIRM, + sta->sta.addr, sta->llid, + sta->plid, 0); + } + } + + return changed; +} + static void mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, struct ieee802_11_elems *elems) { - struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg; - enum ieee80211_self_protected_actioncode action = 0; struct sta_info *sta; enum plink_event event; enum ieee80211_self_protected_actioncode ftype; bool matches_local; u32 changed = 0; u8 ie_len; - __le16 plid, llid; + __le16 plid, llid = 0; if (!elems->peering) { mpl_dbg(sdata, @@ -847,146 +998,7 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, sta->plid = plid; } - mpl_dbg(sdata, "peer %pM in state %s got event %s\n", mgmt->sa, - mplstates[sta->plink_state], mplevents[event]); - spin_lock_bh(&sta->lock); - switch (sta->plink_state) { - case NL80211_PLINK_LISTEN: - switch (event) { - case CLS_ACPT: - mesh_plink_fsm_restart(sta); - break; - case OPN_ACPT: - sta->plink_state = NL80211_PLINK_OPN_RCVD; - get_random_bytes(&llid, 2); - sta->llid = llid; - mesh_plink_timer_set(sta, - mshcfg->dot11MeshRetryTimeout); - - /* set the non-peer mode to active during peering */ - changed |= ieee80211_mps_local_status_update(sdata); - - action = WLAN_SP_MESH_PEERING_OPEN; - break; - default: - break; - } - break; - - case NL80211_PLINK_OPN_SNT: - switch (event) { - case OPN_RJCT: - case CNF_RJCT: - case CLS_ACPT: - mesh_plink_close(sdata, sta, event); - action = WLAN_SP_MESH_PEERING_CLOSE; - break; - - case OPN_ACPT: - /* retry timer is left untouched */ - sta->plink_state = NL80211_PLINK_OPN_RCVD; - action = WLAN_SP_MESH_PEERING_CONFIRM; - break; - case CNF_ACPT: - sta->plink_state = NL80211_PLINK_CNF_RCVD; - if (!mod_plink_timer(sta, - mshcfg->dot11MeshConfirmTimeout)) - sta->ignore_plink_timer = true; - - break; - default: - break; - } - break; - - case NL80211_PLINK_OPN_RCVD: - switch (event) { - case OPN_RJCT: - case CNF_RJCT: - case CLS_ACPT: - mesh_plink_close(sdata, sta, event); - action = WLAN_SP_MESH_PEERING_CLOSE; - break; - case OPN_ACPT: - action = WLAN_SP_MESH_PEERING_CONFIRM; - break; - case CNF_ACPT: - changed |= mesh_plink_establish(sdata, sta); - break; - default: - break; - } - break; - - case NL80211_PLINK_CNF_RCVD: - switch (event) { - case OPN_RJCT: - case CNF_RJCT: - case CLS_ACPT: - mesh_plink_close(sdata, sta, event); - action = WLAN_SP_MESH_PEERING_CLOSE; - break; - case OPN_ACPT: - changed |= mesh_plink_establish(sdata, sta); - action = WLAN_SP_MESH_PEERING_CONFIRM; - break; - default: - break; - } - break; - - case NL80211_PLINK_ESTAB: - switch (event) { - case CLS_ACPT: - changed |= __mesh_plink_deactivate(sta); - changed |= mesh_set_ht_prot_mode(sdata); - changed |= mesh_set_short_slot_time(sdata); - mesh_plink_close(sdata, sta, event); - action = WLAN_SP_MESH_PEERING_CLOSE; - break; - case OPN_ACPT: - action = WLAN_SP_MESH_PEERING_CONFIRM; - break; - default: - break; - } - break; - case NL80211_PLINK_HOLDING: - switch (event) { - case CLS_ACPT: - if (del_timer(&sta->plink_timer)) - sta->ignore_plink_timer = 1; - mesh_plink_fsm_restart(sta); - break; - case OPN_ACPT: - case CNF_ACPT: - case OPN_RJCT: - case CNF_RJCT: - action = WLAN_SP_MESH_PEERING_CLOSE; - break; - default: - break; - } - break; - default: - /* should not get here, PLINK_BLOCKED is dealt with at the - * beginning of the function - */ - break; - } - spin_unlock_bh(&sta->lock); - if (action) { - mesh_plink_frame_tx(sdata, action, sta->sta.addr, - sta->llid, sta->plid, sta->reason); - - /* also send confirm in open case */ - if (action == WLAN_SP_MESH_PEERING_OPEN) { - mesh_plink_frame_tx(sdata, - WLAN_SP_MESH_PEERING_CONFIRM, - sta->sta.addr, sta->llid, - sta->plid, 0); - } - } + changed |= mesh_plink_fsm(sdata, sta, event); unlock_rcu: rcu_read_unlock(); -- cgit v1.2.3-70-g09d2 From c99a89edb1066e4c1f79b3ca4e91a676d1b25ce1 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Tue, 5 Nov 2013 11:17:03 -0800 Subject: mac80211: factor out plink event gathering Signed-off-by: Thomas Pedersen Signed-off-by: Johannes Berg --- net/mac80211/mesh_plink.c | 195 +++++++++++++++++++++++++++------------------- 1 file changed, 115 insertions(+), 80 deletions(-) diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 4311d4571ec..ee2a97f3173 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -844,6 +844,111 @@ static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata, return changed; } +/* + * mesh_plink_get_event - get correct MPM event + * + * @sdata: interface + * @sta: peer, leave NULL if processing a frame from a new suitable peer + * @elems: peering management IEs + * @ftype: frame type + * @llid: peer's peer link ID + * @plid: peer's local link ID + * + * Return: new peering event for @sta, but PLINK_UNDEFINED should be treated as + * an error. + */ +static enum plink_event +mesh_plink_get_event(struct ieee80211_sub_if_data *sdata, + struct sta_info *sta, + struct ieee802_11_elems *elems, + enum ieee80211_self_protected_actioncode ftype, + __le16 llid, __le16 plid) +{ + enum plink_event event = PLINK_UNDEFINED; + u8 ie_len = elems->peering_len; + bool matches_local; + + matches_local = (ftype == WLAN_SP_MESH_PEERING_CLOSE || + mesh_matches_local(sdata, elems)); + + /* deny open request from non-matching peer */ + if (!matches_local && !sta) { + event = OPN_RJCT; + goto out; + } + + if (!sta) { + if (ftype != WLAN_SP_MESH_PEERING_OPEN) { + mpl_dbg(sdata, "Mesh plink: cls or cnf from unknown peer\n"); + goto out; + } + /* ftype == WLAN_SP_MESH_PEERING_OPEN */ + if (!mesh_plink_free_count(sdata)) { + mpl_dbg(sdata, "Mesh plink error: no more free plinks\n"); + goto out; + } + } else { + if (!test_sta_flag(sta, WLAN_STA_AUTH)) { + mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n"); + goto out; + } + if (sta->plink_state == NL80211_PLINK_BLOCKED) + goto out; + } + + /* new matching peer */ + if (!sta) { + event = OPN_ACPT; + goto out; + } + + switch (ftype) { + case WLAN_SP_MESH_PEERING_OPEN: + if (!matches_local) + event = OPN_RJCT; + if (!mesh_plink_free_count(sdata) || + (sta->plid && sta->plid != plid)) + event = OPN_IGNR; + else + event = OPN_ACPT; + break; + case WLAN_SP_MESH_PEERING_CONFIRM: + if (!matches_local) + event = CNF_RJCT; + if (!mesh_plink_free_count(sdata) || + (sta->llid != llid || sta->plid != plid)) + event = CNF_IGNR; + else + event = CNF_ACPT; + break; + case WLAN_SP_MESH_PEERING_CLOSE: + if (sta->plink_state == NL80211_PLINK_ESTAB) + /* Do not check for llid or plid. This does not + * follow the standard but since multiple plinks + * per sta are not supported, it is necessary in + * order to avoid a livelock when MP A sees an + * establish peer link to MP B but MP B does not + * see it. This can be caused by a timeout in + * B's peer link establishment or B beign + * restarted. + */ + event = CLS_ACPT; + else if (sta->plid != plid) + event = CLS_IGNR; + else if (ie_len == 8 && sta->llid != llid) + event = CLS_IGNR; + else + event = CLS_ACPT; + break; + default: + mpl_dbg(sdata, "Mesh plink: unknown frame subtype\n"); + break; + } + +out: + return event; +} + static void mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, @@ -853,9 +958,8 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, struct sta_info *sta; enum plink_event event; enum ieee80211_self_protected_actioncode ftype; - bool matches_local; u32 changed = 0; - u8 ie_len; + u8 ie_len = elems->peering_len; __le16 plid, llid = 0; if (!elems->peering) { @@ -872,7 +976,6 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, } ftype = mgmt->u.action.u.self_prot.action_code; - ie_len = elems->peering_len; if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 4) || (ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) || (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6 @@ -901,9 +1004,6 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, sta = sta_info_get(sdata, mgmt->sa); - matches_local = (ftype == WLAN_SP_MESH_PEERING_CLOSE || - mesh_matches_local(sdata, elems)); - if (ftype == WLAN_SP_MESH_PEERING_OPEN && !rssi_threshold_check(sdata, sta)) { mpl_dbg(sdata, "Mesh plink: %pM does not meet rssi threshold\n", @@ -911,81 +1011,8 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, goto unlock_rcu; } - if (!sta) { - if (ftype != WLAN_SP_MESH_PEERING_OPEN) { - mpl_dbg(sdata, "Mesh plink: cls or cnf from unknown peer\n"); - goto unlock_rcu; - } - /* ftype == WLAN_SP_MESH_PEERING_OPEN */ - if (!mesh_plink_free_count(sdata)) { - mpl_dbg(sdata, "Mesh plink error: no more free plinks\n"); - goto unlock_rcu; - } - /* deny open request from non-matching peer */ - if (!matches_local) { - mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, - mgmt->sa, 0, plid, - cpu_to_le16(WLAN_REASON_MESH_CONFIG)); - goto unlock_rcu; - } - } else { - if (!test_sta_flag(sta, WLAN_STA_AUTH)) { - mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n"); - goto unlock_rcu; - } - if (sta->plink_state == NL80211_PLINK_BLOCKED) - goto unlock_rcu; - } - /* Now we will figure out the appropriate event... */ - event = PLINK_UNDEFINED; - - if (!sta) - event = OPN_ACPT; - else { - switch (ftype) { - case WLAN_SP_MESH_PEERING_OPEN: - if (!matches_local) - event = OPN_RJCT; - else if (!mesh_plink_free_count(sdata) || - (sta->plid && sta->plid != plid)) - event = OPN_IGNR; - else - event = OPN_ACPT; - break; - case WLAN_SP_MESH_PEERING_CONFIRM: - if (!matches_local) - event = CNF_RJCT; - else if (!mesh_plink_free_count(sdata) || - (sta->llid != llid || sta->plid != plid)) - event = CNF_IGNR; - else - event = CNF_ACPT; - break; - case WLAN_SP_MESH_PEERING_CLOSE: - if (sta->plink_state == NL80211_PLINK_ESTAB) - /* Do not check for llid or plid. This does not - * follow the standard but since multiple plinks - * per sta are not supported, it is necessary in - * order to avoid a livelock when MP A sees an - * establish peer link to MP B but MP B does not - * see it. This can be caused by a timeout in - * B's peer link establishment or B beign - * restarted. - */ - event = CLS_ACPT; - else if (sta->plid != plid) - event = CLS_IGNR; - else if (ie_len == 8 && sta->llid != llid) - event = CLS_IGNR; - else - event = CLS_ACPT; - break; - default: - mpl_dbg(sdata, "Mesh plink: unknown frame subtype\n"); - goto unlock_rcu; - } - } + event = mesh_plink_get_event(sdata, sta, elems, ftype, llid, plid); if (event == OPN_ACPT) { rcu_read_unlock(); @@ -996,6 +1023,14 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, goto unlock_rcu; } sta->plid = plid; + } else if (!sta && event == OPN_RJCT) { + mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, + mgmt->sa, 0, plid, + cpu_to_le16(WLAN_REASON_MESH_CONFIG)); + goto unlock_rcu; + } else if (!sta || event == PLINK_UNDEFINED) { + /* something went wrong */ + goto unlock_rcu; } changed |= mesh_plink_fsm(sdata, sta, event); -- cgit v1.2.3-70-g09d2 From 204d130426206071b08c0aa74002fbdb67960eed Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Tue, 5 Nov 2013 11:17:05 -0800 Subject: mac80211: clean up mesh local link ID generation 802.11-2012 13.3.1 implicitly limits the mesh local link ID range to that of AID, since for mesh PS the local link ID must be indicated in the TIM IE, which only holds IEEE80211_MAX_AID bits. Also the code was allowing a local link ID of 0, but this is not correct since that TIM bit is used for indicating buffered mcast frames. Generate a random, unique, link ID from 1 - 2007, and drop a modulo conversion for the local link ID, but keep it for the peer link ID in case he chose something > MAX_AID. Signed-off-by: Thomas Pedersen Signed-off-by: Johannes Berg --- net/mac80211/mesh_plink.c | 40 +++++++++++++++++++++++++++++++++++----- net/mac80211/mesh_ps.c | 3 +-- net/mac80211/sta_info.c | 4 ++-- 3 files changed, 38 insertions(+), 9 deletions(-) diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index ee2a97f3173..fadc3e18913 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -615,9 +615,40 @@ static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout) add_timer(&sta->plink_timer); } +static bool llid_in_use(struct ieee80211_sub_if_data *sdata, + __le16 llid) +{ + struct ieee80211_local *local = sdata->local; + bool in_use = false; + struct sta_info *sta; + + rcu_read_lock(); + list_for_each_entry_rcu(sta, &local->sta_list, list) { + if (!memcmp(&sta->llid, &llid, sizeof(llid))) { + in_use = true; + break; + } + } + rcu_read_unlock(); + + return in_use; +} + +static __le16 mesh_get_new_llid(struct ieee80211_sub_if_data *sdata) +{ + u16 llid; + + do { + get_random_bytes(&llid, sizeof(llid)); + /* for mesh PS we still only have the AID range for TIM bits */ + llid = (llid % IEEE80211_MAX_AID) + 1; + } while (llid_in_use(sdata, cpu_to_le16(llid))); + + return cpu_to_le16(llid); +} + u32 mesh_plink_open(struct sta_info *sta) { - __le16 llid; struct ieee80211_sub_if_data *sdata = sta->sdata; u32 changed; @@ -625,8 +656,7 @@ u32 mesh_plink_open(struct sta_info *sta) return 0; spin_lock_bh(&sta->lock); - get_random_bytes(&llid, 2); - sta->llid = llid; + sta->llid = mesh_get_new_llid(sdata); if (sta->plink_state != NL80211_PLINK_LISTEN && sta->plink_state != NL80211_PLINK_BLOCKED) { spin_unlock_bh(&sta->lock); @@ -643,7 +673,7 @@ u32 mesh_plink_open(struct sta_info *sta) changed = ieee80211_mps_local_status_update(sdata); mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN, - sta->sta.addr, llid, 0, 0); + sta->sta.addr, sta->llid, 0, 0); return changed; } @@ -719,7 +749,7 @@ static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata, break; case OPN_ACPT: sta->plink_state = NL80211_PLINK_OPN_RCVD; - get_random_bytes(&sta->llid, 2); + sta->llid = mesh_get_new_llid(sdata); mesh_plink_timer_set(sta, mshcfg->dot11MeshRetryTimeout); diff --git a/net/mac80211/mesh_ps.c b/net/mac80211/mesh_ps.c index 0f79b78b5e8..9493868ef6c 100644 --- a/net/mac80211/mesh_ps.c +++ b/net/mac80211/mesh_ps.c @@ -576,10 +576,9 @@ void ieee80211_mps_frame_release(struct sta_info *sta, int ac, buffer_local = 0; bool has_buffered = false; - /* TIM map only for LLID <= IEEE80211_MAX_AID */ if (sta->plink_state == NL80211_PLINK_ESTAB) has_buffered = ieee80211_check_tim(elems->tim, elems->tim_len, - le16_to_cpu(sta->llid) % IEEE80211_MAX_AID); + le16_to_cpu(sta->llid)); if (has_buffered) mps_dbg(sta->sdata, "%pM indicates buffered frames\n", diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 1eb66e26e49..7a9151590cc 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -630,8 +630,8 @@ void sta_info_recalc_tim(struct sta_info *sta) #ifdef CONFIG_MAC80211_MESH } else if (ieee80211_vif_is_mesh(&sta->sdata->vif)) { ps = &sta->sdata->u.mesh.ps; - /* TIM map only for PLID <= IEEE80211_MAX_AID */ - id = le16_to_cpu(sta->plid) % IEEE80211_MAX_AID; + /* TIM map only for 1 <= PLID <= IEEE80211_MAX_AID */ + id = le16_to_cpu(sta->plid) % (IEEE80211_MAX_AID + 1); #endif } else { return; -- cgit v1.2.3-70-g09d2 From b3f51e941bdd559775c80c137c355ce71efb49d7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 25 Oct 2013 11:31:42 +0200 Subject: mac80211: remove useless tests for array Coverity points out that checking assoc_data->ie is completely useless since it's an array in the struct and can't be NULL - remove the useless checks. Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index d7504ab61a3..eb660310ea7 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -714,7 +714,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) } /* if present, add any custom IEs that go before HT */ - if (assoc_data->ie_len && assoc_data->ie) { + if (assoc_data->ie_len) { static const u8 before_ht[] = { WLAN_EID_SSID, WLAN_EID_SUPP_RATES, @@ -748,7 +748,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) &assoc_data->ap_vht_cap); /* if present, add any custom non-vendor IEs that go after HT */ - if (assoc_data->ie_len && assoc_data->ie) { + if (assoc_data->ie_len) { noffset = ieee80211_ie_split_vendor(assoc_data->ie, assoc_data->ie_len, offset); @@ -779,7 +779,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) } /* add any remaining custom (i.e. vendor specific here) IEs */ - if (assoc_data->ie_len && assoc_data->ie) { + if (assoc_data->ie_len) { noffset = assoc_data->ie_len; pos = skb_put(skb, noffset - offset); memcpy(pos, assoc_data->ie + offset, noffset - offset); -- cgit v1.2.3-70-g09d2 From 0f0094b3c7b8fef51f1ea6a0abc08b99d1444506 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 25 Oct 2013 12:46:44 +0200 Subject: cfg80211: add missing break in cfg80211_get_chan_state() Improve readability of the function by adding the break, there's no functional impact but it's confusing to fall through. Signed-off-by: Johannes Berg --- net/wireless/chan.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 96c97800e24..3b6daf8b47d 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -599,6 +599,7 @@ cfg80211_get_chan_state(struct wireless_dev *wdev, : CHAN_MODE_EXCLUSIVE; return; } + break; case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: if (wdev->current_bss) { -- cgit v1.2.3-70-g09d2 From 00c3a6ed649c3305b52ff51e187717365aa39d4a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 26 Oct 2013 17:14:38 +0200 Subject: cfg80211: don't allow drivers to unset NL80211_FEATURE_SCAN_FLUSH As the flag is entirely implemented in cfg80211, it should have been a global feature flag (which I believe didn't exist at the time). However, there's no reason to allow drivers to unset the flag, so don't allow it and remove the validation of NL80211_SCAN_FLAG_FLUSH. Signed-off-by: Johannes Berg --- net/wireless/core.c | 4 ++-- net/wireless/nl80211.c | 12 ++++-------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/net/wireless/core.c b/net/wireless/core.c index aff959e5a1b..9dca0925a1a 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -357,8 +357,6 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) rdev->wiphy.rts_threshold = (u32) -1; rdev->wiphy.coverage_class = 0; - rdev->wiphy.features = NL80211_FEATURE_SCAN_FLUSH; - return &rdev->wiphy; } EXPORT_SYMBOL(wiphy_new); @@ -566,6 +564,8 @@ int wiphy_register(struct wiphy *wiphy) /* check and set up bitrates */ ieee80211_set_bitrate_flags(wiphy); + rdev->wiphy.features |= NL80211_FEATURE_SCAN_FLUSH; + rtnl_lock(); res = device_add(&rdev->wiphy.dev); if (res) { diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index e2bb4276af1..1ad11de6dd2 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -5342,10 +5342,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) { request->flags = nla_get_u32( info->attrs[NL80211_ATTR_SCAN_FLAGS]); - if (((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && - !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) || - ((request->flags & NL80211_SCAN_FLAG_FLUSH) && - !(wiphy->features & NL80211_FEATURE_SCAN_FLUSH))) { + if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && + !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) { err = -EOPNOTSUPP; goto out_free; } @@ -5585,10 +5583,8 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) { request->flags = nla_get_u32( info->attrs[NL80211_ATTR_SCAN_FLAGS]); - if (((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && - !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) || - ((request->flags & NL80211_SCAN_FLAG_FLUSH) && - !(wiphy->features & NL80211_FEATURE_SCAN_FLUSH))) { + if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && + !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) { err = -EOPNOTSUPP; goto out_free; } -- cgit v1.2.3-70-g09d2 From 5282c3ba4c5a24b2ab45a6742f9ab01a3d90c167 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 29 Oct 2013 10:00:08 +0100 Subject: mac80211: verify ieee80211_key_replace() arguments There's no code calling ieee80211_key_replace() with both arguments NULL and it wouldn't make sense, but in the interest of maintainability add a warning for it. As a side effect, this also shuts up a smatch warning. Signed-off-by: Johannes Berg --- net/mac80211/key.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 3e51dd7d98b..ab846804720 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -260,6 +260,10 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, int idx; bool defunikey, defmultikey, defmgmtkey; + /* caller must provide at least one old/new */ + if (WARN_ON(!new && !old)) + return; + if (new) list_add_tail(&new->list, &sdata->key_list); -- cgit v1.2.3-70-g09d2 From d2859df5e7f00469011482d850fba652517a2eab Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Wed, 6 Nov 2013 13:55:51 +0100 Subject: cfg80211/mac80211: DFS setup chandef for cac event To report channel width correctly we have to send correct channel parameters from mac80211 when calling cfg80211_cac_event(). This is required in case of using channel width higher than 20MHz and we have to set correct dfs channel state after CAC (NL80211_DFS_AVAILABLE). Signed-off-by: Janusz Dziedzic Reviewed-by: Luis R. Rodriguez Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 2 ++ net/mac80211/cfg.c | 5 ++++- net/mac80211/iface.c | 5 ++++- net/mac80211/mlme.c | 6 ++++-- net/mac80211/util.c | 3 +++ net/wireless/mlme.c | 8 +++----- net/wireless/nl80211.c | 4 ++-- net/wireless/nl80211.h | 2 +- 8 files changed, 23 insertions(+), 12 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index b7a825ecff5..968f2ad40cc 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -4150,6 +4150,7 @@ void cfg80211_radar_event(struct wiphy *wiphy, /** * cfg80211_cac_event - Channel availability check (CAC) event * @netdev: network device + * @chandef: chandef for the current channel * @event: type of event * @gfp: context flags * @@ -4158,6 +4159,7 @@ void cfg80211_radar_event(struct wiphy *wiphy, * also by full-MAC drivers. */ void cfg80211_cac_event(struct net_device *netdev, + const struct cfg80211_chan_def *chandef, enum nl80211_radar_event event, gfp_t gfp); diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 95667b088c5..5232b010214 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1050,6 +1050,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) struct ieee80211_local *local = sdata->local; struct beacon_data *old_beacon; struct probe_resp *old_probe_resp; + struct cfg80211_chan_def chandef; old_beacon = rtnl_dereference(sdata->u.ap.beacon); if (!old_beacon) @@ -1091,8 +1092,10 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); if (sdata->wdev.cac_started) { + chandef = sdata->vif.bss_conf.chandef; cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); - cfg80211_cac_event(sdata->dev, NL80211_RADAR_CAC_ABORTED, + cfg80211_cac_event(sdata->dev, &chandef, + NL80211_RADAR_CAC_ABORTED, GFP_KERNEL); } diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index ff101ea1d9a..c9b04425ffc 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -749,6 +749,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, u32 hw_reconf_flags = 0; int i, flushed; struct ps_data *ps; + struct cfg80211_chan_def chandef; clear_bit(SDATA_STATE_RUNNING, &sdata->state); @@ -823,11 +824,13 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); if (sdata->wdev.cac_started) { + chandef = sdata->vif.bss_conf.chandef; WARN_ON(local->suspended); mutex_lock(&local->iflist_mtx); ieee80211_vif_release_channel(sdata); mutex_unlock(&local->iflist_mtx); - cfg80211_cac_event(sdata->dev, NL80211_RADAR_CAC_ABORTED, + cfg80211_cac_event(sdata->dev, &chandef, + NL80211_RADAR_CAC_ABORTED, GFP_KERNEL); } diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index eb660310ea7..d39d27feb59 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1398,10 +1398,12 @@ void ieee80211_dfs_cac_timer_work(struct work_struct *work) struct ieee80211_sub_if_data *sdata = container_of(delayed_work, struct ieee80211_sub_if_data, dfs_cac_timer_work); + struct cfg80211_chan_def chandef = sdata->vif.bss_conf.chandef; ieee80211_vif_release_channel(sdata); - - cfg80211_cac_event(sdata->dev, NL80211_RADAR_CAC_FINISHED, GFP_KERNEL); + cfg80211_cac_event(sdata->dev, &chandef, + NL80211_RADAR_CAC_FINISHED, + GFP_KERNEL); } /* MLME */ diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 592a18171f9..fd4fe5d6178 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2259,14 +2259,17 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local, void ieee80211_dfs_cac_cancel(struct ieee80211_local *local) { struct ieee80211_sub_if_data *sdata; + struct cfg80211_chan_def chandef; mutex_lock(&local->iflist_mtx); list_for_each_entry(sdata, &local->interfaces, list) { cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); if (sdata->wdev.cac_started) { + chandef = sdata->vif.bss_conf.chandef; ieee80211_vif_release_channel(sdata); cfg80211_cac_event(sdata->dev, + &chandef, NL80211_RADAR_CAC_ABORTED, GFP_KERNEL); } diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 6a6b1c8e907..31f541f7e4e 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -763,12 +763,12 @@ void cfg80211_radar_event(struct wiphy *wiphy, EXPORT_SYMBOL(cfg80211_radar_event); void cfg80211_cac_event(struct net_device *netdev, + const struct cfg80211_chan_def *chandef, enum nl80211_radar_event event, gfp_t gfp) { struct wireless_dev *wdev = netdev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - struct cfg80211_chan_def chandef; unsigned long timeout; trace_cfg80211_cac_event(netdev, event); @@ -779,14 +779,12 @@ void cfg80211_cac_event(struct net_device *netdev, if (WARN_ON(!wdev->channel)) return; - cfg80211_chandef_create(&chandef, wdev->channel, NL80211_CHAN_NO_HT); - switch (event) { case NL80211_RADAR_CAC_FINISHED: timeout = wdev->cac_start_time + msecs_to_jiffies(IEEE80211_DFS_MIN_CAC_TIME_MS); WARN_ON(!time_after_eq(jiffies, timeout)); - cfg80211_set_dfs_state(wiphy, &chandef, NL80211_DFS_AVAILABLE); + cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_AVAILABLE); break; case NL80211_RADAR_CAC_ABORTED: break; @@ -796,6 +794,6 @@ void cfg80211_cac_event(struct net_device *netdev, } wdev->cac_started = false; - nl80211_radar_notify(rdev, &chandef, event, netdev, gfp); + nl80211_radar_notify(rdev, chandef, event, netdev, gfp); } EXPORT_SYMBOL(cfg80211_cac_event); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 1ad11de6dd2..04fa8bb1b4b 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2168,7 +2168,7 @@ static inline u64 wdev_id(struct wireless_dev *wdev) } static int nl80211_send_chandef(struct sk_buff *msg, - struct cfg80211_chan_def *chandef) + const struct cfg80211_chan_def *chandef) { WARN_ON(!cfg80211_chandef_valid(chandef)); @@ -10874,7 +10874,7 @@ EXPORT_SYMBOL(cfg80211_cqm_txe_notify); void nl80211_radar_notify(struct cfg80211_registered_device *rdev, - struct cfg80211_chan_def *chandef, + const struct cfg80211_chan_def *chandef, enum nl80211_radar_event event, struct net_device *netdev, gfp_t gfp) { diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 2c0f2b3c07c..b1b231324e1 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -70,7 +70,7 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, void nl80211_radar_notify(struct cfg80211_registered_device *rdev, - struct cfg80211_chan_def *chandef, + const struct cfg80211_chan_def *chandef, enum nl80211_radar_event event, struct net_device *netdev, gfp_t gfp); -- cgit v1.2.3-70-g09d2 From 6bc54fbcee6836f08355fcca76549c22ad2c2940 Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Wed, 6 Nov 2013 13:55:53 +0100 Subject: cfg80211: allow beaconing after DFS CAC Allow beconing after we pass Channel Availability Check (CAC). Allow non-DFS and DFS channels mix. All DFS channels have to be in NL80211_DFS_AVAILABLE state (pass CAC). Signed-off-by: Janusz Dziedzic Signed-off-by: Johannes Berg --- net/wireless/chan.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 74 insertions(+), 11 deletions(-) diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 3b6daf8b47d..78559b5bbd1 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -425,9 +425,9 @@ bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy, } -static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, - u32 center_freq, u32 bandwidth, - u32 prohibited_flags) +static bool cfg80211_get_chans_dfs_available(struct wiphy *wiphy, + u32 center_freq, + u32 bandwidth) { struct ieee80211_channel *c; u32 freq, start_freq, end_freq; @@ -435,18 +435,75 @@ static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, start_freq = cfg80211_get_start_freq(center_freq, bandwidth); end_freq = cfg80211_get_end_freq(center_freq, bandwidth); + /* + * Check entire range of channels for the bandwidth. + * If any channel in between is disabled or has not + * had gone through CAC return false + */ for (freq = start_freq; freq <= end_freq; freq += 20) { c = ieee80211_get_channel(wiphy, freq); if (!c) return false; - /* check for radar flags */ - if ((prohibited_flags & c->flags & IEEE80211_CHAN_RADAR) && + if (c->flags & IEEE80211_CHAN_DISABLED) + return false; + + if ((c->flags & IEEE80211_CHAN_RADAR) && (c->dfs_state != NL80211_DFS_AVAILABLE)) return false; + } + + return true; +} + +static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy, + const struct cfg80211_chan_def *chandef) +{ + int width; + int r; + + if (WARN_ON(!cfg80211_chandef_valid(chandef))) + return false; + + width = cfg80211_chandef_get_width(chandef); + if (width < 0) + return false; + + r = cfg80211_get_chans_dfs_available(wiphy, chandef->center_freq1, + width); + + /* If any of channels unavailable for cf1 just return */ + if (!r) + return r; + + switch (chandef->width) { + case NL80211_CHAN_WIDTH_80P80: + WARN_ON(!chandef->center_freq2); + r = cfg80211_get_chans_dfs_available(wiphy, + chandef->center_freq2, + width); + default: + WARN_ON(chandef->center_freq2); + break; + } + + return r; +} + + +static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, + u32 center_freq, u32 bandwidth, + u32 prohibited_flags) +{ + struct ieee80211_channel *c; + u32 freq, start_freq, end_freq; - /* check for the other flags */ - if (c->flags & prohibited_flags & ~IEEE80211_CHAN_RADAR) + start_freq = cfg80211_get_start_freq(center_freq, bandwidth); + end_freq = cfg80211_get_end_freq(center_freq, bandwidth); + + for (freq = start_freq; freq <= end_freq; freq += 20) { + c = ieee80211_get_channel(wiphy, freq); + if (!c || c->flags & prohibited_flags) return false; } @@ -552,13 +609,19 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy, struct cfg80211_chan_def *chandef) { bool res; + u32 prohibited_flags = IEEE80211_CHAN_DISABLED | + IEEE80211_CHAN_NO_IR | + IEEE80211_CHAN_RADAR; trace_cfg80211_reg_can_beacon(wiphy, chandef); - res = cfg80211_chandef_usable(wiphy, chandef, - IEEE80211_CHAN_DISABLED | - IEEE80211_CHAN_NO_IR | - IEEE80211_CHAN_RADAR); + if (cfg80211_chandef_dfs_required(wiphy, chandef) > 0 && + cfg80211_chandef_dfs_available(wiphy, chandef)) { + /* We can skip IEEE80211_CHAN_NO_IR if chandef dfs available */ + prohibited_flags = IEEE80211_CHAN_DISABLED; + } + + res = cfg80211_chandef_usable(wiphy, chandef, prohibited_flags); trace_cfg80211_return_bool(res); return res; -- cgit v1.2.3-70-g09d2 From 2475b1cc0d5283a33144b79f3eba6d401d873962 Mon Sep 17 00:00:00 2001 From: Max Stepanov Date: Sun, 24 Mar 2013 14:23:27 +0200 Subject: mac80211: add generic cipher scheme support This adds generic cipher scheme support to mac80211, such schemes are fully under control by the driver. On hw registration drivers may specify additional HW ciphers with a scheme how these ciphers have to be handled by mac80211 TX/RR. A cipher scheme specifies a cipher suite value, a size of the security header to be added to or stripped from frames and how the PN is to be verified on RX. Signed-off-by: Max Stepanov Signed-off-by: Johannes Berg --- include/net/mac80211.h | 36 +++++++++++ net/mac80211/cfg.c | 31 ++++++++-- net/mac80211/ieee80211_i.h | 10 ++++ net/mac80211/iface.c | 5 ++ net/mac80211/key.c | 58 +++++++++++------- net/mac80211/key.h | 13 +++- net/mac80211/main.c | 145 +++++++++++++++++++++++++++++++-------------- net/mac80211/mesh_hwmp.c | 4 +- net/mac80211/mlme.c | 4 ++ net/mac80211/rx.c | 65 +++++++++++++++----- net/mac80211/sta_info.h | 10 +++- net/mac80211/tx.c | 14 +++-- net/mac80211/util.c | 68 +++++++++++++++++++++ net/mac80211/wpa.c | 116 ++++++++++++++++++++++++++++++++++++ net/mac80211/wpa.h | 2 + 15 files changed, 480 insertions(+), 101 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 7ceed99a05b..cca02b2f5c7 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1228,6 +1228,36 @@ struct ieee80211_key_conf { u8 key[0]; }; +/** + * struct ieee80211_cipher_scheme - cipher scheme + * + * This structure contains a cipher scheme information defining + * the secure packet crypto handling. + * + * @cipher: a cipher suite selector + * @iftype: a cipher iftype bit mask indicating an allowed cipher usage + * @hdr_len: a length of a security header used the cipher + * @pn_len: a length of a packet number in the security header + * @pn_off: an offset of pn from the beginning of the security header + * @key_idx_off: an offset of key index byte in the security header + * @key_idx_mask: a bit mask of key_idx bits + * @key_idx_shift: a bit shift needed to get key_idx + * key_idx value calculation: + * (sec_header_base[key_idx_off] & key_idx_mask) >> key_idx_shift + * @mic_len: a mic length in bytes + */ +struct ieee80211_cipher_scheme { + u32 cipher; + u16 iftype; + u8 hdr_len; + u8 pn_len; + u8 pn_off; + u8 key_idx_off; + u8 key_idx_mask; + u8 key_idx_shift; + u8 mic_len; +}; + /** * enum set_key_cmd - key command * @@ -1636,6 +1666,10 @@ enum ieee80211_hw_flags { * @uapsd_max_sp_len: maximum number of total buffered frames the WMM AP may * deliver to a WMM STA during any Service Period triggered by the WMM STA. * Use IEEE80211_WMM_IE_STA_QOSINFO_SP_* for correct values. + * + * @n_cipher_schemes: a size of an array of cipher schemes definitions. + * @cipher_schemes: a pointer to an array of cipher scheme definitions + * supported by HW. */ struct ieee80211_hw { struct ieee80211_conf conf; @@ -1663,6 +1697,8 @@ struct ieee80211_hw { netdev_features_t netdev_features; u8 uapsd_queues; u8 uapsd_max_sp_len; + u8 n_cipher_schemes; + const struct ieee80211_cipher_scheme *cipher_schemes; }; /** diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 5232b010214..f6b9265cf04 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -133,7 +133,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, struct key_params *params) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; struct sta_info *sta = NULL; + const struct ieee80211_cipher_scheme *cs = NULL; struct ieee80211_key *key; int err; @@ -145,22 +147,28 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_TKIP: case WLAN_CIPHER_SUITE_WEP104: - if (IS_ERR(sdata->local->wep_tx_tfm)) + if (IS_ERR(local->wep_tx_tfm)) return -EINVAL; break; + case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_AES_CMAC: + case WLAN_CIPHER_SUITE_GCMP: + break; default: + cs = ieee80211_cs_get(local, params->cipher, sdata->vif.type); break; } key = ieee80211_key_alloc(params->cipher, key_idx, params->key_len, - params->key, params->seq_len, params->seq); + params->key, params->seq_len, params->seq, + cs); if (IS_ERR(key)) return PTR_ERR(key); if (pairwise) key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE; - mutex_lock(&sdata->local->sta_mtx); + mutex_lock(&local->sta_mtx); if (mac_addr) { if (ieee80211_vif_is_mesh(&sdata->vif)) @@ -216,10 +224,13 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, break; } + if (sta) + sta->cipher_scheme = cs; + err = ieee80211_key_link(key, sdata, sta); out_unlock: - mutex_unlock(&sdata->local->sta_mtx); + mutex_unlock(&local->sta_mtx); return err; } @@ -244,7 +255,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, goto out_unlock; if (pairwise) - key = key_mtx_dereference(local, sta->ptk); + key = key_mtx_dereference(local, sta->ptk[key_idx]); else key = key_mtx_dereference(local, sta->gtk[key_idx]); } else @@ -291,7 +302,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, goto out; if (pairwise) - key = rcu_dereference(sta->ptk); + key = rcu_dereference(sta->ptk[key_idx]); else if (key_idx < NUM_DEFAULT_KEYS) key = rcu_dereference(sta->gtk[key_idx]); } else @@ -968,11 +979,19 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, */ sdata->control_port_protocol = params->crypto.control_port_ethertype; sdata->control_port_no_encrypt = params->crypto.control_port_no_encrypt; + sdata->encrypt_headroom = ieee80211_cs_headroom(sdata->local, + ¶ms->crypto, + sdata->vif.type); + list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) { vlan->control_port_protocol = params->crypto.control_port_ethertype; vlan->control_port_no_encrypt = params->crypto.control_port_no_encrypt; + vlan->encrypt_headroom = + ieee80211_cs_headroom(sdata->local, + ¶ms->crypto, + vlan->vif.type); } sdata->vif.bss_conf.beacon_int = params->beacon_interval; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 29dc505be12..16f5ba4a325 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -728,6 +728,7 @@ struct ieee80211_sub_if_data { u16 sequence_number; __be16 control_port_protocol; bool control_port_no_encrypt; + int encrypt_headroom; struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS]; @@ -1749,6 +1750,15 @@ void ieee80211_dfs_radar_detected_work(struct work_struct *work); int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata, struct cfg80211_csa_settings *csa_settings); +bool ieee80211_cs_valid(const struct ieee80211_cipher_scheme *cs); +bool ieee80211_cs_list_valid(const struct ieee80211_cipher_scheme *cs, int n); +const struct ieee80211_cipher_scheme * +ieee80211_cs_get(struct ieee80211_local *local, u32 cipher, + enum nl80211_iftype iftype); +int ieee80211_cs_headroom(struct ieee80211_local *local, + struct cfg80211_crypto_settings *crypto, + enum nl80211_iftype iftype); + #ifdef CONFIG_MAC80211_NOINLINE #define debug_noinline noinline #else diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index c9b04425ffc..a851bf4f05e 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -401,6 +401,8 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) snprintf(sdata->name, IFNAMSIZ, "%s-monitor", wiphy_name(local->hw.wiphy)); + sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; + ieee80211_set_default_queues(sdata); ret = drv_add_interface(local, sdata); @@ -1273,6 +1275,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, sdata->control_port_protocol = cpu_to_be16(ETH_P_PAE); sdata->control_port_no_encrypt = false; + sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; sdata->noack_map = 0; @@ -1689,6 +1692,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; sdata->user_power_level = local->user_power_level; + sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; + /* setup type-dependent data */ ieee80211_setup_sdata(sdata, type); diff --git a/net/mac80211/key.c b/net/mac80211/key.c index ab846804720..e568d98167d 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -267,22 +267,22 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, if (new) list_add_tail(&new->list, &sdata->key_list); - if (sta && pairwise) { - rcu_assign_pointer(sta->ptk, new); - } else if (sta) { - if (old) - idx = old->conf.keyidx; - else - idx = new->conf.keyidx; - rcu_assign_pointer(sta->gtk[idx], new); - } else { - WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx); + WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx); - if (old) - idx = old->conf.keyidx; - else - idx = new->conf.keyidx; + if (old) + idx = old->conf.keyidx; + else + idx = new->conf.keyidx; + if (sta) { + if (pairwise) { + rcu_assign_pointer(sta->ptk[idx], new); + sta->ptk_idx = idx; + } else { + rcu_assign_pointer(sta->gtk[idx], new); + sta->gtk_idx = idx; + } + } else { defunikey = old && old == key_mtx_dereference(sdata->local, sdata->default_unicast_key); @@ -316,9 +316,11 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, list_del(&old->list); } -struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, - const u8 *key_data, - size_t seq_len, const u8 *seq) +struct ieee80211_key * +ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, + const u8 *key_data, + size_t seq_len, const u8 *seq, + const struct ieee80211_cipher_scheme *cs) { struct ieee80211_key *key; int i, j, err; @@ -397,6 +399,18 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, return ERR_PTR(err); } break; + default: + if (cs) { + size_t len = (seq_len > MAX_PN_LEN) ? + MAX_PN_LEN : seq_len; + + key->conf.iv_len = cs->hdr_len; + key->conf.icv_len = cs->mic_len; + for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) + for (j = 0; j < len; j++) + key->u.gen.rx_pn[i][j] = + seq[len - j - 1]; + } } memcpy(key->conf.key, key_data, key_len); INIT_LIST_HEAD(&key->list); @@ -479,7 +493,7 @@ int ieee80211_key_link(struct ieee80211_key *key, mutex_lock(&sdata->local->key_mtx); if (sta && pairwise) - old_key = key_mtx_dereference(sdata->local, sta->ptk); + old_key = key_mtx_dereference(sdata->local, sta->ptk[idx]); else if (sta) old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]); else @@ -629,8 +643,10 @@ void ieee80211_free_sta_keys(struct ieee80211_local *local, list_add(&key->list, &keys); } - key = key_mtx_dereference(local, sta->ptk); - if (key) { + for (i = 0; i < NUM_DEFAULT_KEYS; i++) { + key = key_mtx_dereference(local, sta->ptk[i]); + if (!key) + continue; ieee80211_key_replace(key->sdata, key->sta, key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, key, NULL); @@ -881,7 +897,7 @@ ieee80211_gtk_rekey_add(struct ieee80211_vif *vif, key = ieee80211_key_alloc(keyconf->cipher, keyconf->keyidx, keyconf->keylen, keyconf->key, - 0, NULL); + 0, NULL, NULL); if (IS_ERR(key)) return ERR_CAST(key); diff --git a/net/mac80211/key.h b/net/mac80211/key.h index aaae0ed3700..0aebb889cab 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h @@ -18,6 +18,7 @@ #define NUM_DEFAULT_KEYS 4 #define NUM_DEFAULT_MGMT_KEYS 2 +#define MAX_PN_LEN 16 struct ieee80211_local; struct ieee80211_sub_if_data; @@ -93,6 +94,10 @@ struct ieee80211_key { u32 replays; /* dot11RSNAStatsCMACReplays */ u32 icverrors; /* dot11RSNAStatsCMACICVErrors */ } aes_cmac; + struct { + /* generic cipher scheme */ + u8 rx_pn[IEEE80211_NUM_TIDS + 1][MAX_PN_LEN]; + } gen; } u; /* number of times this key has been used */ @@ -113,9 +118,11 @@ struct ieee80211_key { struct ieee80211_key_conf conf; }; -struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, - const u8 *key_data, - size_t seq_len, const u8 *seq); +struct ieee80211_key * +ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, + const u8 *key_data, + size_t seq_len, const u8 *seq, + const struct ieee80211_cipher_scheme *cs); /* * Insert a key into data structures (sdata, sta if necessary) * to make it used, free old key. On failure, also free the new key. diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 21d5d44444d..bdb0b6c104b 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -651,15 +651,14 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, } EXPORT_SYMBOL(ieee80211_alloc_hw); -int ieee80211_register_hw(struct ieee80211_hw *hw) +static int ieee80211_init_cipher_suites(struct ieee80211_local *local) { - struct ieee80211_local *local = hw_to_local(hw); - int result, i; - enum ieee80211_band band; - int channels, max_bitrates; - bool supp_ht, supp_vht; - netdev_features_t feature_whitelist; - struct cfg80211_chan_def dflt_chandef = {}; + bool have_wep = !(IS_ERR(local->wep_tx_tfm) || + IS_ERR(local->wep_rx_tfm)); + bool have_mfp = local->hw.flags & IEEE80211_HW_MFP_CAPABLE; + const struct ieee80211_cipher_scheme *cs = local->hw.cipher_schemes; + int n_suites = 0, r = 0, w = 0; + u32 *suites; static const u32 cipher_suites[] = { /* keep WEP first, it may be removed below */ WLAN_CIPHER_SUITE_WEP40, @@ -671,6 +670,93 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) WLAN_CIPHER_SUITE_AES_CMAC }; + /* Driver specifies the ciphers, we have nothing to do... */ + if (local->hw.wiphy->cipher_suites && have_wep) + return 0; + + /* Set up cipher suites if driver relies on mac80211 cipher defs */ + if (!local->hw.wiphy->cipher_suites && !cs) { + local->hw.wiphy->cipher_suites = cipher_suites; + local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); + + if (!have_mfp) + local->hw.wiphy->n_cipher_suites--; + + if (!have_wep) { + local->hw.wiphy->cipher_suites += 2; + local->hw.wiphy->n_cipher_suites -= 2; + } + + return 0; + } + + if (!local->hw.wiphy->cipher_suites) { + /* + * Driver specifies cipher schemes only + * We start counting ciphers defined by schemes, TKIP and CCMP + */ + n_suites = local->hw.n_cipher_schemes + 2; + + /* check if we have WEP40 and WEP104 */ + if (have_wep) + n_suites += 2; + + /* check if we have AES_CMAC */ + if (have_mfp) + n_suites++; + + suites = kmalloc(sizeof(u32) * n_suites, GFP_KERNEL); + if (!suites) + return -ENOMEM; + + suites[w++] = WLAN_CIPHER_SUITE_CCMP; + suites[w++] = WLAN_CIPHER_SUITE_TKIP; + + if (have_wep) { + suites[w++] = WLAN_CIPHER_SUITE_WEP40; + suites[w++] = WLAN_CIPHER_SUITE_WEP104; + } + + if (have_mfp) + suites[w++] = WLAN_CIPHER_SUITE_AES_CMAC; + + for (r = 0; r < local->hw.n_cipher_schemes; r++) + suites[w++] = cs[r].cipher; + } else { + /* Driver provides cipher suites, but we need to exclude WEP */ + suites = kmemdup(local->hw.wiphy->cipher_suites, + sizeof(u32) * local->hw.wiphy->n_cipher_suites, + GFP_KERNEL); + if (!suites) + return -ENOMEM; + + for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) { + u32 suite = local->hw.wiphy->cipher_suites[r]; + + if (suite == WLAN_CIPHER_SUITE_WEP40 || + suite == WLAN_CIPHER_SUITE_WEP104) + continue; + suites[w++] = suite; + } + } + + local->hw.wiphy->cipher_suites = suites; + local->hw.wiphy->n_cipher_suites = w; + local->wiphy_ciphers_allocated = true; + + return 0; +} + +int ieee80211_register_hw(struct ieee80211_hw *hw) +{ + struct ieee80211_local *local = hw_to_local(hw); + int result, i; + enum ieee80211_band band; + int channels, max_bitrates; + bool supp_ht, supp_vht; + netdev_features_t feature_whitelist; + struct cfg80211_chan_def dflt_chandef = {}; + if (hw->flags & IEEE80211_HW_QUEUE_CONTROL && (local->hw.offchannel_tx_hw_queue == IEEE80211_INVAL_HW_QUEUE || local->hw.offchannel_tx_hw_queue >= local->hw.queues)) @@ -851,43 +937,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (local->hw.wiphy->max_scan_ie_len) local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len; - /* Set up cipher suites unless driver already did */ - if (!local->hw.wiphy->cipher_suites) { - local->hw.wiphy->cipher_suites = cipher_suites; - local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); - if (!(local->hw.flags & IEEE80211_HW_MFP_CAPABLE)) - local->hw.wiphy->n_cipher_suites--; - } - if (IS_ERR(local->wep_tx_tfm) || IS_ERR(local->wep_rx_tfm)) { - if (local->hw.wiphy->cipher_suites == cipher_suites) { - local->hw.wiphy->cipher_suites += 2; - local->hw.wiphy->n_cipher_suites -= 2; - } else { - u32 *suites; - int r, w = 0; - - /* Filter out WEP */ - - suites = kmemdup( - local->hw.wiphy->cipher_suites, - sizeof(u32) * local->hw.wiphy->n_cipher_suites, - GFP_KERNEL); - if (!suites) { - result = -ENOMEM; - goto fail_wiphy_register; - } - for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) { - u32 suite = local->hw.wiphy->cipher_suites[r]; - if (suite == WLAN_CIPHER_SUITE_WEP40 || - suite == WLAN_CIPHER_SUITE_WEP104) - continue; - suites[w++] = suite; - } - local->hw.wiphy->cipher_suites = suites; - local->hw.wiphy->n_cipher_suites = w; - local->wiphy_ciphers_allocated = true; - } - } + WARN_ON(!ieee80211_cs_list_valid(local->hw.cipher_schemes, + local->hw.n_cipher_schemes)); + + result = ieee80211_init_cipher_suites(local); + if (result < 0) + goto fail_wiphy_register; if (!local->ops->remain_on_channel) local->hw.wiphy->max_remain_on_channel_duration = 5000; diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 486819cd02c..56e0c072007 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -254,13 +254,13 @@ int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata, return -EAGAIN; skb = dev_alloc_skb(local->tx_headroom + - IEEE80211_ENCRYPT_HEADROOM + + sdata->encrypt_headroom + IEEE80211_ENCRYPT_TAILROOM + hdr_len + 2 + 15 /* PERR IE */); if (!skb) return -1; - skb_reserve(skb, local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM); + skb_reserve(skb, local->tx_headroom + sdata->encrypt_headroom); mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len); memset(mgmt, 0, hdr_len); mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index d39d27feb59..f8dca58b7e5 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1747,6 +1747,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, ifmgd->flags = 0; ieee80211_vif_release_channel(sdata); + + sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; } void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, @@ -4191,6 +4193,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, sdata->control_port_protocol = req->crypto.control_port_ethertype; sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt; + sdata->encrypt_headroom = ieee80211_cs_headroom(local, &req->crypto, + sdata->vif.type); /* kick off associate process */ diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 401f3c26e70..79f76791f77 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -638,6 +638,27 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb) return le16_to_cpu(mmie->key_id); } +static int iwl80211_get_cs_keyid(const struct ieee80211_cipher_scheme *cs, + struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + __le16 fc; + int hdrlen; + u8 keyid; + + fc = hdr->frame_control; + hdrlen = ieee80211_hdrlen(fc); + + if (skb->len < hdrlen + cs->hdr_len) + return -EINVAL; + + skb_copy_bits(skb, hdrlen + cs->key_idx_off, &keyid, 1); + keyid &= cs->key_idx_mask; + keyid >>= cs->key_idx_shift; + + return keyid; +} + static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; @@ -1360,6 +1381,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) struct ieee80211_key *sta_ptk = NULL; int mmie_keyidx = -1; __le16 fc; + const struct ieee80211_cipher_scheme *cs = NULL; /* * Key selection 101 @@ -1397,11 +1419,19 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) /* start without a key */ rx->key = NULL; + fc = hdr->frame_control; - if (rx->sta) - sta_ptk = rcu_dereference(rx->sta->ptk); + if (rx->sta) { + int keyid = rx->sta->ptk_idx; - fc = hdr->frame_control; + if (ieee80211_has_protected(fc) && rx->sta->cipher_scheme) { + cs = rx->sta->cipher_scheme; + keyid = iwl80211_get_cs_keyid(cs, rx->skb); + if (unlikely(keyid < 0)) + return RX_DROP_UNUSABLE; + } + sta_ptk = rcu_dereference(rx->sta->ptk[keyid]); + } if (!ieee80211_has_protected(fc)) mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb); @@ -1463,6 +1493,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) return RX_CONTINUE; } else { u8 keyid; + /* * The device doesn't give us the IV so we won't be * able to look up the key. That's ok though, we @@ -1478,15 +1509,21 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) hdrlen = ieee80211_hdrlen(fc); - if (rx->skb->len < 8 + hdrlen) - return RX_DROP_UNUSABLE; /* TODO: count this? */ + if (cs) { + keyidx = iwl80211_get_cs_keyid(cs, rx->skb); - /* - * no need to call ieee80211_wep_get_keyidx, - * it verifies a bunch of things we've done already - */ - skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1); - keyidx = keyid >> 6; + if (unlikely(keyidx < 0)) + return RX_DROP_UNUSABLE; + } else { + if (rx->skb->len < 8 + hdrlen) + return RX_DROP_UNUSABLE; /* TODO: count this? */ + /* + * no need to call ieee80211_wep_get_keyidx, + * it verifies a bunch of things we've done already + */ + skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1); + keyidx = keyid >> 6; + } /* check per-station GTK first, if multicast packet */ if (is_multicast_ether_addr(hdr->addr1) && rx->sta) @@ -1534,11 +1571,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) result = ieee80211_crypto_aes_cmac_decrypt(rx); break; default: - /* - * We can reach here only with HW-only algorithms - * but why didn't it decrypt the frame?! - */ - return RX_DROP_UNUSABLE; + result = ieee80211_crypto_hw_decrypt(rx); } /* the hdr variable is invalid after the decrypt handlers */ diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 3ef06a26b9c..6b0d6c2dcba 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -231,8 +231,10 @@ struct sta_ampdu_mlme { * @hnext: hash table linked list pointer * @local: pointer to the global information * @sdata: virtual interface this station belongs to - * @ptk: peer key negotiated with this station, if any + * @ptk: peer keys negotiated with this station, if any + * @ptk_idx: last installed peer key index * @gtk: group keys negotiated with this station, if any + * @gtk_idx: last installed group key index * @rate_ctrl: rate control algorithm reference * @rate_ctrl_priv: rate control private per-STA pointer * @last_tx_rate: rate used for last transmit, to report to userspace as @@ -303,6 +305,7 @@ struct sta_ampdu_mlme { * @chain_signal_avg: signal average (per chain) * @known_smps_mode: the smps_mode the client thinks we are in. Relevant for * AP only. + * @cipher_scheme: optional cipher scheme for this station */ struct sta_info { /* General information, mostly static */ @@ -312,7 +315,9 @@ struct sta_info { struct ieee80211_local *local; struct ieee80211_sub_if_data *sdata; struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; - struct ieee80211_key __rcu *ptk; + struct ieee80211_key __rcu *ptk[NUM_DEFAULT_KEYS]; + u8 gtk_idx; + u8 ptk_idx; struct rate_control_ref *rate_ctrl; void *rate_ctrl_priv; spinlock_t lock; @@ -414,6 +419,7 @@ struct sta_info { unsigned int beacon_loss_count; enum ieee80211_smps_mode known_smps_mode; + const struct ieee80211_cipher_scheme *cipher_scheme; /* keep last! */ struct ieee80211_sta sta; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 5ad2e8b1f92..e541856b400 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -557,7 +557,8 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) tx->key = NULL; - else if (tx->sta && (key = rcu_dereference(tx->sta->ptk))) + else if (tx->sta && + (key = rcu_dereference(tx->sta->ptk[tx->sta->ptk_idx]))) tx->key = key; else if (ieee80211_is_mgmt(hdr->frame_control) && is_multicast_ether_addr(hdr->addr1) && @@ -840,15 +841,16 @@ static int ieee80211_fragment(struct ieee80211_tx_data *tx, rem -= fraglen; tmp = dev_alloc_skb(local->tx_headroom + frag_threshold + - IEEE80211_ENCRYPT_HEADROOM + + tx->sdata->encrypt_headroom + IEEE80211_ENCRYPT_TAILROOM); if (!tmp) return -ENOMEM; __skb_queue_tail(&tx->skbs, tmp); - skb_reserve(tmp, local->tx_headroom + - IEEE80211_ENCRYPT_HEADROOM); + skb_reserve(tmp, + local->tx_headroom + tx->sdata->encrypt_headroom); + /* copy control information */ memcpy(tmp->cb, skb->cb, sizeof(tmp->cb)); @@ -1485,7 +1487,7 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, headroom = local->tx_headroom; if (may_encrypt) - headroom += IEEE80211_ENCRYPT_HEADROOM; + headroom += sdata->encrypt_headroom; headroom -= skb_headroom(skb); headroom = max_t(int, 0, headroom); @@ -2108,7 +2110,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, */ if (head_need > 0 || skb_cloned(skb)) { - head_need += IEEE80211_ENCRYPT_HEADROOM; + head_need += sdata->encrypt_headroom; head_need += local->tx_headroom; head_need = max_t(int, 0, head_need); if (ieee80211_skb_resize(sdata, skb, head_need, true)) { diff --git a/net/mac80211/util.c b/net/mac80211/util.c index fd4fe5d6178..5dfa41abdf8 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2475,3 +2475,71 @@ int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata, ieee80211_tx_skb(sdata, skb); return 0; } + +bool ieee80211_cs_valid(const struct ieee80211_cipher_scheme *cs) +{ + return !(cs == NULL || cs->cipher == 0 || + cs->hdr_len < cs->pn_len + cs->pn_off || + cs->hdr_len <= cs->key_idx_off || + cs->key_idx_shift > 7 || + cs->key_idx_mask == 0); +} + +bool ieee80211_cs_list_valid(const struct ieee80211_cipher_scheme *cs, int n) +{ + int i; + + /* Ensure we have enough iftype bitmap space for all iftype values */ + WARN_ON((NUM_NL80211_IFTYPES / 8 + 1) > sizeof(cs[0].iftype)); + + for (i = 0; i < n; i++) + if (!ieee80211_cs_valid(&cs[i])) + return false; + + return true; +} + +const struct ieee80211_cipher_scheme * +ieee80211_cs_get(struct ieee80211_local *local, u32 cipher, + enum nl80211_iftype iftype) +{ + const struct ieee80211_cipher_scheme *l = local->hw.cipher_schemes; + int n = local->hw.n_cipher_schemes; + int i; + const struct ieee80211_cipher_scheme *cs = NULL; + + for (i = 0; i < n; i++) { + if (l[i].cipher == cipher) { + cs = &l[i]; + break; + } + } + + if (!cs || !(cs->iftype & BIT(iftype))) + return NULL; + + return cs; +} + +int ieee80211_cs_headroom(struct ieee80211_local *local, + struct cfg80211_crypto_settings *crypto, + enum nl80211_iftype iftype) +{ + const struct ieee80211_cipher_scheme *cs; + int headroom = IEEE80211_ENCRYPT_HEADROOM; + int i; + + for (i = 0; i < crypto->n_ciphers_pairwise; i++) { + cs = ieee80211_cs_get(local, crypto->ciphers_pairwise[i], + iftype); + + if (cs && headroom < cs->hdr_len) + headroom = cs->hdr_len; + } + + cs = ieee80211_cs_get(local, crypto->cipher_group, iftype); + if (cs && headroom < cs->hdr_len) + headroom = cs->hdr_len; + + return headroom; +} diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index d6572822076..7313d379c0d 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -545,6 +545,106 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) return RX_CONTINUE; } +static ieee80211_tx_result +ieee80211_crypto_cs_encrypt(struct ieee80211_tx_data *tx, + struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_key *key = tx->key; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + const struct ieee80211_cipher_scheme *cs = key->sta->cipher_scheme; + int hdrlen; + u8 *pos; + + if (info->control.hw_key && + !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) { + /* hwaccel has no need for preallocated head room */ + return TX_CONTINUE; + } + + if (unlikely(skb_headroom(skb) < cs->hdr_len && + pskb_expand_head(skb, cs->hdr_len, 0, GFP_ATOMIC))) + return TX_DROP; + + hdrlen = ieee80211_hdrlen(hdr->frame_control); + + pos = skb_push(skb, cs->hdr_len); + memmove(pos, pos + cs->hdr_len, hdrlen); + skb_set_network_header(skb, skb_network_offset(skb) + cs->hdr_len); + + return TX_CONTINUE; +} + +static inline int ieee80211_crypto_cs_pn_compare(u8 *pn1, u8 *pn2, int len) +{ + int i; + + /* pn is little endian */ + for (i = len - 1; i >= 0; i--) { + if (pn1[i] < pn2[i]) + return -1; + else if (pn1[i] > pn2[i]) + return 1; + } + + return 0; +} + +static ieee80211_rx_result +ieee80211_crypto_cs_decrypt(struct ieee80211_rx_data *rx) +{ + struct ieee80211_key *key = rx->key; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; + const struct ieee80211_cipher_scheme *cs = NULL; + int hdrlen = ieee80211_hdrlen(hdr->frame_control); + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); + int data_len; + u8 *rx_pn; + u8 *skb_pn; + u8 qos_tid; + + if (!rx->sta || !rx->sta->cipher_scheme || + !(status->flag & RX_FLAG_DECRYPTED)) + return RX_DROP_UNUSABLE; + + if (!ieee80211_is_data(hdr->frame_control)) + return RX_CONTINUE; + + cs = rx->sta->cipher_scheme; + + data_len = rx->skb->len - hdrlen - cs->hdr_len; + + if (data_len < 0) + return RX_DROP_UNUSABLE; + + if (ieee80211_is_data_qos(hdr->frame_control)) + qos_tid = *ieee80211_get_qos_ctl(hdr) & + IEEE80211_QOS_CTL_TID_MASK; + else + qos_tid = 0; + + if (skb_linearize(rx->skb)) + return RX_DROP_UNUSABLE; + + hdr = (struct ieee80211_hdr *)rx->skb->data; + + rx_pn = key->u.gen.rx_pn[qos_tid]; + skb_pn = rx->skb->data + hdrlen + cs->pn_off; + + if (ieee80211_crypto_cs_pn_compare(skb_pn, rx_pn, cs->pn_len) <= 0) + return RX_DROP_UNUSABLE; + + memcpy(rx_pn, skb_pn, cs->pn_len); + + /* remove security header and MIC */ + if (pskb_trim(rx->skb, rx->skb->len - cs->mic_len)) + return RX_DROP_UNUSABLE; + + memmove(rx->skb->data + cs->hdr_len, rx->skb->data, hdrlen); + skb_pull(rx->skb, cs->hdr_len); + + return RX_CONTINUE; +} static void bip_aad(struct sk_buff *skb, u8 *aad) { @@ -685,6 +785,7 @@ ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx) { struct sk_buff *skb; struct ieee80211_tx_info *info = NULL; + ieee80211_tx_result res; skb_queue_walk(&tx->skbs, skb) { info = IEEE80211_SKB_CB(skb); @@ -692,9 +793,24 @@ ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx) /* handle hw-only algorithm */ if (!info->control.hw_key) return TX_DROP; + + if (tx->key->sta->cipher_scheme) { + res = ieee80211_crypto_cs_encrypt(tx, skb); + if (res != TX_CONTINUE) + return res; + } } ieee80211_tx_set_protected(tx); return TX_CONTINUE; } + +ieee80211_rx_result +ieee80211_crypto_hw_decrypt(struct ieee80211_rx_data *rx) +{ + if (rx->sta->cipher_scheme) + return ieee80211_crypto_cs_decrypt(rx); + + return RX_DROP_UNUSABLE; +} diff --git a/net/mac80211/wpa.h b/net/mac80211/wpa.h index 07e33f899c7..62e5a12dfe0 100644 --- a/net/mac80211/wpa.h +++ b/net/mac80211/wpa.h @@ -34,5 +34,7 @@ ieee80211_rx_result ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx); ieee80211_tx_result ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx); +ieee80211_rx_result +ieee80211_crypto_hw_decrypt(struct ieee80211_rx_data *rx); #endif /* WPA_H */ -- cgit v1.2.3-70-g09d2 From af9b223551634ce1881de258169f3a1ea686a865 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 28 Oct 2013 03:19:45 +0100 Subject: cfg80211: add function helpers to genregdb.awk This has no functional change, this just lets us reuse helpers at a later time. Signed-off-by: Luis R. Rodriguez Acked-by: John W. Linville Signed-off-by: Johannes Berg --- net/wireless/genregdb.awk | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/net/wireless/genregdb.awk b/net/wireless/genregdb.awk index c808619ac9c..42cd3fd2aa1 100644 --- a/net/wireless/genregdb.awk +++ b/net/wireless/genregdb.awk @@ -33,15 +33,7 @@ BEGIN { regdb = "const struct ieee80211_regdomain *reg_regdb[] = {\n" } -/^[ \t]*#/ { - # Ignore -} - -!active && /^[ \t]*$/ { - # Ignore -} - -!active && /country/ { +function parse_country_head() { country=$2 sub(/:/, "", country) printf "static const struct ieee80211_regdomain regdom_%s = {\n", country @@ -57,7 +49,8 @@ BEGIN { regdb = regdb "\t®dom_" country ",\n" } -active && /^[ \t]*\(/ { +function parse_reg_rule() +{ start = $1 sub(/\(/, "", start) end = $3 @@ -120,7 +113,8 @@ active && /^[ \t]*\(/ { rules++ } -active && /^[ \t]*$/ { +function print_tail_country() +{ active = 0 printf "\t},\n" printf "\t.n_reg_rules = %d\n", rules @@ -128,6 +122,26 @@ active && /^[ \t]*$/ { rules = 0; } +/^[ \t]*#/ { + # Ignore +} + +!active && /^[ \t]*$/ { + # Ignore +} + +!active && /country/ { + parse_country_head() +} + +active && /^[ \t]*\(/ { + parse_reg_rule() +} + +active && /^[ \t]*$/ { + print_tail_country() +} + END { print regdb "};" print "" -- cgit v1.2.3-70-g09d2 From ae689390b09d1f5b274c83dbbd3836fedb692e31 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 28 Oct 2013 03:19:46 +0100 Subject: cfg80211: fix parsing when db.txt ends on a rule If genregdb.awk assumes the file will end with an extra empty line or a comment line. This is could not be true so just address this. Signed-off-by: Luis R. Rodriguez Acked-by: John W. Linville Signed-off-by: Johannes Berg --- net/wireless/genregdb.awk | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/wireless/genregdb.awk b/net/wireless/genregdb.awk index 42cd3fd2aa1..9a8217d2a90 100644 --- a/net/wireless/genregdb.awk +++ b/net/wireless/genregdb.awk @@ -143,6 +143,8 @@ active && /^[ \t]*$/ { } END { + if (active) + print_tail_country() print regdb "};" print "" print "int reg_regdb_size = ARRAY_SIZE(reg_regdb);" -- cgit v1.2.3-70-g09d2 From cc493e4f5296f4da111f25ea4a216bb77270ccc6 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 6 Nov 2013 17:54:44 +0100 Subject: cfg80211: enforce disabling channels by custom or strict settings If a custom regulatory domain is passed and if a rule for a channel indicates it should be disabled that channel should always remain disabled as per its documentation and design. Likewise if WIPHY_FLAG_STRICT_REGULATORY flag is set and a regulatory_hint() is issued if a channel is disabled that channel should remain disabled. Without this change only drivers that set the _orig flags appropriately on their own would ensure disallowed channels remaind disabled. This helps drivers save code by relying on the APIS provided to entrust channels that should not be enabled be respected by only having to use wiphy_apply_custom_regulatory() or regulatory_hint() with the WIPHY_FLAG_STRICT_REGULATORY set. If wiphy_apply_custom_regulatory() is used together with WIPHY_FLAG_STRICT_REGULATORY and a regulatory_hint() issued later, the incoming regulatory domain can override previously set _orig parameters from the initial custom regulatory setting. Signed-off-by: Luis R. Rodriguez Signed-off-by: Johannes Berg --- net/wireless/reg.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index dccdfe36a31..b4b16871a56 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -846,8 +846,18 @@ static void handle_channel(struct wiphy *wiphy, PTR_ERR(reg_rule) == -ERANGE) return; - REG_DBG_PRINT("Disabling freq %d MHz\n", chan->center_freq); - chan->flags |= IEEE80211_CHAN_DISABLED; + if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER && + request_wiphy && request_wiphy == wiphy && + request_wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) { + REG_DBG_PRINT("Disabling freq %d MHz for good\n", + chan->center_freq); + chan->orig_flags |= IEEE80211_CHAN_DISABLED; + chan->flags = chan->orig_flags; + } else { + REG_DBG_PRINT("Disabling freq %d MHz\n", + chan->center_freq); + chan->flags |= IEEE80211_CHAN_DISABLED; + } return; } @@ -1250,7 +1260,8 @@ static void handle_channel_custom(struct wiphy *wiphy, if (IS_ERR(reg_rule)) { REG_DBG_PRINT("Disabling freq %d MHz as custom regd has no rule that fits it\n", chan->center_freq); - chan->flags = IEEE80211_CHAN_DISABLED; + chan->orig_flags |= IEEE80211_CHAN_DISABLED; + chan->flags = chan->orig_flags; return; } -- cgit v1.2.3-70-g09d2 From e438768ff9b22c83a968e14b79e8c83128e8bfe4 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 5 Nov 2013 09:18:01 -0800 Subject: cfg80211: check regulatory request alpha2 early Currently nl80211 allows userspace to send the kernel a bogus regulatory domain with at most 32 rules set and it won't reject it until after its allocated memory. Let's be smart about it and take advantage that the last_request is now available under RTNL and check if the alpha2 matches an expected request and reject any bogus userspace requests prior to hitting the memory allocator. Signed-off-by: Luis R. Rodriguez Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 3 +++ net/wireless/reg.c | 2 +- net/wireless/reg.h | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 04fa8bb1b4b..7b73132910b 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -5100,6 +5100,9 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) return -EINVAL; } + if (!reg_is_valid_request(alpha2)) + return -EINVAL; + size_of_regd = sizeof(struct ieee80211_regdomain) + num_rules * sizeof(struct ieee80211_reg_rule); diff --git a/net/wireless/reg.c b/net/wireless/reg.c index b4b16871a56..d8f047aadd4 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -450,7 +450,7 @@ static int call_crda(const char *alpha2) return kobject_uevent(®_pdev->dev.kobj, KOBJ_CHANGE); } -static bool reg_is_valid_request(const char *alpha2) +bool reg_is_valid_request(const char *alpha2) { struct regulatory_request *lr = get_last_request(); diff --git a/net/wireless/reg.h b/net/wireless/reg.h index 9677e3c13da..b4076babaf4 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h @@ -18,6 +18,7 @@ extern const struct ieee80211_regdomain __rcu *cfg80211_regdomain; +bool reg_is_valid_request(const char *alpha2); bool is_world_regdom(const char *alpha2); bool reg_supported_dfs_region(u8 dfs_region); -- cgit v1.2.3-70-g09d2 From b3eb7f3f592c0a5ae96c0cf53037f1a1d7eb4a85 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 5 Nov 2013 09:18:03 -0800 Subject: cfg80211: processing core regulatory hints on its own This makes the code path easier to read for the core case. Signed-off-by: Luis R. Rodriguez [add warning to default case in switch to avoid compile warning] Signed-off-by: Johannes Berg --- net/wireless/reg.c | 46 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index d8f047aadd4..2b7ab01b261 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1337,7 +1337,7 @@ get_reg_request_treatment(struct wiphy *wiphy, switch (pending_request->initiator) { case NL80211_REGDOM_SET_BY_CORE: - return REG_REQ_OK; + return REG_REQ_IGNORE; case NL80211_REGDOM_SET_BY_COUNTRY_IE: if (reg_request_cell_base(lr)) { /* Trust a Cell base station over the AP's country IE */ @@ -1442,6 +1442,33 @@ static void reg_set_request_processed(void) schedule_work(®_work); } +/** + * reg_process_hint_core - process core regulatory requests + * @pending_request: a pending core regulatory request + * + * The wireless subsystem can use this function to process + * a regulatory request issued by the regulatory core. + * + * Returns one of the different reg request treatment values. + */ +static enum reg_request_treatment +reg_process_hint_core(struct regulatory_request *core_request) +{ + struct regulatory_request *lr; + + lr = get_last_request(); + if (lr != &core_request_world && lr) + kfree_rcu(lr, rcu_head); + + core_request->intersect = false; + core_request->processed = false; + rcu_assign_pointer(last_request, core_request); + + if (call_crda(core_request->alpha2)) + return REG_REQ_IGNORE; + return REG_REQ_OK; +} + /** * __regulatory_hint - hint to the wireless core a regulatory domain * @wiphy: if the hint comes from country information from an AP, this @@ -1540,6 +1567,7 @@ new_request: static void reg_process_hint(struct regulatory_request *reg_request) { struct wiphy *wiphy = NULL; + enum reg_request_treatment treatment; if (WARN_ON(!reg_request->alpha2)) return; @@ -1552,7 +1580,21 @@ static void reg_process_hint(struct regulatory_request *reg_request) return; } - switch (__regulatory_hint(wiphy, reg_request)) { + switch (reg_request->initiator) { + case NL80211_REGDOM_SET_BY_CORE: + reg_process_hint_core(reg_request); + return; + case NL80211_REGDOM_SET_BY_USER: + case NL80211_REGDOM_SET_BY_DRIVER: + case NL80211_REGDOM_SET_BY_COUNTRY_IE: + treatment = __regulatory_hint(wiphy, reg_request); + break; + default: + WARN(1, "invalid initiator %d\n", reg_request->initiator); + return; + } + + switch (treatment) { case REG_REQ_ALREADY_SET: /* This is required so that the orig_* parameters are saved */ if (wiphy && wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) -- cgit v1.2.3-70-g09d2 From 0d97a61917d8c00adb9e445ec23ee09150d720a4 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 5 Nov 2013 09:18:04 -0800 Subject: cfg80211: process user regulatory requests on its own This makes the code path easier to read and lets us split out some functionality that is only user specific, that makes it easier to read the other types of requests. Signed-off-by: Luis R. Rodriguez Signed-off-by: Johannes Berg --- net/wireless/reg.c | 114 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 81 insertions(+), 33 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 2b7ab01b261..1bd590c2ed7 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1337,6 +1337,7 @@ get_reg_request_treatment(struct wiphy *wiphy, switch (pending_request->initiator) { case NL80211_REGDOM_SET_BY_CORE: + case NL80211_REGDOM_SET_BY_USER: return REG_REQ_IGNORE; case NL80211_REGDOM_SET_BY_COUNTRY_IE: if (reg_request_cell_base(lr)) { @@ -1388,36 +1389,6 @@ get_reg_request_treatment(struct wiphy *wiphy, return REG_REQ_ALREADY_SET; return REG_REQ_INTERSECT; - case NL80211_REGDOM_SET_BY_USER: - if (reg_request_cell_base(pending_request)) - return reg_ignore_cell_hint(pending_request); - - if (reg_request_cell_base(lr)) - return REG_REQ_IGNORE; - - if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) - return REG_REQ_INTERSECT; - /* - * If the user knows better the user should set the regdom - * to their country before the IE is picked up - */ - if (lr->initiator == NL80211_REGDOM_SET_BY_USER && - lr->intersect) - return REG_REQ_IGNORE; - /* - * Process user requests only after previous user/driver/core - * requests have been processed - */ - if ((lr->initiator == NL80211_REGDOM_SET_BY_CORE || - lr->initiator == NL80211_REGDOM_SET_BY_DRIVER || - lr->initiator == NL80211_REGDOM_SET_BY_USER) && - regdom_changes(lr->alpha2)) - return REG_REQ_IGNORE; - - if (!regdom_changes(pending_request->alpha2)) - return REG_REQ_ALREADY_SET; - - return REG_REQ_OK; } return REG_REQ_IGNORE; @@ -1469,6 +1440,80 @@ reg_process_hint_core(struct regulatory_request *core_request) return REG_REQ_OK; } +static enum reg_request_treatment +__reg_process_hint_user(struct regulatory_request *user_request) +{ + struct regulatory_request *lr = get_last_request(); + + if (reg_request_cell_base(user_request)) + return reg_ignore_cell_hint(user_request); + + if (reg_request_cell_base(lr)) + return REG_REQ_IGNORE; + + if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) + return REG_REQ_INTERSECT; + /* + * If the user knows better the user should set the regdom + * to their country before the IE is picked up + */ + if (lr->initiator == NL80211_REGDOM_SET_BY_USER && + lr->intersect) + return REG_REQ_IGNORE; + /* + * Process user requests only after previous user/driver/core + * requests have been processed + */ + if ((lr->initiator == NL80211_REGDOM_SET_BY_CORE || + lr->initiator == NL80211_REGDOM_SET_BY_DRIVER || + lr->initiator == NL80211_REGDOM_SET_BY_USER) && + regdom_changes(lr->alpha2)) + return REG_REQ_IGNORE; + + if (!regdom_changes(user_request->alpha2)) + return REG_REQ_ALREADY_SET; + + return REG_REQ_OK; +} + +/** + * reg_process_hint_user - process user regulatory requests + * @user_request: a pending user regulatory request + * + * The wireless subsystem can use this function to process + * a regulatory request initiated by userspace. + * + * Returns one of the different reg request treatment values. + */ +static enum reg_request_treatment +reg_process_hint_user(struct regulatory_request *user_request) +{ + enum reg_request_treatment treatment; + struct regulatory_request *lr; + + treatment = __reg_process_hint_user(user_request); + if (treatment == REG_REQ_IGNORE || + treatment == REG_REQ_ALREADY_SET) { + kfree(user_request); + return treatment; + } + + lr = get_last_request(); + if (lr != &core_request_world && lr) + kfree_rcu(lr, rcu_head); + + user_request->intersect = treatment == REG_REQ_INTERSECT; + user_request->processed = false; + rcu_assign_pointer(last_request, user_request); + + user_alpha2[0] = user_request->alpha2[0]; + user_alpha2[1] = user_request->alpha2[1]; + + if (call_crda(user_request->alpha2)) + return REG_REQ_IGNORE; + return REG_REQ_OK; +} + /** * __regulatory_hint - hint to the wireless core a regulatory domain * @wiphy: if the hint comes from country information from an AP, this @@ -1585,6 +1630,12 @@ static void reg_process_hint(struct regulatory_request *reg_request) reg_process_hint_core(reg_request); return; case NL80211_REGDOM_SET_BY_USER: + treatment = reg_process_hint_user(reg_request); + if (treatment == REG_REQ_OK || + treatment == REG_REQ_ALREADY_SET) + return; + schedule_delayed_work(®_timeout, msecs_to_jiffies(3142)); + return; case NL80211_REGDOM_SET_BY_DRIVER: case NL80211_REGDOM_SET_BY_COUNTRY_IE: treatment = __regulatory_hint(wiphy, reg_request); @@ -1601,9 +1652,6 @@ static void reg_process_hint(struct regulatory_request *reg_request) wiphy_update_regulatory(wiphy, reg_request->initiator); break; default: - if (reg_request->initiator == NL80211_REGDOM_SET_BY_USER) - schedule_delayed_work(®_timeout, - msecs_to_jiffies(3142)); break; } } -- cgit v1.2.3-70-g09d2 From 21636c7faae0a980e73f366e164ffaa77a424786 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 5 Nov 2013 09:18:05 -0800 Subject: cfg80211: process driver regulatory requests on its own This makes the code easier to read and follow. Signed-off-by: Luis R. Rodriguez Signed-off-by: Johannes Berg --- net/wireless/reg.c | 103 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 86 insertions(+), 17 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 1bd590c2ed7..7188ef9f07b 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1338,6 +1338,7 @@ get_reg_request_treatment(struct wiphy *wiphy, switch (pending_request->initiator) { case NL80211_REGDOM_SET_BY_CORE: case NL80211_REGDOM_SET_BY_USER: + case NL80211_REGDOM_SET_BY_DRIVER: return REG_REQ_IGNORE; case NL80211_REGDOM_SET_BY_COUNTRY_IE: if (reg_request_cell_base(lr)) { @@ -1372,23 +1373,6 @@ get_reg_request_treatment(struct wiphy *wiphy, return REG_REQ_ALREADY_SET; } return REG_REQ_OK; - case NL80211_REGDOM_SET_BY_DRIVER: - if (lr->initiator == NL80211_REGDOM_SET_BY_CORE) { - if (regdom_changes(pending_request->alpha2)) - return REG_REQ_OK; - return REG_REQ_ALREADY_SET; - } - - /* - * This would happen if you unplug and plug your card - * back in or if you add a new device for which the previously - * loaded card also agrees on the regulatory domain. - */ - if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER && - !regdom_changes(pending_request->alpha2)) - return REG_REQ_ALREADY_SET; - - return REG_REQ_INTERSECT; } return REG_REQ_IGNORE; @@ -1514,6 +1498,89 @@ reg_process_hint_user(struct regulatory_request *user_request) return REG_REQ_OK; } +static enum reg_request_treatment +__reg_process_hint_driver(struct regulatory_request *driver_request) +{ + struct regulatory_request *lr = get_last_request(); + + if (lr->initiator == NL80211_REGDOM_SET_BY_CORE) { + if (regdom_changes(driver_request->alpha2)) + return REG_REQ_OK; + return REG_REQ_ALREADY_SET; + } + + /* + * This would happen if you unplug and plug your card + * back in or if you add a new device for which the previously + * loaded card also agrees on the regulatory domain. + */ + if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER && + !regdom_changes(driver_request->alpha2)) + return REG_REQ_ALREADY_SET; + + return REG_REQ_INTERSECT; +} + +/** + * reg_process_hint_driver - process driver regulatory requests + * @driver_request: a pending driver regulatory request + * + * The wireless subsystem can use this function to process + * a regulatory request issued by an 802.11 driver. + * + * Returns one of the different reg request treatment values. + */ +static enum reg_request_treatment +reg_process_hint_driver(struct wiphy *wiphy, + struct regulatory_request *driver_request) +{ + const struct ieee80211_regdomain *regd; + enum reg_request_treatment treatment; + struct regulatory_request *lr; + + treatment = __reg_process_hint_driver(driver_request); + + switch (treatment) { + case REG_REQ_OK: + break; + case REG_REQ_IGNORE: + kfree(driver_request); + return treatment; + case REG_REQ_INTERSECT: + /* fall through */ + case REG_REQ_ALREADY_SET: + regd = reg_copy_regd(get_cfg80211_regdom()); + if (IS_ERR(regd)) { + kfree(driver_request); + return REG_REQ_IGNORE; + } + rcu_assign_pointer(wiphy->regd, regd); + } + + lr = get_last_request(); + if (lr != &core_request_world && lr) + kfree_rcu(lr, rcu_head); + + driver_request->intersect = treatment == REG_REQ_INTERSECT; + driver_request->processed = false; + rcu_assign_pointer(last_request, driver_request); + + /* + * Since CRDA will not be called in this case as we already + * have applied the requested regulatory domain before we just + * inform userspace we have processed the request + */ + if (treatment == REG_REQ_ALREADY_SET) { + nl80211_send_reg_change_event(driver_request); + reg_set_request_processed(); + return treatment; + } + + if (call_crda(driver_request->alpha2)) + return REG_REQ_IGNORE; + return REG_REQ_OK; +} + /** * __regulatory_hint - hint to the wireless core a regulatory domain * @wiphy: if the hint comes from country information from an AP, this @@ -1637,6 +1704,8 @@ static void reg_process_hint(struct regulatory_request *reg_request) schedule_delayed_work(®_timeout, msecs_to_jiffies(3142)); return; case NL80211_REGDOM_SET_BY_DRIVER: + treatment = reg_process_hint_driver(wiphy, reg_request); + break; case NL80211_REGDOM_SET_BY_COUNTRY_IE: treatment = __regulatory_hint(wiphy, reg_request); break; -- cgit v1.2.3-70-g09d2 From b23e7a9e6b1f4c3070f9ce59e82b9dff69b11fe1 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 5 Nov 2013 09:18:06 -0800 Subject: cfg80211: process country IE regulatory requests on their own This is the last split up of the old unified __regultory_hint() processing set of functionality, it moves the country IE processing all on its own. This makes it easier to follow and read what exactly is going on for the case of processing country IEs. Signed-off-by: Luis R. Rodriguez Signed-off-by: Johannes Berg --- net/wireless/reg.c | 201 ++++++++++++++++++----------------------------------- 1 file changed, 68 insertions(+), 133 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 7188ef9f07b..aef39243595 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1322,62 +1322,6 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy, } EXPORT_SYMBOL(wiphy_apply_custom_regulatory); -/* This has the logic which determines when a new request - * should be ignored. */ -static enum reg_request_treatment -get_reg_request_treatment(struct wiphy *wiphy, - struct regulatory_request *pending_request) -{ - struct wiphy *last_wiphy = NULL; - struct regulatory_request *lr = get_last_request(); - - /* All initial requests are respected */ - if (!lr) - return REG_REQ_OK; - - switch (pending_request->initiator) { - case NL80211_REGDOM_SET_BY_CORE: - case NL80211_REGDOM_SET_BY_USER: - case NL80211_REGDOM_SET_BY_DRIVER: - return REG_REQ_IGNORE; - case NL80211_REGDOM_SET_BY_COUNTRY_IE: - if (reg_request_cell_base(lr)) { - /* Trust a Cell base station over the AP's country IE */ - if (regdom_changes(pending_request->alpha2)) - return REG_REQ_IGNORE; - return REG_REQ_ALREADY_SET; - } - - last_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx); - - if (unlikely(!is_an_alpha2(pending_request->alpha2))) - return -EINVAL; - if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) { - if (last_wiphy != wiphy) { - /* - * Two cards with two APs claiming different - * Country IE alpha2s. We could - * intersect them, but that seems unlikely - * to be correct. Reject second one for now. - */ - if (regdom_changes(pending_request->alpha2)) - return REG_REQ_IGNORE; - return REG_REQ_ALREADY_SET; - } - /* - * Two consecutive Country IE hints on the same wiphy. - * This should be picked up early by the driver/stack - */ - if (WARN_ON(regdom_changes(pending_request->alpha2))) - return REG_REQ_OK; - return REG_REQ_ALREADY_SET; - } - return REG_REQ_OK; - } - - return REG_REQ_IGNORE; -} - static void reg_set_request_processed(void) { bool need_more_processing = false; @@ -1581,96 +1525,92 @@ reg_process_hint_driver(struct wiphy *wiphy, return REG_REQ_OK; } +static enum reg_request_treatment +__reg_process_hint_country_ie(struct wiphy *wiphy, + struct regulatory_request *country_ie_request) +{ + struct wiphy *last_wiphy = NULL; + struct regulatory_request *lr = get_last_request(); + + if (reg_request_cell_base(lr)) { + /* Trust a Cell base station over the AP's country IE */ + if (regdom_changes(country_ie_request->alpha2)) + return REG_REQ_IGNORE; + return REG_REQ_ALREADY_SET; + } + + last_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx); + + if (unlikely(!is_an_alpha2(country_ie_request->alpha2))) + return -EINVAL; + if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) { + if (last_wiphy != wiphy) { + /* + * Two cards with two APs claiming different + * Country IE alpha2s. We could + * intersect them, but that seems unlikely + * to be correct. Reject second one for now. + */ + if (regdom_changes(country_ie_request->alpha2)) + return REG_REQ_IGNORE; + return REG_REQ_ALREADY_SET; + } + /* + * Two consecutive Country IE hints on the same wiphy. + * This should be picked up early by the driver/stack + */ + if (WARN_ON(regdom_changes(country_ie_request->alpha2))) + return REG_REQ_OK; + return REG_REQ_ALREADY_SET; + } + return REG_REQ_OK; +} + /** - * __regulatory_hint - hint to the wireless core a regulatory domain - * @wiphy: if the hint comes from country information from an AP, this - * is required to be set to the wiphy that received the information - * @pending_request: the regulatory request currently being processed + * reg_process_hint_country_ie - process regulatory requests from country IEs + * @country_ie_request: a regulatory request from a country IE * - * The Wireless subsystem can use this function to hint to the wireless core - * what it believes should be the current regulatory domain. + * The wireless subsystem can use this function to process + * a regulatory request issued by a country Information Element. * * Returns one of the different reg request treatment values. */ static enum reg_request_treatment -__regulatory_hint(struct wiphy *wiphy, - struct regulatory_request *pending_request) +reg_process_hint_country_ie(struct wiphy *wiphy, + struct regulatory_request *country_ie_request) { - const struct ieee80211_regdomain *regd; - bool intersect = false; enum reg_request_treatment treatment; struct regulatory_request *lr; - treatment = get_reg_request_treatment(wiphy, pending_request); + treatment = __reg_process_hint_country_ie(wiphy, country_ie_request); switch (treatment) { - case REG_REQ_INTERSECT: - if (pending_request->initiator == - NL80211_REGDOM_SET_BY_DRIVER) { - regd = reg_copy_regd(get_cfg80211_regdom()); - if (IS_ERR(regd)) { - kfree(pending_request); - return PTR_ERR(regd); - } - rcu_assign_pointer(wiphy->regd, regd); - } - intersect = true; - break; case REG_REQ_OK: break; - default: + case REG_REQ_IGNORE: + /* fall through */ + case REG_REQ_ALREADY_SET: + kfree(country_ie_request); + return treatment; + case REG_REQ_INTERSECT: + kfree(country_ie_request); /* - * If the regulatory domain being requested by the - * driver has already been set just copy it to the - * wiphy + * This doesn't happen yet, not sure we + * ever want to support it for this case. */ - if (treatment == REG_REQ_ALREADY_SET && - pending_request->initiator == NL80211_REGDOM_SET_BY_DRIVER) { - regd = reg_copy_regd(get_cfg80211_regdom()); - if (IS_ERR(regd)) { - kfree(pending_request); - return REG_REQ_IGNORE; - } - treatment = REG_REQ_ALREADY_SET; - rcu_assign_pointer(wiphy->regd, regd); - goto new_request; - } - kfree(pending_request); - return treatment; + WARN_ONCE(1, "Unexpected intersection for country IEs"); + return REG_REQ_IGNORE; } -new_request: lr = get_last_request(); if (lr != &core_request_world && lr) kfree_rcu(lr, rcu_head); - pending_request->intersect = intersect; - pending_request->processed = false; - rcu_assign_pointer(last_request, pending_request); - lr = pending_request; - - pending_request = NULL; + country_ie_request->intersect = false; + country_ie_request->processed = false; + rcu_assign_pointer(last_request, country_ie_request); - if (lr->initiator == NL80211_REGDOM_SET_BY_USER) { - user_alpha2[0] = lr->alpha2[0]; - user_alpha2[1] = lr->alpha2[1]; - } - - /* When r == REG_REQ_INTERSECT we do need to call CRDA */ - if (treatment != REG_REQ_OK && treatment != REG_REQ_INTERSECT) { - /* - * Since CRDA will not be called in this case as we already - * have applied the requested regulatory domain before we just - * inform userspace we have processed the request - */ - if (treatment == REG_REQ_ALREADY_SET) { - nl80211_send_reg_change_event(lr); - reg_set_request_processed(); - } - return treatment; - } - - if (call_crda(lr->alpha2)) + if (call_crda(country_ie_request->alpha2)) return REG_REQ_IGNORE; return REG_REQ_OK; } @@ -1707,22 +1647,17 @@ static void reg_process_hint(struct regulatory_request *reg_request) treatment = reg_process_hint_driver(wiphy, reg_request); break; case NL80211_REGDOM_SET_BY_COUNTRY_IE: - treatment = __regulatory_hint(wiphy, reg_request); + treatment = reg_process_hint_country_ie(wiphy, reg_request); break; default: WARN(1, "invalid initiator %d\n", reg_request->initiator); return; } - switch (treatment) { - case REG_REQ_ALREADY_SET: - /* This is required so that the orig_* parameters are saved */ - if (wiphy && wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) - wiphy_update_regulatory(wiphy, reg_request->initiator); - break; - default: - break; - } + /* This is required so that the orig_* parameters are saved */ + if (treatment == REG_REQ_ALREADY_SET && wiphy && + wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) + wiphy_update_regulatory(wiphy, reg_request->initiator); } /* -- cgit v1.2.3-70-g09d2 From 2f1c6c572d7b6cbe2e3c9bbb427769f6c79089bb Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 5 Nov 2013 09:18:07 -0800 Subject: cfg80211: process non country IE conflicting first By dealing with non country IE conficts first we can shift the code that deals with the conflict to the left. This has no functional changes. Signed-off-by: Luis R. Rodriguez Signed-off-by: Johannes Berg --- net/wireless/reg.c | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index aef39243595..875fffc284c 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1539,31 +1539,32 @@ __reg_process_hint_country_ie(struct wiphy *wiphy, return REG_REQ_ALREADY_SET; } - last_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx); - if (unlikely(!is_an_alpha2(country_ie_request->alpha2))) return -EINVAL; - if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) { - if (last_wiphy != wiphy) { - /* - * Two cards with two APs claiming different - * Country IE alpha2s. We could - * intersect them, but that seems unlikely - * to be correct. Reject second one for now. - */ - if (regdom_changes(country_ie_request->alpha2)) - return REG_REQ_IGNORE; - return REG_REQ_ALREADY_SET; - } + + if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) + return REG_REQ_OK; + + last_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx); + + if (last_wiphy != wiphy) { /* - * Two consecutive Country IE hints on the same wiphy. - * This should be picked up early by the driver/stack + * Two cards with two APs claiming different + * Country IE alpha2s. We could + * intersect them, but that seems unlikely + * to be correct. Reject second one for now. */ - if (WARN_ON(regdom_changes(country_ie_request->alpha2))) - return REG_REQ_OK; + if (regdom_changes(country_ie_request->alpha2)) + return REG_REQ_IGNORE; return REG_REQ_ALREADY_SET; } - return REG_REQ_OK; + /* + * Two consecutive Country IE hints on the same wiphy. + * This should be picked up early by the driver/stack + */ + if (WARN_ON(regdom_changes(country_ie_request->alpha2))) + return REG_REQ_OK; + return REG_REQ_ALREADY_SET; } /** -- cgit v1.2.3-70-g09d2 From 5ad6ef5e06a1c9feb934c13b3a5f5303833fef4e Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 5 Nov 2013 09:18:08 -0800 Subject: cfg80211: add helper for kfree'ing last_request This is common code, this reduces the chance of making a mistake of how we free it. Signed-off-by: Luis R. Rodriguez Signed-off-by: Johannes Berg --- net/wireless/reg.c | 42 +++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 875fffc284c..6ad7b296886 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -202,11 +202,20 @@ static char user_alpha2[2]; module_param(ieee80211_regdom, charp, 0444); MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); +static void reg_kfree_last_request(void) +{ + struct regulatory_request *lr; + + lr = get_last_request(); + + if (lr != &core_request_world && lr) + kfree_rcu(lr, rcu_head); +} + static void reset_regdomains(bool full_reset, const struct ieee80211_regdomain *new_regdom) { const struct ieee80211_regdomain *r; - struct regulatory_request *lr; ASSERT_RTNL(); @@ -229,9 +238,7 @@ static void reset_regdomains(bool full_reset, if (!full_reset) return; - lr = get_last_request(); - if (lr != &core_request_world && lr) - kfree_rcu(lr, rcu_head); + reg_kfree_last_request(); rcu_assign_pointer(last_request, &core_request_world); } @@ -1353,14 +1360,11 @@ static void reg_set_request_processed(void) static enum reg_request_treatment reg_process_hint_core(struct regulatory_request *core_request) { - struct regulatory_request *lr; - - lr = get_last_request(); - if (lr != &core_request_world && lr) - kfree_rcu(lr, rcu_head); core_request->intersect = false; core_request->processed = false; + + reg_kfree_last_request(); rcu_assign_pointer(last_request, core_request); if (call_crda(core_request->alpha2)) @@ -1417,7 +1421,6 @@ static enum reg_request_treatment reg_process_hint_user(struct regulatory_request *user_request) { enum reg_request_treatment treatment; - struct regulatory_request *lr; treatment = __reg_process_hint_user(user_request); if (treatment == REG_REQ_IGNORE || @@ -1426,12 +1429,10 @@ reg_process_hint_user(struct regulatory_request *user_request) return treatment; } - lr = get_last_request(); - if (lr != &core_request_world && lr) - kfree_rcu(lr, rcu_head); - user_request->intersect = treatment == REG_REQ_INTERSECT; user_request->processed = false; + + reg_kfree_last_request(); rcu_assign_pointer(last_request, user_request); user_alpha2[0] = user_request->alpha2[0]; @@ -1480,7 +1481,6 @@ reg_process_hint_driver(struct wiphy *wiphy, { const struct ieee80211_regdomain *regd; enum reg_request_treatment treatment; - struct regulatory_request *lr; treatment = __reg_process_hint_driver(driver_request); @@ -1501,12 +1501,11 @@ reg_process_hint_driver(struct wiphy *wiphy, rcu_assign_pointer(wiphy->regd, regd); } - lr = get_last_request(); - if (lr != &core_request_world && lr) - kfree_rcu(lr, rcu_head); driver_request->intersect = treatment == REG_REQ_INTERSECT; driver_request->processed = false; + + reg_kfree_last_request(); rcu_assign_pointer(last_request, driver_request); /* @@ -1581,7 +1580,6 @@ reg_process_hint_country_ie(struct wiphy *wiphy, struct regulatory_request *country_ie_request) { enum reg_request_treatment treatment; - struct regulatory_request *lr; treatment = __reg_process_hint_country_ie(wiphy, country_ie_request); @@ -1603,12 +1601,10 @@ reg_process_hint_country_ie(struct wiphy *wiphy, return REG_REQ_IGNORE; } - lr = get_last_request(); - if (lr != &core_request_world && lr) - kfree_rcu(lr, rcu_head); - country_ie_request->intersect = false; country_ie_request->processed = false; + + reg_kfree_last_request(); rcu_assign_pointer(last_request, country_ie_request); if (call_crda(country_ie_request->alpha2)) -- cgit v1.2.3-70-g09d2 From 05f1a3ea2dc0d5ae31c8a3a1588cc21bbd5f8413 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 5 Nov 2013 09:18:09 -0800 Subject: cfg80211: add helper for kfree'ing and assigning last_request This enforces proper RCU APIs accross the code. Signed-off-by: Luis R. Rodriguez Signed-off-by: Johannes Berg --- net/wireless/reg.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 6ad7b296886..e93a078e5ae 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -212,6 +212,12 @@ static void reg_kfree_last_request(void) kfree_rcu(lr, rcu_head); } +static void reg_update_last_request(struct regulatory_request *request) +{ + reg_kfree_last_request(); + rcu_assign_pointer(last_request, request); +} + static void reset_regdomains(bool full_reset, const struct ieee80211_regdomain *new_regdom) { @@ -238,8 +244,7 @@ static void reset_regdomains(bool full_reset, if (!full_reset) return; - reg_kfree_last_request(); - rcu_assign_pointer(last_request, &core_request_world); + reg_update_last_request(&core_request_world); } /* @@ -1364,8 +1369,7 @@ reg_process_hint_core(struct regulatory_request *core_request) core_request->intersect = false; core_request->processed = false; - reg_kfree_last_request(); - rcu_assign_pointer(last_request, core_request); + reg_update_last_request(core_request); if (call_crda(core_request->alpha2)) return REG_REQ_IGNORE; @@ -1432,8 +1436,7 @@ reg_process_hint_user(struct regulatory_request *user_request) user_request->intersect = treatment == REG_REQ_INTERSECT; user_request->processed = false; - reg_kfree_last_request(); - rcu_assign_pointer(last_request, user_request); + reg_update_last_request(user_request); user_alpha2[0] = user_request->alpha2[0]; user_alpha2[1] = user_request->alpha2[1]; @@ -1505,8 +1508,7 @@ reg_process_hint_driver(struct wiphy *wiphy, driver_request->intersect = treatment == REG_REQ_INTERSECT; driver_request->processed = false; - reg_kfree_last_request(); - rcu_assign_pointer(last_request, driver_request); + reg_update_last_request(driver_request); /* * Since CRDA will not be called in this case as we already @@ -1604,8 +1606,7 @@ reg_process_hint_country_ie(struct wiphy *wiphy, country_ie_request->intersect = false; country_ie_request->processed = false; - reg_kfree_last_request(); - rcu_assign_pointer(last_request, country_ie_request); + reg_update_last_request(country_ie_request); if (call_crda(country_ie_request->alpha2)) return REG_REQ_IGNORE; -- cgit v1.2.3-70-g09d2 From fe6631ff093150eabc4ab73b948577e9b3bc5b76 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 5 Nov 2013 09:18:10 -0800 Subject: cfg80211: add helper for calling CRDA All the regulatory request process routines use the same pattern. Signed-off-by: Luis R. Rodriguez Signed-off-by: Johannes Berg --- net/wireless/reg.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index e93a078e5ae..130cfdaa7f4 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -462,6 +462,14 @@ static int call_crda(const char *alpha2) return kobject_uevent(®_pdev->dev.kobj, KOBJ_CHANGE); } +static enum reg_request_treatment +reg_call_crda(struct regulatory_request *request) +{ + if (call_crda(request->alpha2)) + return REG_REQ_IGNORE; + return REG_REQ_OK; +} + bool reg_is_valid_request(const char *alpha2) { struct regulatory_request *lr = get_last_request(); @@ -1371,9 +1379,7 @@ reg_process_hint_core(struct regulatory_request *core_request) reg_update_last_request(core_request); - if (call_crda(core_request->alpha2)) - return REG_REQ_IGNORE; - return REG_REQ_OK; + return reg_call_crda(core_request); } static enum reg_request_treatment @@ -1441,9 +1447,7 @@ reg_process_hint_user(struct regulatory_request *user_request) user_alpha2[0] = user_request->alpha2[0]; user_alpha2[1] = user_request->alpha2[1]; - if (call_crda(user_request->alpha2)) - return REG_REQ_IGNORE; - return REG_REQ_OK; + return reg_call_crda(user_request); } static enum reg_request_treatment @@ -1521,9 +1525,7 @@ reg_process_hint_driver(struct wiphy *wiphy, return treatment; } - if (call_crda(driver_request->alpha2)) - return REG_REQ_IGNORE; - return REG_REQ_OK; + return reg_call_crda(driver_request); } static enum reg_request_treatment @@ -1608,9 +1610,7 @@ reg_process_hint_country_ie(struct wiphy *wiphy, reg_update_last_request(country_ie_request); - if (call_crda(country_ie_request->alpha2)) - return REG_REQ_IGNORE; - return REG_REQ_OK; + return reg_call_crda(country_ie_request); } /* This processes *all* regulatory hints */ -- cgit v1.2.3-70-g09d2 From f75c30ef084fb57d3edab6722077e0adf16ed8fd Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 5 Nov 2013 09:18:11 -0800 Subject: cfg80211: allow only the core to request to update the world regdom It seems some out of tree drivers were using a regulatory_hint("00") to trigger off the wiphy regulatory notifier, for those cases just setting the WIPHY_FLAG_CUSTOM_REGULATORY would suffice to call the reg_notifier() for a world regulatory domain update. If drivers find other needs for calling the reg_notifier() a proper implemenation is preferred. Signed-off-by: Luis R. Rodriguez Signed-off-by: Johannes Berg --- net/wireless/reg.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 130cfdaa7f4..cd50bb56c7e 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -2200,6 +2200,8 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) return -EINVAL; if (is_world_regdom(rd->alpha2)) { + if (lr->initiator != NL80211_REGDOM_SET_BY_CORE) + return -EINVAL; update_world_regdomain(rd); return 0; } -- cgit v1.2.3-70-g09d2 From 0e3802dbfe53bc27a6bf019d022d743349a8d67d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 5 Nov 2013 09:18:12 -0800 Subject: cfg80211: move core reg_notfier() check to source Drivers that set the WIPHY_FLAG_CUSTOM_REGULATORY skip the core world regulatory domain updates, but do want their reg_notifier() called. Move the check for this closer to the source of the check that detected skipped was required and while at it add a helper for the notifier calling. This has no functional changes. This brings together the place where we call the reg_notifier() will be called. Signed-off-by: Luis R. Rodriguez Signed-off-by: Johannes Berg --- net/wireless/reg.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index cd50bb56c7e..38c252f9108 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1222,14 +1222,30 @@ static void reg_process_ht_flags(struct wiphy *wiphy) reg_process_ht_flags_band(wiphy, wiphy->bands[band]); } +static void reg_call_notifier(struct wiphy *wiphy, + struct regulatory_request *request) +{ + if (wiphy->reg_notifier) + wiphy->reg_notifier(wiphy, request); +} + static void wiphy_update_regulatory(struct wiphy *wiphy, enum nl80211_reg_initiator initiator) { enum ieee80211_band band; struct regulatory_request *lr = get_last_request(); - if (ignore_reg_update(wiphy, initiator)) + if (ignore_reg_update(wiphy, initiator)) { + /* + * Regulatory updates set by CORE are ignored for custom + * regulatory cards. Let us notify the changes to the driver, + * as some drivers used this to restore its orig_* reg domain. + */ + if (initiator == NL80211_REGDOM_SET_BY_CORE && + wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) + reg_call_notifier(wiphy, lr); return; + } lr->dfs_region = get_cfg80211_regdom()->dfs_region; @@ -1238,9 +1254,7 @@ static void wiphy_update_regulatory(struct wiphy *wiphy, reg_process_beacons(wiphy); reg_process_ht_flags(wiphy); - - if (wiphy->reg_notifier) - wiphy->reg_notifier(wiphy, lr); + reg_call_notifier(wiphy, lr); } static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator) @@ -1253,15 +1267,6 @@ static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator) list_for_each_entry(rdev, &cfg80211_rdev_list, list) { wiphy = &rdev->wiphy; wiphy_update_regulatory(wiphy, initiator); - /* - * Regulatory updates set by CORE are ignored for custom - * regulatory cards. Let us notify the changes to the driver, - * as some drivers used this to restore its orig_* reg domain. - */ - if (initiator == NL80211_REGDOM_SET_BY_CORE && - wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY && - wiphy->reg_notifier) - wiphy->reg_notifier(wiphy, get_last_request()); } } -- cgit v1.2.3-70-g09d2 From db0e066a986e025781dcd4c05dc4cf480ae884b6 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 5 Nov 2013 09:18:13 -0800 Subject: cfg80211: pass the last_request to __set_regdom() last_request is RCU protected, since we're getting it on set_regdom() we might as well pass it to ensure the same request is being processed, otherwise there is a small race it could have changed. This makes processing of the request atomic. Signed-off-by: Luis R. Rodriguez Signed-off-by: Johannes Berg --- net/wireless/reg.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 38c252f9108..ca11f31b3be 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -2192,12 +2192,12 @@ static void print_regdomain_info(const struct ieee80211_regdomain *rd) } /* Takes ownership of rd only if it doesn't fail */ -static int __set_regdom(const struct ieee80211_regdomain *rd) +static int __set_regdom(const struct ieee80211_regdomain *rd, + struct regulatory_request *lr) { const struct ieee80211_regdomain *regd; const struct ieee80211_regdomain *intersected_rd = NULL; struct wiphy *request_wiphy; - struct regulatory_request *lr = get_last_request(); /* Some basic sanity checks first */ @@ -2323,7 +2323,7 @@ int set_regdom(const struct ieee80211_regdomain *rd) lr = get_last_request(); /* Note that this doesn't update the wiphys, this is done below */ - r = __set_regdom(rd); + r = __set_regdom(rd, lr); if (r) { if (r == -EALREADY) reg_set_request_processed(); -- cgit v1.2.3-70-g09d2 From 3b9e5aca461ff3c83fb29ff021af19c127efa351 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 5 Nov 2013 09:18:14 -0800 Subject: cfg80211: set core regulatory updates on its own This splits up the core regulatory update to be set on its own helper. This should make it easier to read exactly what type of requests should be expected there. In this case its clear that NL80211_REGDOM_SET_BY_CORE is only used by the core for updating the world regulatory domain. This is consistant with the nl80211.h documentation. Signed-off-by: Luis R. Rodriguez [add warning to default switch case to avoid compiler warning] Signed-off-by: Johannes Berg --- net/wireless/reg.c | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index ca11f31b3be..9f4f8439e16 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -2191,6 +2191,14 @@ static void print_regdomain_info(const struct ieee80211_regdomain *rd) print_rd_rules(rd); } +static int reg_set_rd_core(const struct ieee80211_regdomain *rd) +{ + if (!is_world_regdom(rd->alpha2)) + return -EINVAL; + update_world_regdomain(rd); + return 0; +} + /* Takes ownership of rd only if it doesn't fail */ static int __set_regdom(const struct ieee80211_regdomain *rd, struct regulatory_request *lr) @@ -2199,18 +2207,6 @@ static int __set_regdom(const struct ieee80211_regdomain *rd, const struct ieee80211_regdomain *intersected_rd = NULL; struct wiphy *request_wiphy; - /* Some basic sanity checks first */ - - if (!reg_is_valid_request(rd->alpha2)) - return -EINVAL; - - if (is_world_regdom(rd->alpha2)) { - if (lr->initiator != NL80211_REGDOM_SET_BY_CORE) - return -EINVAL; - update_world_regdomain(rd); - return 0; - } - if (!is_alpha2_set(rd->alpha2) && !is_an_alpha2(rd->alpha2) && !is_unknown_alpha2(rd->alpha2)) return -EINVAL; @@ -2320,10 +2316,28 @@ int set_regdom(const struct ieee80211_regdomain *rd) struct regulatory_request *lr; int r; + if (!reg_is_valid_request(rd->alpha2)) { + kfree(rd); + return -EINVAL; + } + lr = get_last_request(); /* Note that this doesn't update the wiphys, this is done below */ - r = __set_regdom(rd, lr); + switch (lr->initiator) { + case NL80211_REGDOM_SET_BY_CORE: + r = reg_set_rd_core(rd); + break; + case NL80211_REGDOM_SET_BY_USER: + case NL80211_REGDOM_SET_BY_DRIVER: + case NL80211_REGDOM_SET_BY_COUNTRY_IE: + r = __set_regdom(rd, lr); + break; + default: + WARN(1, "invalid initiator %d\n", lr->initiator); + return -EINVAL; + } + if (r) { if (r == -EALREADY) reg_set_request_processed(); -- cgit v1.2.3-70-g09d2 From 84721d44906f9a4ee8b0d41b31fcc9f45295c3a6 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 5 Nov 2013 09:18:15 -0800 Subject: cfg80211: set user regulatory updates on its own This splits out the user regulatory update on its own, this helps simplify reading the case. Signed-off-by: Luis R. Rodriguez Signed-off-by: Johannes Berg --- net/wireless/reg.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 9f4f8439e16..1f6abba6027 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -2199,6 +2199,39 @@ static int reg_set_rd_core(const struct ieee80211_regdomain *rd) return 0; } +static int reg_set_rd_user(const struct ieee80211_regdomain *rd, + struct regulatory_request *user_request) +{ + const struct ieee80211_regdomain *intersected_rd = NULL; + + if (is_world_regdom(rd->alpha2)) + return -EINVAL; + + if (!regdom_changes(rd->alpha2)) + return -EALREADY; + + if (!is_valid_rd(rd)) { + pr_err("Invalid regulatory domain detected:\n"); + print_regdomain_info(rd); + return -EINVAL; + } + + if (!user_request->intersect) { + reset_regdomains(false, rd); + return 0; + } + + intersected_rd = regdom_intersect(rd, get_cfg80211_regdom()); + if (!intersected_rd) + return -EINVAL; + + kfree(rd); + rd = NULL; + reset_regdomains(false, intersected_rd); + + return 0; +} + /* Takes ownership of rd only if it doesn't fail */ static int __set_regdom(const struct ieee80211_regdomain *rd, struct regulatory_request *lr) @@ -2329,6 +2362,8 @@ int set_regdom(const struct ieee80211_regdomain *rd) r = reg_set_rd_core(rd); break; case NL80211_REGDOM_SET_BY_USER: + r = reg_set_rd_user(rd, lr); + break; case NL80211_REGDOM_SET_BY_DRIVER: case NL80211_REGDOM_SET_BY_COUNTRY_IE: r = __set_regdom(rd, lr); -- cgit v1.2.3-70-g09d2 From f5fe3247809815153e9fe88a989c251bd17059b9 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 5 Nov 2013 09:18:16 -0800 Subject: cfg80211: set driver regulatory updates on its own This splits up the driver regulatory update on its own, this helps simplify the reading the case. Signed-off-by: Luis R. Rodriguez Signed-off-by: Johannes Berg --- net/wireless/reg.c | 123 ++++++++++++++++++++++++----------------------------- 1 file changed, 56 insertions(+), 67 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 1f6abba6027..b622ab0be55 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -2232,38 +2232,19 @@ static int reg_set_rd_user(const struct ieee80211_regdomain *rd, return 0; } -/* Takes ownership of rd only if it doesn't fail */ -static int __set_regdom(const struct ieee80211_regdomain *rd, - struct regulatory_request *lr) +static int reg_set_rd_driver(const struct ieee80211_regdomain *rd, + struct regulatory_request *driver_request) { const struct ieee80211_regdomain *regd; const struct ieee80211_regdomain *intersected_rd = NULL; + const struct ieee80211_regdomain *tmp; struct wiphy *request_wiphy; - if (!is_alpha2_set(rd->alpha2) && !is_an_alpha2(rd->alpha2) && - !is_unknown_alpha2(rd->alpha2)) + if (is_world_regdom(rd->alpha2)) return -EINVAL; - /* - * Lets only bother proceeding on the same alpha2 if the current - * rd is non static (it means CRDA was present and was used last) - * and the pending request came in from a country IE - */ - if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) { - /* - * If someone else asked us to change the rd lets only bother - * checking if the alpha2 changes if CRDA was already called - */ - if (!regdom_changes(rd->alpha2)) - return -EALREADY; - } - - /* - * Now lets set the regulatory domain, update all driver channels - * and finally inform them of what we have done, in case they want - * to review or adjust their own settings based on their own - * internal EEPROM data - */ + if (!regdom_changes(rd->alpha2)) + return -EALREADY; if (!is_valid_rd(rd)) { pr_err("Invalid regulatory domain detected:\n"); @@ -2271,29 +2252,13 @@ static int __set_regdom(const struct ieee80211_regdomain *rd, return -EINVAL; } - request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx); - if (!request_wiphy && - (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER || - lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)) { + request_wiphy = wiphy_idx_to_wiphy(driver_request->wiphy_idx); + if (!request_wiphy) { schedule_delayed_work(®_timeout, 0); return -ENODEV; } - if (!lr->intersect) { - if (lr->initiator != NL80211_REGDOM_SET_BY_DRIVER) { - reset_regdomains(false, rd); - return 0; - } - - /* - * For a driver hint, lets copy the regulatory domain the - * driver wanted to the wiphy to deal with conflicts - */ - - /* - * Userspace could have sent two replies with only - * one kernel request. - */ + if (!driver_request->intersect) { if (request_wiphy->regd) return -EALREADY; @@ -2306,38 +2271,60 @@ static int __set_regdom(const struct ieee80211_regdomain *rd, return 0; } - /* Intersection requires a bit more work */ + intersected_rd = regdom_intersect(rd, get_cfg80211_regdom()); + if (!intersected_rd) + return -EINVAL; - if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) { - intersected_rd = regdom_intersect(rd, get_cfg80211_regdom()); - if (!intersected_rd) - return -EINVAL; + /* + * We can trash what CRDA provided now. + * However if a driver requested this specific regulatory + * domain we keep it for its private use + */ + tmp = get_wiphy_regdom(request_wiphy); + rcu_assign_pointer(request_wiphy->regd, rd); + rcu_free_regdom(tmp); - /* - * We can trash what CRDA provided now. - * However if a driver requested this specific regulatory - * domain we keep it for its private use - */ - if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER) { - const struct ieee80211_regdomain *tmp; + rd = NULL; - tmp = get_wiphy_regdom(request_wiphy); - rcu_assign_pointer(request_wiphy->regd, rd); - rcu_free_regdom(tmp); - } else { - kfree(rd); - } + reset_regdomains(false, intersected_rd); - rd = NULL; + return 0; +} + +/* Takes ownership of rd only if it doesn't fail */ +static int __set_regdom(const struct ieee80211_regdomain *rd, + struct regulatory_request *lr) +{ + struct wiphy *request_wiphy; - reset_regdomains(false, intersected_rd); + if (!is_alpha2_set(rd->alpha2) && !is_an_alpha2(rd->alpha2) && + !is_unknown_alpha2(rd->alpha2)) + return -EINVAL; - return 0; + /* + * Lets only bother proceeding on the same alpha2 if the current + * rd is non static (it means CRDA was present and was used last) + * and the pending request came in from a country IE + */ + + if (!is_valid_rd(rd)) { + pr_err("Invalid regulatory domain detected:\n"); + print_regdomain_info(rd); + return -EINVAL; } - return -EINVAL; -} + request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx); + if (!request_wiphy) { + schedule_delayed_work(®_timeout, 0); + return -ENODEV; + } + if (lr->intersect) + return -EINVAL; + + reset_regdomains(false, rd); + return 0; +} /* * Use this call to set the current regulatory domain. Conflicts with @@ -2365,6 +2352,8 @@ int set_regdom(const struct ieee80211_regdomain *rd) r = reg_set_rd_user(rd, lr); break; case NL80211_REGDOM_SET_BY_DRIVER: + r = reg_set_rd_driver(rd, lr); + break; case NL80211_REGDOM_SET_BY_COUNTRY_IE: r = __set_regdom(rd, lr); break; -- cgit v1.2.3-70-g09d2 From 01992406d3be60bbd6e19797385ac452bdc8ecc8 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 5 Nov 2013 09:18:17 -0800 Subject: cfg80211: rename __set_regdom() to reg_set_rd_country_ie() This reflects that case is now completely separated. Signed-off-by: Luis R. Rodriguez Signed-off-by: Johannes Berg --- net/wireless/reg.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index b622ab0be55..a75c5eddd25 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -2291,9 +2291,8 @@ static int reg_set_rd_driver(const struct ieee80211_regdomain *rd, return 0; } -/* Takes ownership of rd only if it doesn't fail */ -static int __set_regdom(const struct ieee80211_regdomain *rd, - struct regulatory_request *lr) +static int reg_set_rd_country_ie(const struct ieee80211_regdomain *rd, + struct regulatory_request *country_ie_request) { struct wiphy *request_wiphy; @@ -2313,13 +2312,13 @@ static int __set_regdom(const struct ieee80211_regdomain *rd, return -EINVAL; } - request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx); + request_wiphy = wiphy_idx_to_wiphy(country_ie_request->wiphy_idx); if (!request_wiphy) { schedule_delayed_work(®_timeout, 0); return -ENODEV; } - if (lr->intersect) + if (country_ie_request->intersect) return -EINVAL; reset_regdomains(false, rd); @@ -2355,7 +2354,7 @@ int set_regdom(const struct ieee80211_regdomain *rd) r = reg_set_rd_driver(rd, lr); break; case NL80211_REGDOM_SET_BY_COUNTRY_IE: - r = __set_regdom(rd, lr); + r = reg_set_rd_country_ie(rd, lr); break; default: WARN(1, "invalid initiator %d\n", lr->initiator); -- cgit v1.2.3-70-g09d2 From 3751c4edc6275e345d5978b1cb92265945399f69 Mon Sep 17 00:00:00 2001 From: Karl Beldan Date: Mon, 11 Nov 2013 13:29:33 +0100 Subject: mac80211_hwsim: claim CCK support for HT clients Signed-off-by: Karl Beldan Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index bd7dd0d242d..8c7f4ab70d2 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2352,7 +2352,8 @@ static int __init init_mac80211_hwsim(void) IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | IEEE80211_HW_AMPDU_AGGREGATION | IEEE80211_HW_WANT_MONITOR_VIF | - IEEE80211_HW_QUEUE_CONTROL; + IEEE80211_HW_QUEUE_CONTROL | + IEEE80211_HW_SUPPORTS_HT_CCK_RATES; if (rctbl) hw->flags |= IEEE80211_HW_SUPPORTS_RC_TABLE; -- cgit v1.2.3-70-g09d2 From ca91dc97b8a0ffd05721806654eaff2cf13ba5cb Mon Sep 17 00:00:00 2001 From: Chun-Yeow Yeoh Date: Tue, 12 Nov 2013 10:31:48 +0800 Subject: mac80211: use put_unaligned_le16 for precedence value in mesh use put_unaligned_le16 for precedence value in mesh channel switch support Signed-off-by: Chun-Yeow Yeoh Signed-off-by: Johannes Berg --- net/mac80211/mesh.c | 5 +---- net/mac80211/util.c | 4 +--- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 896fe3bd599..e0538b92083 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -674,8 +674,6 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) rcu_read_lock(); csa = rcu_dereference(ifmsh->csa); if (csa) { - __le16 pre_value; - pos = skb_put(skb, 13); memset(pos, 0, 13); *pos++ = WLAN_EID_CHANNEL_SWITCH; @@ -697,8 +695,7 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00; put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos); pos += 2; - pre_value = cpu_to_le16(ifmsh->pre_value); - memcpy(pos, &pre_value, 2); + put_unaligned_le16(ifmsh->pre_value, pos); pos += 2; } rcu_read_unlock(); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 5dfa41abdf8..bb92f8e0f84 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2450,7 +2450,6 @@ int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata, if (ieee80211_vif_is_mesh(&sdata->vif)) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; - __le16 pre_value; skb_put(skb, 8); *pos++ = WLAN_EID_CHAN_SWITCH_PARAM; /* EID */ @@ -2466,8 +2465,7 @@ int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata, ifmsh->pre_value = 1; else ifmsh->pre_value++; - pre_value = cpu_to_le16(ifmsh->pre_value); - memcpy(pos, &pre_value, 2); /* Precedence Value */ + put_unaligned_le16(ifmsh->pre_value, pos);/* Precedence Value */ pos += 2; ifmsh->chsw_init = true; } -- cgit v1.2.3-70-g09d2 From a2f73b6c5db3c272d87eaebb5bed355d75a0f25f Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 11 Nov 2013 22:15:29 +0100 Subject: cfg80211: move regulatory flags to their own variable We'll expand this later, this will make it easier to classify and review what things are related to regulatory or not. Coccinelle only missed 4 hits, which I had to do manually, supplying the SmPL in case of merge conflicts. @@ struct wiphy *wiphy; @@ -wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY +wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG @@ expression e; @@ -e->flags |= WIPHY_FLAG_CUSTOM_REGULATORY +e->regulatory_flags |= REGULATORY_CUSTOM_REG @@ struct wiphy *wiphy; @@ -wiphy->flags &= ~WIPHY_FLAG_CUSTOM_REGULATORY +wiphy->regulatory_flags &= ~REGULATORY_CUSTOM_REG @@ struct wiphy *wiphy; @@ -wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY +wiphy->regulatory_flags & REGULATORY_CUSTOM_REG @@ struct wiphy *wiphy; @@ -wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY +wiphy->regulatory_flags |= REGULATORY_STRICT_REG @@ expression e; @@ -e->flags |= WIPHY_FLAG_STRICT_REGULATORY +e->regulatory_flags |= REGULATORY_STRICT_REG @@ struct wiphy *wiphy; @@ -wiphy->flags &= ~WIPHY_FLAG_STRICT_REGULATORY +wiphy->regulatory_flags &= ~REGULATORY_STRICT_REG @@ struct wiphy *wiphy; @@ -wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY +wiphy->regulatory_flags & REGULATORY_STRICT_REG @@ struct wiphy *wiphy; @@ -wiphy->flags |= WIPHY_FLAG_DISABLE_BEACON_HINTS +wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS @@ expression e; @@ -e->flags |= WIPHY_FLAG_DISABLE_BEACON_HINTS +e->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS @@ struct wiphy *wiphy; @@ -wiphy->flags &= ~WIPHY_FLAG_DISABLE_BEACON_HINTS +wiphy->regulatory_flags &= ~REGULATORY_DISABLE_BEACON_HINTS @@ struct wiphy *wiphy; @@ -wiphy->flags & WIPHY_FLAG_DISABLE_BEACON_HINTS +wiphy->regulatory_flags & REGULATORY_DISABLE_BEACON_HINTS Generated-by: Coccinelle SmPL Cc: Julia Lawall Cc: Peter Senna Tschudin Cc: Mihir Shete Cc: Henri Bahini Cc: Tushnim Bhattacharyya Signed-off-by: Luis R. Rodriguez [fix up whitespace damage, overly long lines] Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/regd.c | 4 +- .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 2 +- drivers/net/wireless/brcm80211/brcmsmac/channel.c | 4 +- drivers/net/wireless/iwlegacy/3945-mac.c | 6 +-- drivers/net/wireless/iwlegacy/4965-mac.c | 6 +-- drivers/net/wireless/iwlwifi/dvm/mac80211.c | 6 +-- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 6 +-- drivers/net/wireless/mac80211_hwsim.c | 25 +++++---- drivers/net/wireless/mwifiex/cfg80211.c | 5 +- drivers/net/wireless/rtlwifi/regd.c | 6 +-- include/net/cfg80211.h | 33 +++--------- include/net/regulatory.h | 59 +++++++++++++++++----- net/wireless/core.c | 2 +- net/wireless/reg.c | 32 ++++++------ 14 files changed, 108 insertions(+), 88 deletions(-) diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index e93e517a699..aba782cd09a 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -601,7 +601,7 @@ ath_regd_init_wiphy(struct ath_regulatory *reg, const struct ieee80211_regdomain *regd; wiphy->reg_notifier = reg_notifier; - wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY; + wiphy->regulatory_flags |= REGULATORY_STRICT_REG; if (ath_is_world_regd(reg)) { /* @@ -609,7 +609,7 @@ ath_regd_init_wiphy(struct ath_regulatory *reg, * saved on the wiphy orig_* parameters */ regd = ath_world_regdomain(reg); - wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; + wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; } else { /* * This gets applied in the case of the absence of CRDA, diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index b6a09f97f9a..1850efa83cf 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -4341,7 +4341,7 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev) wiphy->max_remain_on_channel_duration = 5000; brcmf_wiphy_pno_params(wiphy); brcmf_dbg(INFO, "Registering custom regulatory\n"); - wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; + wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom); err = wiphy_register(wiphy); if (err < 0) { diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/brcm80211/brcmsmac/channel.c index 7d8f3fd69a8..ef05df04136 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/channel.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.c @@ -766,8 +766,8 @@ void brcms_c_regd_init(struct brcms_c_info *wlc) } wlc->wiphy->reg_notifier = brcms_reg_notifier; - wlc->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY | - WIPHY_FLAG_STRICT_REGULATORY; + wlc->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG | + REGULATORY_STRICT_REG; wiphy_apply_custom_regulatory(wlc->wiphy, regd->regdomain); brcms_reg_apply_beaconing_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER); } diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c index 5a66595b0fa..5c3bcedd679 100644 --- a/drivers/net/wireless/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/iwlegacy/3945-mac.c @@ -3575,9 +3575,9 @@ il3945_setup_mac(struct il_priv *il) hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); - hw->wiphy->flags |= - WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_DISABLE_BEACON_HINTS | - WIPHY_FLAG_IBSS_RSN; + hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG | + REGULATORY_DISABLE_BEACON_HINTS; hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c index 1c5f8cdbd3a..43f488a8cda 100644 --- a/drivers/net/wireless/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/iwlegacy/4965-mac.c @@ -5778,9 +5778,9 @@ il4965_mac_setup_register(struct il_priv *il, u32 max_probe_length) hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); - hw->wiphy->flags |= - WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_DISABLE_BEACON_HINTS | - WIPHY_FLAG_IBSS_RSN; + hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG | + REGULATORY_DISABLE_BEACON_HINTS; /* * For now, disable PS by default because it affects diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index cae4d3182e3..217f1ca321a 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c @@ -155,9 +155,9 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, ARRAY_SIZE(iwlagn_iface_combinations_dualmode); } - hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY | - WIPHY_FLAG_DISABLE_BEACON_HINTS | - WIPHY_FLAG_IBSS_RSN; + hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG | + REGULATORY_DISABLE_BEACON_HINTS; #ifdef CONFIG_PM_SLEEP if (priv->fw->img[IWL_UCODE_WOWLAN].sec[0].len && diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 74bc2c8af06..b56c989ad78 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -199,9 +199,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 8) hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC); - hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY | - WIPHY_FLAG_DISABLE_BEACON_HINTS | - WIPHY_FLAG_IBSS_RSN; + hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG | + REGULATORY_DISABLE_BEACON_HINTS; hw->wiphy->iface_combinations = iwl_mvm_iface_combinations; hw->wiphy->n_iface_combinations = diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 8c7f4ab70d2..bcc7d8208f2 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2456,46 +2456,53 @@ static int __init init_mac80211_hwsim(void) break; case HWSIM_REGTEST_WORLD_ROAM: if (i == 0) { - hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; + hw->wiphy->regulatory_flags |= + REGULATORY_CUSTOM_REG; wiphy_apply_custom_regulatory(hw->wiphy, &hwsim_world_regdom_custom_01); } break; case HWSIM_REGTEST_CUSTOM_WORLD: - hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; + hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; wiphy_apply_custom_regulatory(hw->wiphy, &hwsim_world_regdom_custom_01); break; case HWSIM_REGTEST_CUSTOM_WORLD_2: if (i == 0) { - hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; + hw->wiphy->regulatory_flags |= + REGULATORY_CUSTOM_REG; wiphy_apply_custom_regulatory(hw->wiphy, &hwsim_world_regdom_custom_01); } else if (i == 1) { - hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; + hw->wiphy->regulatory_flags |= + REGULATORY_CUSTOM_REG; wiphy_apply_custom_regulatory(hw->wiphy, &hwsim_world_regdom_custom_02); } break; case HWSIM_REGTEST_STRICT_ALL: - hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY; + hw->wiphy->regulatory_flags |= REGULATORY_STRICT_REG; break; case HWSIM_REGTEST_STRICT_FOLLOW: case HWSIM_REGTEST_STRICT_AND_DRIVER_REG: if (i == 0) - hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY; + hw->wiphy->regulatory_flags |= + REGULATORY_STRICT_REG; break; case HWSIM_REGTEST_ALL: if (i == 0) { - hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; + hw->wiphy->regulatory_flags |= + REGULATORY_CUSTOM_REG; wiphy_apply_custom_regulatory(hw->wiphy, &hwsim_world_regdom_custom_01); } else if (i == 1) { - hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; + hw->wiphy->regulatory_flags |= + REGULATORY_CUSTOM_REG; wiphy_apply_custom_regulatory(hw->wiphy, &hwsim_world_regdom_custom_02); } else if (i == 4) - hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY; + hw->wiphy->regulatory_flags |= + REGULATORY_STRICT_REG; break; default: break; diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 7f68943f02c..d6d1d91a26d 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -2687,9 +2687,10 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD | WIPHY_FLAG_AP_UAPSD | - WIPHY_FLAG_CUSTOM_REGULATORY | - WIPHY_FLAG_STRICT_REGULATORY | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + wiphy->regulatory_flags |= + REGULATORY_CUSTOM_REG | + REGULATORY_STRICT_REG; wiphy_apply_custom_regulatory(wiphy, &mwifiex_world_regdom_custom); diff --git a/drivers/net/wireless/rtlwifi/regd.c b/drivers/net/wireless/rtlwifi/regd.c index 8453c53143f..89e36568e70 100644 --- a/drivers/net/wireless/rtlwifi/regd.c +++ b/drivers/net/wireless/rtlwifi/regd.c @@ -344,9 +344,9 @@ static int _rtl_regd_init_wiphy(struct rtl_regulatory *reg, wiphy->reg_notifier = reg_notifier; - wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; - wiphy->flags &= ~WIPHY_FLAG_STRICT_REGULATORY; - wiphy->flags &= ~WIPHY_FLAG_DISABLE_BEACON_HINTS; + wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; + wiphy->regulatory_flags &= ~REGULATORY_STRICT_REG; + wiphy->regulatory_flags &= ~REGULATORY_DISABLE_BEACON_HINTS; regd = _rtl_regdomain_select(reg); wiphy_apply_custom_regulatory(wiphy, regd); diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 968f2ad40cc..bacc5033f0b 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2437,29 +2437,6 @@ struct cfg80211_ops { /** * enum wiphy_flags - wiphy capability flags * - * @WIPHY_FLAG_CUSTOM_REGULATORY: tells us the driver for this device - * has its own custom regulatory domain and cannot identify the - * ISO / IEC 3166 alpha2 it belongs to. When this is enabled - * we will disregard the first regulatory hint (when the - * initiator is %REGDOM_SET_BY_CORE). Drivers that use - * wiphy_apply_custom_regulatory() should have this flag set - * or the regulatory core will set it for wiphy. - * @WIPHY_FLAG_STRICT_REGULATORY: tells us the driver for this device will - * ignore regulatory domain settings until it gets its own regulatory - * domain via its regulatory_hint() unless the regulatory hint is - * from a country IE. After its gets its own regulatory domain it will - * only allow further regulatory domain settings to further enhance - * compliance. For example if channel 13 and 14 are disabled by this - * regulatory domain no user regulatory domain can enable these channels - * at a later time. This can be used for devices which do not have - * calibration information guaranteed for frequencies or settings - * outside of its regulatory domain. If used in combination with - * WIPHY_FLAG_CUSTOM_REGULATORY the inspected country IE power settings - * will be followed. - * @WIPHY_FLAG_DISABLE_BEACON_HINTS: enable this if your driver needs to ensure - * that passive scan flags and beaconing flags may not be lifted by - * cfg80211 due to regulatory beacon hints. For more information on beacon - * hints read the documenation for regulatory_hint_found_beacon() * @WIPHY_FLAG_NETNS_OK: if not set, do not allow changing the netns of this * wiphy at all * @WIPHY_FLAG_PS_ON_BY_DEFAULT: if set to true, powersave will be enabled @@ -2498,9 +2475,9 @@ struct cfg80211_ops { * beaconing mode (AP, IBSS, Mesh, ...). */ enum wiphy_flags { - WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0), - WIPHY_FLAG_STRICT_REGULATORY = BIT(1), - WIPHY_FLAG_DISABLE_BEACON_HINTS = BIT(2), + /* use hole at 0 */ + /* use hole at 1 */ + /* use hole at 2 */ WIPHY_FLAG_NETNS_OK = BIT(3), WIPHY_FLAG_PS_ON_BY_DEFAULT = BIT(4), WIPHY_FLAG_4ADDR_AP = BIT(5), @@ -2722,6 +2699,8 @@ struct wiphy_coalesce_support { * @software_iftypes: bitmask of software interface types, these are not * subject to any restrictions since they are purely managed in SW. * @flags: wiphy flags, see &enum wiphy_flags + * @regulatory_flags: wiphy regulatory flags, see + * &enum ieee80211_regulatory_flags * @features: features advertised to nl80211, see &enum nl80211_feature_flags. * @bss_priv_size: each BSS struct has private data allocated with it, * this variable determines its size @@ -2810,7 +2789,7 @@ struct wiphy { u16 max_acl_mac_addrs; - u32 flags, features; + u32 flags, regulatory_flags, features; u32 ap_sme_capa; diff --git a/include/net/regulatory.h b/include/net/regulatory.h index f17ed590d64..a6a20e2a54c 100644 --- a/include/net/regulatory.h +++ b/include/net/regulatory.h @@ -38,17 +38,17 @@ enum environment_cap { * * @rcu_head: RCU head struct used to free the request * @wiphy_idx: this is set if this request's initiator is - * %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This - * can be used by the wireless core to deal with conflicts - * and potentially inform users of which devices specifically - * cased the conflicts. + * %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This + * can be used by the wireless core to deal with conflicts + * and potentially inform users of which devices specifically + * cased the conflicts. * @initiator: indicates who sent this request, could be any of - * of those set in nl80211_reg_initiator (%NL80211_REGDOM_SET_BY_*) + * of those set in nl80211_reg_initiator (%NL80211_REGDOM_SET_BY_*) * @alpha2: the ISO / IEC 3166 alpha2 country code of the requested - * regulatory domain. We have a few special codes: - * 00 - World regulatory domain - * 99 - built by driver but a specific alpha2 cannot be determined - * 98 - result of an intersection between two regulatory domains + * regulatory domain. We have a few special codes: + * 00 - World regulatory domain + * 99 - built by driver but a specific alpha2 cannot be determined + * 98 - result of an intersection between two regulatory domains * 97 - regulatory domain has not yet been configured * @dfs_region: If CRDA responded with a regulatory domain that requires * DFS master operation on a known DFS region (NL80211_DFS_*), @@ -59,8 +59,8 @@ enum environment_cap { * of hint passed. This could be any of the %NL80211_USER_REG_HINT_* * types. * @intersect: indicates whether the wireless core should intersect - * the requested regulatory domain with the presently set regulatory - * domain. + * the requested regulatory domain with the presently set regulatory + * domain. * @processed: indicates whether or not this requests has already been * processed. When the last request is processed it means that the * currently regulatory domain set on cfg80211 is updated from @@ -68,9 +68,9 @@ enum environment_cap { * the last request is not yet processed we must yield until it * is processed before processing any new requests. * @country_ie_checksum: checksum of the last processed and accepted - * country IE + * country IE * @country_ie_env: lets us know if the AP is telling us we are outdoor, - * indoor, or if it doesn't matter + * indoor, or if it doesn't matter * @list: used to insert into the reg_requests_list linked list */ struct regulatory_request { @@ -86,6 +86,39 @@ struct regulatory_request { struct list_head list; }; +/** + * enum ieee80211_regulatory_flags - device regulatory flags + * + * @REGULATORY_CUSTOM_REG: tells us the driver for this device + * has its own custom regulatory domain and cannot identify the + * ISO / IEC 3166 alpha2 it belongs to. When this is enabled + * we will disregard the first regulatory hint (when the + * initiator is %REGDOM_SET_BY_CORE). Drivers that use + * wiphy_apply_custom_regulatory() should have this flag set + * or the regulatory core will set it for the wiphy. + * @REGULATORY_STRICT_REG: tells us the driver for this device will + * ignore regulatory domain settings until it gets its own regulatory + * domain via its regulatory_hint() unless the regulatory hint is + * from a country IE. After its gets its own regulatory domain it will + * only allow further regulatory domain settings to further enhance + * compliance. For example if channel 13 and 14 are disabled by this + * regulatory domain no user regulatory domain can enable these channels + * at a later time. This can be used for devices which do not have + * calibration information guaranteed for frequencies or settings + * outside of its regulatory domain. If used in combination with + * REGULATORY_FLAG_CUSTOM_REG the inspected country IE power settings + * will be followed. + * @REGULATORY_DISABLE_BEACON_HINTS: enable this if your driver needs to + * ensure that passive scan flags and beaconing flags may not be lifted by + * cfg80211 due to regulatory beacon hints. For more information on beacon + * hints read the documenation for regulatory_hint_found_beacon() + */ +enum ieee80211_regulatory_flags { + REGULATORY_CUSTOM_REG = BIT(0), + REGULATORY_STRICT_REG = BIT(1), + REGULATORY_DISABLE_BEACON_HINTS = BIT(2), +}; + struct ieee80211_freq_range { u32 start_freq_khz; u32 end_freq_khz; diff --git a/net/wireless/core.c b/net/wireless/core.c index 9dca0925a1a..fc968c861ee 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -586,7 +586,7 @@ int wiphy_register(struct wiphy *wiphy) if (IS_ERR(rdev->wiphy.debugfsdir)) rdev->wiphy.debugfsdir = NULL; - if (wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) { + if (wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) { struct regulatory_request request; request.wiphy_idx = get_wiphy_idx(wiphy); diff --git a/net/wireless/reg.c b/net/wireless/reg.c index a75c5eddd25..e44b4bb20b9 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -868,7 +868,7 @@ static void handle_channel(struct wiphy *wiphy, if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER && request_wiphy && request_wiphy == wiphy && - request_wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) { + request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) { REG_DBG_PRINT("Disabling freq %d MHz for good\n", chan->center_freq); chan->orig_flags |= IEEE80211_CHAN_DISABLED; @@ -895,7 +895,7 @@ static void handle_channel(struct wiphy *wiphy, if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER && request_wiphy && request_wiphy == wiphy && - request_wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) { + request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) { /* * This guarantees the driver's requested regulatory domain * will always be used as a base for further regulatory @@ -922,12 +922,12 @@ static void handle_channel(struct wiphy *wiphy, if (chan->orig_mpwr) { /* * Devices that have their own custom regulatory domain - * but also use WIPHY_FLAG_STRICT_REGULATORY will follow the + * but also use REGULATORY_STRICT_REG will follow the * passed country IE power settings. */ if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE && - wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY && - wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) + wiphy->regulatory_flags & REGULATORY_CUSTOM_REG && + wiphy->regulatory_flags & REGULATORY_STRICT_REG) chan->max_power = chan->max_reg_power; else chan->max_power = min(chan->orig_mpwr, @@ -997,8 +997,8 @@ static bool reg_dev_ignore_cell_hint(struct wiphy *wiphy) static bool wiphy_strict_alpha2_regd(struct wiphy *wiphy) { - if (wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY && - !(wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY)) + if (wiphy->regulatory_flags & REGULATORY_STRICT_REG && + !(wiphy->regulatory_flags & REGULATORY_CUSTOM_REG)) return true; return false; } @@ -1016,7 +1016,7 @@ static bool ignore_reg_update(struct wiphy *wiphy, } if (initiator == NL80211_REGDOM_SET_BY_CORE && - wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) { + wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) { REG_DBG_PRINT("Ignoring regulatory request set by %s " "since the driver uses its own custom " "regulatory domain\n", @@ -1054,7 +1054,7 @@ static bool reg_is_world_roaming(struct wiphy *wiphy) return true; if (lr && lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && - wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) + wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) return true; return false; @@ -1082,7 +1082,7 @@ static void handle_reg_beacon(struct wiphy *wiphy, unsigned int chan_idx, if (!reg_is_world_roaming(wiphy)) return; - if (wiphy->flags & WIPHY_FLAG_DISABLE_BEACON_HINTS) + if (wiphy->regulatory_flags & REGULATORY_DISABLE_BEACON_HINTS) return; chan_before.center_freq = chan->center_freq; @@ -1242,7 +1242,7 @@ static void wiphy_update_regulatory(struct wiphy *wiphy, * as some drivers used this to restore its orig_* reg domain. */ if (initiator == NL80211_REGDOM_SET_BY_CORE && - wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) + wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) reg_call_notifier(wiphy, lr); return; } @@ -1328,9 +1328,9 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy, enum ieee80211_band band; unsigned int bands_set = 0; - WARN(!(wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY), - "wiphy should have WIPHY_FLAG_CUSTOM_REGULATORY\n"); - wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; + WARN(!(wiphy->regulatory_flags & REGULATORY_CUSTOM_REG), + "wiphy should have REGULATORY_CUSTOM_REG\n"); + wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; for (band = 0; band < IEEE80211_NUM_BANDS; band++) { if (!wiphy->bands[band]) @@ -1659,7 +1659,7 @@ static void reg_process_hint(struct regulatory_request *reg_request) /* This is required so that the orig_* parameters are saved */ if (treatment == REG_REQ_ALREADY_SET && wiphy && - wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) + wiphy->regulatory_flags & REGULATORY_STRICT_REG) wiphy_update_regulatory(wiphy, reg_request->initiator); } @@ -1986,7 +1986,7 @@ static void restore_regulatory_settings(bool reset_user) world_alpha2[1] = cfg80211_world_regdom->alpha2[1]; list_for_each_entry(rdev, &cfg80211_rdev_list, list) { - if (rdev->wiphy.flags & WIPHY_FLAG_CUSTOM_REGULATORY) + if (rdev->wiphy.regulatory_flags & REGULATORY_CUSTOM_REG) restore_custom_reg_settings(&rdev->wiphy); } -- cgit v1.2.3-70-g09d2 From a09a85a013523a8b572dc5732b5c30e0785195f3 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 11 Nov 2013 22:15:30 +0100 Subject: cfg80211: add flags to define country IE processing rules 802.11 cards may have different country IE parsing behavioural preferences and vendors may want to support these. These preferences were managed by the REGULATORY_CUSTOM_REG and the REGULATORY_STRICT_REG flags and their combination. Instead of using this existing notation, split out the country IE behavioural preferences as a new flag. This will allow us to add more customizations easily and make the code more maintainable. Cc: Mihir Shete Cc: Henri Bahini Cc: Tushnim Bhattacharyya Signed-off-by: Luis R. Rodriguez [fix up conflicts] Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/regd.c | 3 ++- include/net/regulatory.h | 36 ++++++++++++++++++++++++------------ net/wireless/reg.c | 8 +++----- 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index aba782cd09a..bef5539192c 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -609,7 +609,8 @@ ath_regd_init_wiphy(struct ath_regulatory *reg, * saved on the wiphy orig_* parameters */ regd = ath_world_regdomain(reg); - wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; + wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG | + REGULATORY_COUNTRY_IE_FOLLOW_POWER; } else { /* * This gets applied in the case of the absence of CRDA, diff --git a/include/net/regulatory.h b/include/net/regulatory.h index a6a20e2a54c..b03ddee3341 100644 --- a/include/net/regulatory.h +++ b/include/net/regulatory.h @@ -96,27 +96,39 @@ struct regulatory_request { * initiator is %REGDOM_SET_BY_CORE). Drivers that use * wiphy_apply_custom_regulatory() should have this flag set * or the regulatory core will set it for the wiphy. - * @REGULATORY_STRICT_REG: tells us the driver for this device will - * ignore regulatory domain settings until it gets its own regulatory - * domain via its regulatory_hint() unless the regulatory hint is - * from a country IE. After its gets its own regulatory domain it will - * only allow further regulatory domain settings to further enhance - * compliance. For example if channel 13 and 14 are disabled by this - * regulatory domain no user regulatory domain can enable these channels - * at a later time. This can be used for devices which do not have - * calibration information guaranteed for frequencies or settings - * outside of its regulatory domain. If used in combination with - * REGULATORY_FLAG_CUSTOM_REG the inspected country IE power settings - * will be followed. + * @REGULATORY_STRICT_REG: tells us that the wiphy for this device + * has regulatory domain that it wishes to be considered as the + * superset for regulatory rules. After this device gets its regulatory + * domain programmed further regulatory hints shall only be considered + * for this device to enhance regulatory compliance, forcing the + * device to only possibly use subsets of the original regulatory + * rules. For example if channel 13 and 14 are disabled by this + * device's regulatory domain no user specified regulatory hint which + * has these channels enabled would enable them for this wiphy, + * the device's original regulatory domain will be trusted as the + * base. You can program the superset of regulatory rules for this + * wiphy with regulatory_hint() for cards programmed with an + * ISO3166-alpha2 country code. wiphys that use regulatory_hint() + * will have their wiphy->regd programmed once the regulatory + * domain is set, and all other regulatory hints will be ignored + * until their own regulatory domain gets programmed. * @REGULATORY_DISABLE_BEACON_HINTS: enable this if your driver needs to * ensure that passive scan flags and beaconing flags may not be lifted by * cfg80211 due to regulatory beacon hints. For more information on beacon * hints read the documenation for regulatory_hint_found_beacon() + * @REGULATORY_COUNTRY_IE_FOLLOW_POWER: for devices that have a preference + * that even though they may have programmed their own custom power + * setting prior to wiphy registration, they want to ensure their channel + * power settings are updated for this connection with the power settings + * derived from the regulatory domain. The regulatory domain used will be + * based on the ISO3166-alpha2 from country IE provided through + * regulatory_hint_country_ie() */ enum ieee80211_regulatory_flags { REGULATORY_CUSTOM_REG = BIT(0), REGULATORY_STRICT_REG = BIT(1), REGULATORY_DISABLE_BEACON_HINTS = BIT(2), + REGULATORY_COUNTRY_IE_FOLLOW_POWER = BIT(3), }; struct ieee80211_freq_range { diff --git a/net/wireless/reg.c b/net/wireless/reg.c index e44b4bb20b9..6b3051f6a8a 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -921,13 +921,11 @@ static void handle_channel(struct wiphy *wiphy, chan->max_reg_power = (int) MBM_TO_DBM(power_rule->max_eirp); if (chan->orig_mpwr) { /* - * Devices that have their own custom regulatory domain - * but also use REGULATORY_STRICT_REG will follow the - * passed country IE power settings. + * Devices that use REGULATORY_COUNTRY_IE_FOLLOW_POWER + * will always follow the passed country IE power settings. */ if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE && - wiphy->regulatory_flags & REGULATORY_CUSTOM_REG && - wiphy->regulatory_flags & REGULATORY_STRICT_REG) + wiphy->regulatory_flags & REGULATORY_COUNTRY_IE_FOLLOW_POWER) chan->max_power = chan->max_reg_power; else chan->max_power = min(chan->orig_mpwr, -- cgit v1.2.3-70-g09d2 From 2a901468c221e778af52603e006a53d286e81f90 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 11 Nov 2013 22:15:31 +0100 Subject: cfg80211: add an option to disable processing country IEs Certain vendors may want to disable the processing of country IEs so that they can continue using the regulatory domain the driver or user has set. Currently there is no way to stop the core from processing country IEs, so add support to the core to ignore country IE hints. Cc: Mihir Shete Cc: Henri Bahini Cc: Tushnim Bhattacharyya Signed-off-by: Luis R. Rodriguez Signed-off-by: Johannes Berg --- include/net/regulatory.h | 5 +++++ net/wireless/reg.c | 3 +++ 2 files changed, 8 insertions(+) diff --git a/include/net/regulatory.h b/include/net/regulatory.h index b03ddee3341..92ab80f69ef 100644 --- a/include/net/regulatory.h +++ b/include/net/regulatory.h @@ -123,12 +123,17 @@ struct regulatory_request { * derived from the regulatory domain. The regulatory domain used will be * based on the ISO3166-alpha2 from country IE provided through * regulatory_hint_country_ie() + * @REGULATORY_COUNTRY_IE_IGNORE: for devices that have a preference to ignore + * all country IE information processed by the regulatory core. This will + * override %REGULATORY_COUNTRY_IE_FOLLOW_POWER as all country IEs will + * be ignored. */ enum ieee80211_regulatory_flags { REGULATORY_CUSTOM_REG = BIT(0), REGULATORY_STRICT_REG = BIT(1), REGULATORY_DISABLE_BEACON_HINTS = BIT(2), REGULATORY_COUNTRY_IE_FOLLOW_POWER = BIT(3), + REGULATORY_COUNTRY_IE_IGNORE = BIT(4), }; struct ieee80211_freq_range { diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 6b3051f6a8a..067c1f63a1a 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1543,6 +1543,9 @@ __reg_process_hint_country_ie(struct wiphy *wiphy, if (regdom_changes(country_ie_request->alpha2)) return REG_REQ_IGNORE; return REG_REQ_ALREADY_SET; + } else { + if (wiphy->regulatory_flags & REGULATORY_COUNTRY_IE_IGNORE) + return REG_REQ_IGNORE; } if (unlikely(!is_an_alpha2(country_ie_request->alpha2))) -- cgit v1.2.3-70-g09d2 From 6f101ef04b77bcad71049e07007d34d14cab7b2f Mon Sep 17 00:00:00 2001 From: Chun-Yeow Yeoh Date: Wed, 13 Nov 2013 15:43:03 +0800 Subject: mac80211: use put_unaligned_le16 in mesh_plink_frame_tx Use put_unaligned_le16 in mesh_plink_frame_tx. Signed-off-by: Chun-Yeow Yeoh Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 4 ++-- net/mac80211/mesh_plink.c | 54 +++++++++++++++++++++++------------------------ net/mac80211/mesh_ps.c | 2 +- net/mac80211/sta_info.c | 2 +- net/mac80211/sta_info.h | 6 +++--- 5 files changed, 34 insertions(+), 34 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index f6b9265cf04..b2cbe7a533f 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -532,8 +532,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) STATION_INFO_PEER_PM | STATION_INFO_NONPEER_PM; - sinfo->llid = le16_to_cpu(sta->llid); - sinfo->plid = le16_to_cpu(sta->plid); + sinfo->llid = sta->llid; + sinfo->plid = sta->plid; sinfo->plink_state = sta->plink_state; if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) { sinfo->filled |= STATION_INFO_T_OFFSET; diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index fadc3e18913..cf83217103f 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -55,7 +55,7 @@ static const char * const mplevents[] = { static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, enum ieee80211_self_protected_actioncode action, - u8 *da, __le16 llid, __le16 plid, __le16 reason); + u8 *da, u16 llid, u16 plid, u16 reason); /* We only need a valid sta if user configured a minimum rssi_threshold. */ @@ -246,7 +246,7 @@ u32 mesh_plink_deactivate(struct sta_info *sta) spin_lock_bh(&sta->lock); changed = __mesh_plink_deactivate(sta); - sta->reason = cpu_to_le16(WLAN_REASON_MESH_PEER_CANCELED); + sta->reason = WLAN_REASON_MESH_PEER_CANCELED; mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, sta->sta.addr, sta->llid, sta->plid, sta->reason); @@ -257,7 +257,7 @@ u32 mesh_plink_deactivate(struct sta_info *sta) static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, enum ieee80211_self_protected_actioncode action, - u8 *da, __le16 llid, __le16 plid, __le16 reason) + u8 *da, u16 llid, u16 plid, u16 reason) { struct ieee80211_local *local = sdata->local; struct sk_buff *skb; @@ -305,7 +305,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, if (action == WLAN_SP_MESH_PEERING_CONFIRM) { /* AID */ pos = skb_put(skb, 2); - memcpy(pos + 2, &plid, 2); + put_unaligned_le16(plid, pos + 2); } if (ieee80211_add_srates_ie(sdata, skb, true, band) || ieee80211_add_ext_srates_ie(sdata, skb, true, band) || @@ -347,14 +347,14 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, *pos++ = ie_len; memcpy(pos, &peering_proto, 2); pos += 2; - memcpy(pos, &llid, 2); + put_unaligned_le16(llid, pos); pos += 2; if (include_plid) { - memcpy(pos, &plid, 2); + put_unaligned_le16(plid, pos); pos += 2; } if (action == WLAN_SP_MESH_PEERING_CLOSE) { - memcpy(pos, &reason, 2); + put_unaligned_le16(reason, pos); pos += 2; } @@ -534,7 +534,7 @@ out: static void mesh_plink_timer(unsigned long data) { struct sta_info *sta; - __le16 llid, plid, reason; + u16 reason = 0; struct ieee80211_sub_if_data *sdata; struct mesh_config *mshcfg; enum ieee80211_self_protected_actioncode action = 0; @@ -558,9 +558,6 @@ static void mesh_plink_timer(unsigned long data) mpl_dbg(sta->sdata, "Mesh plink timer for %pM fired on state %s\n", sta->sta.addr, mplstates[sta->plink_state]); - reason = 0; - llid = sta->llid; - plid = sta->plid; sdata = sta->sdata; mshcfg = &sdata->u.mesh.mshcfg; @@ -582,12 +579,12 @@ static void mesh_plink_timer(unsigned long data) action = WLAN_SP_MESH_PEERING_OPEN; break; } - reason = cpu_to_le16(WLAN_REASON_MESH_MAX_RETRIES); + reason = WLAN_REASON_MESH_MAX_RETRIES; /* fall through on else */ case NL80211_PLINK_CNF_RCVD: /* confirm timer */ if (!reason) - reason = cpu_to_le16(WLAN_REASON_MESH_CONFIRM_TIMEOUT); + reason = WLAN_REASON_MESH_CONFIRM_TIMEOUT; sta->plink_state = NL80211_PLINK_HOLDING; mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout); action = WLAN_SP_MESH_PEERING_CLOSE; @@ -603,7 +600,7 @@ static void mesh_plink_timer(unsigned long data) spin_unlock_bh(&sta->lock); if (action) mesh_plink_frame_tx(sdata, action, sta->sta.addr, - llid, plid, reason); + sta->llid, sta->plid, reason); } static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout) @@ -616,7 +613,7 @@ static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout) } static bool llid_in_use(struct ieee80211_sub_if_data *sdata, - __le16 llid) + u16 llid) { struct ieee80211_local *local = sdata->local; bool in_use = false; @@ -634,7 +631,7 @@ static bool llid_in_use(struct ieee80211_sub_if_data *sdata, return in_use; } -static __le16 mesh_get_new_llid(struct ieee80211_sub_if_data *sdata) +static u16 mesh_get_new_llid(struct ieee80211_sub_if_data *sdata) { u16 llid; @@ -642,9 +639,9 @@ static __le16 mesh_get_new_llid(struct ieee80211_sub_if_data *sdata) get_random_bytes(&llid, sizeof(llid)); /* for mesh PS we still only have the AID range for TIM bits */ llid = (llid % IEEE80211_MAX_AID) + 1; - } while (llid_in_use(sdata, cpu_to_le16(llid))); + } while (llid_in_use(sdata, llid)); - return cpu_to_le16(llid); + return llid; } u32 mesh_plink_open(struct sta_info *sta) @@ -695,9 +692,8 @@ static void mesh_plink_close(struct ieee80211_sub_if_data *sdata, { struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg; - __le16 reason = (event == CLS_ACPT) ? - cpu_to_le16(WLAN_REASON_MESH_CLOSE) : - cpu_to_le16(WLAN_REASON_MESH_CONFIG); + u16 reason = (event == CLS_ACPT) ? + WLAN_REASON_MESH_CLOSE : WLAN_REASON_MESH_CONFIG; sta->reason = reason; sta->plink_state = NL80211_PLINK_HOLDING; @@ -892,7 +888,7 @@ mesh_plink_get_event(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, struct ieee802_11_elems *elems, enum ieee80211_self_protected_actioncode ftype, - __le16 llid, __le16 plid) + u16 llid, u16 plid) { enum plink_event event = PLINK_UNDEFINED; u8 ie_len = elems->peering_len; @@ -990,7 +986,8 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, enum ieee80211_self_protected_actioncode ftype; u32 changed = 0; u8 ie_len = elems->peering_len; - __le16 plid, llid = 0; + __le16 _plid, _llid; + u16 plid, llid = 0; if (!elems->peering) { mpl_dbg(sdata, @@ -1024,10 +1021,13 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, /* Note the lines below are correct, the llid in the frame is the plid * from the point of view of this host. */ - memcpy(&plid, PLINK_GET_LLID(elems->peering), 2); + memcpy(&_plid, PLINK_GET_LLID(elems->peering), sizeof(__le16)); + plid = le16_to_cpu(_plid); if (ftype == WLAN_SP_MESH_PEERING_CONFIRM || - (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8)) - memcpy(&llid, PLINK_GET_PLID(elems->peering), 2); + (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8)) { + memcpy(&_llid, PLINK_GET_PLID(elems->peering), sizeof(__le16)); + llid = le16_to_cpu(_llid); + } /* WARNING: Only for sta pointer, is dropped & re-acquired */ rcu_read_lock(); @@ -1056,7 +1056,7 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, } else if (!sta && event == OPN_RJCT) { mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, mgmt->sa, 0, plid, - cpu_to_le16(WLAN_REASON_MESH_CONFIG)); + WLAN_REASON_MESH_CONFIG); goto unlock_rcu; } else if (!sta || event == PLINK_UNDEFINED) { /* something went wrong */ diff --git a/net/mac80211/mesh_ps.c b/net/mac80211/mesh_ps.c index 9493868ef6c..2802f9d9279 100644 --- a/net/mac80211/mesh_ps.c +++ b/net/mac80211/mesh_ps.c @@ -578,7 +578,7 @@ void ieee80211_mps_frame_release(struct sta_info *sta, if (sta->plink_state == NL80211_PLINK_ESTAB) has_buffered = ieee80211_check_tim(elems->tim, elems->tim_len, - le16_to_cpu(sta->llid)); + sta->llid); if (has_buffered) mps_dbg(sta->sdata, "%pM indicates buffered frames\n", diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 7a9151590cc..45b5f610674 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -631,7 +631,7 @@ void sta_info_recalc_tim(struct sta_info *sta) } else if (ieee80211_vif_is_mesh(&sta->sdata->vif)) { ps = &sta->sdata->u.mesh.ps; /* TIM map only for 1 <= PLID <= IEEE80211_MAX_AID */ - id = le16_to_cpu(sta->plid) % (IEEE80211_MAX_AID + 1); + id = sta->plid % (IEEE80211_MAX_AID + 1); #endif } else { return; diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 6b0d6c2dcba..a2c9a4c45aa 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -390,9 +390,9 @@ struct sta_info { * Mesh peer link attributes * TODO: move to a sub-structure that is referenced with pointer? */ - __le16 llid; - __le16 plid; - __le16 reason; + u16 llid; + u16 plid; + u16 reason; u8 plink_retries; bool ignore_plink_timer; enum nl80211_plink_state plink_state; -- cgit v1.2.3-70-g09d2 From f63f8421d468575ae7bb62cfcf0398613c746975 Mon Sep 17 00:00:00 2001 From: Chun-Yeow Yeoh Date: Wed, 13 Nov 2013 15:39:12 +0800 Subject: mac80211: use put_unaligned_le in mesh when necessary Use put_unaligned_le16 and put_unaligned_le32 for mesh_path_error_tx and mesh_path_sel_frame_tx. Signed-off-by: Chun-Yeow Yeoh Signed-off-by: Johannes Berg --- net/mac80211/mesh.h | 4 +-- net/mac80211/mesh_hwmp.c | 87 +++++++++++++++++++-------------------------- net/mac80211/mesh_pathtbl.c | 7 ++-- net/mac80211/rx.c | 5 +-- 4 files changed, 45 insertions(+), 58 deletions(-) diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 3f867e52c33..f39a19f9090 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -301,8 +301,8 @@ void mesh_mpath_table_grow(void); void mesh_mpp_table_grow(void); /* Mesh paths */ int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata, - u8 ttl, const u8 *target, __le32 target_sn, - __le16 target_rcode, const u8 *ra); + u8 ttl, const u8 *target, u32 target_sn, + u16 target_rcode, const u8 *ra); void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta); void mesh_path_flush_pending(struct mesh_path *mpath); void mesh_path_tx_pending(struct mesh_path *mpath); diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 56e0c072007..f9514685d45 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -102,12 +102,11 @@ enum mpath_frame_type { static const u8 broadcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, - const u8 *orig_addr, __le32 orig_sn, + const u8 *orig_addr, u32 orig_sn, u8 target_flags, const u8 *target, - __le32 target_sn, const u8 *da, + u32 target_sn, const u8 *da, u8 hop_count, u8 ttl, - __le32 lifetime, __le32 metric, - __le32 preq_id, + u32 lifetime, u32 metric, u32 preq_id, struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; @@ -167,33 +166,33 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, if (action == MPATH_PREP) { memcpy(pos, target, ETH_ALEN); pos += ETH_ALEN; - memcpy(pos, &target_sn, 4); + put_unaligned_le32(target_sn, pos); pos += 4; } else { if (action == MPATH_PREQ) { - memcpy(pos, &preq_id, 4); + put_unaligned_le32(preq_id, pos); pos += 4; } memcpy(pos, orig_addr, ETH_ALEN); pos += ETH_ALEN; - memcpy(pos, &orig_sn, 4); + put_unaligned_le32(orig_sn, pos); pos += 4; } - memcpy(pos, &lifetime, 4); /* interval for RANN */ + put_unaligned_le32(lifetime, pos); /* interval for RANN */ pos += 4; - memcpy(pos, &metric, 4); + put_unaligned_le32(metric, pos); pos += 4; if (action == MPATH_PREQ) { *pos++ = 1; /* destination count */ *pos++ = target_flags; memcpy(pos, target, ETH_ALEN); pos += ETH_ALEN; - memcpy(pos, &target_sn, 4); + put_unaligned_le32(target_sn, pos); pos += 4; } else if (action == MPATH_PREP) { memcpy(pos, orig_addr, ETH_ALEN); pos += ETH_ALEN; - memcpy(pos, &orig_sn, 4); + put_unaligned_le32(orig_sn, pos); pos += 4; } @@ -239,8 +238,8 @@ static void prepare_frame_for_deferred_tx(struct ieee80211_sub_if_data *sdata, * frame directly but add it to the pending queue instead. */ int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata, - u8 ttl, const u8 *target, __le32 target_sn, - __le16 target_rcode, const u8 *ra) + u8 ttl, const u8 *target, u32 target_sn, + u16 target_rcode, const u8 *ra) { struct ieee80211_local *local = sdata->local; struct sk_buff *skb; @@ -293,9 +292,9 @@ int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata, pos++; memcpy(pos, target, ETH_ALEN); pos += ETH_ALEN; - memcpy(pos, &target_sn, 4); + put_unaligned_le32(target_sn, pos); pos += 4; - memcpy(pos, &target_rcode, 2); + put_unaligned_le16(target_rcode, pos); /* see note in function header */ prepare_frame_for_deferred_tx(sdata, skb); @@ -592,10 +591,9 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, if (ttl != 0) { mhwmp_dbg(sdata, "replying to the PREQ\n"); mesh_path_sel_frame_tx(MPATH_PREP, 0, orig_addr, - cpu_to_le32(orig_sn), 0, target_addr, - cpu_to_le32(target_sn), mgmt->sa, 0, ttl, - cpu_to_le32(lifetime), cpu_to_le32(metric), - 0, sdata); + orig_sn, 0, target_addr, + target_sn, mgmt->sa, 0, ttl, + lifetime, metric, 0, sdata); } else { ifmsh->mshstats.dropped_frames_ttl++; } @@ -625,11 +623,9 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, } mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr, - cpu_to_le32(orig_sn), target_flags, target_addr, - cpu_to_le32(target_sn), da, - hopcount, ttl, cpu_to_le32(lifetime), - cpu_to_le32(metric), cpu_to_le32(preq_id), - sdata); + orig_sn, target_flags, target_addr, + target_sn, da, hopcount, ttl, lifetime, + metric, preq_id, sdata); if (!is_multicast_ether_addr(da)) ifmsh->mshstats.fwded_unicast++; else @@ -695,11 +691,9 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, target_sn = PREP_IE_TARGET_SN(prep_elem); orig_sn = PREP_IE_ORIG_SN(prep_elem); - mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr, - cpu_to_le32(orig_sn), 0, target_addr, - cpu_to_le32(target_sn), next_hop, hopcount, - ttl, cpu_to_le32(lifetime), cpu_to_le32(metric), - 0, sdata); + mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr, orig_sn, 0, + target_addr, target_sn, next_hop, hopcount, + ttl, lifetime, metric, 0, sdata); rcu_read_unlock(); sdata->u.mesh.mshstats.fwded_unicast++; @@ -750,8 +744,7 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, if (!ifmsh->mshcfg.dot11MeshForwarding) goto endperr; mesh_path_error_tx(sdata, ttl, target_addr, - cpu_to_le32(target_sn), - cpu_to_le16(target_rcode), + target_sn, target_rcode, broadcast_addr); } else spin_unlock_bh(&mpath->state_lock); @@ -847,11 +840,9 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, if (ifmsh->mshcfg.dot11MeshForwarding) { mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr, - cpu_to_le32(orig_sn), - 0, NULL, 0, broadcast_addr, - hopcount, ttl, cpu_to_le32(interval), - cpu_to_le32(metric + metric_txsta), - 0, sdata); + orig_sn, 0, NULL, 0, broadcast_addr, + hopcount, ttl, interval, + metric + metric_txsta, 0, sdata); } rcu_read_unlock(); @@ -1049,11 +1040,9 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata) spin_unlock_bh(&mpath->state_lock); da = (mpath->is_root) ? mpath->rann_snd_addr : broadcast_addr; - mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->vif.addr, - cpu_to_le32(ifmsh->sn), target_flags, mpath->dst, - cpu_to_le32(mpath->sn), da, 0, - ttl, cpu_to_le32(lifetime), 0, - cpu_to_le32(ifmsh->preq_id++), sdata); + mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->vif.addr, ifmsh->sn, + target_flags, mpath->dst, mpath->sn, da, 0, + ttl, lifetime, 0, ifmsh->preq_id++, sdata); mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout); enddiscovery: @@ -1212,10 +1201,9 @@ void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata) switch (ifmsh->mshcfg.dot11MeshHWMPRootMode) { case IEEE80211_PROACTIVE_RANN: mesh_path_sel_frame_tx(MPATH_RANN, flags, sdata->vif.addr, - cpu_to_le32(++ifmsh->sn), - 0, NULL, 0, broadcast_addr, - 0, ifmsh->mshcfg.element_ttl, - cpu_to_le32(interval), 0, 0, sdata); + ++ifmsh->sn, 0, NULL, 0, broadcast_addr, + 0, ifmsh->mshcfg.element_ttl, + interval, 0, 0, sdata); break; case IEEE80211_PROACTIVE_PREQ_WITH_PREP: flags |= IEEE80211_PREQ_PROACTIVE_PREP_FLAG; @@ -1224,11 +1212,10 @@ void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata) target_flags |= IEEE80211_PREQ_TO_FLAG | IEEE80211_PREQ_USN_FLAG; mesh_path_sel_frame_tx(MPATH_PREQ, flags, sdata->vif.addr, - cpu_to_le32(++ifmsh->sn), target_flags, - (u8 *) broadcast_addr, 0, broadcast_addr, - 0, ifmsh->mshcfg.element_ttl, - cpu_to_le32(interval), - 0, cpu_to_le32(ifmsh->preq_id++), sdata); + ++ifmsh->sn, target_flags, + (u8 *) broadcast_addr, 0, broadcast_addr, + 0, ifmsh->mshcfg.element_ttl, interval, + 0, ifmsh->preq_id++, sdata); break; default: mhwmp_dbg(sdata, "Proactive mechanism not supported\n"); diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 89aacfd2756..7d050ed6fe5 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -722,7 +722,6 @@ void mesh_plink_broken(struct sta_info *sta) struct mpath_node *node; struct ieee80211_sub_if_data *sdata = sta->sdata; int i; - __le16 reason = cpu_to_le16(WLAN_REASON_MESH_PATH_DEST_UNREACHABLE); rcu_read_lock(); tbl = rcu_dereference(mesh_paths); @@ -736,9 +735,9 @@ void mesh_plink_broken(struct sta_info *sta) ++mpath->sn; spin_unlock_bh(&mpath->state_lock); mesh_path_error_tx(sdata, - sdata->u.mesh.mshcfg.element_ttl, - mpath->dst, cpu_to_le32(mpath->sn), - reason, bcast); + sdata->u.mesh.mshcfg.element_ttl, + mpath->dst, mpath->sn, + WLAN_REASON_MESH_PATH_DEST_UNREACHABLE, bcast); } } rcu_read_unlock(); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 79f76791f77..30ac6099da0 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2081,7 +2081,6 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) struct ieee80211_sub_if_data *sdata = rx->sdata; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; - __le16 reason = cpu_to_le16(WLAN_REASON_MESH_PATH_NOFORWARD); u16 q, hdrlen; hdr = (struct ieee80211_hdr *) skb->data; @@ -2189,7 +2188,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) } else { /* unable to resolve next hop */ mesh_path_error_tx(sdata, ifmsh->mshcfg.element_ttl, - fwd_hdr->addr3, 0, reason, fwd_hdr->addr2); + fwd_hdr->addr3, 0, + WLAN_REASON_MESH_PATH_NOFORWARD, + fwd_hdr->addr2); IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route); kfree_skb(fwd_skb); return RX_DROP_MONITOR; -- cgit v1.2.3-70-g09d2 From 33787fc4bea0347d78a211d1f38289b73d9ec1a6 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Mon, 11 Nov 2013 20:34:54 +0200 Subject: mac80211: move csa_chandef to sdata There is no reason why we should have only one channel switch announcement at a time for a single phy. When support for channel switch with multiple contexts and multiple vifs per context is implemented, we will need the chandef data for each vif. Move the csa_chandef structure to sdata to prepare for this. Reviewed-by: Johannes Berg Signed-off-by: Luciano Coelho [Fixed compilation with mesh] Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 9 ++++----- net/mac80211/chan.c | 2 +- net/mac80211/ibss.c | 6 +++--- net/mac80211/ieee80211_i.h | 3 +-- net/mac80211/mesh.c | 2 +- net/mac80211/mlme.c | 9 ++++----- 6 files changed, 14 insertions(+), 17 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index b2cbe7a533f..c7b3e57aec0 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2990,13 +2990,12 @@ void ieee80211_csa_finalize_work(struct work_struct *work) return; sdata->radar_required = sdata->csa_radar_required; - err = ieee80211_vif_change_channel(sdata, &local->csa_chandef, - &changed); + err = ieee80211_vif_change_channel(sdata, &changed); if (WARN_ON(err < 0)) return; if (!local->use_chanctx) { - local->_oper_chandef = local->csa_chandef; + local->_oper_chandef = sdata->csa_chandef; ieee80211_hw_config(local, 0); } @@ -3033,7 +3032,7 @@ void ieee80211_csa_finalize_work(struct work_struct *work) IEEE80211_MAX_QUEUE_MAP, IEEE80211_QUEUE_STOP_REASON_CSA); - cfg80211_ch_switch_notify(sdata->dev, &local->csa_chandef); + cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef); } static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, @@ -3158,7 +3157,7 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, IEEE80211_MAX_QUEUE_MAP, IEEE80211_QUEUE_STOP_REASON_CSA); - local->csa_chandef = params->chandef; + sdata->csa_chandef = params->chandef; sdata->vif.csa_active = true; ieee80211_bss_info_change_notify(sdata, err); diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 03ba6b5c537..cefee2be0b8 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -411,12 +411,12 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, } int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, - const struct cfg80211_chan_def *chandef, u32 *changed) { struct ieee80211_local *local = sdata->local; struct ieee80211_chanctx_conf *conf; struct ieee80211_chanctx *ctx; + const struct cfg80211_chan_def *chandef = &sdata->csa_chandef; int ret; u32 chanctx_changed = 0; diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 531be040b9a..0f1fb5db4bd 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -550,12 +550,12 @@ int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata) capability); /* XXX: should not really modify cfg80211 data */ if (cbss) { - cbss->channel = sdata->local->csa_chandef.chan; + cbss->channel = sdata->csa_chandef.chan; cfg80211_put_bss(sdata->local->hw.wiphy, cbss); } } - ifibss->chandef = sdata->local->csa_chandef; + ifibss->chandef = sdata->csa_chandef; /* generate the beacon */ err = ieee80211_ibss_csa_beacon(sdata, NULL); @@ -922,7 +922,7 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata, IEEE80211_MAX_QUEUE_MAP, IEEE80211_QUEUE_STOP_REASON_CSA); - sdata->local->csa_chandef = params.chandef; + sdata->csa_chandef = params.chandef; sdata->vif.csa_active = true; ieee80211_bss_info_change_notify(sdata, err); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 16f5ba4a325..0faadf15cd5 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -736,6 +736,7 @@ struct ieee80211_sub_if_data { int csa_counter_offset_beacon; int csa_counter_offset_presp; bool csa_radar_required; + struct cfg80211_chan_def csa_chandef; /* used to reconfigure hardware SM PS */ struct work_struct recalc_smps; @@ -1094,7 +1095,6 @@ struct ieee80211_local { enum mac80211_scan_state next_scan_state; struct delayed_work scan_work; struct ieee80211_sub_if_data __rcu *scan_sdata; - struct cfg80211_chan_def csa_chandef; /* For backward compatibility only -- do not use */ struct cfg80211_chan_def _oper_chandef; @@ -1731,7 +1731,6 @@ ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, /* NOTE: only use ieee80211_vif_change_channel() for channel switch */ int __must_check ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, - const struct cfg80211_chan_def *chandef, u32 *changed); void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata); void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata); diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index e0538b92083..330d1f71c0c 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -956,7 +956,7 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata, IEEE80211_MAX_QUEUE_MAP, IEEE80211_QUEUE_STOP_REASON_CSA); - sdata->local->csa_chandef = params.chandef; + sdata->csa_chandef = params.chandef; sdata->vif.csa_active = true; ieee80211_bss_info_change_notify(sdata, err); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index f8dca58b7e5..2bb3a8631b1 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -886,8 +886,7 @@ static void ieee80211_chswitch_work(struct work_struct *work) if (!ifmgd->associated) goto out; - ret = ieee80211_vif_change_channel(sdata, &local->csa_chandef, - &changed); + ret = ieee80211_vif_change_channel(sdata, &changed); if (ret) { sdata_info(sdata, "vif channel switch failed, disconnecting\n"); @@ -897,7 +896,7 @@ static void ieee80211_chswitch_work(struct work_struct *work) } if (!local->use_chanctx) { - local->_oper_chandef = local->csa_chandef; + local->_oper_chandef = sdata->csa_chandef; /* Call "hw_config" only if doing sw channel switch. * Otherwise update the channel directly */ @@ -908,7 +907,7 @@ static void ieee80211_chswitch_work(struct work_struct *work) } /* XXX: shouldn't really modify cfg80211-owned data! */ - ifmgd->associated->channel = local->csa_chandef.chan; + ifmgd->associated->channel = sdata->csa_chandef.chan; /* XXX: wait for a beacon first? */ ieee80211_wake_queues_by_reason(&local->hw, @@ -1035,7 +1034,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, } mutex_unlock(&local->chanctx_mtx); - local->csa_chandef = csa_ie.chandef; + sdata->csa_chandef = csa_ie.chandef; if (csa_ie.mode) ieee80211_stop_queues_by_reason(&local->hw, -- cgit v1.2.3-70-g09d2 From fbdd90ea830162960fb8fbe377dfef9a54d74d2f Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Mon, 11 Nov 2013 20:14:00 +0200 Subject: mac80211: enable easier manipulation of VHT beamforming caps Introduce shift and mask defines for beamformee STS cap and number of sounding dimensions cap as these can take any 3 bit value. While at it also cleanup an unrequired parenthesis. Signed-off-by: Eyal Shapira Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 8 ++++++-- net/mac80211/vht.c | 7 +++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 8c3b26a2157..776cbb80d09 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1411,8 +1411,12 @@ struct ieee80211_vht_operation { #define IEEE80211_VHT_CAP_RXSTBC_MASK 0x00000700 #define IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE 0x00000800 #define IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE 0x00001000 -#define IEEE80211_VHT_CAP_BEAMFORMEE_STS_MAX 0x0000e000 -#define IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MAX 0x00070000 +#define IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT 13 +#define IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK \ + (7 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT) +#define IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT 16 +#define IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK \ + (7 << IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT) #define IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE 0x00080000 #define IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE 0x00100000 #define IEEE80211_VHT_CAP_VHT_TXOP_PS 0x00200000 diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index de0112785aa..d75f35c6e1a 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c @@ -182,16 +182,15 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, IEEE80211_VHT_CAP_SHORT_GI_160); /* remaining ones */ - if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) { + if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) vht_cap->cap |= cap_info & (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | - IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MAX); - } + IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK); if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) vht_cap->cap |= cap_info & (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | - IEEE80211_VHT_CAP_BEAMFORMEE_STS_MAX); + IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK); if (own_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) vht_cap->cap |= cap_info & -- cgit v1.2.3-70-g09d2 From 21f659bf1f93f7052b977d95cca560f02dc2edce Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Mon, 11 Nov 2013 20:14:01 +0200 Subject: mac80211: add min required channel definition field Add a new field to ieee80211_chanctx_conf to indicate the min required channel configuration. Tuning to a narrower channel might help reducing the noise level and saving some power. The min required channel definition is the max of all min required channel definitions of the interfaces bound to this channel context. In AP mode, use 20MHz when there are no connected station. When a new station is added/removed, calculate the new max bandwidth supported by any of the stations (e.g. 80MHz when 80MHz and 40MHz stations are connected). In other cases, simply use bss_conf.chandef as the min required chandef. Notify drivers about changes to this field by calling drv_change_chanctx with a new CHANGE_MIN_WIDTH notification. Signed-off-by: Eliad Peller Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- include/net/mac80211.h | 4 ++ net/mac80211/chan.c | 139 +++++++++++++++++++++++++++++++++++++++++++++ net/mac80211/ieee80211_i.h | 3 + net/mac80211/sta_info.c | 2 + net/mac80211/trace.h | 21 ++++++- net/mac80211/util.c | 20 +++++++ 6 files changed, 187 insertions(+), 2 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index cca02b2f5c7..3cd408b326d 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -154,12 +154,14 @@ struct ieee80211_low_level_stats { * @IEEE80211_CHANCTX_CHANGE_RADAR: radar detection flag changed * @IEEE80211_CHANCTX_CHANGE_CHANNEL: switched to another operating channel, * this is used only with channel switching with CSA + * @IEEE80211_CHANCTX_CHANGE_MIN_WIDTH: The min required channel width changed */ enum ieee80211_chanctx_change { IEEE80211_CHANCTX_CHANGE_WIDTH = BIT(0), IEEE80211_CHANCTX_CHANGE_RX_CHAINS = BIT(1), IEEE80211_CHANCTX_CHANGE_RADAR = BIT(2), IEEE80211_CHANCTX_CHANGE_CHANNEL = BIT(3), + IEEE80211_CHANCTX_CHANGE_MIN_WIDTH = BIT(4), }; /** @@ -169,6 +171,7 @@ enum ieee80211_chanctx_change { * that contains it is visible in mac80211 only. * * @def: the channel definition + * @min_def: the minimum channel definition currently required. * @rx_chains_static: The number of RX chains that must always be * active on the channel to receive MIMO transmissions * @rx_chains_dynamic: The number of RX chains that must be enabled @@ -180,6 +183,7 @@ enum ieee80211_chanctx_change { */ struct ieee80211_chanctx_conf { struct cfg80211_chan_def def; + struct cfg80211_chan_def min_def; u8 rx_chains_static, rx_chains_dynamic; diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index cefee2be0b8..a57d5d9466b 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -9,6 +9,140 @@ #include "ieee80211_i.h" #include "driver-ops.h" +static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta) +{ + switch (sta->bandwidth) { + case IEEE80211_STA_RX_BW_20: + if (sta->ht_cap.ht_supported) + return NL80211_CHAN_WIDTH_20; + else + return NL80211_CHAN_WIDTH_20_NOHT; + case IEEE80211_STA_RX_BW_40: + return NL80211_CHAN_WIDTH_40; + case IEEE80211_STA_RX_BW_80: + return NL80211_CHAN_WIDTH_80; + case IEEE80211_STA_RX_BW_160: + /* + * This applied for both 160 and 80+80. since we use + * the returned value to consider degradation of + * ctx->conf.min_def, we have to make sure to take + * the bigger one (NL80211_CHAN_WIDTH_160). + * Otherwise we might try degrading even when not + * needed, as the max required sta_bw returned (80+80) + * might be smaller than the configured bw (160). + */ + return NL80211_CHAN_WIDTH_160; + default: + WARN_ON(1); + return NL80211_CHAN_WIDTH_20; + } +} + +static enum nl80211_chan_width +ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata) +{ + enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT; + struct sta_info *sta; + + rcu_read_lock(); + list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) { + if (sdata != sta->sdata && + !(sta->sdata->bss && sta->sdata->bss == sdata->bss)) + continue; + + if (!sta->uploaded) + continue; + + max_bw = max(max_bw, ieee80211_get_sta_bw(&sta->sta)); + } + rcu_read_unlock(); + + return max_bw; +} + +static enum nl80211_chan_width +ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local, + struct ieee80211_chanctx_conf *conf) +{ + struct ieee80211_sub_if_data *sdata; + enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT; + + rcu_read_lock(); + list_for_each_entry_rcu(sdata, &local->interfaces, list) { + struct ieee80211_vif *vif = &sdata->vif; + enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20_NOHT; + + if (!ieee80211_sdata_running(sdata)) + continue; + + if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf) + continue; + + switch (vif->type) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP_VLAN: + width = ieee80211_get_max_required_bw(sdata); + break; + case NL80211_IFTYPE_P2P_DEVICE: + continue; + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_WDS: + case NL80211_IFTYPE_MESH_POINT: + width = vif->bss_conf.chandef.width; + break; + case NL80211_IFTYPE_UNSPECIFIED: + case NUM_NL80211_IFTYPES: + case NL80211_IFTYPE_MONITOR: + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_P2P_GO: + WARN_ON_ONCE(1); + } + max_bw = max(max_bw, width); + } + rcu_read_unlock(); + + return max_bw; +} + +/* + * recalc the min required chan width of the channel context, which is + * the max of min required widths of all the interfaces bound to this + * channel context. + */ +void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local, + struct ieee80211_chanctx *ctx) +{ + enum nl80211_chan_width max_bw; + struct cfg80211_chan_def min_def; + + lockdep_assert_held(&local->chanctx_mtx); + + /* don't optimize 5MHz, 10MHz, and radar_enabled confs */ + if (ctx->conf.def.width == NL80211_CHAN_WIDTH_5 || + ctx->conf.def.width == NL80211_CHAN_WIDTH_10 || + ctx->conf.radar_enabled) { + ctx->conf.min_def = ctx->conf.def; + return; + } + + max_bw = ieee80211_get_chanctx_max_required_bw(local, &ctx->conf); + + /* downgrade chandef up to max_bw */ + min_def = ctx->conf.def; + while (min_def.width > max_bw) + ieee80211_chandef_downgrade(&min_def); + + if (cfg80211_chandef_identical(&ctx->conf.min_def, &min_def)) + return; + + ctx->conf.min_def = min_def; + if (!ctx->driver_present) + return; + + drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_MIN_WIDTH); +} + static void ieee80211_change_chanctx(struct ieee80211_local *local, struct ieee80211_chanctx *ctx, const struct cfg80211_chan_def *chandef) @@ -20,6 +154,7 @@ static void ieee80211_change_chanctx(struct ieee80211_local *local, ctx->conf.def = *chandef; drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_WIDTH); + ieee80211_recalc_chanctx_min_def(local, ctx); if (!local->use_chanctx) { local->_oper_chandef = *chandef; @@ -93,6 +228,7 @@ ieee80211_new_chanctx(struct ieee80211_local *local, ctx->conf.rx_chains_dynamic = 1; ctx->mode = mode; ctx->conf.radar_enabled = ieee80211_is_radar_required(local); + ieee80211_recalc_chanctx_min_def(local, ctx); if (!local->use_chanctx) local->hw.conf.radar_enabled = ctx->conf.radar_enabled; @@ -179,6 +315,7 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, ctx->refcount++; ieee80211_recalc_txpower(sdata); + ieee80211_recalc_chanctx_min_def(local, ctx); sdata->vif.bss_conf.idle = false; if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE && @@ -243,6 +380,7 @@ static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata, ieee80211_recalc_chanctx_chantype(sdata->local, ctx); ieee80211_recalc_smps_chanctx(local, ctx); ieee80211_recalc_radar_chanctx(local, ctx); + ieee80211_recalc_chanctx_min_def(local, ctx); } } @@ -456,6 +594,7 @@ int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, ieee80211_recalc_chanctx_chantype(local, ctx); ieee80211_recalc_smps_chanctx(local, ctx); ieee80211_recalc_radar_chanctx(local, ctx); + ieee80211_recalc_chanctx_min_def(local, ctx); ret = 0; out: diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 0faadf15cd5..4022ee1afb9 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1693,6 +1693,7 @@ int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata, int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata, enum ieee80211_smps_mode smps_mode); void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata); +void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata); size_t ieee80211_ie_split(const u8 *ies, size_t ielen, const u8 *ids, int n_ids, size_t offset); @@ -1741,6 +1742,8 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, struct ieee80211_chanctx *chanctx); void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local, struct ieee80211_chanctx *chanctx); +void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local, + struct ieee80211_chanctx *ctx); void ieee80211_dfs_cac_timer(unsigned long data); void ieee80211_dfs_cac_timer_work(struct work_struct *work); diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 45b5f610674..7b69d4c3db5 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -507,6 +507,7 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) set_sta_flag(sta, WLAN_STA_INSERTED); + ieee80211_recalc_min_chandef(sdata); ieee80211_sta_debugfs_add(sta); rate_control_add_sta_debugfs(sta); @@ -869,6 +870,7 @@ int __must_check __sta_info_destroy(struct sta_info *sta) rate_control_remove_sta_debugfs(sta); ieee80211_sta_debugfs_remove(sta); + ieee80211_recalc_min_chandef(sdata); call_rcu(&sta->rcu_head, free_sta_rcu); diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 5d62c580481..8db560190ca 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -41,14 +41,31 @@ #define CHANDEF_PR_ARG __entry->control_freq, __entry->chan_width, \ __entry->center_freq1, __entry->center_freq2 +#define MIN_CHANDEF_ENTRY \ + __field(u32, min_control_freq) \ + __field(u32, min_chan_width) \ + __field(u32, min_center_freq1) \ + __field(u32, min_center_freq2) + +#define MIN_CHANDEF_ASSIGN(c) \ + __entry->min_control_freq = (c)->chan ? (c)->chan->center_freq : 0; \ + __entry->min_chan_width = (c)->width; \ + __entry->min_center_freq1 = (c)->center_freq1; \ + __entry->min_center_freq2 = (c)->center_freq2; +#define MIN_CHANDEF_PR_FMT " min_control:%d MHz min_width:%d min_center: %d/%d MHz" +#define MIN_CHANDEF_PR_ARG __entry->min_control_freq, __entry->min_chan_width, \ + __entry->min_center_freq1, __entry->min_center_freq2 + #define CHANCTX_ENTRY CHANDEF_ENTRY \ + MIN_CHANDEF_ENTRY \ __field(u8, rx_chains_static) \ __field(u8, rx_chains_dynamic) #define CHANCTX_ASSIGN CHANDEF_ASSIGN(&ctx->conf.def) \ + MIN_CHANDEF_ASSIGN(&ctx->conf.min_def) \ __entry->rx_chains_static = ctx->conf.rx_chains_static; \ __entry->rx_chains_dynamic = ctx->conf.rx_chains_dynamic -#define CHANCTX_PR_FMT CHANDEF_PR_FMT " chains:%d/%d" -#define CHANCTX_PR_ARG CHANDEF_PR_ARG, \ +#define CHANCTX_PR_FMT CHANDEF_PR_FMT MIN_CHANDEF_PR_FMT " chains:%d/%d" +#define CHANCTX_PR_ARG CHANDEF_PR_ARG, MIN_CHANDEF_PR_ARG, \ __entry->rx_chains_static, __entry->rx_chains_dynamic diff --git a/net/mac80211/util.c b/net/mac80211/util.c index bb92f8e0f84..06265d7f8cc 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1804,6 +1804,26 @@ void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata) mutex_unlock(&local->chanctx_mtx); } +void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_chanctx_conf *chanctx_conf; + struct ieee80211_chanctx *chanctx; + + mutex_lock(&local->chanctx_mtx); + + chanctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf, + lockdep_is_held(&local->chanctx_mtx)); + + if (WARN_ON_ONCE(!chanctx_conf)) + goto unlock; + + chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf); + ieee80211_recalc_chanctx_min_def(local, chanctx); + unlock: + mutex_unlock(&local->chanctx_mtx); +} + static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id) { int i; -- cgit v1.2.3-70-g09d2 From 7a5e3fa2c81ca2fdc514c61ad90fb4e0b632258c Mon Sep 17 00:00:00 2001 From: Karl Beldan Date: Mon, 11 Nov 2013 13:12:55 +0100 Subject: mac80211: minstrel_ht: replace some occurences of MCS_GROUP_RATES Consecutive MCSes in [8*(NSS-1)->8*NSS[ have the same number NSS of streams (except for MCS32 which is mishandled ATM). ATM minstrel_ht uses MCS_GROUP_RATES in place of this 8 modulus. This change replaces such occurences and by doing so allows for different values of MCS_GROUP_RATES (e.g to cope with VHT MCS8,9). Signed-off-by: Karl Beldan Signed-off-by: Johannes Berg --- net/mac80211/rc80211_minstrel_ht.c | 9 ++++----- net/mac80211/rc80211_minstrel_ht_debugfs.c | 3 +-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 5d60779a0c1..0a4a7c78e81 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -135,7 +135,7 @@ minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi); static int minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate) { - return GROUP_IDX((rate->idx / MCS_GROUP_RATES) + 1, + return GROUP_IDX((rate->idx / 8) + 1, !!(rate->flags & IEEE80211_TX_RC_SHORT_GI), !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)); } @@ -148,7 +148,7 @@ minstrel_ht_get_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, if (rate->flags & IEEE80211_TX_RC_MCS) { group = minstrel_ht_get_group_idx(rate); - idx = rate->idx % MCS_GROUP_RATES; + idx = rate->idx % 8; } else { group = MINSTREL_CCK_GROUP; @@ -636,8 +636,7 @@ minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)]; flags = 0; } else { - idx = index % MCS_GROUP_RATES + - (group->streams - 1) * MCS_GROUP_RATES; + idx = index % MCS_GROUP_RATES + (group->streams - 1) * 8; flags = IEEE80211_TX_RC_MCS | group->flags; } @@ -817,7 +816,7 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, } rate->idx = sample_idx % MCS_GROUP_RATES + - (sample_group->streams - 1) * MCS_GROUP_RATES; + (sample_group->streams - 1) * 8; rate->flags = IEEE80211_TX_RC_MCS | sample_group->flags; } diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c index df44a5ad827..3e7d793de0c 100644 --- a/net/mac80211/rc80211_minstrel_ht_debugfs.c +++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c @@ -54,8 +54,7 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) int r = bitrates[j % 4]; p += sprintf(p, " %2u.%1uM", r / 10, r % 10); } else { - p += sprintf(p, " MCS%-2u", (mg->streams - 1) * - MCS_GROUP_RATES + j); + p += sprintf(p, " MCS%-2u", (mg->streams - 1) * 8 + j); } tp = mr->cur_tp / 10; -- cgit v1.2.3-70-g09d2 From f7d8ad81ca8c447124821e58f876d1aff996c85f Mon Sep 17 00:00:00 2001 From: Karl Beldan Date: Wed, 13 Nov 2013 10:54:19 +0100 Subject: mac80211: minstrels: spare numerous useless calls to get_random_bytes ATM, only the first array value returned by get_random_bytes is used. This change moves the call to get_random_bytes from the nested loop it is in to its parent. While at it, replace get_random_bytes with prandom_bytes since PRNs are way enough for the selection process. After this, minstrel_ht reclaims 80 PR-bytes instead of 640 R-bytes. minstrels use sample tables to probe different rates in a randomized manner. minstrel_ht inits one single sample table upon registration (during subsys_initcalls) and minstrel uses one per STA addition in minstrel. Signed-off-by: Karl Beldan Signed-off-by: Johannes Berg --- net/mac80211/rc80211_minstrel.c | 3 +-- net/mac80211/rc80211_minstrel_ht.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 7fa1b36e620..d2f19f7e709 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -422,10 +422,9 @@ init_sample_table(struct minstrel_sta_info *mi) memset(mi->sample_table, 0xff, SAMPLE_COLUMNS * mi->n_rates); for (col = 0; col < SAMPLE_COLUMNS; col++) { + prandom_bytes(rnd, sizeof(rnd)); for (i = 0; i < mi->n_rates; i++) { - get_random_bytes(rnd, sizeof(rnd)); new_idx = (i + rnd[i & 7]) % mi->n_rates; - while (SAMPLE_TBL(mi, new_idx, col) != 0xff) new_idx = (new_idx + 1) % mi->n_rates; diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 0a4a7c78e81..e66e9f9fd0d 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -1051,10 +1051,9 @@ init_sample_table(void) memset(sample_table, 0xff, sizeof(sample_table)); for (col = 0; col < SAMPLE_COLUMNS; col++) { + prandom_bytes(rnd, sizeof(rnd)); for (i = 0; i < MCS_GROUP_RATES; i++) { - get_random_bytes(rnd, sizeof(rnd)); new_idx = (i + rnd[i]) % MCS_GROUP_RATES; - while (sample_table[col][new_idx] != 0xff) new_idx = (new_idx + 1) % MCS_GROUP_RATES; -- cgit v1.2.3-70-g09d2 From 4c7d3982a6e37831382b9ef90aa0dbadc0bf3a22 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 13 Nov 2013 18:54:02 +0100 Subject: cfg80211: use enum nl80211_dfs_regions for dfs_region everywhere u8 was used in some other places, just stick to the enum, this forces us to express the values that are expected. Signed-off-by: Luis R. Rodriguez Signed-off-by: Johannes Berg --- include/net/regulatory.h | 4 ++-- net/wireless/nl80211.c | 2 +- net/wireless/reg.c | 4 ++-- net/wireless/reg.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/net/regulatory.h b/include/net/regulatory.h index 92ab80f69ef..c96a0b86f34 100644 --- a/include/net/regulatory.h +++ b/include/net/regulatory.h @@ -79,7 +79,7 @@ struct regulatory_request { enum nl80211_reg_initiator initiator; enum nl80211_user_reg_hint_type user_reg_hint_type; char alpha2[2]; - u8 dfs_region; + enum nl80211_dfs_regions dfs_region; bool intersect; bool processed; enum environment_cap country_ie_env; @@ -157,7 +157,7 @@ struct ieee80211_regdomain { struct rcu_head rcu_head; u32 n_reg_rules; char alpha2[2]; - u8 dfs_region; + enum nl80211_dfs_regions dfs_region; struct ieee80211_reg_rule reg_rules[]; }; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 7b73132910b..79632edebb6 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -5079,7 +5079,7 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) char *alpha2 = NULL; int rem_reg_rules = 0, r = 0; u32 num_rules = 0, rule_idx = 0, size_of_regd; - u8 dfs_region = 0; + enum nl80211_dfs_regions dfs_region = NL80211_DFS_UNSET; struct ieee80211_regdomain *rd = NULL; if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 067c1f63a1a..2796b622890 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -2115,7 +2115,7 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd) } } -bool reg_supported_dfs_region(u8 dfs_region) +bool reg_supported_dfs_region(enum nl80211_dfs_regions dfs_region) { switch (dfs_region) { case NL80211_DFS_UNSET: @@ -2130,7 +2130,7 @@ bool reg_supported_dfs_region(u8 dfs_region) } } -static void print_dfs_region(u8 dfs_region) +static void print_dfs_region(enum nl80211_dfs_regions dfs_region) { if (!dfs_region) return; diff --git a/net/wireless/reg.h b/net/wireless/reg.h index b4076babaf4..cc4c2c0a672 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h @@ -20,7 +20,7 @@ extern const struct ieee80211_regdomain __rcu *cfg80211_regdomain; bool reg_is_valid_request(const char *alpha2); bool is_world_regdom(const char *alpha2); -bool reg_supported_dfs_region(u8 dfs_region); +bool reg_supported_dfs_region(enum nl80211_dfs_regions dfs_region); int regulatory_hint_user(const char *alpha2, enum nl80211_user_reg_hint_type user_reg_hint_type); -- cgit v1.2.3-70-g09d2 From adbfb058155dfabe77ea73c303cbd75af7e4d9d3 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 13 Nov 2013 18:54:03 +0100 Subject: cfg80211: intersection dfs regions when intersecting regdomains Only allow DFS to be set if the DFS regions agree. Signed-off-by: Luis R. Rodriguez Signed-off-by: Johannes Berg --- net/wireless/reg.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 2796b622890..068cb4055a6 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -570,6 +570,20 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range, #undef ONE_GHZ_IN_KHZ } +/* + * Later on we can perhaps use the more restrictive DFS + * region but we don't have information for that yet so + * for now simply disallow conflicts. + */ +static enum nl80211_dfs_regions +reg_intersect_dfs_region(const enum nl80211_dfs_regions dfs_region1, + const enum nl80211_dfs_regions dfs_region2) +{ + if (dfs_region1 != dfs_region2) + return NL80211_DFS_UNSET; + return dfs_region1; +} + /* * Helper for regdom_intersect(), this does the real * mathematical intersection fun @@ -701,6 +715,8 @@ regdom_intersect(const struct ieee80211_regdomain *rd1, rd->n_reg_rules = num_rules; rd->alpha2[0] = '9'; rd->alpha2[1] = '8'; + rd->dfs_region = reg_intersect_dfs_region(rd1->dfs_region, + rd2->dfs_region); return rd; } -- cgit v1.2.3-70-g09d2 From d7a4b05a2794fc8f2a545272048c7212951c1946 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 13 Nov 2013 18:54:04 +0100 Subject: cfg80211: distinguish unset DFS region from unknown Signed-off-by: Luis R. Rodriguez Signed-off-by: Johannes Berg --- net/wireless/reg.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 068cb4055a6..740eccb4206 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -2152,6 +2152,9 @@ static void print_dfs_region(enum nl80211_dfs_regions dfs_region) return; switch (dfs_region) { + case NL80211_DFS_UNSET: + pr_info(" DFS Master region unset"); + break; case NL80211_DFS_FCC: pr_info(" DFS Master region FCC"); break; -- cgit v1.2.3-70-g09d2 From 3ef121b51164282e9eaa732bf79ff027599867c6 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 13 Nov 2013 18:54:05 +0100 Subject: cfg80211: replace print_dfs_region() with reg_dfs_region_str() helper This lets us later reuse the more generic reg_dfs_region_str(). Signed-off-by: Luis R. Rodriguez Signed-off-by: Johannes Berg --- net/wireless/reg.c | 41 ++++++++++++++++------------------------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 740eccb4206..ec54e1aac8e 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -120,6 +120,21 @@ static const struct ieee80211_regdomain *get_wiphy_regdom(struct wiphy *wiphy) return rtnl_dereference(wiphy->regd); } +static const char *reg_dfs_region_str(enum nl80211_dfs_regions dfs_region) +{ + switch (dfs_region) { + case NL80211_DFS_UNSET: + return "unset"; + case NL80211_DFS_FCC: + return "FCC"; + case NL80211_DFS_ETSI: + return "ETSI"; + case NL80211_DFS_JP: + return "JP"; + } + return "Unknown"; +} + static void rcu_free_regdom(const struct ieee80211_regdomain *r) { if (!r) @@ -2146,30 +2161,6 @@ bool reg_supported_dfs_region(enum nl80211_dfs_regions dfs_region) } } -static void print_dfs_region(enum nl80211_dfs_regions dfs_region) -{ - if (!dfs_region) - return; - - switch (dfs_region) { - case NL80211_DFS_UNSET: - pr_info(" DFS Master region unset"); - break; - case NL80211_DFS_FCC: - pr_info(" DFS Master region FCC"); - break; - case NL80211_DFS_ETSI: - pr_info(" DFS Master region ETSI"); - break; - case NL80211_DFS_JP: - pr_info(" DFS Master region JP"); - break; - default: - pr_info(" DFS Master region Unknown"); - break; - } -} - static void print_regdomain(const struct ieee80211_regdomain *rd) { struct regulatory_request *lr = get_last_request(); @@ -2201,7 +2192,7 @@ static void print_regdomain(const struct ieee80211_regdomain *rd) } } - print_dfs_region(rd->dfs_region); + pr_info(" DFS Master region: %s", reg_dfs_region_str(rd->dfs_region)); print_rd_rules(rd); } -- cgit v1.2.3-70-g09d2 From f12140c04ca49ea34c448b1bd8aa40fb9411690c Mon Sep 17 00:00:00 2001 From: Karl Beldan Date: Mon, 11 Nov 2013 13:10:49 +0100 Subject: mac80211: minstrel_ht: do not sample unsupported rates ATM minstrel_ht does not check whether a sampling rate is supported. Unsupported rates attempts can trigger when there are holes in bitfields of supported MCSes belonging to the same group (e.g many devices are MCS32 capable without MCS33->39 capable, also we systematically have a hole for CCK rates). Drop any attempts to sample unsupported rates, as suggested by Felix. This is not a problem in minstrel which fills a per STA sample table with only supported rates (though only at init). Signed-off-by: Karl Beldan Signed-off-by: Johannes Berg --- net/mac80211/rc80211_minstrel_ht.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index e66e9f9fd0d..b91655a0d8f 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -700,12 +700,16 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) if (!mi->sample_tries) return -1; - mg = &mi->groups[mi->sample_group]; + sample_group = mi->sample_group; + mg = &mi->groups[sample_group]; sample_idx = sample_table[mg->column][mg->index]; + minstrel_next_sample_idx(mi); + + if (!(mg->supported & BIT(sample_idx))) + return -1; + mr = &mg->rates[sample_idx]; - sample_group = mi->sample_group; sample_idx += sample_group * MCS_GROUP_RATES; - minstrel_next_sample_idx(mi); /* * Sampling might add some overhead (RTS, no aggregation) -- cgit v1.2.3-70-g09d2 From e539887b1521ed4aefce7387bc3f33814b11442d Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 25 Nov 2013 14:06:20 +0100 Subject: ath10k: don't consume other's shared interrupts ath10k assumed all interrupts were directed to it. This isn't the case for legacy shared interrupts. ath10k consumed interrupts for other devices. Check device irq status and return IRQ_NONE when appropriate. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/hw.h | 1 + drivers/net/wireless/ath/ath10k/pci.c | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 8aeb46d9b53..9535eaa09f0 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -269,6 +269,7 @@ enum ath10k_mcast2ucast_mode { #define CORE_CTRL_CPU_INTR_MASK 0x00002000 #define CORE_CTRL_ADDRESS 0x0000 #define PCIE_INTR_ENABLE_ADDRESS 0x0008 +#define PCIE_INTR_CAUSE_ADDRESS 0x000c #define PCIE_INTR_CLR_ADDRESS 0x0014 #define SCRATCH_3_ADDRESS 0x0030 diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 2457c8ba901..12fb12ea218 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -201,6 +201,19 @@ static const struct ce_pipe_config target_ce_config_wlan[] = { /* CE7 used only by Host */ }; +static bool ath10k_pci_irq_pending(struct ath10k *ar) +{ + u32 cause; + + /* Check if the shared legacy irq is for us */ + cause = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + + PCIE_INTR_CAUSE_ADDRESS); + if (cause & (PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL)) + return true; + + return false; +} + /* * Diagnostic read/write access is provided for startup/config/debug usage. * Caller must guarantee proper alignment, when applicable, and single user @@ -2086,6 +2099,9 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg) struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); if (ar_pci->num_msi_intrs == 0) { + if (!ath10k_pci_irq_pending(ar)) + return IRQ_NONE; + /* * IMPORTANT: INTR_CLR regiser has to be set after * INTR_ENABLE is set to 0, otherwise interrupt can not be -- cgit v1.2.3-70-g09d2 From fc15ca13a6c95e0d6af682af118c3c8e679a8152 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 25 Nov 2013 14:06:21 +0100 Subject: ath10k: split up pci irq code Hardware waits until host signals whether it has chosen MSI(-X) or shared legacy interrupts. It is not required for the driver to register interrupt handlers immediately. This patch prepares the pci irq code for more changes. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 225 ++++++++++++++++++++-------------- 1 file changed, 131 insertions(+), 94 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 12fb12ea218..957fc59c225 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -55,8 +55,10 @@ static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info); static void ath10k_pci_stop_ce(struct ath10k *ar); static int ath10k_pci_device_reset(struct ath10k *ar); static int ath10k_pci_wait_for_target_init(struct ath10k *ar); -static int ath10k_pci_start_intr(struct ath10k *ar); -static void ath10k_pci_stop_intr(struct ath10k *ar); +static int ath10k_pci_init_irq(struct ath10k *ar); +static int ath10k_pci_deinit_irq(struct ath10k *ar); +static int ath10k_pci_request_irq(struct ath10k *ar); +static void ath10k_pci_free_irq(struct ath10k *ar); static const struct ce_attr host_ce_config_wlan[] = { /* CE0: host->target HTC control and raw streams */ @@ -1354,7 +1356,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar) ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__); /* Irqs are never explicitly re-enabled. They are implicitly re-enabled - * by ath10k_pci_start_intr(). */ + * by upon power_up. */ ath10k_pci_disable_irqs(ar); ath10k_pci_stop_ce(ar); @@ -1900,34 +1902,40 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) goto err_ce; } - ret = ath10k_pci_start_intr(ar); + ret = ath10k_pci_init_irq(ar); if (ret) { - ath10k_err("failed to start interrupt handling: %d\n", ret); + ath10k_err("failed to init irqs: %d\n", ret); goto err_ce; } + ret = ath10k_pci_request_irq(ar); + if (ret) { + ath10k_err("failed to request irqs: %d\n", ret); + goto err_deinit_irq; + } + ret = ath10k_pci_wait_for_target_init(ar); if (ret) { ath10k_err("failed to wait for target to init: %d\n", ret); - goto err_irq; + goto err_free_irq; } ret = ath10k_ce_enable_err_irq(ar); if (ret) { ath10k_err("failed to enable CE error irq: %d\n", ret); - goto err_irq; + goto err_free_irq; } ret = ath10k_pci_init_config(ar); if (ret) { ath10k_err("failed to setup init config: %d\n", ret); - goto err_irq; + goto err_free_irq; } ret = ath10k_pci_wake_target_cpu(ar); if (ret) { ath10k_err("could not wake up target CPU: %d\n", ret); - goto err_irq; + goto err_free_irq; } ath10k_pci_start_bmi(ar); @@ -1944,11 +1952,12 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) return 0; -err_irq: - ath10k_ce_disable_interrupts(ar); - ath10k_pci_stop_intr(ar); +err_free_irq: + ath10k_pci_free_irq(ar); ath10k_pci_kill_tasklet(ar); ath10k_pci_device_reset(ar); +err_deinit_irq: + ath10k_pci_deinit_irq(ar); err_ce: ath10k_pci_ce_deinit(ar); err_ps: @@ -1962,7 +1971,8 @@ static void ath10k_pci_hif_power_down(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - ath10k_pci_stop_intr(ar); + ath10k_pci_free_irq(ar); + ath10k_pci_deinit_irq(ar); ath10k_pci_device_reset(ar); ath10k_pci_ce_deinit(ar); @@ -2152,24 +2162,17 @@ static void ath10k_pci_tasklet(unsigned long data) } } -static int ath10k_pci_start_intr_msix(struct ath10k *ar, int num) +static int ath10k_pci_request_irq_msix(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - int ret; - int i; - - ret = pci_enable_msi_block(ar_pci->pdev, num); - if (ret) - return ret; + int ret, i; ret = request_irq(ar_pci->pdev->irq + MSI_ASSIGN_FW, ath10k_pci_msi_fw_handler, IRQF_SHARED, "ath10k_pci", ar); if (ret) { - ath10k_warn("request_irq(%d) failed %d\n", + ath10k_warn("failed to request MSI-X fw irq %d: %d\n", ar_pci->pdev->irq + MSI_ASSIGN_FW, ret); - - pci_disable_msi(ar_pci->pdev); return ret; } @@ -2178,45 +2181,38 @@ static int ath10k_pci_start_intr_msix(struct ath10k *ar, int num) ath10k_pci_per_engine_handler, IRQF_SHARED, "ath10k_pci", ar); if (ret) { - ath10k_warn("request_irq(%d) failed %d\n", + ath10k_warn("failed to request MSI-X ce irq %d: %d\n", ar_pci->pdev->irq + i, ret); for (i--; i >= MSI_ASSIGN_CE_INITIAL; i--) free_irq(ar_pci->pdev->irq + i, ar); free_irq(ar_pci->pdev->irq + MSI_ASSIGN_FW, ar); - pci_disable_msi(ar_pci->pdev); return ret; } } - ath10k_dbg(ATH10K_DBG_BOOT, - "MSI-X interrupt handling (%d intrs)\n", num); return 0; } -static int ath10k_pci_start_intr_msi(struct ath10k *ar) +static int ath10k_pci_request_irq_msi(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ret; - ret = pci_enable_msi(ar_pci->pdev); - if (ret < 0) - return ret; - ret = request_irq(ar_pci->pdev->irq, ath10k_pci_interrupt_handler, IRQF_SHARED, "ath10k_pci", ar); - if (ret < 0) { - pci_disable_msi(ar_pci->pdev); + if (ret) { + ath10k_warn("failed to request MSI irq %d: %d\n", + ar_pci->pdev->irq, ret); return ret; } - ath10k_dbg(ATH10K_DBG_BOOT, "MSI interrupt handling\n"); return 0; } -static int ath10k_pci_start_intr_legacy(struct ath10k *ar) +static int ath10k_pci_request_irq_legacy(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ret; @@ -2224,99 +2220,140 @@ static int ath10k_pci_start_intr_legacy(struct ath10k *ar) ret = request_irq(ar_pci->pdev->irq, ath10k_pci_interrupt_handler, IRQF_SHARED, "ath10k_pci", ar); - if (ret < 0) - return ret; - - ret = ath10k_pci_wake(ar); if (ret) { - free_irq(ar_pci->pdev->irq, ar); - ath10k_err("failed to wake up target: %d\n", ret); + ath10k_warn("failed to request legacy irq %d: %d\n", + ar_pci->pdev->irq, ret); return ret; } - /* - * A potential race occurs here: The CORE_BASE write - * depends on target correctly decoding AXI address but - * host won't know when target writes BAR to CORE_CTRL. - * This write might get lost if target has NOT written BAR. - * For now, fix the race by repeating the write in below - * synchronization checking. - */ - iowrite32(PCIE_INTR_FIRMWARE_MASK | - PCIE_INTR_CE_MASK_ALL, - ar_pci->mem + (SOC_CORE_BASE_ADDRESS | - PCIE_INTR_ENABLE_ADDRESS)); - - ath10k_pci_sleep(ar); - ath10k_dbg(ATH10K_DBG_BOOT, "legacy interrupt handling\n"); return 0; } -static int ath10k_pci_start_intr(struct ath10k *ar) +static int ath10k_pci_request_irq(struct ath10k *ar) +{ + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + + switch (ar_pci->num_msi_intrs) { + case 0: + return ath10k_pci_request_irq_legacy(ar); + case 1: + return ath10k_pci_request_irq_msi(ar); + case MSI_NUM_REQUEST: + return ath10k_pci_request_irq_msix(ar); + } + + ath10k_warn("unknown irq configuration upon request\n"); + return -EINVAL; +} + +static void ath10k_pci_free_irq(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - int num = MSI_NUM_REQUEST; - int ret; int i; - tasklet_init(&ar_pci->intr_tq, ath10k_pci_tasklet, (unsigned long) ar); + /* There's at least one interrupt irregardless whether its legacy INTR + * or MSI or MSI-X */ + for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++) + free_irq(ar_pci->pdev->irq + i, ar); +} + +static void ath10k_pci_init_irq_tasklets(struct ath10k *ar) +{ + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + int i; + + tasklet_init(&ar_pci->intr_tq, ath10k_pci_tasklet, (unsigned long)ar); tasklet_init(&ar_pci->msi_fw_err, ath10k_msi_err_tasklet, - (unsigned long) ar); + (unsigned long)ar); for (i = 0; i < CE_COUNT; i++) { ar_pci->pipe_info[i].ar_pci = ar_pci; - tasklet_init(&ar_pci->pipe_info[i].intr, - ath10k_pci_ce_tasklet, + tasklet_init(&ar_pci->pipe_info[i].intr, ath10k_pci_ce_tasklet, (unsigned long)&ar_pci->pipe_info[i]); } +} + +static int ath10k_pci_init_irq(struct ath10k *ar) +{ + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + int ret; + + ath10k_pci_init_irq_tasklets(ar); if (!test_bit(ATH10K_PCI_FEATURE_MSI_X, ar_pci->features)) - num = 1; + goto msi; - if (num > 1) { - ret = ath10k_pci_start_intr_msix(ar, num); - if (ret == 0) - goto exit; + /* Try MSI-X */ + ar_pci->num_msi_intrs = MSI_NUM_REQUEST; + ret = pci_enable_msi_block(ar_pci->pdev, ar_pci->num_msi_intrs); + if (ret == 0) + return 0; + if (ret > 0) + pci_disable_msi(ar_pci->pdev); - ath10k_dbg(ATH10K_DBG_BOOT, - "MSI-X didn't succeed (%d), trying MSI\n", ret); - num = 1; - } +msi: + /* Try MSI */ + ar_pci->num_msi_intrs = 1; + ret = pci_enable_msi(ar_pci->pdev); + if (ret == 0) + return 0; - if (num == 1) { - ret = ath10k_pci_start_intr_msi(ar); - if (ret == 0) - goto exit; + /* Try legacy irq + * + * A potential race occurs here: The CORE_BASE write + * depends on target correctly decoding AXI address but + * host won't know when target writes BAR to CORE_CTRL. + * This write might get lost if target has NOT written BAR. + * For now, fix the race by repeating the write in below + * synchronization checking. */ + ar_pci->num_msi_intrs = 0; - ath10k_dbg(ATH10K_DBG_BOOT, - "MSI didn't succeed (%d), trying legacy INTR\n", - ret); - num = 0; + ret = ath10k_pci_wake(ar); + if (ret) { + ath10k_warn("failed to wake target: %d\n", ret); + return ret; } - ret = ath10k_pci_start_intr_legacy(ar); + ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS, + PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL); + ath10k_pci_sleep(ar); + + return 0; +} + +static int ath10k_pci_deinit_irq_legacy(struct ath10k *ar) +{ + int ret; + + ret = ath10k_pci_wake(ar); if (ret) { - ath10k_warn("Failed to start legacy interrupts: %d\n", ret); + ath10k_warn("failed to wake target: %d\n", ret); return ret; } -exit: - ar_pci->num_msi_intrs = num; - return ret; + ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS, + 0); + ath10k_pci_sleep(ar); + + return 0; } -static void ath10k_pci_stop_intr(struct ath10k *ar) +static int ath10k_pci_deinit_irq(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - int i; - /* There's at least one interrupt irregardless whether its legacy INTR - * or MSI or MSI-X */ - for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++) - free_irq(ar_pci->pdev->irq + i, ar); - - if (ar_pci->num_msi_intrs > 0) + switch (ar_pci->num_msi_intrs) { + case 0: + return ath10k_pci_deinit_irq_legacy(ar); + case 1: + /* fall-through */ + case MSI_NUM_REQUEST: pci_disable_msi(ar_pci->pdev); + return 0; + } + + ath10k_warn("unknown irq configuration upon deinit\n"); + return -EINVAL; } static int ath10k_pci_wait_for_target_init(struct ath10k *ar) -- cgit v1.2.3-70-g09d2 From 85622cde05c18371c79a7f2a6a122271170f3ff1 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 25 Nov 2013 14:06:22 +0100 Subject: ath10k: don't use interrupts for BMI It's not really necessary for interrupts to be used for BMI. BMI already assumes there's only one caller at a time and it works directly with CE. Make BMI poll for CE completions instead of waiting for interrupts. This makes disabling interrupts during early boot possible. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 50 ++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 957fc59c225..327afbcd569 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -59,6 +59,9 @@ static int ath10k_pci_init_irq(struct ath10k *ar); static int ath10k_pci_deinit_irq(struct ath10k *ar); static int ath10k_pci_request_irq(struct ath10k *ar); static void ath10k_pci_free_irq(struct ath10k *ar); +static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe, + struct ath10k_ce_pipe *rx_pipe, + struct bmi_xfer *xfer); static const struct ce_attr host_ce_config_wlan[] = { /* CE0: host->target HTC control and raw streams */ @@ -1394,6 +1397,8 @@ static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar, void *treq, *tresp = NULL; int ret = 0; + might_sleep(); + if (resp && !resp_len) return -EINVAL; @@ -1434,14 +1439,12 @@ static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar, if (ret) goto err_resp; - ret = wait_for_completion_timeout(&xfer.done, - BMI_COMMUNICATION_TIMEOUT_HZ); - if (ret <= 0) { + ret = ath10k_pci_bmi_wait(ce_tx, ce_rx, &xfer); + if (ret) { u32 unused_buffer; unsigned int unused_nbytes; unsigned int unused_id; - ret = -ETIMEDOUT; ath10k_ce_cancel_send_next(ce_tx, NULL, &unused_buffer, &unused_nbytes, &unused_id); } else { @@ -1509,6 +1512,25 @@ static void ath10k_pci_bmi_recv_data(struct ath10k_ce_pipe *ce_state) complete(&xfer->done); } +static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe, + struct ath10k_ce_pipe *rx_pipe, + struct bmi_xfer *xfer) +{ + unsigned long timeout = jiffies + BMI_COMMUNICATION_TIMEOUT_HZ; + + while (time_before_eq(jiffies, timeout)) { + ath10k_pci_bmi_send_done(tx_pipe); + ath10k_pci_bmi_recv_data(rx_pipe); + + if (completion_done(&xfer->done)) + return 0; + + schedule(); + } + + return -ETIMEDOUT; +} + /* * Map from service/endpoint to Copy Engine. * This table is derived from the CE_PCI TABLE, above. @@ -1846,24 +1868,6 @@ static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar) ath10k_pci_sleep(ar); } -static void ath10k_pci_start_bmi(struct ath10k *ar) -{ - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_pci_pipe *pipe; - - /* - * Initially, establish CE completion handlers for use with BMI. - * These are overwritten with generic handlers after we exit BMI phase. - */ - pipe = &ar_pci->pipe_info[BMI_CE_NUM_TO_TARG]; - ath10k_ce_send_cb_register(pipe->ce_hdl, ath10k_pci_bmi_send_done, 0); - - pipe = &ar_pci->pipe_info[BMI_CE_NUM_TO_HOST]; - ath10k_ce_recv_cb_register(pipe->ce_hdl, ath10k_pci_bmi_recv_data); - - ath10k_dbg(ATH10K_DBG_BOOT, "boot start bmi\n"); -} - static int ath10k_pci_hif_power_up(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); @@ -1938,8 +1942,6 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) goto err_free_irq; } - ath10k_pci_start_bmi(ar); - if (ar_pci->num_msi_intrs > 1) irq_mode = "MSI-X"; else if (ar_pci->num_msi_intrs == 1) -- cgit v1.2.3-70-g09d2 From c80de12b3e9bde0736f66feed8dd7b6fdc739d16 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 25 Nov 2013 14:06:23 +0100 Subject: ath10k: decouple ath10k_pci_start_ce() The function did a couple of things: it allocated CE completions, registered CE callbacks and enabled CE interrupts through HW registers. This cannot be so. Split the function into one that allocates CE completions and the other one that starts off CE operation. This is required for future legacy shared interrupt handling. This also fixes possible memory leak if post rx failed. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 75 +++++++++++++++++++++++++---------- 1 file changed, 54 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 327afbcd569..05e6f8b4f1b 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -62,6 +62,7 @@ static void ath10k_pci_free_irq(struct ath10k *ar); static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe, struct ath10k_ce_pipe *rx_pipe, struct bmi_xfer *xfer); +static void ath10k_pci_cleanup_ce(struct ath10k *ar); static const struct ce_attr host_ce_config_wlan[] = { /* CE0: host->target HTC control and raw streams */ @@ -824,14 +825,13 @@ static void ath10k_pci_hif_set_callbacks(struct ath10k *ar, sizeof(ar_pci->msg_callbacks_current)); } -static int ath10k_pci_start_ce(struct ath10k *ar) +static int ath10k_pci_alloc_compl(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_ce_pipe *ce_diag = ar_pci->ce_diag; const struct ce_attr *attr; struct ath10k_pci_pipe *pipe_info; struct ath10k_pci_compl *compl; - int i, pipe_num, completions, disable_interrupts; + int i, pipe_num, completions; spin_lock_init(&ar_pci->compl_lock); INIT_LIST_HEAD(&ar_pci->compl_process); @@ -843,34 +843,23 @@ static int ath10k_pci_start_ce(struct ath10k *ar) INIT_LIST_HEAD(&pipe_info->compl_free); /* Handle Diagnostic CE specially */ - if (pipe_info->ce_hdl == ce_diag) + if (pipe_info->ce_hdl == ar_pci->ce_diag) continue; attr = &host_ce_config_wlan[pipe_num]; completions = 0; - if (attr->src_nentries) { - disable_interrupts = attr->flags & CE_ATTR_DIS_INTR; - ath10k_ce_send_cb_register(pipe_info->ce_hdl, - ath10k_pci_ce_send_done, - disable_interrupts); + if (attr->src_nentries) completions += attr->src_nentries; - } - if (attr->dest_nentries) { - ath10k_ce_recv_cb_register(pipe_info->ce_hdl, - ath10k_pci_ce_recv_data); + if (attr->dest_nentries) completions += attr->dest_nentries; - } - - if (completions == 0) - continue; for (i = 0; i < completions; i++) { compl = kmalloc(sizeof(*compl), GFP_KERNEL); if (!compl) { ath10k_warn("No memory for completion state\n"); - ath10k_pci_stop_ce(ar); + ath10k_pci_cleanup_ce(ar); return -ENOMEM; } @@ -882,6 +871,37 @@ static int ath10k_pci_start_ce(struct ath10k *ar) return 0; } +static int ath10k_pci_setup_ce_irq(struct ath10k *ar) +{ + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + const struct ce_attr *attr; + struct ath10k_pci_pipe *pipe_info; + int pipe_num, disable_interrupts; + + for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) { + pipe_info = &ar_pci->pipe_info[pipe_num]; + + /* Handle Diagnostic CE specially */ + if (pipe_info->ce_hdl == ar_pci->ce_diag) + continue; + + attr = &host_ce_config_wlan[pipe_num]; + + if (attr->src_nentries) { + disable_interrupts = attr->flags & CE_ATTR_DIS_INTR; + ath10k_ce_send_cb_register(pipe_info->ce_hdl, + ath10k_pci_ce_send_done, + disable_interrupts); + } + + if (attr->dest_nentries) + ath10k_ce_recv_cb_register(pipe_info->ce_hdl, + ath10k_pci_ce_recv_data); + } + + return 0; +} + static void ath10k_pci_kill_tasklet(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); @@ -1210,22 +1230,35 @@ static int ath10k_pci_hif_start(struct ath10k *ar) struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ret; - ret = ath10k_pci_start_ce(ar); + ret = ath10k_pci_alloc_compl(ar); if (ret) { - ath10k_warn("failed to start CE: %d\n", ret); + ath10k_warn("failed to allocate CE completions: %d\n", ret); return ret; } + ret = ath10k_pci_setup_ce_irq(ar); + if (ret) { + ath10k_warn("failed to setup CE interrupts: %d\n", ret); + goto err_free_compl; + } + /* Post buffers once to start things off. */ ret = ath10k_pci_post_rx(ar); if (ret) { ath10k_warn("failed to post RX buffers for all pipes: %d\n", ret); - return ret; + goto err_stop_ce; } ar_pci->started = 1; return 0; + +err_stop_ce: + ath10k_pci_stop_ce(ar); + ath10k_pci_process_ce(ar); +err_free_compl: + ath10k_pci_cleanup_ce(ar); + return ret; } static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info) -- cgit v1.2.3-70-g09d2 From 5d1aa94680f1bf581a4cea2c7137a1423f676795 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 25 Nov 2013 14:06:24 +0100 Subject: ath10k: defer irq registration until hif start() It's impossible to rely on disable_irq() and/or CE interrupt masking with legacy shared interrupts. Other devices sharing the same irq line may assert it while ath10k is doing something that requires no interrupts. Irq handlers are now registered after all preparations are complete so spurious/foreign interrupts won't do any harm. The handlers are unregistered when no interrupts are required (i.e. during driver teardown). This also removes the ability to receive FW early indication (since interrupts are not registered until early boot is complete). This is not mission critical (it's more of a hint that early boot failed due to unexpected FW crash) and will be re-added in a follow up patch. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.c | 15 -------- drivers/net/wireless/ath/ath10k/ce.h | 1 - drivers/net/wireless/ath/ath10k/pci.c | 65 +++++++++++++---------------------- 3 files changed, 23 insertions(+), 58 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index 476928f2dad..d44d618b05f 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -792,21 +792,6 @@ static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state, ath10k_pci_sleep(ar); } -int ath10k_ce_enable_err_irq(struct ath10k *ar) -{ - int i, ret; - - ret = ath10k_pci_wake(ar); - if (ret) - return ret; - - for (i = 0; i < CE_COUNT; i++) - ath10k_ce_error_intr_enable(ar, ath10k_ce_base_address(i)); - - ath10k_pci_sleep(ar); - return 0; -} - int ath10k_ce_disable_interrupts(struct ath10k *ar) { int ce_id, ret; diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index 8a58bac958a..67dbde6a5c7 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -235,7 +235,6 @@ void ath10k_ce_deinit(struct ath10k_ce_pipe *ce_state); void ath10k_ce_per_engine_service_any(struct ath10k *ar); void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id); int ath10k_ce_disable_interrupts(struct ath10k *ar); -int ath10k_ce_enable_err_irq(struct ath10k *ar); /* ce_attr.flags values */ /* Use NonSnooping PCIe accesses? */ diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 05e6f8b4f1b..bd673115ec3 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -919,13 +919,6 @@ static void ath10k_pci_stop_ce(struct ath10k *ar) struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_pci_compl *compl; struct sk_buff *skb; - int ret; - - ret = ath10k_ce_disable_interrupts(ar); - if (ret) - ath10k_warn("failed to disable CE interrupts: %d\n", ret); - - ath10k_pci_kill_tasklet(ar); /* Mark pending completions as aborted, so that upper layers free up * their associated resources */ @@ -1236,10 +1229,17 @@ static int ath10k_pci_hif_start(struct ath10k *ar) return ret; } + ret = ath10k_pci_request_irq(ar); + if (ret) { + ath10k_warn("failed to post RX buffers for all pipes: %d\n", + ret); + goto err_free_compl; + } + ret = ath10k_pci_setup_ce_irq(ar); if (ret) { ath10k_warn("failed to setup CE interrupts: %d\n", ret); - goto err_free_compl; + goto err_stop; } /* Post buffers once to start things off. */ @@ -1247,13 +1247,16 @@ static int ath10k_pci_hif_start(struct ath10k *ar) if (ret) { ath10k_warn("failed to post RX buffers for all pipes: %d\n", ret); - goto err_stop_ce; + goto err_stop; } ar_pci->started = 1; return 0; -err_stop_ce: +err_stop: + ath10k_ce_disable_interrupts(ar); + ath10k_pci_free_irq(ar); + ath10k_pci_kill_tasklet(ar); ath10k_pci_stop_ce(ar); ath10k_pci_process_ce(ar); err_free_compl: @@ -1376,25 +1379,19 @@ static void ath10k_pci_ce_deinit(struct ath10k *ar) } } -static void ath10k_pci_disable_irqs(struct ath10k *ar) -{ - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - int i; - - for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++) - disable_irq(ar_pci->pdev->irq + i); -} - static void ath10k_pci_hif_stop(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + int ret; ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__); - /* Irqs are never explicitly re-enabled. They are implicitly re-enabled - * by upon power_up. */ - ath10k_pci_disable_irqs(ar); + ret = ath10k_ce_disable_interrupts(ar); + if (ret) + ath10k_warn("failed to disable CE interrupts: %d\n", ret); + ath10k_pci_free_irq(ar); + ath10k_pci_kill_tasklet(ar); ath10k_pci_stop_ce(ar); /* At this point, asynchronous threads are stopped, the target should @@ -1945,34 +1942,22 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) goto err_ce; } - ret = ath10k_pci_request_irq(ar); - if (ret) { - ath10k_err("failed to request irqs: %d\n", ret); - goto err_deinit_irq; - } - ret = ath10k_pci_wait_for_target_init(ar); if (ret) { ath10k_err("failed to wait for target to init: %d\n", ret); - goto err_free_irq; - } - - ret = ath10k_ce_enable_err_irq(ar); - if (ret) { - ath10k_err("failed to enable CE error irq: %d\n", ret); - goto err_free_irq; + goto err_deinit_irq; } ret = ath10k_pci_init_config(ar); if (ret) { ath10k_err("failed to setup init config: %d\n", ret); - goto err_free_irq; + goto err_deinit_irq; } ret = ath10k_pci_wake_target_cpu(ar); if (ret) { ath10k_err("could not wake up target CPU: %d\n", ret); - goto err_free_irq; + goto err_deinit_irq; } if (ar_pci->num_msi_intrs > 1) @@ -1987,14 +1972,11 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) return 0; -err_free_irq: - ath10k_pci_free_irq(ar); - ath10k_pci_kill_tasklet(ar); - ath10k_pci_device_reset(ar); err_deinit_irq: ath10k_pci_deinit_irq(ar); err_ce: ath10k_pci_ce_deinit(ar); + ath10k_pci_device_reset(ar); err_ps: if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features)) ath10k_do_pci_sleep(ar); @@ -2006,7 +1988,6 @@ static void ath10k_pci_hif_power_down(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - ath10k_pci_free_irq(ar); ath10k_pci_deinit_irq(ar); ath10k_pci_device_reset(ar); -- cgit v1.2.3-70-g09d2 From 2685218b3f3dd2af1c9ac09d7b3800725bb34d9c Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 25 Nov 2013 14:06:25 +0100 Subject: ath10k: extract functions for legacy irq handling Preparation for code re-use. Also use ioread/write wrappers. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 65 +++++++++++++++++------------------ 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index bd673115ec3..1d2939c35d9 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -220,6 +220,34 @@ static bool ath10k_pci_irq_pending(struct ath10k *ar) return false; } +static void ath10k_pci_disable_and_clear_legacy_irq(struct ath10k *ar) +{ + /* IMPORTANT: INTR_CLR register has to be set after + * INTR_ENABLE is set to 0, otherwise interrupt can not be + * really cleared. */ + ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS, + 0); + ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_CLR_ADDRESS, + PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL); + + /* IMPORTANT: this extra read transaction is required to + * flush the posted write buffer. */ + (void) ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + + PCIE_INTR_ENABLE_ADDRESS); +} + +static void ath10k_pci_enable_legacy_irq(struct ath10k *ar) +{ + ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + + PCIE_INTR_ENABLE_ADDRESS, + PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL); + + /* IMPORTANT: this extra read transaction is required to + * flush the posted write buffer. */ + (void) ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + + PCIE_INTR_ENABLE_ADDRESS); +} + /* * Diagnostic read/write access is provided for startup/config/debug usage. * Caller must guarantee proper alignment, when applicable, and single user @@ -2128,25 +2156,7 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg) if (!ath10k_pci_irq_pending(ar)) return IRQ_NONE; - /* - * IMPORTANT: INTR_CLR regiser has to be set after - * INTR_ENABLE is set to 0, otherwise interrupt can not be - * really cleared. - */ - iowrite32(0, ar_pci->mem + - (SOC_CORE_BASE_ADDRESS | - PCIE_INTR_ENABLE_ADDRESS)); - iowrite32(PCIE_INTR_FIRMWARE_MASK | - PCIE_INTR_CE_MASK_ALL, - ar_pci->mem + (SOC_CORE_BASE_ADDRESS | - PCIE_INTR_CLR_ADDRESS)); - /* - * IMPORTANT: this extra read transaction is required to - * flush the posted write buffer. - */ - (void) ioread32(ar_pci->mem + - (SOC_CORE_BASE_ADDRESS | - PCIE_INTR_ENABLE_ADDRESS)); + ath10k_pci_disable_and_clear_legacy_irq(ar); } tasklet_schedule(&ar_pci->intr_tq); @@ -2162,20 +2172,9 @@ static void ath10k_pci_tasklet(unsigned long data) ath10k_pci_fw_interrupt_handler(ar); /* FIXME: Handle FW error */ ath10k_ce_per_engine_service_any(ar); - if (ar_pci->num_msi_intrs == 0) { - /* Enable Legacy PCI line interrupts */ - iowrite32(PCIE_INTR_FIRMWARE_MASK | - PCIE_INTR_CE_MASK_ALL, - ar_pci->mem + (SOC_CORE_BASE_ADDRESS | - PCIE_INTR_ENABLE_ADDRESS)); - /* - * IMPORTANT: this extra read transaction is required to - * flush the posted write buffer - */ - (void) ioread32(ar_pci->mem + - (SOC_CORE_BASE_ADDRESS | - PCIE_INTR_ENABLE_ADDRESS)); - } + /* Re-enable legacy irq that was disabled in the irq handler */ + if (ar_pci->num_msi_intrs == 0) + ath10k_pci_enable_legacy_irq(ar); } static int ath10k_pci_request_irq_msix(struct ath10k *ar) -- cgit v1.2.3-70-g09d2 From ab977bd04bd56edf473e0317eb2370abba04356c Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 25 Nov 2013 14:06:26 +0100 Subject: ath10k: re-add support for early fw indication It's possible for FW to panic during early boot. The patch re-introduces support to detect and print those crashes. This introduces an additional irq handler that is set for the duration of early boot and shutdown. The handler is then overriden with regular handlers upon hif start(). Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 106 ++++++++++++++++++++++++++++++++-- drivers/net/wireless/ath/ath10k/pci.h | 1 + 2 files changed, 102 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 1d2939c35d9..0a2d1c20e4d 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -248,6 +248,46 @@ static void ath10k_pci_enable_legacy_irq(struct ath10k *ar) PCIE_INTR_ENABLE_ADDRESS); } +static irqreturn_t ath10k_pci_early_irq_handler(int irq, void *arg) +{ + struct ath10k *ar = arg; + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + + if (ar_pci->num_msi_intrs == 0) { + if (!ath10k_pci_irq_pending(ar)) + return IRQ_NONE; + + ath10k_pci_disable_and_clear_legacy_irq(ar); + } + + tasklet_schedule(&ar_pci->early_irq_tasklet); + + return IRQ_HANDLED; +} + +static int ath10k_pci_request_early_irq(struct ath10k *ar) +{ + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + int ret; + + /* Regardless whether MSI-X/MSI/legacy irqs have been set up the first + * interrupt from irq vector is triggered in all cases for FW + * indication/errors */ + ret = request_irq(ar_pci->pdev->irq, ath10k_pci_early_irq_handler, + IRQF_SHARED, "ath10k_pci (early)", ar); + if (ret) { + ath10k_warn("failed to request early irq: %d\n", ret); + return ret; + } + + return 0; +} + +static void ath10k_pci_free_early_irq(struct ath10k *ar) +{ + free_irq(ath10k_pci_priv(ar)->pdev->irq, ar); +} + /* * Diagnostic read/write access is provided for startup/config/debug usage. * Caller must guarantee proper alignment, when applicable, and single user @@ -937,6 +977,7 @@ static void ath10k_pci_kill_tasklet(struct ath10k *ar) tasklet_kill(&ar_pci->intr_tq); tasklet_kill(&ar_pci->msi_fw_err); + tasklet_kill(&ar_pci->early_irq_tasklet); for (i = 0; i < CE_COUNT; i++) tasklet_kill(&ar_pci->pipe_info[i].intr); @@ -1249,12 +1290,15 @@ static int ath10k_pci_post_rx(struct ath10k *ar) static int ath10k_pci_hif_start(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - int ret; + int ret, ret_early; + + ath10k_pci_free_early_irq(ar); + ath10k_pci_kill_tasklet(ar); ret = ath10k_pci_alloc_compl(ar); if (ret) { ath10k_warn("failed to allocate CE completions: %d\n", ret); - return ret; + goto err_early_irq; } ret = ath10k_pci_request_irq(ar); @@ -1289,6 +1333,14 @@ err_stop: ath10k_pci_process_ce(ar); err_free_compl: ath10k_pci_cleanup_ce(ar); +err_early_irq: + /* Though there should be no interrupts (device was reset) + * power_down() expects the early IRQ to be installed as per the + * driver lifecycle. */ + ret_early = ath10k_pci_request_early_irq(ar); + if (ret_early) + ath10k_warn("failed to re-enable early irq: %d\n", ret_early); + return ret; } @@ -1422,6 +1474,10 @@ static void ath10k_pci_hif_stop(struct ath10k *ar) ath10k_pci_kill_tasklet(ar); ath10k_pci_stop_ce(ar); + ret = ath10k_pci_request_early_irq(ar); + if (ret) + ath10k_warn("failed to re-enable early irq: %d\n", ret); + /* At this point, asynchronous threads are stopped, the target should * not DMA nor interrupt. We process the leftovers and then free * everything else up. */ @@ -1970,22 +2026,28 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) goto err_ce; } + ret = ath10k_pci_request_early_irq(ar); + if (ret) { + ath10k_err("failed to request early irq: %d\n", ret); + goto err_deinit_irq; + } + ret = ath10k_pci_wait_for_target_init(ar); if (ret) { ath10k_err("failed to wait for target to init: %d\n", ret); - goto err_deinit_irq; + goto err_free_early_irq; } ret = ath10k_pci_init_config(ar); if (ret) { ath10k_err("failed to setup init config: %d\n", ret); - goto err_deinit_irq; + goto err_free_early_irq; } ret = ath10k_pci_wake_target_cpu(ar); if (ret) { ath10k_err("could not wake up target CPU: %d\n", ret); - goto err_deinit_irq; + goto err_free_early_irq; } if (ar_pci->num_msi_intrs > 1) @@ -2000,6 +2062,8 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) return 0; +err_free_early_irq: + ath10k_pci_free_early_irq(ar); err_deinit_irq: ath10k_pci_deinit_irq(ar); err_ce: @@ -2016,6 +2080,8 @@ static void ath10k_pci_hif_power_down(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + ath10k_pci_free_early_irq(ar); + ath10k_pci_kill_tasklet(ar); ath10k_pci_deinit_irq(ar); ath10k_pci_device_reset(ar); @@ -2164,6 +2230,34 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg) return IRQ_HANDLED; } +static void ath10k_pci_early_irq_tasklet(unsigned long data) +{ + struct ath10k *ar = (struct ath10k *)data; + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + u32 fw_ind; + int ret; + + ret = ath10k_pci_wake(ar); + if (ret) { + ath10k_warn("failed to wake target in early irq tasklet: %d\n", + ret); + return; + } + + fw_ind = ath10k_pci_read32(ar, ar_pci->fw_indicator_address); + if (fw_ind & FW_IND_EVENT_PENDING) { + ath10k_pci_write32(ar, ar_pci->fw_indicator_address, + fw_ind & ~FW_IND_EVENT_PENDING); + + /* Some structures are unavailable during early boot or at + * driver teardown so just print that the device has crashed. */ + ath10k_warn("device crashed - no diagnostics available\n"); + } + + ath10k_pci_sleep(ar); + ath10k_pci_enable_legacy_irq(ar); +} + static void ath10k_pci_tasklet(unsigned long data) { struct ath10k *ar = (struct ath10k *)data; @@ -2280,6 +2374,8 @@ static void ath10k_pci_init_irq_tasklets(struct ath10k *ar) tasklet_init(&ar_pci->intr_tq, ath10k_pci_tasklet, (unsigned long)ar); tasklet_init(&ar_pci->msi_fw_err, ath10k_msi_err_tasklet, (unsigned long)ar); + tasklet_init(&ar_pci->early_irq_tasklet, ath10k_pci_early_irq_tasklet, + (unsigned long)ar); for (i = 0; i < CE_COUNT; i++) { ar_pci->pipe_info[i].ar_pci = ar_pci; diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index 73a3d4ee6eb..a4f32038c44 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -198,6 +198,7 @@ struct ath10k_pci { struct tasklet_struct intr_tq; struct tasklet_struct msi_fw_err; + struct tasklet_struct early_irq_tasklet; int started; -- cgit v1.2.3-70-g09d2 From cfe9c45b21ce2649e31f7e5d997f9c26b56f29e9 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 25 Nov 2013 14:06:27 +0100 Subject: ath10k: allow explicit MSI/MSI-X disabling This can be useful for testing and debugging. This introduces new ath10k_pci module parameter `irq_mode`. By default it is 0, meaning automatic irq mode (MSI-X as long as both target HW and host platform supports it). The parameter works on a best effort basis. kvalo: fix typo "ayto" Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 47 +++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 0a2d1c20e4d..1365b55e7cc 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -33,10 +33,21 @@ #include "ce.h" #include "pci.h" +enum ath10k_pci_irq_mode { + ATH10K_PCI_IRQ_AUTO = 0, + ATH10K_PCI_IRQ_LEGACY = 1, + ATH10K_PCI_IRQ_MSI = 2, +}; + static unsigned int ath10k_target_ps; +static unsigned int ath10k_pci_irq_mode = ATH10K_PCI_IRQ_AUTO; + module_param(ath10k_target_ps, uint, 0644); MODULE_PARM_DESC(ath10k_target_ps, "Enable ath10k Target (SoC) PS option"); +module_param_named(irq_mode, ath10k_pci_irq_mode, uint, 0644); +MODULE_PARM_DESC(irq_mode, "0: auto, 1: legacy, 2: msi (default: 0)"); + #define QCA988X_2_0_DEVICE_ID (0x003c) static DEFINE_PCI_DEVICE_TABLE(ath10k_pci_id_table) = { @@ -2387,27 +2398,37 @@ static void ath10k_pci_init_irq_tasklets(struct ath10k *ar) static int ath10k_pci_init_irq(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + bool msix_supported = test_bit(ATH10K_PCI_FEATURE_MSI_X, + ar_pci->features); int ret; ath10k_pci_init_irq_tasklets(ar); - if (!test_bit(ATH10K_PCI_FEATURE_MSI_X, ar_pci->features)) - goto msi; + if (ath10k_pci_irq_mode != ATH10K_PCI_IRQ_AUTO && + !test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags)) + ath10k_info("limiting irq mode to: %d\n", ath10k_pci_irq_mode); /* Try MSI-X */ - ar_pci->num_msi_intrs = MSI_NUM_REQUEST; - ret = pci_enable_msi_block(ar_pci->pdev, ar_pci->num_msi_intrs); - if (ret == 0) - return 0; - if (ret > 0) - pci_disable_msi(ar_pci->pdev); + if (ath10k_pci_irq_mode == ATH10K_PCI_IRQ_AUTO && msix_supported) { + ar_pci->num_msi_intrs = MSI_NUM_REQUEST; + ret = pci_enable_msi_block(ar_pci->pdev, ar_pci->num_msi_intrs); + if (ret == 0) + return 0; + if (ret > 0) + pci_disable_msi(ar_pci->pdev); + + /* fall-through */ + } -msi: /* Try MSI */ - ar_pci->num_msi_intrs = 1; - ret = pci_enable_msi(ar_pci->pdev); - if (ret == 0) - return 0; + if (ath10k_pci_irq_mode != ATH10K_PCI_IRQ_LEGACY) { + ar_pci->num_msi_intrs = 1; + ret = pci_enable_msi(ar_pci->pdev); + if (ret == 0) + return 0; + + /* fall-through */ + } /* Try legacy irq * -- cgit v1.2.3-70-g09d2 From 6d33a9a658f73e15ab41ddcfe36f4b774207ef1d Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 26 Nov 2013 14:57:40 +0100 Subject: ath10k: fix Tx status clearing Too much of tx info was being cleared. This caused issues in some setups with tx frame status reporting. This should fix some cases of stations not being able to associate to ath10k AP. Reported-By: Matti Laakso Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/txrx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index d476b2cc9d7..22829803f08 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -75,7 +75,7 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, ath10k_report_offchan_tx(htt->ar, msdu); info = IEEE80211_SKB_CB(msdu); - memset(info, 0, sizeof(*info)); + memset(&info->status, 0, sizeof(info->status)); if (tx_done->discard) { ieee80211_free_txskb(htt->ar->hw, msdu); -- cgit v1.2.3-70-g09d2 From 01e0daa43f129fc1a6bc6f1197343c0293af866d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 9 Nov 2013 14:57:54 +0100 Subject: cfg80211: fix reporting 5/10 MHz support to user space nla_put_flag needs a real nl80211 attribute id, not a wiphy flag bit. While at it, split 5 and 10 MHz capability flags in case we ever need to support hardware that can only do one of the two. Also move the flag settings to the split-only information so we don't increase the space needed for old userspace. Signed-off-by: Felix Fietkau [change location of flag setting] Signed-off-by: Johannes Berg --- include/uapi/linux/nl80211.h | 8 ++++++++ net/wireless/nl80211.c | 9 +++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 7e25164adfe..129b7b08714 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1515,6 +1515,11 @@ enum nl80211_commands { * to react to radar events, e.g. initiate a channel switch or leave the * IBSS network. * + * @NL80211_ATTR_SUPPORT_5_MHZ: A flag indicating that the device supports + * 5 MHz channel bandwidth. + * @NL80211_ATTR_SUPPORT_10_MHZ: A flag indicating that the device supports + * 10 MHz channel bandwidth. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1831,6 +1836,9 @@ enum nl80211_attrs { NL80211_ATTR_HANDLE_DFS, + NL80211_ATTR_SUPPORT_5_MHZ, + NL80211_ATTR_SUPPORT_10_MHZ, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 79632edebb6..8c83fbb3824 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1228,10 +1228,6 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, if ((dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) && nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP)) goto nla_put_failure; - if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ) && - nla_put_flag(msg, WIPHY_FLAG_SUPPORTS_5_10_MHZ)) - goto nla_put_failure; - state->split_start++; if (state->split) break; @@ -1560,6 +1556,11 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, if (nl80211_send_coalesce(msg, dev)) goto nla_put_failure; + if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ) && + (nla_put_flag(msg, NL80211_ATTR_SUPPORT_5_MHZ) || + nla_put_flag(msg, NL80211_ATTR_SUPPORT_10_MHZ))) + goto nla_put_failure; + /* done */ state->split_start = 0; break; -- cgit v1.2.3-70-g09d2 From 1d940aaab881b0ee62557ffbaad877ac5a1b51db Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 18 Nov 2013 17:23:26 +0100 Subject: mac80211_hwsim: use CLOCK_MONOTONIC_RAW The beacon timers really shouldn't use any clock that is subject to adjustments from userspace, particularly not CLOCK_REALTIME. Use CLOCK_MONOTONIC_RAW instead. Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index bcc7d8208f2..ab875566c74 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2580,7 +2580,7 @@ static int __init init_mac80211_hwsim(void) tasklet_hrtimer_init(&data->beacon_timer, mac80211_hwsim_beacon, - CLOCK_REALTIME, HRTIMER_MODE_ABS); + CLOCK_MONOTONIC_RAW, HRTIMER_MODE_ABS); list_add_tail(&data->list, &hwsim_radios); } -- cgit v1.2.3-70-g09d2 From ad38bfc916da6aee9160bfa5335aed8d6c190e39 Mon Sep 17 00:00:00 2001 From: Matti Gottlieb Date: Mon, 18 Nov 2013 19:06:45 +0200 Subject: mac80211: Tx frame latency statistics Measure TX latency and jitter statistics per station per TID. These Measurements are disabled by default and can be enabled via debugfs. Features included for each station's TID: 1. Keep count of the maximum and average latency of Tx frames. 2. Keep track of many frames arrived in a specific time range (need to enable through debugfs and configure the bins ranges) Signed-off-by: Matti Gottlieb Signed-off-by: Johannes Berg --- net/mac80211/debugfs.c | 168 +++++++++++++++++++++++++++++++++++++++++++++ net/mac80211/debugfs_sta.c | 134 ++++++++++++++++++++++++++++++++++++ net/mac80211/ieee80211_i.h | 24 +++++++ net/mac80211/main.c | 2 + net/mac80211/sta_info.c | 34 +++++++++ net/mac80211/sta_info.h | 22 ++++++ net/mac80211/status.c | 78 +++++++++++++++++++++ net/mac80211/tx.c | 24 +++++++ 8 files changed, 486 insertions(+) diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 5c090e41d9b..fa16e54980a 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -17,6 +17,172 @@ #define DEBUGFS_FORMAT_BUFFER_SIZE 100 +#define TX_LATENCY_BIN_DELIMTER_C ',' +#define TX_LATENCY_BIN_DELIMTER_S "," +#define TX_LATENCY_BINS_DISABLED "enable(bins disabled)\n" +#define TX_LATENCY_DISABLED "disable\n" + + +/* + * Display if Tx latency statistics & bins are enabled/disabled + */ +static ssize_t sta_tx_latency_stat_read(struct file *file, + char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct ieee80211_local *local = file->private_data; + struct ieee80211_tx_latency_bin_ranges *tx_latency; + char *buf; + int bufsz, i, ret; + int pos = 0; + + rcu_read_lock(); + + tx_latency = rcu_dereference(local->tx_latency); + + if (tx_latency && tx_latency->n_ranges) { + bufsz = tx_latency->n_ranges * 15; + buf = kzalloc(bufsz, GFP_ATOMIC); + if (!buf) + goto err; + + for (i = 0; i < tx_latency->n_ranges; i++) + pos += scnprintf(buf + pos, bufsz - pos, "%d,", + tx_latency->ranges[i]); + pos += scnprintf(buf + pos, bufsz - pos, "\n"); + } else if (tx_latency) { + bufsz = sizeof(TX_LATENCY_BINS_DISABLED) + 1; + buf = kzalloc(bufsz, GFP_ATOMIC); + if (!buf) + goto err; + + pos += scnprintf(buf + pos, bufsz - pos, "%s\n", + TX_LATENCY_BINS_DISABLED); + } else { + bufsz = sizeof(TX_LATENCY_DISABLED) + 1; + buf = kzalloc(bufsz, GFP_ATOMIC); + if (!buf) + goto err; + + pos += scnprintf(buf + pos, bufsz - pos, "%s\n", + TX_LATENCY_DISABLED); + } + + rcu_read_unlock(); + + ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + kfree(buf); + + return ret; +err: + rcu_read_unlock(); + return -ENOMEM; +} + +/* + * Receive input from user regarding Tx latency statistics + * The input should indicate if Tx latency statistics and bins are + * enabled/disabled. + * If bins are enabled input should indicate the amount of different bins and + * their ranges. Each bin will count how many Tx frames transmitted within the + * appropriate latency. + * Legal input is: + * a) "enable(bins disabled)" - to enable only general statistics + * b) "a,b,c,d,...z" - to enable general statistics and bins, where all are + * numbers and a < b < c < d.. < z + * c) "disable" - disable all statistics + * NOTE: must configure Tx latency statistics bins before stations connected. + */ + +static ssize_t sta_tx_latency_stat_write(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct ieee80211_local *local = file->private_data; + char buf[128] = {}; + char *bins = buf; + char *token; + int buf_size, i, alloc_size; + int prev_bin = 0; + int n_ranges = 0; + int ret = count; + struct ieee80211_tx_latency_bin_ranges *tx_latency; + + if (sizeof(buf) <= count) + return -EINVAL; + buf_size = count; + if (copy_from_user(buf, userbuf, buf_size)) + return -EFAULT; + + mutex_lock(&local->sta_mtx); + + /* cannot change config once we have stations */ + if (local->num_sta) + goto unlock; + + tx_latency = + rcu_dereference_protected(local->tx_latency, + lockdep_is_held(&local->sta_mtx)); + + /* disable Tx statistics */ + if (!strcmp(buf, TX_LATENCY_DISABLED)) { + if (!tx_latency) + goto unlock; + rcu_assign_pointer(local->tx_latency, NULL); + synchronize_rcu(); + kfree(tx_latency); + goto unlock; + } + + /* Tx latency already enabled */ + if (tx_latency) + goto unlock; + + if (strcmp(TX_LATENCY_BINS_DISABLED, buf)) { + /* check how many bins and between what ranges user requested */ + token = buf; + while (*token != '\0') { + if (*token == TX_LATENCY_BIN_DELIMTER_C) + n_ranges++; + token++; + } + n_ranges++; + } + + alloc_size = sizeof(struct ieee80211_tx_latency_bin_ranges) + + n_ranges * sizeof(u32); + tx_latency = kzalloc(alloc_size, GFP_ATOMIC); + if (!tx_latency) { + ret = -ENOMEM; + goto unlock; + } + tx_latency->n_ranges = n_ranges; + for (i = 0; i < n_ranges; i++) { /* setting bin ranges */ + token = strsep(&bins, TX_LATENCY_BIN_DELIMTER_S); + sscanf(token, "%d", &tx_latency->ranges[i]); + /* bins values should be in ascending order */ + if (prev_bin >= tx_latency->ranges[i]) { + ret = -EINVAL; + kfree(tx_latency); + goto unlock; + } + prev_bin = tx_latency->ranges[i]; + } + rcu_assign_pointer(local->tx_latency, tx_latency); + +unlock: + mutex_unlock(&local->sta_mtx); + + return ret; +} + +static const struct file_operations stats_tx_latency_ops = { + .write = sta_tx_latency_stat_write, + .read = sta_tx_latency_stat_read, + .open = simple_open, + .llseek = generic_file_llseek, +}; + int mac80211_format_buffer(char __user *userbuf, size_t count, loff_t *ppos, char *fmt, ...) { @@ -315,4 +481,6 @@ void debugfs_hw_add(struct ieee80211_local *local) DEBUGFS_DEVSTATS_ADD(dot11RTSFailureCount); DEBUGFS_DEVSTATS_ADD(dot11FCSErrorCount); DEBUGFS_DEVSTATS_ADD(dot11RTSSuccessCount); + + DEBUGFS_DEVSTATS_ADD(tx_latency); } diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 19c54a44ed4..80194b557a0 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -38,6 +38,13 @@ static const struct file_operations sta_ ##name## _ops = { \ .llseek = generic_file_llseek, \ } +#define STA_OPS_W(name) \ +static const struct file_operations sta_ ##name## _ops = { \ + .write = sta_##name##_write, \ + .open = simple_open, \ + .llseek = generic_file_llseek, \ +} + #define STA_OPS_RW(name) \ static const struct file_operations sta_ ##name## _ops = { \ .read = sta_##name##_read, \ @@ -388,6 +395,131 @@ static ssize_t sta_last_rx_rate_read(struct file *file, char __user *userbuf, } STA_OPS(last_rx_rate); +static int +sta_tx_latency_stat_header(struct ieee80211_tx_latency_bin_ranges *tx_latency, + char *buf, int pos, int bufsz) +{ + int i; + int range_count = tx_latency->n_ranges; + u32 *bin_ranges = tx_latency->ranges; + + pos += scnprintf(buf + pos, bufsz - pos, + "Station\t\t\tTID\tMax\tAvg"); + if (range_count) { + pos += scnprintf(buf + pos, bufsz - pos, + "\t<=%d", bin_ranges[0]); + for (i = 0; i < range_count - 1; i++) + pos += scnprintf(buf + pos, bufsz - pos, "\t%d-%d", + bin_ranges[i], bin_ranges[i+1]); + pos += scnprintf(buf + pos, bufsz - pos, + "\t%d<", bin_ranges[range_count - 1]); + } + + pos += scnprintf(buf + pos, bufsz - pos, "\n"); + + return pos; +} + +static int +sta_tx_latency_stat_table(struct ieee80211_tx_latency_bin_ranges *tx_lat_range, + struct ieee80211_tx_latency_stat *tx_lat, + char *buf, int pos, int bufsz, int tid) +{ + u32 avg = 0; + int j; + int bin_count = tx_lat->bin_count; + + pos += scnprintf(buf + pos, bufsz - pos, "\t\t\t%d", tid); + /* make sure you don't divide in 0 */ + if (tx_lat->counter) + avg = tx_lat->sum / tx_lat->counter; + + pos += scnprintf(buf + pos, bufsz - pos, "\t%d\t%d", + tx_lat->max, avg); + + if (tx_lat_range->n_ranges && tx_lat->bins) + for (j = 0; j < bin_count; j++) + pos += scnprintf(buf + pos, bufsz - pos, + "\t%d", tx_lat->bins[j]); + pos += scnprintf(buf + pos, bufsz - pos, "\n"); + + return pos; +} + +/* + * Output Tx latency statistics station && restart all statistics information + */ +static ssize_t sta_tx_latency_stat_read(struct file *file, + char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct sta_info *sta = file->private_data; + struct ieee80211_local *local = sta->local; + struct ieee80211_tx_latency_bin_ranges *tx_latency; + char *buf; + int bufsz, ret, i; + int pos = 0; + + bufsz = 20 * IEEE80211_NUM_TIDS * + sizeof(struct ieee80211_tx_latency_stat); + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + rcu_read_lock(); + + tx_latency = rcu_dereference(local->tx_latency); + + if (!sta->tx_lat) { + pos += scnprintf(buf + pos, bufsz - pos, + "Tx latency statistics are not enabled\n"); + goto unlock; + } + + pos = sta_tx_latency_stat_header(tx_latency, buf, pos, bufsz); + + pos += scnprintf(buf + pos, bufsz - pos, "%pM\n", sta->sta.addr); + for (i = 0; i < IEEE80211_NUM_TIDS; i++) + pos = sta_tx_latency_stat_table(tx_latency, &sta->tx_lat[i], + buf, pos, bufsz, i); +unlock: + rcu_read_unlock(); + + ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + kfree(buf); + + return ret; +} +STA_OPS(tx_latency_stat); + +static ssize_t sta_tx_latency_stat_reset_write(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + u32 *bins; + int bin_count; + struct sta_info *sta = file->private_data; + int i; + + if (!sta->tx_lat) + return -EINVAL; + + for (i = 0; i < IEEE80211_NUM_TIDS; i++) { + bins = sta->tx_lat[i].bins; + bin_count = sta->tx_lat[i].bin_count; + + sta->tx_lat[i].max = 0; + sta->tx_lat[i].sum = 0; + sta->tx_lat[i].counter = 0; + + if (bin_count) + memset(bins, 0, bin_count * sizeof(u32)); + } + + return count; +} +STA_OPS_W(tx_latency_stat_reset); + #define DEBUGFS_ADD(name) \ debugfs_create_file(#name, 0400, \ sta->debugfs.dir, sta, &sta_ ##name## _ops); @@ -441,6 +573,8 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) DEBUGFS_ADD(last_ack_signal); DEBUGFS_ADD(current_tx_rate); DEBUGFS_ADD(last_rx_rate); + DEBUGFS_ADD(tx_latency_stat); + DEBUGFS_ADD(tx_latency_stat_reset); DEBUGFS_ADD_COUNTER(rx_packets, rx_packets); DEBUGFS_ADD_COUNTER(tx_packets, tx_packets); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 4022ee1afb9..834f0eb3e42 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -898,6 +898,24 @@ struct tpt_led_trigger { }; #endif +/* + * struct ieee80211_tx_latency_bin_ranges - Tx latency statistics bins ranges + * + * Measuring Tx latency statistics. Counts how many Tx frames transmitted in a + * certain latency range (in Milliseconds). Each station that uses these + * ranges will have bins to count the amount of frames received in that range. + * The user can configure the ranges via debugfs. + * If ranges is NULL then Tx latency statistics bins are disabled for all + * stations. + * + * @n_ranges: number of ranges that are taken in account + * @ranges: the ranges that the user requested or NULL if disabled. + */ +struct ieee80211_tx_latency_bin_ranges { + int n_ranges; + u32 ranges[]; +}; + /** * mac80211 scan flags - currently active scan mode * @@ -1050,6 +1068,12 @@ struct ieee80211_local { struct timer_list sta_cleanup; int sta_generation; + /* + * Tx latency statistics parameters for all stations. + * Can enable via debugfs (NULL when disabled). + */ + struct ieee80211_tx_latency_bin_ranges __rcu *tx_latency; + struct sk_buff_head pending[IEEE80211_MAX_QUEUES]; struct tasklet_struct tx_pending_tasklet; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index bdb0b6c104b..8af75f0eed6 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -1142,6 +1142,8 @@ void ieee80211_free_hw(struct ieee80211_hw *hw) ieee80211_free_ack_frame, NULL); idr_destroy(&local->ack_status_frames); + kfree(rcu_access_pointer(local->tx_latency)); + wiphy_free(local->hw.wiphy); } EXPORT_SYMBOL(ieee80211_free_hw); diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 7b69d4c3db5..8ed97f76c3c 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -266,9 +266,17 @@ struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata, */ void sta_info_free(struct ieee80211_local *local, struct sta_info *sta) { + int i; + if (sta->rate_ctrl) rate_control_free_sta(sta); + if (sta->tx_lat) { + for (i = 0; i < IEEE80211_NUM_TIDS; i++) + kfree(sta->tx_lat[i].bins); + kfree(sta->tx_lat); + } + sta_dbg(sta->sdata, "Destroyed STA %pM\n", sta->sta.addr); kfree(sta); @@ -333,6 +341,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local = sdata->local; struct sta_info *sta; struct timespec uptime; + struct ieee80211_tx_latency_bin_ranges *tx_latency; int i; sta = kzalloc(sizeof(*sta) + local->hw.sta_data_size, gfp); @@ -410,6 +419,31 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, } } + rcu_read_lock(); + + tx_latency = rcu_dereference(local->tx_latency); + /* init stations Tx latency statistics && TID bins */ + if (tx_latency) + sta->tx_lat = kzalloc(IEEE80211_NUM_TIDS * + sizeof(struct ieee80211_tx_latency_stat), + GFP_ATOMIC); + + /* + * if Tx latency and bins are enabled and the previous allocation + * succeeded + */ + if (tx_latency && tx_latency->n_ranges && sta->tx_lat) + for (i = 0; i < IEEE80211_NUM_TIDS; i++) { + /* size of bins is size of the ranges +1 */ + sta->tx_lat[i].bin_count = + tx_latency->n_ranges + 1; + sta->tx_lat[i].bins = kcalloc(sta->tx_lat[i].bin_count, + sizeof(u32), + GFP_ATOMIC); + } + + rcu_read_unlock(); + sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr); return sta; diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index a2c9a4c45aa..0218caf5c14 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -220,6 +220,25 @@ struct sta_ampdu_mlme { u8 dialog_token_allocator; }; +/* + * struct ieee80211_tx_latency_stat - Tx latency statistics + * + * Measures TX latency and jitter for a station per TID. + * + * @max: worst case latency + * @sum: sum of all latencies + * @counter: amount of Tx frames sent from interface + * @bins: each bin counts how many frames transmitted within a certain + * latency range. when disabled it is NULL. + * @bin_count: amount of bins. + */ +struct ieee80211_tx_latency_stat { + u32 max; + u32 sum; + u32 counter; + u32 *bins; + u32 bin_count; +}; /** * struct sta_info - STA information @@ -276,6 +295,7 @@ struct sta_ampdu_mlme { * @tid_seq: per-TID sequence numbers for sending to this STA * @ampdu_mlme: A-MPDU state machine state * @timer_to_tid: identity mapping to ID timers + * @tx_lat: Tx latency statistics * @llid: Local link ID * @plid: Peer link ID * @reason: Cancel reason on PLINK_HOLDING state @@ -385,6 +405,8 @@ struct sta_info { struct sta_ampdu_mlme ampdu_mlme; u8 timer_to_tid[IEEE80211_NUM_TIDS]; + struct ieee80211_tx_latency_stat *tx_lat; + #ifdef CONFIG_MAC80211_MESH /* * Mesh peer link attributes diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 52a152b01b0..1ee85c40243 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include "ieee80211_i.h" @@ -462,6 +463,77 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local, } } +/* + * Measure Tx frame completion and removal time for Tx latency statistics + * calculation. A single Tx frame latency should be measured from when it + * is entering the Kernel until we receive Tx complete confirmation indication + * and remove the skb. + */ +static void ieee80211_tx_latency_end_msrmnt(struct ieee80211_local *local, + struct sk_buff *skb, + struct sta_info *sta, + struct ieee80211_hdr *hdr) +{ + ktime_t skb_dprt; + struct timespec dprt_time; + u32 msrmnt; + u16 tid; + u8 *qc; + int i, bin_range_count, bin_count; + u32 *bin_ranges; + __le16 fc; + struct ieee80211_tx_latency_stat *tx_lat; + struct ieee80211_tx_latency_bin_ranges *tx_latency; + ktime_t skb_arv = skb->tstamp; + + tx_latency = rcu_dereference(local->tx_latency); + + /* assert Tx latency stats are enabled & frame arrived when enabled */ + if (!tx_latency || !ktime_to_ns(skb_arv)) + return; + + fc = hdr->frame_control; + + if (!ieee80211_is_data(fc)) /* make sure it is a data frame */ + return; + + /* get frame tid */ + if (ieee80211_is_data_qos(hdr->frame_control)) { + qc = ieee80211_get_qos_ctl(hdr); + tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; + } else { + tid = 0; + } + + tx_lat = &sta->tx_lat[tid]; + + ktime_get_ts(&dprt_time); /* time stamp completion time */ + skb_dprt = ktime_set(dprt_time.tv_sec, dprt_time.tv_nsec); + msrmnt = ktime_to_ms(ktime_sub(skb_dprt, skb_arv)); + + if (tx_lat->max < msrmnt) /* update stats */ + tx_lat->max = msrmnt; + tx_lat->counter++; + tx_lat->sum += msrmnt; + + if (!tx_lat->bins) /* bins not activated */ + return; + + /* count how many Tx frames transmitted with the appropriate latency */ + bin_range_count = tx_latency->n_ranges; + bin_ranges = tx_latency->ranges; + bin_count = tx_lat->bin_count; + + for (i = 0; i < bin_range_count; i++) { + if (msrmnt <= bin_ranges[i]) { + tx_lat->bins[i]++; + break; + } + } + if (i == bin_range_count) /* msrmnt is bigger than the biggest range */ + tx_lat->bins[i]++; +} + /* * Use a static threshold for now, best value to be determined * by testing ... @@ -620,6 +692,12 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) if (acked) sta->last_ack_signal = info->status.ack_signal; + + /* + * Measure frame removal for tx latency + * statistics calculation + */ + ieee80211_tx_latency_end_msrmnt(local, skb, sta, hdr); } rcu_read_unlock(); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index e541856b400..6d59e21cdb9 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -1741,6 +1742,26 @@ fail: return NETDEV_TX_OK; /* meaning, we dealt with the skb */ } +/* + * Measure Tx frame arrival time for Tx latency statistics calculation + * A single Tx frame latency should be measured from when it is entering the + * Kernel until we receive Tx complete confirmation indication and the skb is + * freed. + */ +static void ieee80211_tx_latency_start_msrmnt(struct ieee80211_local *local, + struct sk_buff *skb) +{ + struct timespec skb_arv; + struct ieee80211_tx_latency_bin_ranges *tx_latency; + + tx_latency = rcu_dereference(local->tx_latency); + if (!tx_latency) + return; + + ktime_get_ts(&skb_arv); + skb->tstamp = ktime_set(skb_arv.tv_sec, skb_arv.tv_nsec); +} + /** * ieee80211_subif_start_xmit - netif start_xmit function for Ethernet-type * subinterfaces (wlan#, WDS, and VLAN interfaces) @@ -1791,6 +1812,9 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, rcu_read_lock(); + /* Measure frame arrival for Tx latency statistics calculation */ + ieee80211_tx_latency_start_msrmnt(local, skb); + switch (sdata->vif.type) { case NL80211_IFTYPE_AP_VLAN: sta = rcu_dereference(sdata->u.vlan.sta); -- cgit v1.2.3-70-g09d2 From 2ce6a0f554868ef6b07966254a612f710a909136 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 18 Nov 2013 19:06:47 +0200 Subject: mac80211: remove sta_info_flush() from interface teardown All interface types now properly clean up their stations using some form of sta_info_flush() themselves, so there's no need to try it again at teardown. Remove the call to get rid of the extra delay from the synchronize_net() and rcu_barrier() calls. Reported-by: Moshe Benji Signed-off-by: Johannes Berg --- net/mac80211/iface.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index a851bf4f05e..d226751ba63 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1041,7 +1041,6 @@ static void ieee80211_set_multicast_list(struct net_device *dev) */ static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata) { - int flushed; int i; /* free extra data */ @@ -1055,9 +1054,6 @@ static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata) if (ieee80211_vif_is_mesh(&sdata->vif)) mesh_rmc_free(sdata); - - flushed = sta_info_flush(sdata); - WARN_ON(flushed); } static void ieee80211_uninit(struct net_device *dev) -- cgit v1.2.3-70-g09d2 From 017b45bb5c5b40d9da1ea671aa8bc2eaec73675f Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Mon, 18 Nov 2013 19:06:48 +0200 Subject: mac80211: update ht flag if bss configuration changed There's a bug in tracking HT opmode changes in mac80211, it fails to update the driver when the channel parameters don't change. Move the code to do the HT opmode checking independently of the channel/bandwidth tracking. Signed-off-by: Avri Altman [edit commit message] Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 2bb3a8631b1..33bcf8018d8 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -330,6 +330,16 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata, if (WARN_ON_ONCE(!sta)) return -EINVAL; + /* + * if bss configuration changed store the new one - + * this may be applicable even if channel is identical + */ + ht_opmode = le16_to_cpu(ht_oper->operation_mode); + if (sdata->vif.bss_conf.ht_operation_mode != ht_opmode) { + *changed |= BSS_CHANGED_HT; + sdata->vif.bss_conf.ht_operation_mode = ht_opmode; + } + chan = sdata->vif.bss_conf.chandef.chan; sband = local->hw.wiphy->bands[chan->band]; @@ -416,14 +426,6 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata, IEEE80211_RC_BW_CHANGED); } - ht_opmode = le16_to_cpu(ht_oper->operation_mode); - - /* if bss configuration changed store the new one */ - if (sdata->vif.bss_conf.ht_operation_mode != ht_opmode) { - *changed |= BSS_CHANGED_HT; - sdata->vif.bss_conf.ht_operation_mode = ht_opmode; - } - return 0; } -- cgit v1.2.3-70-g09d2 From b176e629402f41f2b984d3aa842ddae23ed5562e Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Mon, 18 Nov 2013 19:06:49 +0200 Subject: cfg80211: aggregate mgmt_tx parameters into a struct Change cfg80211 and mac80211 to use cfg80211_mgmt_tx_params struct to aggregate parameters for mgmt_tx functions. This makes the functions' signatures less clumsy and allows less painful parameters extension. Signed-off-by: Andrei Otcheretianski [fix all other drivers] Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 9 ++++-- .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 7 +++-- drivers/net/wireless/mwifiex/cfg80211.c | 6 ++-- include/net/cfg80211.h | 28 +++++++++++++++++-- net/mac80211/cfg.c | 29 ++++++++++---------- net/wireless/core.h | 5 ++-- net/wireless/mlme.c | 12 +++----- net/wireless/nl80211.c | 32 +++++++++++----------- net/wireless/rdev-ops.h | 12 +++----- net/wireless/trace.h | 15 +++++----- 10 files changed, 86 insertions(+), 69 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 2437ad26949..36dc61da833 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -3169,12 +3169,15 @@ static bool ath6kl_is_p2p_go_ssid(const u8 *buf, size_t len) } static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, - struct ieee80211_channel *chan, bool offchan, - unsigned int wait, const u8 *buf, size_t len, - bool no_cck, bool dont_wait_for_ack, u64 *cookie) + struct cfg80211_mgmt_tx_params *params, u64 *cookie) { struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev); struct ath6kl *ar = ath6kl_priv(vif->ndev); + struct ieee80211_channel *chan = params->chan; + const u8 *buf = params->buf; + size_t len = params->len; + unsigned int wait = params->wait; + bool no_cck = params->no_cck; u32 id, freq; const struct ieee80211_mgmt *mgmt; bool more_data, queued; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 1850efa83cf..f0bdfb12066 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -3973,11 +3973,12 @@ brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy, static int brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, - struct ieee80211_channel *chan, bool offchan, - unsigned int wait, const u8 *buf, size_t len, - bool no_cck, bool dont_wait_for_ack, u64 *cookie) + struct cfg80211_mgmt_tx_params *params, u64 *cookie) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct ieee80211_channel *chan = params->chan; + const u8 *buf = params->buf; + size_t len = params->len; const struct ieee80211_mgmt *mgmt; struct brcmf_cfg80211_vif *vif; s32 err = 0; diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index d6d1d91a26d..1c8116d4684 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -184,10 +184,10 @@ mwifiex_form_mgmt_frame(struct sk_buff *skb, const u8 *buf, size_t len) */ static int mwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, - struct ieee80211_channel *chan, bool offchan, - unsigned int wait, const u8 *buf, size_t len, - bool no_cck, bool dont_wait_for_ack, u64 *cookie) + struct cfg80211_mgmt_tx_params *params, u64 *cookie) { + const u8 *buf = params->buf; + size_t len = params->len; struct sk_buff *skb; u16 pkt_len; const struct ieee80211_mgmt *mgmt; diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index bacc5033f0b..6c2bc329a90 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1943,6 +1943,29 @@ struct cfg80211_update_ft_ies_params { size_t ie_len; }; +/** + * struct cfg80211_mgmt_tx_params - mgmt tx parameters + * + * This structure provides information needed to transmit a mgmt frame + * + * @chan: channel to use + * @offchan: indicates wether off channel operation is required + * @wait: duration for ROC + * @buf: buffer to transmit + * @len: buffer length + * @no_cck: don't use cck rates for this frame + * @dont_wait_for_ack: tells the low level not to wait for an ack + */ +struct cfg80211_mgmt_tx_params { + struct ieee80211_channel *chan; + bool offchan; + unsigned int wait; + const u8 *buf; + size_t len; + bool no_cck; + bool dont_wait_for_ack; +}; + /** * struct cfg80211_ops - backend description for wireless configuration * @@ -2341,9 +2364,8 @@ struct cfg80211_ops { u64 cookie); int (*mgmt_tx)(struct wiphy *wiphy, struct wireless_dev *wdev, - struct ieee80211_channel *chan, bool offchan, - unsigned int wait, const u8 *buf, size_t len, - bool no_cck, bool dont_wait_for_ack, u64 *cookie); + struct cfg80211_mgmt_tx_params *params, + u64 *cookie); int (*mgmt_tx_cancel_wait)(struct wiphy *wiphy, struct wireless_dev *wdev, u64 cookie); diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index c7b3e57aec0..267d3aca994 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -3167,26 +3167,25 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, } static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, - struct ieee80211_channel *chan, bool offchan, - unsigned int wait, const u8 *buf, size_t len, - bool no_cck, bool dont_wait_for_ack, u64 *cookie) + struct cfg80211_mgmt_tx_params *params, + u64 *cookie) { struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); struct ieee80211_local *local = sdata->local; struct sk_buff *skb; struct sta_info *sta; - const struct ieee80211_mgmt *mgmt = (void *)buf; + const struct ieee80211_mgmt *mgmt = (void *)params->buf; bool need_offchan = false; u32 flags; int ret; - if (dont_wait_for_ack) + if (params->dont_wait_for_ack) flags = IEEE80211_TX_CTL_NO_ACK; else flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX | IEEE80211_TX_CTL_REQ_TX_STATUS; - if (no_cck) + if (params->no_cck) flags |= IEEE80211_TX_CTL_NO_CCK_RATE; switch (sdata->vif.type) { @@ -3234,7 +3233,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, /* configurations requiring offchan cannot work if no channel has been * specified */ - if (need_offchan && !chan) + if (need_offchan && !params->chan) return -EINVAL; mutex_lock(&local->mtx); @@ -3247,8 +3246,10 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); if (chanctx_conf) { - need_offchan = chan && (chan != chanctx_conf->def.chan); - } else if (!chan) { + need_offchan = params->chan && + (params->chan != + chanctx_conf->def.chan); + } else if (!params->chan) { ret = -EINVAL; rcu_read_unlock(); goto out_unlock; @@ -3258,19 +3259,19 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, rcu_read_unlock(); } - if (need_offchan && !offchan) { + if (need_offchan && !params->offchan) { ret = -EBUSY; goto out_unlock; } - skb = dev_alloc_skb(local->hw.extra_tx_headroom + len); + skb = dev_alloc_skb(local->hw.extra_tx_headroom + params->len); if (!skb) { ret = -ENOMEM; goto out_unlock; } skb_reserve(skb, local->hw.extra_tx_headroom); - memcpy(skb_put(skb, len), buf, len); + memcpy(skb_put(skb, params->len), params->buf, params->len); IEEE80211_SKB_CB(skb)->flags = flags; @@ -3290,8 +3291,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, local->hw.offchannel_tx_hw_queue; /* This will handle all kinds of coalescing and immediate TX */ - ret = ieee80211_start_roc_work(local, sdata, chan, - wait, cookie, skb, + ret = ieee80211_start_roc_work(local, sdata, params->chan, + params->wait, cookie, skb, IEEE80211_ROC_TYPE_MGMT_TX); if (ret) kfree_skb(skb); diff --git a/net/wireless/core.h b/net/wireless/core.h index 2888867ee7c..6716c5c3f74 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -317,9 +317,8 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid); void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev); int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, - struct ieee80211_channel *chan, bool offchan, - unsigned int wait, const u8 *buf, size_t len, - bool no_cck, bool dont_wait_for_ack, u64 *cookie); + struct cfg80211_mgmt_tx_params *params, + u64 *cookie); void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa, const struct ieee80211_ht_cap *ht_capa_mask); void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa, diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 31f541f7e4e..52cca05044a 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -520,9 +520,7 @@ void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev) int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, - struct ieee80211_channel *chan, bool offchan, - unsigned int wait, const u8 *buf, size_t len, - bool no_cck, bool dont_wait_for_ack, u64 *cookie) + struct cfg80211_mgmt_tx_params *params, u64 *cookie) { const struct ieee80211_mgmt *mgmt; u16 stype; @@ -533,10 +531,10 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, if (!rdev->ops->mgmt_tx) return -EOPNOTSUPP; - if (len < 24 + 1) + if (params->len < 24 + 1) return -EINVAL; - mgmt = (const struct ieee80211_mgmt *) buf; + mgmt = (const struct ieee80211_mgmt *)params->buf; if (!ieee80211_is_mgmt(mgmt->frame_control)) return -EINVAL; @@ -615,9 +613,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, return -EINVAL; /* Transmit the Action frame as requested by user space */ - return rdev_mgmt_tx(rdev, wdev, chan, offchan, - wait, buf, len, no_cck, dont_wait_for_ack, - cookie); + return rdev_mgmt_tx(rdev, wdev, params, cookie); } bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 8c83fbb3824..703155b1aa7 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -7428,10 +7428,10 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) void *hdr = NULL; u64 cookie; struct sk_buff *msg = NULL; - unsigned int wait = 0; - bool offchan, no_cck, dont_wait_for_ack; - - dont_wait_for_ack = info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK]; + struct cfg80211_mgmt_tx_params params = { + .dont_wait_for_ack = + info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK], + }; if (!info->attrs[NL80211_ATTR_FRAME]) return -EINVAL; @@ -7458,24 +7458,24 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_DURATION]) { if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX)) return -EINVAL; - wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]); + params.wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]); /* * We should wait on the channel for at least a minimum amount * of time (10ms) but no longer than the driver supports. */ - if (wait < NL80211_MIN_REMAIN_ON_CHANNEL_TIME || - wait > rdev->wiphy.max_remain_on_channel_duration) + if (params.wait < NL80211_MIN_REMAIN_ON_CHANNEL_TIME || + params.wait > rdev->wiphy.max_remain_on_channel_duration) return -EINVAL; } - offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK]; + params.offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK]; - if (offchan && !(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX)) + if (params.offchan && !(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX)) return -EINVAL; - no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]); + params.no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]); /* get the channel if any has been specified, otherwise pass NULL to * the driver. The latter will use the current one @@ -7487,10 +7487,10 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) return err; } - if (!chandef.chan && offchan) + if (!chandef.chan && params.offchan) return -EINVAL; - if (!dont_wait_for_ack) { + if (!params.dont_wait_for_ack) { msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) return -ENOMEM; @@ -7503,10 +7503,10 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) } } - err = cfg80211_mlme_mgmt_tx(rdev, wdev, chandef.chan, offchan, wait, - nla_data(info->attrs[NL80211_ATTR_FRAME]), - nla_len(info->attrs[NL80211_ATTR_FRAME]), - no_cck, dont_wait_for_ack, &cookie); + params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]); + params.len = nla_len(info->attrs[NL80211_ATTR_FRAME]); + params.chan = chandef.chan; + err = cfg80211_mlme_mgmt_tx(rdev, wdev, ¶ms, &cookie); if (err) goto free_msg; diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 37ce9fdfe93..a6c03ab14a0 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -624,16 +624,12 @@ rdev_cancel_remain_on_channel(struct cfg80211_registered_device *rdev, static inline int rdev_mgmt_tx(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, - struct ieee80211_channel *chan, bool offchan, - unsigned int wait, const u8 *buf, size_t len, - bool no_cck, bool dont_wait_for_ack, u64 *cookie) + struct cfg80211_mgmt_tx_params *params, + u64 *cookie) { int ret; - trace_rdev_mgmt_tx(&rdev->wiphy, wdev, chan, offchan, - wait, no_cck, dont_wait_for_ack); - ret = rdev->ops->mgmt_tx(&rdev->wiphy, wdev, chan, offchan, - wait, buf, len, no_cck, - dont_wait_for_ack, cookie); + trace_rdev_mgmt_tx(&rdev->wiphy, wdev, params); + ret = rdev->ops->mgmt_tx(&rdev->wiphy, wdev, params, cookie); trace_rdev_return_int_cookie(&rdev->wiphy, ret, *cookie); return ret; } diff --git a/net/wireless/trace.h b/net/wireless/trace.h index ba5f0d6614d..f7aa7a72d9b 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -1653,9 +1653,8 @@ TRACE_EVENT(rdev_cancel_remain_on_channel, TRACE_EVENT(rdev_mgmt_tx, TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, - struct ieee80211_channel *chan, bool offchan, - unsigned int wait, bool no_cck, bool dont_wait_for_ack), - TP_ARGS(wiphy, wdev, chan, offchan, wait, no_cck, dont_wait_for_ack), + struct cfg80211_mgmt_tx_params *params), + TP_ARGS(wiphy, wdev, params), TP_STRUCT__entry( WIPHY_ENTRY WDEV_ENTRY @@ -1668,11 +1667,11 @@ TRACE_EVENT(rdev_mgmt_tx, TP_fast_assign( WIPHY_ASSIGN; WDEV_ASSIGN; - CHAN_ASSIGN(chan); - __entry->offchan = offchan; - __entry->wait = wait; - __entry->no_cck = no_cck; - __entry->dont_wait_for_ack = dont_wait_for_ack; + CHAN_ASSIGN(params->chan); + __entry->offchan = params->offchan; + __entry->wait = params->wait; + __entry->no_cck = params->no_cck; + __entry->dont_wait_for_ack = params->dont_wait_for_ack; ), TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", " CHAN_PR_FMT ", offchan: %s," " wait: %u, no cck: %s, dont wait for ack: %s", -- cgit v1.2.3-70-g09d2 From ce95320443c72ba43f8f9c6ceb276673cc30e2ce Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Mon, 18 Nov 2013 17:25:28 -0500 Subject: mac80211: mesh: only get tsf if we need it The local TSF timer is used to compute the timing offset between mesh peers on beacon reception. However, asking the device for the TSF is not very accurate, so we prefer to use rx->mactime if available. In the latter case, calling drv_get_tsf() just adds more delay into the RX path, so skip it if we can. Signed-off-by: Bob Copeland Signed-off-by: Johannes Berg --- net/mac80211/mesh_sync.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/net/mac80211/mesh_sync.c b/net/mac80211/mesh_sync.c index 05a256b38e2..d1cf2d55349 100644 --- a/net/mac80211/mesh_sync.c +++ b/net/mac80211/mesh_sync.c @@ -92,12 +92,20 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, if (stype != IEEE80211_STYPE_BEACON) return; - /* The current tsf is a first approximation for the timestamp - * for the received beacon. Further down we try to get a - * better value from the rx_status->mactime field if - * available. Also we have to call drv_get_tsf() before - * entering the rcu-read section.*/ - t_r = drv_get_tsf(local, sdata); + /* + * Get time when timestamp field was received. If we don't + * have rx timestamps, then use current tsf as an approximation. + * drv_get_tsf() must be called before entering the rcu-read + * section. + */ + if (ieee80211_have_rx_timestamp(rx_status)) + t_r = ieee80211_calculate_rx_timestamp(local, rx_status, + 24 + 12 + + elems->total_len + + FCS_LEN, + 24); + else + t_r = drv_get_tsf(local, sdata); rcu_read_lock(); sta = sta_info_get(sdata, mgmt->sa); @@ -117,14 +125,6 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, goto no_sync; } - if (ieee80211_have_rx_timestamp(rx_status)) - /* time when timestamp field was received */ - t_r = ieee80211_calculate_rx_timestamp(local, rx_status, - 24 + 12 + - elems->total_len + - FCS_LEN, - 24); - /* Timing offset calculation (see 13.13.2.2.2) */ t_t = le64_to_cpu(mgmt->u.beacon.timestamp); sta->t_offset = t_t - t_r; -- cgit v1.2.3-70-g09d2 From c56589ed1d25ae110a5b000bc1edea8f6861348f Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Thu, 21 Nov 2013 18:19:49 +0100 Subject: cfg80211: protect beacon changing functions with wdev-lock To avoid race conditions in functions which modify the beacon information, lock these using the wdev lock. This is especially required to avoid problems for csa handling functions which modify beacons but can not be called under rtnl lock. Reported-by: Johannes Berg Signed-off-by: Simon Wunderlich Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 703155b1aa7..398756c226c 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3218,6 +3218,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) return PTR_ERR(params.acl); } + wdev_lock(wdev); err = rdev_start_ap(rdev, dev, ¶ms); if (!err) { wdev->preset_chandef = params.chandef; @@ -3226,6 +3227,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) wdev->ssid_len = params.ssid_len; memcpy(wdev->ssid, params.ssid, wdev->ssid_len); } + wdev_unlock(wdev); kfree(params.acl); @@ -3254,7 +3256,11 @@ static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info) if (err) return err; - return rdev_change_beacon(rdev, dev, ¶ms); + wdev_lock(wdev); + err = rdev_change_beacon(rdev, dev, ¶ms); + wdev_unlock(wdev); + + return err; } static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info) @@ -4460,7 +4466,9 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = dev->ieee80211_ptr; struct bss_parameters params; + int err; memset(¶ms, 0, sizeof(params)); /* default to not changing parameters */ @@ -4526,7 +4534,11 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) return -EOPNOTSUPP; - return rdev_change_bss(rdev, dev, ¶ms); + wdev_lock(wdev); + err = rdev_change_bss(rdev, dev, ¶ms); + wdev_unlock(wdev); + + return err; } static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = { @@ -5791,7 +5803,11 @@ skip_beacons: if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX]) params.block_tx = true; - return rdev_channel_switch(rdev, dev, ¶ms); + wdev_lock(wdev); + err = rdev_channel_switch(rdev, dev, ¶ms); + wdev_unlock(wdev); + + return err; } static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, -- cgit v1.2.3-70-g09d2 From 7ca133bc7f9dd5cee2b469eb917bd352be80a690 Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Thu, 21 Nov 2013 18:19:50 +0100 Subject: mac80211: modify beacon using sdata/wdev-lock, not rtnl lock The csa finalize worker needs to change the beacon information (for different modes). These are normally protected under rtnl lock, but the csa finalize worker is called by drivers and should not acquire the RTNL lock. Therefore change access protection for beacons to sdata/wdev lock. Reported-by: Johannes Berg Signed-off-by: Simon Wunderlich [fix sdata_dereference] Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 20 ++++++++++++-------- net/mac80211/ieee80211_i.h | 3 +++ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 267d3aca994..4a5c21ed64d 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -857,7 +857,7 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, if (!resp || !resp_len) return 1; - old = rtnl_dereference(sdata->u.ap.probe_resp); + old = sdata_dereference(sdata->u.ap.probe_resp, sdata); new = kzalloc(sizeof(struct probe_resp) + resp_len, GFP_KERNEL); if (!new) @@ -881,7 +881,8 @@ int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, int size, err; u32 changed = BSS_CHANGED_BEACON; - old = rtnl_dereference(sdata->u.ap.beacon); + old = sdata_dereference(sdata->u.ap.beacon, sdata); + /* Need to have a beacon head if we don't have one yet */ if (!params->head && !old) @@ -958,7 +959,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, BSS_CHANGED_P2P_PS; int err; - old = rtnl_dereference(sdata->u.ap.beacon); + old = sdata_dereference(sdata->u.ap.beacon, sdata); if (old) return -EALREADY; @@ -1020,7 +1021,8 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, err = drv_start_ap(sdata->local, sdata); if (err) { - old = rtnl_dereference(sdata->u.ap.beacon); + old = sdata_dereference(sdata->u.ap.beacon, sdata); + if (old) kfree_rcu(old, rcu_head); RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); @@ -1051,7 +1053,7 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, if (sdata->vif.csa_active) return -EBUSY; - old = rtnl_dereference(sdata->u.ap.beacon); + old = sdata_dereference(sdata->u.ap.beacon, sdata); if (!old) return -ENOENT; @@ -1071,10 +1073,10 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) struct probe_resp *old_probe_resp; struct cfg80211_chan_def chandef; - old_beacon = rtnl_dereference(sdata->u.ap.beacon); + old_beacon = sdata_dereference(sdata->u.ap.beacon, sdata); if (!old_beacon) return -ENOENT; - old_probe_resp = rtnl_dereference(sdata->u.ap.probe_resp); + old_probe_resp = sdata_dereference(sdata->u.ap.probe_resp, sdata); /* abort any running channel switch */ sdata->vif.csa_active = false; @@ -1975,7 +1977,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy, enum ieee80211_band band; u32 changed = 0; - if (!rtnl_dereference(sdata->u.ap.beacon)) + if (!sdata_dereference(sdata->u.ap.beacon, sdata)) return -ENOENT; band = ieee80211_get_sdata_band(sdata); @@ -3045,6 +3047,8 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_if_mesh __maybe_unused *ifmsh; int err, num_chanctx; + lockdep_assert_held(&sdata->wdev.mtx); + if (!list_empty(&local->roc_list) || local->scanning) return -EBUSY; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 834f0eb3e42..32bae218d6e 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -813,6 +813,9 @@ static inline void sdata_unlock(struct ieee80211_sub_if_data *sdata) __release(&sdata->wdev.mtx); } +#define sdata_dereference(p, sdata) \ + rcu_dereference_protected(p, lockdep_is_held(&sdata->wdev.mtx)) + static inline void sdata_assert_lock(struct ieee80211_sub_if_data *sdata) { -- cgit v1.2.3-70-g09d2 From e487eaeb076a44c69dc61348cbc903151bb8fcbd Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Thu, 21 Nov 2013 18:19:51 +0100 Subject: cfg80211/mac80211/ath6kl: acquire wdev lock outside ch_switch_notify The channel switch notification should be sent under the wdev/sdata-lock, preferably in the same moment as the channel change happens, to avoid races by other callers (e.g. start/stop_ap). This also adds the previously missing sdata_lock protection in csa_finalize_work. Reported-by: Johannes Berg Signed-off-by: Simon Wunderlich Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 2 ++ include/net/cfg80211.h | 3 ++- net/mac80211/cfg.c | 21 +++++++++++++++------ net/wireless/nl80211.c | 9 +++------ 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 36dc61da833..fd4c89df67e 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -1109,7 +1109,9 @@ void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq, (mode == WMI_11G_HT20) ? NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT); + mutex_lock(&vif->wdev.mtx); cfg80211_ch_switch_notify(vif->ndev, &chandef); + mutex_unlock(&vif->wdev.mtx); } static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 6c2bc329a90..e9abc7b536c 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -4286,7 +4286,8 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy, * @dev: the device which switched channels * @chandef: the new channel definition * - * Acquires wdev_lock, so must only be called from sleepable driver context! + * Caller must acquire wdev_lock, therefore must only be called from sleepable + * driver context! */ void cfg80211_ch_switch_notify(struct net_device *dev, struct cfg80211_chan_def *chandef); diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 4a5c21ed64d..1d446ac97ab 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2988,13 +2988,18 @@ void ieee80211_csa_finalize_work(struct work_struct *work) struct ieee80211_local *local = sdata->local; int err, changed = 0; + sdata_lock(sdata); + /* AP might have been stopped while waiting for the lock. */ + if (!sdata->vif.csa_active) + goto unlock; + if (!ieee80211_sdata_running(sdata)) - return; + goto unlock; sdata->radar_required = sdata->csa_radar_required; err = ieee80211_vif_change_channel(sdata, &changed); if (WARN_ON(err < 0)) - return; + goto unlock; if (!local->use_chanctx) { local->_oper_chandef = sdata->csa_chandef; @@ -3003,11 +3008,13 @@ void ieee80211_csa_finalize_work(struct work_struct *work) ieee80211_bss_info_change_notify(sdata, changed); + sdata->vif.csa_active = false; switch (sdata->vif.type) { case NL80211_IFTYPE_AP: err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon); if (err < 0) - return; + goto unlock; + changed |= err; kfree(sdata->u.ap.next_beacon); sdata->u.ap.next_beacon = NULL; @@ -3021,20 +3028,22 @@ void ieee80211_csa_finalize_work(struct work_struct *work) case NL80211_IFTYPE_MESH_POINT: err = ieee80211_mesh_finish_csa(sdata); if (err < 0) - return; + goto unlock; break; #endif default: WARN_ON(1); - return; + goto unlock; } - sdata->vif.csa_active = false; ieee80211_wake_queues_by_reason(&sdata->local->hw, IEEE80211_MAX_QUEUE_MAP, IEEE80211_QUEUE_STOP_REASON_CSA); cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef); + +unlock: + sdata_unlock(sdata); } static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 398756c226c..95882a788b5 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -10821,21 +10821,18 @@ void cfg80211_ch_switch_notify(struct net_device *dev, struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - trace_cfg80211_ch_switch_notify(dev, chandef); + ASSERT_WDEV_LOCK(wdev); - wdev_lock(wdev); + trace_cfg80211_ch_switch_notify(dev, chandef); if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && wdev->iftype != NL80211_IFTYPE_P2P_GO && wdev->iftype != NL80211_IFTYPE_ADHOC && wdev->iftype != NL80211_IFTYPE_MESH_POINT)) - goto out; + return; wdev->channel = chandef->chan; nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL); -out: - wdev_unlock(wdev); - return; } EXPORT_SYMBOL(cfg80211_ch_switch_notify); -- cgit v1.2.3-70-g09d2 From beffd138d358b69bf15f5a46cb18b31a9b37befb Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Thu, 21 Nov 2013 18:19:52 +0100 Subject: mac80211: don't cancel csa finalize work within stop_ap The current channel switch code has a potential deadlock: 1) * cfg80211_stop_ap acquires wdev-lock * ieee80211_stop_ap calls cancel_work_sync for the csa_finalize_work, which acquires the associated worker-lock 2) * ieee80211_csa_finalize_work holds the worker-lock when run * it calls cfg80211_ch_switch_notify which will claim the wdev-lock, and also needs to claim the sdata-lock (which is the same as the wdev-lock) to modify the beacons. It is sufficient to just set the channel switch active to false. If the worker is running later, it will find the channel switch to not be active anymore and returns immediately without changing anything. Canceling the worker is done anyway when the interface goes down (ieee80211_do_stop). Reported-by: Johannes Berg Signed-off-by: Simon Wunderlich Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 1d446ac97ab..a66f4f1eb86 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1080,7 +1080,6 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) /* abort any running channel switch */ sdata->vif.csa_active = false; - cancel_work_sync(&sdata->csa_finalize_work); cancel_work_sync(&sdata->u.ap.request_smps_work); /* turn off carrier for this interface and dependent VLANs */ -- cgit v1.2.3-70-g09d2 From 1f3b8a2bdeccac8abe6817b7b70cea90c93ed3e4 Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Thu, 21 Nov 2013 18:19:53 +0100 Subject: mac80211: don't leak next beacon when csa is aborted Signed-off-by: Simon Wunderlich Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index a66f4f1eb86..754069cbb75 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1080,6 +1080,9 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) /* abort any running channel switch */ sdata->vif.csa_active = false; + kfree(sdata->u.ap.next_beacon); + sdata->u.ap.next_beacon = NULL; + cancel_work_sync(&sdata->u.ap.request_smps_work); /* turn off carrier for this interface and dependent VLANs */ -- cgit v1.2.3-70-g09d2 From ddcc347b70f298f9d624cd0e250581d831d915fb Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 2 Dec 2013 11:54:07 +0100 Subject: mac80211: fix rx_nss calculation for drivers with hw rc Drivers with hardware rate control were given sta->rx_nss set to 0. This was because rx_nss calculation procedure was protected by hw/sw rate control check. Signed-off-by: Michal Kazior Signed-off-by: Johannes Berg --- net/mac80211/rate.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index 5dedc56c94d..32cdbd22c5f 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h @@ -54,6 +54,8 @@ static inline void rate_control_rate_init(struct sta_info *sta) struct ieee80211_supported_band *sband; struct ieee80211_chanctx_conf *chanctx_conf; + ieee80211_sta_set_rx_nss(sta); + if (!ref) return; @@ -67,8 +69,6 @@ static inline void rate_control_rate_init(struct sta_info *sta) sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band]; - ieee80211_sta_set_rx_nss(sta); - ref->ops->rate_init(ref->priv, sband, &chanctx_conf->def, ista, priv_sta); rcu_read_unlock(); -- cgit v1.2.3-70-g09d2 From cfb27d29b61cc32c0bb75f741aeabb9c6e6af742 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 2 Dec 2013 09:06:36 +0100 Subject: ath10k: fix multi BSSID with WPA on FW 10.1 FW 10.1 seems to require the default key index to be updated to point to group key after it is installed. Otherwise Txed frames are corrupted. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 40 +++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index b70a3b2f9f4..7d3d3ac2343 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2717,6 +2717,44 @@ static void ath10k_cancel_hw_scan(struct ieee80211_hw *hw, mutex_unlock(&ar->conf_mutex); } +static void ath10k_set_key_h_def_keyidx(struct ath10k *ar, + struct ath10k_vif *arvif, + enum set_key_cmd cmd, + struct ieee80211_key_conf *key) +{ + u32 vdev_param = arvif->ar->wmi.vdev_param->def_keyid; + int ret; + + /* 10.1 firmware branch requires default key index to be set to group + * key index after installing it. Otherwise FW/HW Txes corrupted + * frames with multi-vif APs. This is not required for main firmware + * branch (e.g. 636). + * + * FIXME: This has been tested only in AP. It remains unknown if this + * is required for multi-vif STA interfaces on 10.1 */ + + if (arvif->vdev_type != WMI_VDEV_TYPE_AP) + return; + + if (key->cipher == WLAN_CIPHER_SUITE_WEP40) + return; + + if (key->cipher == WLAN_CIPHER_SUITE_WEP104) + return; + + if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) + return; + + if (cmd != SET_KEY) + return; + + ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, + key->keyidx); + if (ret) + ath10k_warn("failed to set group key as default key: %d\n", + ret); +} + static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) @@ -2778,6 +2816,8 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, goto exit; } + ath10k_set_key_h_def_keyidx(ar, arvif, cmd, key); + spin_lock_bh(&ar->data_lock); peer = ath10k_peer_find(ar, arvif->vdev_id, peer_addr); if (peer && cmd == SET_KEY) -- cgit v1.2.3-70-g09d2 From 96581132423d71195b49fa7286dc1c0663ce21b5 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 23 Oct 2013 13:53:28 +0530 Subject: ath9k: Add WB335 PCI IDs Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/pci.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index b5656fce4ff..44761bbb2ad 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -446,6 +446,11 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { 0x11AD, /* LITEON */ 0x0662), .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x0682), + .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, PCI_VENDOR_ID_AZWAVE, @@ -456,6 +461,11 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { PCI_VENDOR_ID_LENOVO, 0x3026), .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_LENOVO, + 0x4026), + .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, PCI_VENDOR_ID_HP, @@ -466,6 +476,11 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { PCI_VENDOR_ID_HP, 0x217F), .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_HP, + 0x2005), + .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, PCI_VENDOR_ID_DELL, @@ -545,6 +560,16 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { 0x185F, /* WNC */ 0x3027), .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x185F, /* WNC */ + 0xA120), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_FOXCONN, + 0xE07F), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, /* PCI-E AR9565 (WB335) */ { PCI_VDEVICE(ATHEROS, 0x0036), -- cgit v1.2.3-70-g09d2 From 4dd3564030020f8beb8dc7bbfea05781648836d0 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 23 Oct 2013 14:26:04 +0530 Subject: ath9k: Identify Killer Wireless cards Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 + drivers/net/wireless/ath/ath9k/init.c | 3 +++ drivers/net/wireless/ath/ath9k/pci.c | 20 ++++++++++++++++++++ 3 files changed, 24 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 60a5da53668..9cf412c6c32 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -642,6 +642,7 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs); #define ATH9K_PCI_AR9565_1ANT 0x0080 #define ATH9K_PCI_AR9565_2ANT 0x0100 #define ATH9K_PCI_NO_PLL_PWRSAVE 0x0200 +#define ATH9K_PCI_KILLER 0x0400 /* * Default cache line size, in bytes. diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 710192ed27e..6ef4c0635b3 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -589,6 +589,9 @@ static void ath9k_init_platform(struct ath_softc *sc) if (sc->driver_data & ATH9K_PCI_AR9565_2ANT) ath_info(common, "WB335 2-ANT card detected\n"); + if (sc->driver_data & ATH9K_PCI_KILLER) + ath_info(common, "Killer Wireless card detected\n"); + /* * Some WB335 cards do not support antenna diversity. Since * we use a hardcoded value for AR9565 instead of using the diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 44761bbb2ad..e9a58575894 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -87,6 +87,19 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { { PCI_VDEVICE(ATHEROS, 0x002C) }, /* PCI-E 802.11n bonded out */ { PCI_VDEVICE(ATHEROS, 0x002D) }, /* PCI */ { PCI_VDEVICE(ATHEROS, 0x002E) }, /* PCI-E */ + + /* Killer Wireless (3x3) */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0030, + 0x1A56, + 0x2000), + .driver_data = ATH9K_PCI_KILLER }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0030, + 0x1A56, + 0x2001), + .driver_data = ATH9K_PCI_KILLER }, + { PCI_VDEVICE(ATHEROS, 0x0030) }, /* PCI-E AR9300 */ /* PCI-E CUS198 */ @@ -354,6 +367,13 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { 0x1783), .driver_data = ATH9K_PCI_WOW }, + /* Killer Wireless (2x2) */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0030, + 0x1A56, + 0x2003), + .driver_data = ATH9K_PCI_KILLER }, + { PCI_VDEVICE(ATHEROS, 0x0034) }, /* PCI-E AR9462 */ { PCI_VDEVICE(ATHEROS, 0x0037) }, /* PCI-E AR1111/AR9485 */ -- cgit v1.2.3-70-g09d2 From ef6b19e40f525777a0052956bf7d9a1985f74993 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Thu, 24 Oct 2013 12:04:39 +0530 Subject: ath9k: Fix TX99 config option usage Use CONFIG_ATH9K_TX99 to properly enclose the tx99 code and make sure that it is not compiled as part of the driver when it is not selected. Move the tx99 code to a new file tx99.c and also add ATH9K_DEBUGFS as a dependency in Kconfig. This reduces the module size on platforms like OpenWrt where ATH9K_DEBUGFS is selected, but TX99 might be disabled. Cc: Luis R. Rodriguez Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/Kconfig | 2 +- drivers/net/wireless/ath/ath9k/Makefile | 4 +- drivers/net/wireless/ath/ath9k/ath9k.h | 20 ++- drivers/net/wireless/ath/ath9k/debug.c | 115 +------------- drivers/net/wireless/ath/ath9k/main.c | 130 +--------------- drivers/net/wireless/ath/ath9k/tx99.c | 263 ++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/xmit.c | 4 + 7 files changed, 290 insertions(+), 248 deletions(-) create mode 100644 drivers/net/wireless/ath/ath9k/tx99.c diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index 32f139e2e89..3ffa4ea8fcb 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -86,7 +86,7 @@ config ATH9K_DFS_CERTIFIED config ATH9K_TX99 bool "Atheros ath9k TX99 testing support" - depends on CFG80211_CERTIFICATION_ONUS + depends on ATH9K_DEBUGFS && CFG80211_CERTIFICATION_ONUS default n ---help--- Say N. This should only be enabled on systems undergoing diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 6205ef5a932..f86a261e708 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -13,9 +13,9 @@ ath9k-$(CONFIG_ATH9K_PCI) += pci.o ath9k-$(CONFIG_ATH9K_AHB) += ahb.o ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o ath9k-$(CONFIG_ATH9K_DFS_DEBUGFS) += dfs_debug.o -ath9k-$(CONFIG_ATH9K_DFS_CERTIFIED) += \ - dfs.o +ath9k-$(CONFIG_ATH9K_DFS_CERTIFIED) += dfs.o ath9k-$(CONFIG_PM_SLEEP) += wow.o +ath9k-$(CONFIG_ATH9K_TX99) += tx99.o obj-$(CONFIG_ATH9K) += ath9k.o diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 9cf412c6c32..b39ffac3b93 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -948,10 +948,25 @@ struct fft_sample_ht20_40 { u8 data[SPECTRAL_HT20_40_NUM_BINS]; } __packed; -int ath9k_tx99_init(struct ath_softc *sc); -void ath9k_tx99_deinit(struct ath_softc *sc); +/********/ +/* TX99 */ +/********/ + +#ifdef CONFIG_ATH9K_TX99 +void ath9k_tx99_init_debug(struct ath_softc *sc); int ath9k_tx99_send(struct ath_softc *sc, struct sk_buff *skb, struct ath_tx_control *txctl); +#else +static inline void ath9k_tx99_init_debug(struct ath_softc *sc) +{ +} +static inline int ath9k_tx99_send(struct ath_softc *sc, + struct sk_buff *skb, + struct ath_tx_control *txctl) +{ + return 0; +} +#endif /* CONFIG_ATH9K_TX99 */ void ath9k_tasklet(unsigned long data); int ath_cabq_update(struct ath_softc *); @@ -968,6 +983,7 @@ extern bool is_ath9k_unloaded; u8 ath9k_parse_mpdudensity(u8 mpdudensity); irqreturn_t ath_isr(int irq, void *dev); +int ath_reset(struct ath_softc *sc); int ath9k_init_device(u16 devid, struct ath_softc *sc, const struct ath_bus_ops *bus_ops); void ath9k_deinit_device(struct ath_softc *sc); diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 83a2c59f680..2f7dccfdb72 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -1778,111 +1778,6 @@ void ath9k_deinit_debug(struct ath_softc *sc) } } -static ssize_t read_file_tx99(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - char buf[3]; - unsigned int len; - - len = sprintf(buf, "%d\n", sc->tx99_state); - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static ssize_t write_file_tx99(struct file *file, const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - char buf[32]; - bool start; - ssize_t len; - int r; - - if (sc->nvifs > 1) - return -EOPNOTSUPP; - - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - - if (strtobool(buf, &start)) - return -EINVAL; - - if (start == sc->tx99_state) { - if (!start) - return count; - ath_dbg(common, XMIT, "Resetting TX99\n"); - ath9k_tx99_deinit(sc); - } - - if (!start) { - ath9k_tx99_deinit(sc); - return count; - } - - r = ath9k_tx99_init(sc); - if (r) - return r; - - return count; -} - -static const struct file_operations fops_tx99 = { - .read = read_file_tx99, - .write = write_file_tx99, - .open = simple_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - -static ssize_t read_file_tx99_power(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - char buf[32]; - unsigned int len; - - len = sprintf(buf, "%d (%d dBm)\n", - sc->tx99_power, - sc->tx99_power / 2); - - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static ssize_t write_file_tx99_power(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - int r; - u8 tx_power; - - r = kstrtou8_from_user(user_buf, count, 0, &tx_power); - if (r) - return r; - - if (tx_power > MAX_RATE_POWER) - return -EINVAL; - - sc->tx99_power = tx_power; - - ath9k_ps_wakeup(sc); - ath9k_hw_tx99_set_txpower(sc->sc_ah, sc->tx99_power); - ath9k_ps_restore(sc); - - return count; -} - -static const struct file_operations fops_tx99_power = { - .read = read_file_tx99_power, - .write = write_file_tx99_power, - .open = simple_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - int ath9k_init_debug(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); @@ -1899,6 +1794,7 @@ int ath9k_init_debug(struct ath_hw *ah) #endif ath9k_dfs_init_debug(sc); + ath9k_tx99_init_debug(sc); debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_dma); @@ -1974,15 +1870,6 @@ int ath9k_init_debug(struct ath_hw *ah) debugfs_create_file("btcoex", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_btcoex); #endif - if (config_enabled(CONFIG_ATH9K_TX99) && - AR_SREV_9300_20_OR_LATER(ah)) { - debugfs_create_file("tx99", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, - &fops_tx99); - debugfs_create_file("tx99_power", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, - &fops_tx99_power); - } return 0; } diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 74f452c7b16..3d173986435 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -627,7 +627,7 @@ chip_reset: #undef SCHED_INTR } -static int ath_reset(struct ath_softc *sc) +int ath_reset(struct ath_softc *sc) { int r; @@ -2373,134 +2373,6 @@ static void ath9k_channel_switch_beacon(struct ieee80211_hw *hw, sc->csa_vif = vif; } -static void ath9k_tx99_stop(struct ath_softc *sc) -{ - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - - ath_drain_all_txq(sc); - ath_startrecv(sc); - - ath9k_hw_set_interrupts(ah); - ath9k_hw_enable_interrupts(ah); - - ieee80211_wake_queues(sc->hw); - - kfree_skb(sc->tx99_skb); - sc->tx99_skb = NULL; - sc->tx99_state = false; - - ath9k_hw_tx99_stop(sc->sc_ah); - ath_dbg(common, XMIT, "TX99 stopped\n"); -} - -static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc) -{ - static u8 PN9Data[] = {0xff, 0x87, 0xb8, 0x59, 0xb7, 0xa1, 0xcc, 0x24, - 0x57, 0x5e, 0x4b, 0x9c, 0x0e, 0xe9, 0xea, 0x50, - 0x2a, 0xbe, 0xb4, 0x1b, 0xb6, 0xb0, 0x5d, 0xf1, - 0xe6, 0x9a, 0xe3, 0x45, 0xfd, 0x2c, 0x53, 0x18, - 0x0c, 0xca, 0xc9, 0xfb, 0x49, 0x37, 0xe5, 0xa8, - 0x51, 0x3b, 0x2f, 0x61, 0xaa, 0x72, 0x18, 0x84, - 0x02, 0x23, 0x23, 0xab, 0x63, 0x89, 0x51, 0xb3, - 0xe7, 0x8b, 0x72, 0x90, 0x4c, 0xe8, 0xfb, 0xc0}; - u32 len = 1200; - struct ieee80211_hw *hw = sc->hw; - struct ieee80211_hdr *hdr; - struct ieee80211_tx_info *tx_info; - struct sk_buff *skb; - - skb = alloc_skb(len, GFP_KERNEL); - if (!skb) - return NULL; - - skb_put(skb, len); - - memset(skb->data, 0, len); - - hdr = (struct ieee80211_hdr *)skb->data; - hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA); - hdr->duration_id = 0; - - memcpy(hdr->addr1, hw->wiphy->perm_addr, ETH_ALEN); - memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN); - memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN); - - hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); - - tx_info = IEEE80211_SKB_CB(skb); - memset(tx_info, 0, sizeof(*tx_info)); - tx_info->band = hw->conf.chandef.chan->band; - tx_info->flags = IEEE80211_TX_CTL_NO_ACK; - tx_info->control.vif = sc->tx99_vif; - - memcpy(skb->data + sizeof(*hdr), PN9Data, sizeof(PN9Data)); - - return skb; -} - -void ath9k_tx99_deinit(struct ath_softc *sc) -{ - ath_reset(sc); - - ath9k_ps_wakeup(sc); - ath9k_tx99_stop(sc); - ath9k_ps_restore(sc); -} - -int ath9k_tx99_init(struct ath_softc *sc) -{ - struct ieee80211_hw *hw = sc->hw; - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - struct ath_tx_control txctl; - int r; - - if (sc->sc_flags & SC_OP_INVALID) { - ath_err(common, - "driver is in invalid state unable to use TX99"); - return -EINVAL; - } - - sc->tx99_skb = ath9k_build_tx99_skb(sc); - if (!sc->tx99_skb) - return -ENOMEM; - - memset(&txctl, 0, sizeof(txctl)); - txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO]; - - ath_reset(sc); - - ath9k_ps_wakeup(sc); - - ath9k_hw_disable_interrupts(ah); - atomic_set(&ah->intr_ref_cnt, -1); - ath_drain_all_txq(sc); - ath_stoprecv(sc); - - sc->tx99_state = true; - - ieee80211_stop_queues(hw); - - if (sc->tx99_power == MAX_RATE_POWER + 1) - sc->tx99_power = MAX_RATE_POWER; - - ath9k_hw_tx99_set_txpower(ah, sc->tx99_power); - r = ath9k_tx99_send(sc, sc->tx99_skb, &txctl); - if (r) { - ath_dbg(common, XMIT, "Failed to xmit TX99 skb\n"); - return r; - } - - ath_dbg(common, XMIT, "TX99 xmit started using %d ( %ddBm)\n", - sc->tx99_power, - sc->tx99_power / 2); - - /* We leave the harware awake as it will be chugging on */ - - return 0; -} - struct ieee80211_ops ath9k_ops = { .tx = ath9k_tx, .start = ath9k_start, diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c new file mode 100644 index 00000000000..6668197c277 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/tx99.c @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2013 Qualcomm Atheros, Inc. + * + * 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 "ath9k.h" + +static void ath9k_tx99_stop(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + + ath_drain_all_txq(sc); + ath_startrecv(sc); + + ath9k_hw_set_interrupts(ah); + ath9k_hw_enable_interrupts(ah); + + ieee80211_wake_queues(sc->hw); + + kfree_skb(sc->tx99_skb); + sc->tx99_skb = NULL; + sc->tx99_state = false; + + ath9k_hw_tx99_stop(sc->sc_ah); + ath_dbg(common, XMIT, "TX99 stopped\n"); +} + +static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc) +{ + static u8 PN9Data[] = {0xff, 0x87, 0xb8, 0x59, 0xb7, 0xa1, 0xcc, 0x24, + 0x57, 0x5e, 0x4b, 0x9c, 0x0e, 0xe9, 0xea, 0x50, + 0x2a, 0xbe, 0xb4, 0x1b, 0xb6, 0xb0, 0x5d, 0xf1, + 0xe6, 0x9a, 0xe3, 0x45, 0xfd, 0x2c, 0x53, 0x18, + 0x0c, 0xca, 0xc9, 0xfb, 0x49, 0x37, 0xe5, 0xa8, + 0x51, 0x3b, 0x2f, 0x61, 0xaa, 0x72, 0x18, 0x84, + 0x02, 0x23, 0x23, 0xab, 0x63, 0x89, 0x51, 0xb3, + 0xe7, 0x8b, 0x72, 0x90, 0x4c, 0xe8, 0xfb, 0xc0}; + u32 len = 1200; + struct ieee80211_hw *hw = sc->hw; + struct ieee80211_hdr *hdr; + struct ieee80211_tx_info *tx_info; + struct sk_buff *skb; + + skb = alloc_skb(len, GFP_KERNEL); + if (!skb) + return NULL; + + skb_put(skb, len); + + memset(skb->data, 0, len); + + hdr = (struct ieee80211_hdr *)skb->data; + hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA); + hdr->duration_id = 0; + + memcpy(hdr->addr1, hw->wiphy->perm_addr, ETH_ALEN); + memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN); + memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN); + + hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); + + tx_info = IEEE80211_SKB_CB(skb); + memset(tx_info, 0, sizeof(*tx_info)); + tx_info->band = hw->conf.chandef.chan->band; + tx_info->flags = IEEE80211_TX_CTL_NO_ACK; + tx_info->control.vif = sc->tx99_vif; + + memcpy(skb->data + sizeof(*hdr), PN9Data, sizeof(PN9Data)); + + return skb; +} + +static void ath9k_tx99_deinit(struct ath_softc *sc) +{ + ath_reset(sc); + + ath9k_ps_wakeup(sc); + ath9k_tx99_stop(sc); + ath9k_ps_restore(sc); +} + +static int ath9k_tx99_init(struct ath_softc *sc) +{ + struct ieee80211_hw *hw = sc->hw; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ath_tx_control txctl; + int r; + + if (sc->sc_flags & SC_OP_INVALID) { + ath_err(common, + "driver is in invalid state unable to use TX99"); + return -EINVAL; + } + + sc->tx99_skb = ath9k_build_tx99_skb(sc); + if (!sc->tx99_skb) + return -ENOMEM; + + memset(&txctl, 0, sizeof(txctl)); + txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO]; + + ath_reset(sc); + + ath9k_ps_wakeup(sc); + + ath9k_hw_disable_interrupts(ah); + atomic_set(&ah->intr_ref_cnt, -1); + ath_drain_all_txq(sc); + ath_stoprecv(sc); + + sc->tx99_state = true; + + ieee80211_stop_queues(hw); + + if (sc->tx99_power == MAX_RATE_POWER + 1) + sc->tx99_power = MAX_RATE_POWER; + + ath9k_hw_tx99_set_txpower(ah, sc->tx99_power); + r = ath9k_tx99_send(sc, sc->tx99_skb, &txctl); + if (r) { + ath_dbg(common, XMIT, "Failed to xmit TX99 skb\n"); + return r; + } + + ath_dbg(common, XMIT, "TX99 xmit started using %d ( %ddBm)\n", + sc->tx99_power, + sc->tx99_power / 2); + + /* We leave the harware awake as it will be chugging on */ + + return 0; +} + +static ssize_t read_file_tx99(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + char buf[3]; + unsigned int len; + + len = sprintf(buf, "%d\n", sc->tx99_state); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_tx99(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + char buf[32]; + bool start; + ssize_t len; + int r; + + if (sc->nvifs > 1) + return -EOPNOTSUPP; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + + if (strtobool(buf, &start)) + return -EINVAL; + + if (start == sc->tx99_state) { + if (!start) + return count; + ath_dbg(common, XMIT, "Resetting TX99\n"); + ath9k_tx99_deinit(sc); + } + + if (!start) { + ath9k_tx99_deinit(sc); + return count; + } + + r = ath9k_tx99_init(sc); + if (r) + return r; + + return count; +} + +static const struct file_operations fops_tx99 = { + .read = read_file_tx99, + .write = write_file_tx99, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t read_file_tx99_power(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + char buf[32]; + unsigned int len; + + len = sprintf(buf, "%d (%d dBm)\n", + sc->tx99_power, + sc->tx99_power / 2); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_tx99_power(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + int r; + u8 tx_power; + + r = kstrtou8_from_user(user_buf, count, 0, &tx_power); + if (r) + return r; + + if (tx_power > MAX_RATE_POWER) + return -EINVAL; + + sc->tx99_power = tx_power; + + ath9k_ps_wakeup(sc); + ath9k_hw_tx99_set_txpower(sc->sc_ah, sc->tx99_power); + ath9k_ps_restore(sc); + + return count; +} + +static const struct file_operations fops_tx99_power = { + .read = read_file_tx99_power, + .write = write_file_tx99_power, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +void ath9k_tx99_init_debug(struct ath_softc *sc) +{ + if (!AR_SREV_9300_20_OR_LATER(sc->sc_ah)) + return; + + debugfs_create_file("tx99", S_IRUSR | S_IWUSR, + sc->debug.debugfs_phy, sc, + &fops_tx99); + debugfs_create_file("tx99_power", S_IRUSR | S_IWUSR, + sc->debug.debugfs_phy, sc, + &fops_tx99_power); +} diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 09cdbcd0973..95f6c5a8ee1 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2749,6 +2749,8 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) } } +#ifdef CONFIG_ATH9K_TX99 + int ath9k_tx99_send(struct ath_softc *sc, struct sk_buff *skb, struct ath_tx_control *txctl) { @@ -2791,3 +2793,5 @@ int ath9k_tx99_send(struct ath_softc *sc, struct sk_buff *skb, return 0; } + +#endif /* CONFIG_ATH9K_TX99 */ -- cgit v1.2.3-70-g09d2 From 9c9cb10fcb500e52097f2535011cd5cf87b93f21 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 28 Oct 2013 11:47:43 +0530 Subject: ath9k: Fix wow.c compilation The HW routines to set various WoW registers are present in wow.c. For some reason, it has been compiled as part of the main ath9k.ko module all this time, when it should really be part of ath9k_hw.ko. This patch renames the file to ar9003_wow.ko and adds it to ath9k_hw.ko. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/Makefile | 3 +- drivers/net/wireless/ath/ath9k/ar9003_wow.c | 422 ++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/wow.c | 422 ---------------------------- 3 files changed, 424 insertions(+), 423 deletions(-) create mode 100644 drivers/net/wireless/ath/ath9k/ar9003_wow.c delete mode 100644 drivers/net/wireless/ath/ath9k/wow.c diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index f86a261e708..796686a65b4 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -14,7 +14,6 @@ ath9k-$(CONFIG_ATH9K_AHB) += ahb.o ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o ath9k-$(CONFIG_ATH9K_DFS_DEBUGFS) += dfs_debug.o ath9k-$(CONFIG_ATH9K_DFS_CERTIFIED) += dfs.o -ath9k-$(CONFIG_PM_SLEEP) += wow.o ath9k-$(CONFIG_ATH9K_TX99) += tx99.o obj-$(CONFIG_ATH9K) += ath9k.o @@ -41,6 +40,8 @@ ath9k_hw-y:= \ ar9003_eeprom.o \ ar9003_paprd.o +ath9k_hw-$(CONFIG_PM_SLEEP) += ar9003_wow.o + ath9k_hw-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += btcoex.o \ ar9003_mci.o obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o diff --git a/drivers/net/wireless/ath/ath9k/ar9003_wow.c b/drivers/net/wireless/ath/ath9k/ar9003_wow.c new file mode 100644 index 00000000000..81c88dd606d --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9003_wow.c @@ -0,0 +1,422 @@ +/* + * Copyright (c) 2012 Qualcomm Atheros, Inc. + * + * 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 "ath9k.h" +#include "reg.h" +#include "hw-ops.h" + +const char *ath9k_hw_wow_event_to_string(u32 wow_event) +{ + if (wow_event & AH_WOW_MAGIC_PATTERN_EN) + return "Magic pattern"; + if (wow_event & AH_WOW_USER_PATTERN_EN) + return "User pattern"; + if (wow_event & AH_WOW_LINK_CHANGE) + return "Link change"; + if (wow_event & AH_WOW_BEACON_MISS) + return "Beacon miss"; + + return "unknown reason"; +} +EXPORT_SYMBOL(ath9k_hw_wow_event_to_string); + +static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + + REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); + + /* set rx disable bit */ + REG_WRITE(ah, AR_CR, AR_CR_RXD); + + if (!ath9k_hw_wait(ah, AR_CR, AR_CR_RXE, 0, AH_WAIT_TIMEOUT)) { + ath_err(common, "Failed to stop Rx DMA in 10ms AR_CR=0x%08x AR_DIAG_SW=0x%08x\n", + REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW)); + return; + } + + REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_ON_INT); +} + +static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + u8 sta_mac_addr[ETH_ALEN], ap_mac_addr[ETH_ALEN]; + u32 ctl[13] = {0}; + u32 data_word[KAL_NUM_DATA_WORDS]; + u8 i; + u32 wow_ka_data_word0; + + memcpy(sta_mac_addr, common->macaddr, ETH_ALEN); + memcpy(ap_mac_addr, common->curbssid, ETH_ALEN); + + /* set the transmit buffer */ + ctl[0] = (KAL_FRAME_LEN | (MAX_RATE_POWER << 16)); + ctl[1] = 0; + ctl[3] = 0xb; /* OFDM_6M hardware value for this rate */ + ctl[4] = 0; + ctl[7] = (ah->txchainmask) << 2; + ctl[2] = 0xf << 16; /* tx_tries 0 */ + + for (i = 0; i < KAL_NUM_DESC_WORDS; i++) + REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]); + + REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]); + + data_word[0] = (KAL_FRAME_TYPE << 2) | (KAL_FRAME_SUB_TYPE << 4) | + (KAL_TO_DS << 8) | (KAL_DURATION_ID << 16); + data_word[1] = (ap_mac_addr[3] << 24) | (ap_mac_addr[2] << 16) | + (ap_mac_addr[1] << 8) | (ap_mac_addr[0]); + data_word[2] = (sta_mac_addr[1] << 24) | (sta_mac_addr[0] << 16) | + (ap_mac_addr[5] << 8) | (ap_mac_addr[4]); + data_word[3] = (sta_mac_addr[5] << 24) | (sta_mac_addr[4] << 16) | + (sta_mac_addr[3] << 8) | (sta_mac_addr[2]); + data_word[4] = (ap_mac_addr[3] << 24) | (ap_mac_addr[2] << 16) | + (ap_mac_addr[1] << 8) | (ap_mac_addr[0]); + data_word[5] = (ap_mac_addr[5] << 8) | (ap_mac_addr[4]); + + if (AR_SREV_9462_20(ah)) { + /* AR9462 2.0 has an extra descriptor word (time based + * discard) compared to other chips */ + REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + (12 * 4)), 0); + wow_ka_data_word0 = AR_WOW_TXBUF(13); + } else { + wow_ka_data_word0 = AR_WOW_TXBUF(12); + } + + for (i = 0; i < KAL_NUM_DATA_WORDS; i++) + REG_WRITE(ah, (wow_ka_data_word0 + i*4), data_word[i]); + +} + +void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, + u8 *user_mask, int pattern_count, + int pattern_len) +{ + int i; + u32 pattern_val, mask_val; + u32 set, clr; + + /* FIXME: should check count by querying the hardware capability */ + if (pattern_count >= MAX_NUM_PATTERN) + return; + + REG_SET_BIT(ah, AR_WOW_PATTERN, BIT(pattern_count)); + + /* set the registers for pattern */ + for (i = 0; i < MAX_PATTERN_SIZE; i += 4) { + memcpy(&pattern_val, user_pattern, 4); + REG_WRITE(ah, (AR_WOW_TB_PATTERN(pattern_count) + i), + pattern_val); + user_pattern += 4; + } + + /* set the registers for mask */ + for (i = 0; i < MAX_PATTERN_MASK_SIZE; i += 4) { + memcpy(&mask_val, user_mask, 4); + REG_WRITE(ah, (AR_WOW_TB_MASK(pattern_count) + i), mask_val); + user_mask += 4; + } + + /* set the pattern length to be matched + * + * AR_WOW_LENGTH1_REG1 + * bit 31:24 pattern 0 length + * bit 23:16 pattern 1 length + * bit 15:8 pattern 2 length + * bit 7:0 pattern 3 length + * + * AR_WOW_LENGTH1_REG2 + * bit 31:24 pattern 4 length + * bit 23:16 pattern 5 length + * bit 15:8 pattern 6 length + * bit 7:0 pattern 7 length + * + * the below logic writes out the new + * pattern length for the corresponding + * pattern_count, while masking out the + * other fields + */ + + ah->wow_event_mask |= BIT(pattern_count + AR_WOW_PAT_FOUND_SHIFT); + + if (pattern_count < 4) { + /* Pattern 0-3 uses AR_WOW_LENGTH1 register */ + set = (pattern_len & AR_WOW_LENGTH_MAX) << + AR_WOW_LEN1_SHIFT(pattern_count); + clr = AR_WOW_LENGTH1_MASK(pattern_count); + REG_RMW(ah, AR_WOW_LENGTH1, set, clr); + } else { + /* Pattern 4-7 uses AR_WOW_LENGTH2 register */ + set = (pattern_len & AR_WOW_LENGTH_MAX) << + AR_WOW_LEN2_SHIFT(pattern_count); + clr = AR_WOW_LENGTH2_MASK(pattern_count); + REG_RMW(ah, AR_WOW_LENGTH2, set, clr); + } + +} +EXPORT_SYMBOL(ath9k_hw_wow_apply_pattern); + +u32 ath9k_hw_wow_wakeup(struct ath_hw *ah) +{ + u32 wow_status = 0; + u32 val = 0, rval; + + /* + * read the WoW status register to know + * the wakeup reason + */ + rval = REG_READ(ah, AR_WOW_PATTERN); + val = AR_WOW_STATUS(rval); + + /* + * mask only the WoW events that we have enabled. Sometimes + * we have spurious WoW events from the AR_WOW_PATTERN + * register. This mask will clean it up. + */ + + val &= ah->wow_event_mask; + + if (val) { + if (val & AR_WOW_MAGIC_PAT_FOUND) + wow_status |= AH_WOW_MAGIC_PATTERN_EN; + if (AR_WOW_PATTERN_FOUND(val)) + wow_status |= AH_WOW_USER_PATTERN_EN; + if (val & AR_WOW_KEEP_ALIVE_FAIL) + wow_status |= AH_WOW_LINK_CHANGE; + if (val & AR_WOW_BEACON_FAIL) + wow_status |= AH_WOW_BEACON_MISS; + } + + /* + * set and clear WOW_PME_CLEAR registers for the chip to + * generate next wow signal. + * disable D3 before accessing other registers ? + */ + + /* do we need to check the bit value 0x01000000 (7-10) ?? */ + REG_RMW(ah, AR_PCIE_PM_CTRL, AR_PMCTRL_WOW_PME_CLR, + AR_PMCTRL_PWR_STATE_D1D3); + + /* + * clear all events + */ + REG_WRITE(ah, AR_WOW_PATTERN, + AR_WOW_CLEAR_EVENTS(REG_READ(ah, AR_WOW_PATTERN))); + + /* + * restore the beacon threshold to init value + */ + REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR); + + /* + * Restore the way the PCI-E reset, Power-On-Reset, external + * PCIE_POR_SHORT pins are tied to its original value. + * Previously just before WoW sleep, we untie the PCI-E + * reset to our Chip's Power On Reset so that any PCI-E + * reset from the bus will not reset our chip + */ + if (ah->is_pciexpress) + ath9k_hw_configpcipowersave(ah, false); + + ah->wow_event_mask = 0; + + return wow_status; +} +EXPORT_SYMBOL(ath9k_hw_wow_wakeup); + +void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) +{ + u32 wow_event_mask; + u32 set, clr; + + /* + * wow_event_mask is a mask to the AR_WOW_PATTERN register to + * indicate which WoW events we have enabled. The WoW events + * are from the 'pattern_enable' in this function and + * 'pattern_count' of ath9k_hw_wow_apply_pattern() + */ + wow_event_mask = ah->wow_event_mask; + + /* + * Untie Power-on-Reset from the PCI-E-Reset. When we are in + * WOW sleep, we do want the Reset from the PCI-E to disturb + * our hw state + */ + if (ah->is_pciexpress) { + /* + * we need to untie the internal POR (power-on-reset) + * to the external PCI-E reset. We also need to tie + * the PCI-E Phy reset to the PCI-E reset. + */ + set = AR_WA_RESET_EN | AR_WA_POR_SHORT; + clr = AR_WA_UNTIE_RESET_EN | AR_WA_D3_L1_DISABLE; + REG_RMW(ah, AR_WA, set, clr); + } + + /* + * set the power states appropriately and enable PME + */ + set = AR_PMCTRL_HOST_PME_EN | AR_PMCTRL_PWR_PM_CTRL_ENA | + AR_PMCTRL_AUX_PWR_DET | AR_PMCTRL_WOW_PME_CLR; + + /* + * set and clear WOW_PME_CLEAR registers for the chip + * to generate next wow signal. + */ + REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set); + clr = AR_PMCTRL_WOW_PME_CLR; + REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr); + + /* + * Setup for: + * - beacon misses + * - magic pattern + * - keep alive timeout + * - pattern matching + */ + + /* + * Program default values for pattern backoff, aifs/slot/KAL count, + * beacon miss timeout, KAL timeout, etc. + */ + set = AR_WOW_BACK_OFF_SHIFT(AR_WOW_PAT_BACKOFF); + REG_SET_BIT(ah, AR_WOW_PATTERN, set); + + set = AR_WOW_AIFS_CNT(AR_WOW_CNT_AIFS_CNT) | + AR_WOW_SLOT_CNT(AR_WOW_CNT_SLOT_CNT) | + AR_WOW_KEEP_ALIVE_CNT(AR_WOW_CNT_KA_CNT); + REG_SET_BIT(ah, AR_WOW_COUNT, set); + + if (pattern_enable & AH_WOW_BEACON_MISS) + set = AR_WOW_BEACON_TIMO; + /* We are not using beacon miss, program a large value */ + else + set = AR_WOW_BEACON_TIMO_MAX; + + REG_WRITE(ah, AR_WOW_BCN_TIMO, set); + + /* + * Keep alive timo in ms except AR9280 + */ + if (!pattern_enable) + set = AR_WOW_KEEP_ALIVE_NEVER; + else + set = KAL_TIMEOUT * 32; + + REG_WRITE(ah, AR_WOW_KEEP_ALIVE_TIMO, set); + + /* + * Keep alive delay in us. based on 'power on clock', + * therefore in usec + */ + set = KAL_DELAY * 1000; + REG_WRITE(ah, AR_WOW_KEEP_ALIVE_DELAY, set); + + /* + * Create keep alive pattern to respond to beacons + */ + ath9k_wow_create_keep_alive_pattern(ah); + + /* + * Configure MAC WoW Registers + */ + set = 0; + /* Send keep alive timeouts anyway */ + clr = AR_WOW_KEEP_ALIVE_AUTO_DIS; + + if (pattern_enable & AH_WOW_LINK_CHANGE) + wow_event_mask |= AR_WOW_KEEP_ALIVE_FAIL; + else + set = AR_WOW_KEEP_ALIVE_FAIL_DIS; + + set = AR_WOW_KEEP_ALIVE_FAIL_DIS; + REG_RMW(ah, AR_WOW_KEEP_ALIVE, set, clr); + + /* + * we are relying on a bmiss failure. ensure we have + * enough threshold to prevent false positives + */ + REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_THR_BM_THR, + AR_WOW_BMISSTHRESHOLD); + + set = 0; + clr = 0; + + if (pattern_enable & AH_WOW_BEACON_MISS) { + set = AR_WOW_BEACON_FAIL_EN; + wow_event_mask |= AR_WOW_BEACON_FAIL; + } else { + clr = AR_WOW_BEACON_FAIL_EN; + } + + REG_RMW(ah, AR_WOW_BCN_EN, set, clr); + + set = 0; + clr = 0; + /* + * Enable the magic packet registers + */ + if (pattern_enable & AH_WOW_MAGIC_PATTERN_EN) { + set = AR_WOW_MAGIC_EN; + wow_event_mask |= AR_WOW_MAGIC_PAT_FOUND; + } else { + clr = AR_WOW_MAGIC_EN; + } + set |= AR_WOW_MAC_INTR_EN; + REG_RMW(ah, AR_WOW_PATTERN, set, clr); + + REG_WRITE(ah, AR_WOW_PATTERN_MATCH_LT_256B, + AR_WOW_PATTERN_SUPPORTED); + + /* + * Set the power states appropriately and enable PME + */ + clr = 0; + set = AR_PMCTRL_PWR_STATE_D1D3 | AR_PMCTRL_HOST_PME_EN | + AR_PMCTRL_PWR_PM_CTRL_ENA; + + clr = AR_PCIE_PM_CTRL_ENA; + REG_RMW(ah, AR_PCIE_PM_CTRL, set, clr); + + /* + * this is needed to prevent the chip waking up + * the host within 3-4 seconds with certain + * platform/BIOS. The fix is to enable + * D1 & D3 to match original definition and + * also match the OTP value. Anyway this + * is more related to SW WOW. + */ + clr = AR_PMCTRL_PWR_STATE_D1D3; + REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr); + + set = AR_PMCTRL_PWR_STATE_D1D3_REAL; + REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set); + + REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM); + + /* to bring down WOW power low margin */ + set = BIT(13); + REG_SET_BIT(ah, AR_PCIE_PHY_REG3, set); + /* HW WoW */ + clr = BIT(5); + REG_CLR_BIT(ah, AR_PCU_MISC_MODE3, clr); + + ath9k_hw_set_powermode_wow_sleep(ah); + ah->wow_event_mask = wow_event_mask; +} +EXPORT_SYMBOL(ath9k_hw_wow_enable); diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c deleted file mode 100644 index 81c88dd606d..00000000000 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ /dev/null @@ -1,422 +0,0 @@ -/* - * Copyright (c) 2012 Qualcomm Atheros, Inc. - * - * 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 "ath9k.h" -#include "reg.h" -#include "hw-ops.h" - -const char *ath9k_hw_wow_event_to_string(u32 wow_event) -{ - if (wow_event & AH_WOW_MAGIC_PATTERN_EN) - return "Magic pattern"; - if (wow_event & AH_WOW_USER_PATTERN_EN) - return "User pattern"; - if (wow_event & AH_WOW_LINK_CHANGE) - return "Link change"; - if (wow_event & AH_WOW_BEACON_MISS) - return "Beacon miss"; - - return "unknown reason"; -} -EXPORT_SYMBOL(ath9k_hw_wow_event_to_string); - -static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah) -{ - struct ath_common *common = ath9k_hw_common(ah); - - REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); - - /* set rx disable bit */ - REG_WRITE(ah, AR_CR, AR_CR_RXD); - - if (!ath9k_hw_wait(ah, AR_CR, AR_CR_RXE, 0, AH_WAIT_TIMEOUT)) { - ath_err(common, "Failed to stop Rx DMA in 10ms AR_CR=0x%08x AR_DIAG_SW=0x%08x\n", - REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW)); - return; - } - - REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_ON_INT); -} - -static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah) -{ - struct ath_common *common = ath9k_hw_common(ah); - u8 sta_mac_addr[ETH_ALEN], ap_mac_addr[ETH_ALEN]; - u32 ctl[13] = {0}; - u32 data_word[KAL_NUM_DATA_WORDS]; - u8 i; - u32 wow_ka_data_word0; - - memcpy(sta_mac_addr, common->macaddr, ETH_ALEN); - memcpy(ap_mac_addr, common->curbssid, ETH_ALEN); - - /* set the transmit buffer */ - ctl[0] = (KAL_FRAME_LEN | (MAX_RATE_POWER << 16)); - ctl[1] = 0; - ctl[3] = 0xb; /* OFDM_6M hardware value for this rate */ - ctl[4] = 0; - ctl[7] = (ah->txchainmask) << 2; - ctl[2] = 0xf << 16; /* tx_tries 0 */ - - for (i = 0; i < KAL_NUM_DESC_WORDS; i++) - REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]); - - REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]); - - data_word[0] = (KAL_FRAME_TYPE << 2) | (KAL_FRAME_SUB_TYPE << 4) | - (KAL_TO_DS << 8) | (KAL_DURATION_ID << 16); - data_word[1] = (ap_mac_addr[3] << 24) | (ap_mac_addr[2] << 16) | - (ap_mac_addr[1] << 8) | (ap_mac_addr[0]); - data_word[2] = (sta_mac_addr[1] << 24) | (sta_mac_addr[0] << 16) | - (ap_mac_addr[5] << 8) | (ap_mac_addr[4]); - data_word[3] = (sta_mac_addr[5] << 24) | (sta_mac_addr[4] << 16) | - (sta_mac_addr[3] << 8) | (sta_mac_addr[2]); - data_word[4] = (ap_mac_addr[3] << 24) | (ap_mac_addr[2] << 16) | - (ap_mac_addr[1] << 8) | (ap_mac_addr[0]); - data_word[5] = (ap_mac_addr[5] << 8) | (ap_mac_addr[4]); - - if (AR_SREV_9462_20(ah)) { - /* AR9462 2.0 has an extra descriptor word (time based - * discard) compared to other chips */ - REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + (12 * 4)), 0); - wow_ka_data_word0 = AR_WOW_TXBUF(13); - } else { - wow_ka_data_word0 = AR_WOW_TXBUF(12); - } - - for (i = 0; i < KAL_NUM_DATA_WORDS; i++) - REG_WRITE(ah, (wow_ka_data_word0 + i*4), data_word[i]); - -} - -void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, - u8 *user_mask, int pattern_count, - int pattern_len) -{ - int i; - u32 pattern_val, mask_val; - u32 set, clr; - - /* FIXME: should check count by querying the hardware capability */ - if (pattern_count >= MAX_NUM_PATTERN) - return; - - REG_SET_BIT(ah, AR_WOW_PATTERN, BIT(pattern_count)); - - /* set the registers for pattern */ - for (i = 0; i < MAX_PATTERN_SIZE; i += 4) { - memcpy(&pattern_val, user_pattern, 4); - REG_WRITE(ah, (AR_WOW_TB_PATTERN(pattern_count) + i), - pattern_val); - user_pattern += 4; - } - - /* set the registers for mask */ - for (i = 0; i < MAX_PATTERN_MASK_SIZE; i += 4) { - memcpy(&mask_val, user_mask, 4); - REG_WRITE(ah, (AR_WOW_TB_MASK(pattern_count) + i), mask_val); - user_mask += 4; - } - - /* set the pattern length to be matched - * - * AR_WOW_LENGTH1_REG1 - * bit 31:24 pattern 0 length - * bit 23:16 pattern 1 length - * bit 15:8 pattern 2 length - * bit 7:0 pattern 3 length - * - * AR_WOW_LENGTH1_REG2 - * bit 31:24 pattern 4 length - * bit 23:16 pattern 5 length - * bit 15:8 pattern 6 length - * bit 7:0 pattern 7 length - * - * the below logic writes out the new - * pattern length for the corresponding - * pattern_count, while masking out the - * other fields - */ - - ah->wow_event_mask |= BIT(pattern_count + AR_WOW_PAT_FOUND_SHIFT); - - if (pattern_count < 4) { - /* Pattern 0-3 uses AR_WOW_LENGTH1 register */ - set = (pattern_len & AR_WOW_LENGTH_MAX) << - AR_WOW_LEN1_SHIFT(pattern_count); - clr = AR_WOW_LENGTH1_MASK(pattern_count); - REG_RMW(ah, AR_WOW_LENGTH1, set, clr); - } else { - /* Pattern 4-7 uses AR_WOW_LENGTH2 register */ - set = (pattern_len & AR_WOW_LENGTH_MAX) << - AR_WOW_LEN2_SHIFT(pattern_count); - clr = AR_WOW_LENGTH2_MASK(pattern_count); - REG_RMW(ah, AR_WOW_LENGTH2, set, clr); - } - -} -EXPORT_SYMBOL(ath9k_hw_wow_apply_pattern); - -u32 ath9k_hw_wow_wakeup(struct ath_hw *ah) -{ - u32 wow_status = 0; - u32 val = 0, rval; - - /* - * read the WoW status register to know - * the wakeup reason - */ - rval = REG_READ(ah, AR_WOW_PATTERN); - val = AR_WOW_STATUS(rval); - - /* - * mask only the WoW events that we have enabled. Sometimes - * we have spurious WoW events from the AR_WOW_PATTERN - * register. This mask will clean it up. - */ - - val &= ah->wow_event_mask; - - if (val) { - if (val & AR_WOW_MAGIC_PAT_FOUND) - wow_status |= AH_WOW_MAGIC_PATTERN_EN; - if (AR_WOW_PATTERN_FOUND(val)) - wow_status |= AH_WOW_USER_PATTERN_EN; - if (val & AR_WOW_KEEP_ALIVE_FAIL) - wow_status |= AH_WOW_LINK_CHANGE; - if (val & AR_WOW_BEACON_FAIL) - wow_status |= AH_WOW_BEACON_MISS; - } - - /* - * set and clear WOW_PME_CLEAR registers for the chip to - * generate next wow signal. - * disable D3 before accessing other registers ? - */ - - /* do we need to check the bit value 0x01000000 (7-10) ?? */ - REG_RMW(ah, AR_PCIE_PM_CTRL, AR_PMCTRL_WOW_PME_CLR, - AR_PMCTRL_PWR_STATE_D1D3); - - /* - * clear all events - */ - REG_WRITE(ah, AR_WOW_PATTERN, - AR_WOW_CLEAR_EVENTS(REG_READ(ah, AR_WOW_PATTERN))); - - /* - * restore the beacon threshold to init value - */ - REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR); - - /* - * Restore the way the PCI-E reset, Power-On-Reset, external - * PCIE_POR_SHORT pins are tied to its original value. - * Previously just before WoW sleep, we untie the PCI-E - * reset to our Chip's Power On Reset so that any PCI-E - * reset from the bus will not reset our chip - */ - if (ah->is_pciexpress) - ath9k_hw_configpcipowersave(ah, false); - - ah->wow_event_mask = 0; - - return wow_status; -} -EXPORT_SYMBOL(ath9k_hw_wow_wakeup); - -void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) -{ - u32 wow_event_mask; - u32 set, clr; - - /* - * wow_event_mask is a mask to the AR_WOW_PATTERN register to - * indicate which WoW events we have enabled. The WoW events - * are from the 'pattern_enable' in this function and - * 'pattern_count' of ath9k_hw_wow_apply_pattern() - */ - wow_event_mask = ah->wow_event_mask; - - /* - * Untie Power-on-Reset from the PCI-E-Reset. When we are in - * WOW sleep, we do want the Reset from the PCI-E to disturb - * our hw state - */ - if (ah->is_pciexpress) { - /* - * we need to untie the internal POR (power-on-reset) - * to the external PCI-E reset. We also need to tie - * the PCI-E Phy reset to the PCI-E reset. - */ - set = AR_WA_RESET_EN | AR_WA_POR_SHORT; - clr = AR_WA_UNTIE_RESET_EN | AR_WA_D3_L1_DISABLE; - REG_RMW(ah, AR_WA, set, clr); - } - - /* - * set the power states appropriately and enable PME - */ - set = AR_PMCTRL_HOST_PME_EN | AR_PMCTRL_PWR_PM_CTRL_ENA | - AR_PMCTRL_AUX_PWR_DET | AR_PMCTRL_WOW_PME_CLR; - - /* - * set and clear WOW_PME_CLEAR registers for the chip - * to generate next wow signal. - */ - REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set); - clr = AR_PMCTRL_WOW_PME_CLR; - REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr); - - /* - * Setup for: - * - beacon misses - * - magic pattern - * - keep alive timeout - * - pattern matching - */ - - /* - * Program default values for pattern backoff, aifs/slot/KAL count, - * beacon miss timeout, KAL timeout, etc. - */ - set = AR_WOW_BACK_OFF_SHIFT(AR_WOW_PAT_BACKOFF); - REG_SET_BIT(ah, AR_WOW_PATTERN, set); - - set = AR_WOW_AIFS_CNT(AR_WOW_CNT_AIFS_CNT) | - AR_WOW_SLOT_CNT(AR_WOW_CNT_SLOT_CNT) | - AR_WOW_KEEP_ALIVE_CNT(AR_WOW_CNT_KA_CNT); - REG_SET_BIT(ah, AR_WOW_COUNT, set); - - if (pattern_enable & AH_WOW_BEACON_MISS) - set = AR_WOW_BEACON_TIMO; - /* We are not using beacon miss, program a large value */ - else - set = AR_WOW_BEACON_TIMO_MAX; - - REG_WRITE(ah, AR_WOW_BCN_TIMO, set); - - /* - * Keep alive timo in ms except AR9280 - */ - if (!pattern_enable) - set = AR_WOW_KEEP_ALIVE_NEVER; - else - set = KAL_TIMEOUT * 32; - - REG_WRITE(ah, AR_WOW_KEEP_ALIVE_TIMO, set); - - /* - * Keep alive delay in us. based on 'power on clock', - * therefore in usec - */ - set = KAL_DELAY * 1000; - REG_WRITE(ah, AR_WOW_KEEP_ALIVE_DELAY, set); - - /* - * Create keep alive pattern to respond to beacons - */ - ath9k_wow_create_keep_alive_pattern(ah); - - /* - * Configure MAC WoW Registers - */ - set = 0; - /* Send keep alive timeouts anyway */ - clr = AR_WOW_KEEP_ALIVE_AUTO_DIS; - - if (pattern_enable & AH_WOW_LINK_CHANGE) - wow_event_mask |= AR_WOW_KEEP_ALIVE_FAIL; - else - set = AR_WOW_KEEP_ALIVE_FAIL_DIS; - - set = AR_WOW_KEEP_ALIVE_FAIL_DIS; - REG_RMW(ah, AR_WOW_KEEP_ALIVE, set, clr); - - /* - * we are relying on a bmiss failure. ensure we have - * enough threshold to prevent false positives - */ - REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_THR_BM_THR, - AR_WOW_BMISSTHRESHOLD); - - set = 0; - clr = 0; - - if (pattern_enable & AH_WOW_BEACON_MISS) { - set = AR_WOW_BEACON_FAIL_EN; - wow_event_mask |= AR_WOW_BEACON_FAIL; - } else { - clr = AR_WOW_BEACON_FAIL_EN; - } - - REG_RMW(ah, AR_WOW_BCN_EN, set, clr); - - set = 0; - clr = 0; - /* - * Enable the magic packet registers - */ - if (pattern_enable & AH_WOW_MAGIC_PATTERN_EN) { - set = AR_WOW_MAGIC_EN; - wow_event_mask |= AR_WOW_MAGIC_PAT_FOUND; - } else { - clr = AR_WOW_MAGIC_EN; - } - set |= AR_WOW_MAC_INTR_EN; - REG_RMW(ah, AR_WOW_PATTERN, set, clr); - - REG_WRITE(ah, AR_WOW_PATTERN_MATCH_LT_256B, - AR_WOW_PATTERN_SUPPORTED); - - /* - * Set the power states appropriately and enable PME - */ - clr = 0; - set = AR_PMCTRL_PWR_STATE_D1D3 | AR_PMCTRL_HOST_PME_EN | - AR_PMCTRL_PWR_PM_CTRL_ENA; - - clr = AR_PCIE_PM_CTRL_ENA; - REG_RMW(ah, AR_PCIE_PM_CTRL, set, clr); - - /* - * this is needed to prevent the chip waking up - * the host within 3-4 seconds with certain - * platform/BIOS. The fix is to enable - * D1 & D3 to match original definition and - * also match the OTP value. Anyway this - * is more related to SW WOW. - */ - clr = AR_PMCTRL_PWR_STATE_D1D3; - REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr); - - set = AR_PMCTRL_PWR_STATE_D1D3_REAL; - REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set); - - REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM); - - /* to bring down WOW power low margin */ - set = BIT(13); - REG_SET_BIT(ah, AR_PCIE_PHY_REG3, set); - /* HW WoW */ - clr = BIT(5); - REG_CLR_BIT(ah, AR_PCU_MISC_MODE3, clr); - - ath9k_hw_set_powermode_wow_sleep(ah); - ah->wow_event_mask = wow_event_mask; -} -EXPORT_SYMBOL(ath9k_hw_wow_enable); -- cgit v1.2.3-70-g09d2 From bb00b1f786efc4c38d8e1e3e0e1996a59277a90e Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 28 Oct 2013 11:33:19 +0530 Subject: ath9k: Add a config option for WoW Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/Kconfig | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index 3ffa4ea8fcb..30d273c61bf 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -104,6 +104,14 @@ config ATH9K_TX99 be evaluated to meet the RF exposure limits set forth in the governmental SAR regulations. +config ATH9K_WOW + bool "Wake on Wireless LAN support (EXPERIMENTAL)" + depends on ATH9K && PM + default n + ---help--- + This option enables Wake on Wireless LAN support for certain cards. + Currently, AR9462 is supported. + config ATH9K_LEGACY_RATE_CONTROL bool "Atheros ath9k rate control" depends on ATH9K -- cgit v1.2.3-70-g09d2 From e60001e7167536d99bb2026367751704c623f9f8 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 28 Oct 2013 12:22:04 +0530 Subject: ath9k: Use CONFIG_ATH9K_WOW Move the WoW code to wow.c and compile it conditionally based on CONFIG_ATH9K_WOW. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/Makefile | 3 +- drivers/net/wireless/ath/ath9k/ath9k.h | 28 ++- drivers/net/wireless/ath/ath9k/hw.h | 4 +- drivers/net/wireless/ath/ath9k/init.c | 4 +- drivers/net/wireless/ath/ath9k/main.c | 338 +------------------------------ drivers/net/wireless/ath/ath9k/wow.c | 341 ++++++++++++++++++++++++++++++++ 6 files changed, 381 insertions(+), 337 deletions(-) create mode 100644 drivers/net/wireless/ath/ath9k/wow.c diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 796686a65b4..337c459eda2 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -15,6 +15,7 @@ ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o ath9k-$(CONFIG_ATH9K_DFS_DEBUGFS) += dfs_debug.o ath9k-$(CONFIG_ATH9K_DFS_CERTIFIED) += dfs.o ath9k-$(CONFIG_ATH9K_TX99) += tx99.o +ath9k-$(CONFIG_ATH9K_WOW) += wow.o obj-$(CONFIG_ATH9K) += ath9k.o @@ -40,7 +41,7 @@ ath9k_hw-y:= \ ar9003_eeprom.o \ ar9003_paprd.o -ath9k_hw-$(CONFIG_PM_SLEEP) += ar9003_wow.o +ath9k_hw-$(CONFIG_ATH9K_WOW) += ar9003_wow.o ath9k_hw-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += btcoex.o \ ar9003_mci.o diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index b39ffac3b93..9927dcaa559 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -570,6 +570,30 @@ static inline void ath_fill_led_pin(struct ath_softc *sc) } #endif +/************************/ +/* Wake on Wireless LAN */ +/************************/ + +#ifdef CONFIG_ATH9K_WOW +int ath9k_suspend(struct ieee80211_hw *hw, + struct cfg80211_wowlan *wowlan); +int ath9k_resume(struct ieee80211_hw *hw); +void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled); +#else +static inline int ath9k_suspend(struct ieee80211_hw *hw, + struct cfg80211_wowlan *wowlan) +{ + return 0; +} +static inline int ath9k_resume(struct ieee80211_hw *hw) +{ + return 0; +} +static inline void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled) +{ +} +#endif /* CONFIG_ATH9K_WOW */ + /*******************************/ /* Antenna diversity/combining */ /*******************************/ @@ -785,7 +809,7 @@ struct ath_softc { bool tx99_state; s16 tx99_power; -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_ATH9K_WOW atomic_t wow_got_bmiss_intr; atomic_t wow_sleep_proc_intr; /* in the middle of WoW sleep ? */ u32 wow_intr_before_sleep; @@ -984,6 +1008,8 @@ extern bool is_ath9k_unloaded; u8 ath9k_parse_mpdudensity(u8 mpdudensity); irqreturn_t ath_isr(int irq, void *dev); int ath_reset(struct ath_softc *sc); +void ath_cancel_work(struct ath_softc *sc); +void ath_restart_work(struct ath_softc *sc); int ath9k_init_device(u16 devid, struct ath_softc *sc, const struct ath_bus_ops *bus_ops); void ath9k_deinit_device(struct ath_softc *sc); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index a2c9a5dbac6..ecc3a4efe18 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -921,7 +921,7 @@ struct ath_hw { /* Enterprise mode cap */ u32 ent_mode; -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_ATH9K_WOW u32 wow_event_mask; #endif bool is_clk_25mhz; @@ -1127,7 +1127,7 @@ ath9k_hw_get_btcoex_scheme(struct ath_hw *ah) #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_ATH9K_WOW const char *ath9k_hw_wow_event_to_string(u32 wow_event); void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, u8 *user_mask, int pattern_count, diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 6ef4c0635b3..cc23436e340 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -876,7 +876,7 @@ static const struct ieee80211_iface_combination if_comb[] = { } }; -#ifdef CONFIG_PM +#ifdef CONFIG_ATH9K_WOW static const struct wiphy_wowlan_support ath9k_wowlan_support = { .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, .n_patterns = MAX_NUM_USER_PATTERN, @@ -934,7 +934,7 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_5_10_MHZ; hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_ATH9K_WOW if ((ah->caps.hw_caps & ATH9K_HW_WOW_DEVICE_CAPABLE) && (sc->driver_data & ATH9K_PCI_WOW) && device_can_wakeup(sc->dev)) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 3d173986435..e54ffdd36e2 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -163,13 +163,13 @@ static void __ath_cancel_work(struct ath_softc *sc) #endif } -static void ath_cancel_work(struct ath_softc *sc) +void ath_cancel_work(struct ath_softc *sc) { __ath_cancel_work(sc); cancel_work_sync(&sc->hw_reset_work); } -static void ath_restart_work(struct ath_softc *sc) +void ath_restart_work(struct ath_softc *sc) { ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); @@ -579,7 +579,8 @@ irqreturn_t ath_isr(int irq, void *dev) goto chip_reset; } -#ifdef CONFIG_PM_SLEEP + +#ifdef CONFIG_ATH9K_WOW if (status & ATH9K_INT_BMISS) { if (atomic_read(&sc->wow_sleep_proc_intr) == 0) { ath_dbg(common, ANY, "during WoW we got a BMISS\n"); @@ -588,6 +589,8 @@ irqreturn_t ath_isr(int irq, void *dev) } } #endif + + if (status & ATH9K_INT_SWBA) tasklet_schedule(&sc->bcon_tasklet); @@ -2021,333 +2024,6 @@ static int ath9k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) return 0; } -#ifdef CONFIG_PM_SLEEP - -static void ath9k_wow_map_triggers(struct ath_softc *sc, - struct cfg80211_wowlan *wowlan, - u32 *wow_triggers) -{ - if (wowlan->disconnect) - *wow_triggers |= AH_WOW_LINK_CHANGE | - AH_WOW_BEACON_MISS; - if (wowlan->magic_pkt) - *wow_triggers |= AH_WOW_MAGIC_PATTERN_EN; - - if (wowlan->n_patterns) - *wow_triggers |= AH_WOW_USER_PATTERN_EN; - - sc->wow_enabled = *wow_triggers; - -} - -static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) -{ - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - int pattern_count = 0; - int i, byte_cnt; - u8 dis_deauth_pattern[MAX_PATTERN_SIZE]; - u8 dis_deauth_mask[MAX_PATTERN_SIZE]; - - memset(dis_deauth_pattern, 0, MAX_PATTERN_SIZE); - memset(dis_deauth_mask, 0, MAX_PATTERN_SIZE); - - /* - * Create Dissassociate / Deauthenticate packet filter - * - * 2 bytes 2 byte 6 bytes 6 bytes 6 bytes - * +--------------+----------+---------+--------+--------+---- - * + Frame Control+ Duration + DA + SA + BSSID + - * +--------------+----------+---------+--------+--------+---- - * - * The above is the management frame format for disassociate/ - * deauthenticate pattern, from this we need to match the first byte - * of 'Frame Control' and DA, SA, and BSSID fields - * (skipping 2nd byte of FC and Duration feild. - * - * Disassociate pattern - * -------------------- - * Frame control = 00 00 1010 - * DA, SA, BSSID = x:x:x:x:x:x - * Pattern will be A0000000 | x:x:x:x:x:x | x:x:x:x:x:x - * | x:x:x:x:x:x -- 22 bytes - * - * Deauthenticate pattern - * ---------------------- - * Frame control = 00 00 1100 - * DA, SA, BSSID = x:x:x:x:x:x - * Pattern will be C0000000 | x:x:x:x:x:x | x:x:x:x:x:x - * | x:x:x:x:x:x -- 22 bytes - */ - - /* Create Disassociate Pattern first */ - - byte_cnt = 0; - - /* Fill out the mask with all FF's */ - - for (i = 0; i < MAX_PATTERN_MASK_SIZE; i++) - dis_deauth_mask[i] = 0xff; - - /* copy the first byte of frame control field */ - dis_deauth_pattern[byte_cnt] = 0xa0; - byte_cnt++; - - /* skip 2nd byte of frame control and Duration field */ - byte_cnt += 3; - - /* - * need not match the destination mac address, it can be a broadcast - * mac address or an unicast to this station - */ - byte_cnt += 6; - - /* copy the source mac address */ - memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN); - - byte_cnt += 6; - - /* copy the bssid, its same as the source mac address */ - - memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN); - - /* Create Disassociate pattern mask */ - - dis_deauth_mask[0] = 0xfe; - dis_deauth_mask[1] = 0x03; - dis_deauth_mask[2] = 0xc0; - - ath_dbg(common, WOW, "Adding disassoc/deauth patterns for WoW\n"); - - ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, - pattern_count, byte_cnt); - - pattern_count++; - /* - * for de-authenticate pattern, only the first byte of the frame - * control field gets changed from 0xA0 to 0xC0 - */ - dis_deauth_pattern[0] = 0xC0; - - ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, - pattern_count, byte_cnt); - -} - -static void ath9k_wow_add_pattern(struct ath_softc *sc, - struct cfg80211_wowlan *wowlan) -{ - struct ath_hw *ah = sc->sc_ah; - struct ath9k_wow_pattern *wow_pattern = NULL; - struct cfg80211_pkt_pattern *patterns = wowlan->patterns; - int mask_len; - s8 i = 0; - - if (!wowlan->n_patterns) - return; - - /* - * Add the new user configured patterns - */ - for (i = 0; i < wowlan->n_patterns; i++) { - - wow_pattern = kzalloc(sizeof(*wow_pattern), GFP_KERNEL); - - if (!wow_pattern) - return; - - /* - * TODO: convert the generic user space pattern to - * appropriate chip specific/802.11 pattern. - */ - - mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8); - memset(wow_pattern->pattern_bytes, 0, MAX_PATTERN_SIZE); - memset(wow_pattern->mask_bytes, 0, MAX_PATTERN_SIZE); - memcpy(wow_pattern->pattern_bytes, patterns[i].pattern, - patterns[i].pattern_len); - memcpy(wow_pattern->mask_bytes, patterns[i].mask, mask_len); - wow_pattern->pattern_len = patterns[i].pattern_len; - - /* - * just need to take care of deauth and disssoc pattern, - * make sure we don't overwrite them. - */ - - ath9k_hw_wow_apply_pattern(ah, wow_pattern->pattern_bytes, - wow_pattern->mask_bytes, - i + 2, - wow_pattern->pattern_len); - kfree(wow_pattern); - - } - -} - -static int ath9k_suspend(struct ieee80211_hw *hw, - struct cfg80211_wowlan *wowlan) -{ - struct ath_softc *sc = hw->priv; - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - u32 wow_triggers_enabled = 0; - int ret = 0; - - mutex_lock(&sc->mutex); - - ath_cancel_work(sc); - ath_stop_ani(sc); - del_timer_sync(&sc->rx_poll_timer); - - if (test_bit(SC_OP_INVALID, &sc->sc_flags)) { - ath_dbg(common, ANY, "Device not present\n"); - ret = -EINVAL; - goto fail_wow; - } - - if (WARN_ON(!wowlan)) { - ath_dbg(common, WOW, "None of the WoW triggers enabled\n"); - ret = -EINVAL; - goto fail_wow; - } - - if (!device_can_wakeup(sc->dev)) { - ath_dbg(common, WOW, "device_can_wakeup failed, WoW is not enabled\n"); - ret = 1; - goto fail_wow; - } - - /* - * none of the sta vifs are associated - * and we are not currently handling multivif - * cases, for instance we have to seperately - * configure 'keep alive frame' for each - * STA. - */ - - if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { - ath_dbg(common, WOW, "None of the STA vifs are associated\n"); - ret = 1; - goto fail_wow; - } - - if (sc->nvifs > 1) { - ath_dbg(common, WOW, "WoW for multivif is not yet supported\n"); - ret = 1; - goto fail_wow; - } - - ath9k_wow_map_triggers(sc, wowlan, &wow_triggers_enabled); - - ath_dbg(common, WOW, "WoW triggers enabled 0x%x\n", - wow_triggers_enabled); - - ath9k_ps_wakeup(sc); - - ath9k_stop_btcoex(sc); - - /* - * Enable wake up on recieving disassoc/deauth - * frame by default. - */ - ath9k_wow_add_disassoc_deauth_pattern(sc); - - if (wow_triggers_enabled & AH_WOW_USER_PATTERN_EN) - ath9k_wow_add_pattern(sc, wowlan); - - spin_lock_bh(&sc->sc_pcu_lock); - /* - * To avoid false wake, we enable beacon miss interrupt only - * when we go to sleep. We save the current interrupt mask - * so we can restore it after the system wakes up - */ - sc->wow_intr_before_sleep = ah->imask; - ah->imask &= ~ATH9K_INT_GLOBAL; - ath9k_hw_disable_interrupts(ah); - ah->imask = ATH9K_INT_BMISS | ATH9K_INT_GLOBAL; - ath9k_hw_set_interrupts(ah); - ath9k_hw_enable_interrupts(ah); - - spin_unlock_bh(&sc->sc_pcu_lock); - - /* - * we can now sync irq and kill any running tasklets, since we already - * disabled interrupts and not holding a spin lock - */ - synchronize_irq(sc->irq); - tasklet_kill(&sc->intr_tq); - - ath9k_hw_wow_enable(ah, wow_triggers_enabled); - - ath9k_ps_restore(sc); - ath_dbg(common, ANY, "WoW enabled in ath9k\n"); - atomic_inc(&sc->wow_sleep_proc_intr); - -fail_wow: - mutex_unlock(&sc->mutex); - return ret; -} - -static int ath9k_resume(struct ieee80211_hw *hw) -{ - struct ath_softc *sc = hw->priv; - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - u32 wow_status; - - mutex_lock(&sc->mutex); - - ath9k_ps_wakeup(sc); - - spin_lock_bh(&sc->sc_pcu_lock); - - ath9k_hw_disable_interrupts(ah); - ah->imask = sc->wow_intr_before_sleep; - ath9k_hw_set_interrupts(ah); - ath9k_hw_enable_interrupts(ah); - - spin_unlock_bh(&sc->sc_pcu_lock); - - wow_status = ath9k_hw_wow_wakeup(ah); - - if (atomic_read(&sc->wow_got_bmiss_intr) == 0) { - /* - * some devices may not pick beacon miss - * as the reason they woke up so we add - * that here for that shortcoming. - */ - wow_status |= AH_WOW_BEACON_MISS; - atomic_dec(&sc->wow_got_bmiss_intr); - ath_dbg(common, ANY, "Beacon miss interrupt picked up during WoW sleep\n"); - } - - atomic_dec(&sc->wow_sleep_proc_intr); - - if (wow_status) { - ath_dbg(common, ANY, "Waking up due to WoW triggers %s with WoW status = %x\n", - ath9k_hw_wow_event_to_string(wow_status), wow_status); - } - - ath_restart_work(sc); - ath9k_start_btcoex(sc); - - ath9k_ps_restore(sc); - mutex_unlock(&sc->mutex); - - return 0; -} - -static void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled) -{ - struct ath_softc *sc = hw->priv; - - mutex_lock(&sc->mutex); - device_init_wakeup(sc->dev, 1); - device_set_wakeup_enable(sc->dev, enabled); - mutex_unlock(&sc->mutex); -} - -#endif static void ath9k_sw_scan_start(struct ieee80211_hw *hw) { struct ath_softc *sc = hw->priv; @@ -2403,7 +2079,7 @@ struct ieee80211_ops ath9k_ops = { .set_antenna = ath9k_set_antenna, .get_antenna = ath9k_get_antenna, -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_ATH9K_WOW .suspend = ath9k_suspend, .resume = ath9k_resume, .set_wakeup = ath9k_set_wakeup, diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c new file mode 100644 index 00000000000..e161bbc04db --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2013 Qualcomm Atheros, Inc. + * + * 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 "ath9k.h" + +static void ath9k_wow_map_triggers(struct ath_softc *sc, + struct cfg80211_wowlan *wowlan, + u32 *wow_triggers) +{ + if (wowlan->disconnect) + *wow_triggers |= AH_WOW_LINK_CHANGE | + AH_WOW_BEACON_MISS; + if (wowlan->magic_pkt) + *wow_triggers |= AH_WOW_MAGIC_PATTERN_EN; + + if (wowlan->n_patterns) + *wow_triggers |= AH_WOW_USER_PATTERN_EN; + + sc->wow_enabled = *wow_triggers; + +} + +static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + int pattern_count = 0; + int i, byte_cnt; + u8 dis_deauth_pattern[MAX_PATTERN_SIZE]; + u8 dis_deauth_mask[MAX_PATTERN_SIZE]; + + memset(dis_deauth_pattern, 0, MAX_PATTERN_SIZE); + memset(dis_deauth_mask, 0, MAX_PATTERN_SIZE); + + /* + * Create Dissassociate / Deauthenticate packet filter + * + * 2 bytes 2 byte 6 bytes 6 bytes 6 bytes + * +--------------+----------+---------+--------+--------+---- + * + Frame Control+ Duration + DA + SA + BSSID + + * +--------------+----------+---------+--------+--------+---- + * + * The above is the management frame format for disassociate/ + * deauthenticate pattern, from this we need to match the first byte + * of 'Frame Control' and DA, SA, and BSSID fields + * (skipping 2nd byte of FC and Duration feild. + * + * Disassociate pattern + * -------------------- + * Frame control = 00 00 1010 + * DA, SA, BSSID = x:x:x:x:x:x + * Pattern will be A0000000 | x:x:x:x:x:x | x:x:x:x:x:x + * | x:x:x:x:x:x -- 22 bytes + * + * Deauthenticate pattern + * ---------------------- + * Frame control = 00 00 1100 + * DA, SA, BSSID = x:x:x:x:x:x + * Pattern will be C0000000 | x:x:x:x:x:x | x:x:x:x:x:x + * | x:x:x:x:x:x -- 22 bytes + */ + + /* Create Disassociate Pattern first */ + + byte_cnt = 0; + + /* Fill out the mask with all FF's */ + + for (i = 0; i < MAX_PATTERN_MASK_SIZE; i++) + dis_deauth_mask[i] = 0xff; + + /* copy the first byte of frame control field */ + dis_deauth_pattern[byte_cnt] = 0xa0; + byte_cnt++; + + /* skip 2nd byte of frame control and Duration field */ + byte_cnt += 3; + + /* + * need not match the destination mac address, it can be a broadcast + * mac address or an unicast to this station + */ + byte_cnt += 6; + + /* copy the source mac address */ + memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN); + + byte_cnt += 6; + + /* copy the bssid, its same as the source mac address */ + + memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN); + + /* Create Disassociate pattern mask */ + + dis_deauth_mask[0] = 0xfe; + dis_deauth_mask[1] = 0x03; + dis_deauth_mask[2] = 0xc0; + + ath_dbg(common, WOW, "Adding disassoc/deauth patterns for WoW\n"); + + ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, + pattern_count, byte_cnt); + + pattern_count++; + /* + * for de-authenticate pattern, only the first byte of the frame + * control field gets changed from 0xA0 to 0xC0 + */ + dis_deauth_pattern[0] = 0xC0; + + ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, + pattern_count, byte_cnt); + +} + +static void ath9k_wow_add_pattern(struct ath_softc *sc, + struct cfg80211_wowlan *wowlan) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath9k_wow_pattern *wow_pattern = NULL; + struct cfg80211_pkt_pattern *patterns = wowlan->patterns; + int mask_len; + s8 i = 0; + + if (!wowlan->n_patterns) + return; + + /* + * Add the new user configured patterns + */ + for (i = 0; i < wowlan->n_patterns; i++) { + + wow_pattern = kzalloc(sizeof(*wow_pattern), GFP_KERNEL); + + if (!wow_pattern) + return; + + /* + * TODO: convert the generic user space pattern to + * appropriate chip specific/802.11 pattern. + */ + + mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8); + memset(wow_pattern->pattern_bytes, 0, MAX_PATTERN_SIZE); + memset(wow_pattern->mask_bytes, 0, MAX_PATTERN_SIZE); + memcpy(wow_pattern->pattern_bytes, patterns[i].pattern, + patterns[i].pattern_len); + memcpy(wow_pattern->mask_bytes, patterns[i].mask, mask_len); + wow_pattern->pattern_len = patterns[i].pattern_len; + + /* + * just need to take care of deauth and disssoc pattern, + * make sure we don't overwrite them. + */ + + ath9k_hw_wow_apply_pattern(ah, wow_pattern->pattern_bytes, + wow_pattern->mask_bytes, + i + 2, + wow_pattern->pattern_len); + kfree(wow_pattern); + + } + +} + +int ath9k_suspend(struct ieee80211_hw *hw, + struct cfg80211_wowlan *wowlan) +{ + struct ath_softc *sc = hw->priv; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + u32 wow_triggers_enabled = 0; + int ret = 0; + + mutex_lock(&sc->mutex); + + ath_cancel_work(sc); + ath_stop_ani(sc); + del_timer_sync(&sc->rx_poll_timer); + + if (test_bit(SC_OP_INVALID, &sc->sc_flags)) { + ath_dbg(common, ANY, "Device not present\n"); + ret = -EINVAL; + goto fail_wow; + } + + if (WARN_ON(!wowlan)) { + ath_dbg(common, WOW, "None of the WoW triggers enabled\n"); + ret = -EINVAL; + goto fail_wow; + } + + if (!device_can_wakeup(sc->dev)) { + ath_dbg(common, WOW, "device_can_wakeup failed, WoW is not enabled\n"); + ret = 1; + goto fail_wow; + } + + /* + * none of the sta vifs are associated + * and we are not currently handling multivif + * cases, for instance we have to seperately + * configure 'keep alive frame' for each + * STA. + */ + + if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { + ath_dbg(common, WOW, "None of the STA vifs are associated\n"); + ret = 1; + goto fail_wow; + } + + if (sc->nvifs > 1) { + ath_dbg(common, WOW, "WoW for multivif is not yet supported\n"); + ret = 1; + goto fail_wow; + } + + ath9k_wow_map_triggers(sc, wowlan, &wow_triggers_enabled); + + ath_dbg(common, WOW, "WoW triggers enabled 0x%x\n", + wow_triggers_enabled); + + ath9k_ps_wakeup(sc); + + ath9k_stop_btcoex(sc); + + /* + * Enable wake up on recieving disassoc/deauth + * frame by default. + */ + ath9k_wow_add_disassoc_deauth_pattern(sc); + + if (wow_triggers_enabled & AH_WOW_USER_PATTERN_EN) + ath9k_wow_add_pattern(sc, wowlan); + + spin_lock_bh(&sc->sc_pcu_lock); + /* + * To avoid false wake, we enable beacon miss interrupt only + * when we go to sleep. We save the current interrupt mask + * so we can restore it after the system wakes up + */ + sc->wow_intr_before_sleep = ah->imask; + ah->imask &= ~ATH9K_INT_GLOBAL; + ath9k_hw_disable_interrupts(ah); + ah->imask = ATH9K_INT_BMISS | ATH9K_INT_GLOBAL; + ath9k_hw_set_interrupts(ah); + ath9k_hw_enable_interrupts(ah); + + spin_unlock_bh(&sc->sc_pcu_lock); + + /* + * we can now sync irq and kill any running tasklets, since we already + * disabled interrupts and not holding a spin lock + */ + synchronize_irq(sc->irq); + tasklet_kill(&sc->intr_tq); + + ath9k_hw_wow_enable(ah, wow_triggers_enabled); + + ath9k_ps_restore(sc); + ath_dbg(common, ANY, "WoW enabled in ath9k\n"); + atomic_inc(&sc->wow_sleep_proc_intr); + +fail_wow: + mutex_unlock(&sc->mutex); + return ret; +} + +int ath9k_resume(struct ieee80211_hw *hw) +{ + struct ath_softc *sc = hw->priv; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + u32 wow_status; + + mutex_lock(&sc->mutex); + + ath9k_ps_wakeup(sc); + + spin_lock_bh(&sc->sc_pcu_lock); + + ath9k_hw_disable_interrupts(ah); + ah->imask = sc->wow_intr_before_sleep; + ath9k_hw_set_interrupts(ah); + ath9k_hw_enable_interrupts(ah); + + spin_unlock_bh(&sc->sc_pcu_lock); + + wow_status = ath9k_hw_wow_wakeup(ah); + + if (atomic_read(&sc->wow_got_bmiss_intr) == 0) { + /* + * some devices may not pick beacon miss + * as the reason they woke up so we add + * that here for that shortcoming. + */ + wow_status |= AH_WOW_BEACON_MISS; + atomic_dec(&sc->wow_got_bmiss_intr); + ath_dbg(common, ANY, "Beacon miss interrupt picked up during WoW sleep\n"); + } + + atomic_dec(&sc->wow_sleep_proc_intr); + + if (wow_status) { + ath_dbg(common, ANY, "Waking up due to WoW triggers %s with WoW status = %x\n", + ath9k_hw_wow_event_to_string(wow_status), wow_status); + } + + ath_restart_work(sc); + ath9k_start_btcoex(sc); + + ath9k_ps_restore(sc); + mutex_unlock(&sc->mutex); + + return 0; +} + +void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled) +{ + struct ath_softc *sc = hw->priv; + + mutex_lock(&sc->mutex); + device_init_wakeup(sc->dev, 1); + device_set_wakeup_enable(sc->dev, enabled); + mutex_unlock(&sc->mutex); +} -- cgit v1.2.3-70-g09d2 From babaa80ac567462a8abda067ec70181d559bbdff Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 28 Oct 2013 13:01:28 +0530 Subject: ath9k: Add an initialization routine for WoW Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 4 ++++ drivers/net/wireless/ath/ath9k/init.c | 20 +------------------- drivers/net/wireless/ath/ath9k/wow.c | 20 ++++++++++++++++++++ 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 9927dcaa559..e1013425cc7 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -575,11 +575,15 @@ static inline void ath_fill_led_pin(struct ath_softc *sc) /************************/ #ifdef CONFIG_ATH9K_WOW +void ath9k_init_wow(struct ieee80211_hw *hw); int ath9k_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan); int ath9k_resume(struct ieee80211_hw *hw); void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled); #else +static inline void ath9k_init_wow(struct ieee80211_hw *hw) +{ +} static inline int ath9k_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) { diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index cc23436e340..fb55302c958 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -876,15 +876,6 @@ static const struct ieee80211_iface_combination if_comb[] = { } }; -#ifdef CONFIG_ATH9K_WOW -static const struct wiphy_wowlan_support ath9k_wowlan_support = { - .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, - .n_patterns = MAX_NUM_USER_PATTERN, - .pattern_min_len = 1, - .pattern_max_len = MAX_PATTERN_SIZE, -}; -#endif - void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) { struct ath_hw *ah = sc->sc_ah; @@ -934,16 +925,6 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_5_10_MHZ; hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; -#ifdef CONFIG_ATH9K_WOW - if ((ah->caps.hw_caps & ATH9K_HW_WOW_DEVICE_CAPABLE) && - (sc->driver_data & ATH9K_PCI_WOW) && - device_can_wakeup(sc->dev)) - hw->wiphy->wowlan = &ath9k_wowlan_support; - - atomic_set(&sc->wow_sleep_proc_intr, -1); - atomic_set(&sc->wow_got_bmiss_intr, -1); -#endif - hw->queues = 4; hw->max_rates = 4; hw->channel_change_time = 5000; @@ -969,6 +950,7 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &sc->sbands[IEEE80211_BAND_5GHZ]; + ath9k_init_wow(hw); ath9k_reload_chainmask_settings(sc); SET_IEEE80211_PERM_ADDR(hw, common->macaddr); diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index e161bbc04db..f1cde81bb7a 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -16,6 +16,13 @@ #include "ath9k.h" +static const struct wiphy_wowlan_support ath9k_wowlan_support = { + .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, + .n_patterns = MAX_NUM_USER_PATTERN, + .pattern_min_len = 1, + .pattern_max_len = MAX_PATTERN_SIZE, +}; + static void ath9k_wow_map_triggers(struct ath_softc *sc, struct cfg80211_wowlan *wowlan, u32 *wow_triggers) @@ -339,3 +346,16 @@ void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled) device_set_wakeup_enable(sc->dev, enabled); mutex_unlock(&sc->mutex); } + +void ath9k_init_wow(struct ieee80211_hw *hw) +{ + struct ath_softc *sc = hw->priv; + + if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_WOW_DEVICE_CAPABLE) && + (sc->driver_data & ATH9K_PCI_WOW) && + device_can_wakeup(sc->dev)) + hw->wiphy->wowlan = &ath9k_wowlan_support; + + atomic_set(&sc->wow_sleep_proc_intr, -1); + atomic_set(&sc->wow_got_bmiss_intr, -1); +} -- cgit v1.2.3-70-g09d2 From f51ecd770cb975adbc7761b6167d2de596e421ea Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Tue, 29 Oct 2013 11:35:31 +0530 Subject: ath9k: Add SERDES initvals for AR9462 2.1 Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_hw.c | 4 ++++ drivers/net/wireless/ath/ath9k/ar9462_2p1_initvals.h | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 20e49095db2..84b83e1e713 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -223,6 +223,10 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ar9462_2p1_modes_fast_clock); INIT_INI_ARRAY(&ah->iniCckfirJapan2484, ar9462_2p1_baseband_core_txfir_coeff_japan_2484); + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9462_2p1_pciephy_clkreq_disable_L1); + INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, + ar9462_2p1_pciephy_clkreq_disable_L1); } else if (AR_SREV_9462_20(ah)) { INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], ar9462_2p0_mac_core); diff --git a/drivers/net/wireless/ath/ath9k/ar9462_2p1_initvals.h b/drivers/net/wireless/ath/ath9k/ar9462_2p1_initvals.h index 57fc5f459d0..0fcce0739a4 100644 --- a/drivers/net/wireless/ath/ath9k/ar9462_2p1_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9462_2p1_initvals.h @@ -1771,4 +1771,11 @@ static const u32 ar9462_2p1_baseband_core_txfir_coeff_japan_2484[][2] = { {0x0000a3a0, 0xca9228ee}, }; +static const u32 ar9462_2p1_pciephy_clkreq_disable_L1[][2] = { + /* Addr allmodes */ + {0x00018c00, 0x18213ede}, + {0x00018c04, 0x000801d8}, + {0x00018c08, 0x0003780c}, +}; + #endif /* INITVALS_9462_2P1_H */ -- cgit v1.2.3-70-g09d2 From 28148db74d69de3d2ed0c401ec6ee53bd603f959 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Tue, 29 Oct 2013 11:40:06 +0530 Subject: ath9k: Remove unused AR9462 2.0 initvals Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h index 092b9d412e7..5a10dcf2adf 100644 --- a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h @@ -33,13 +33,6 @@ static const u32 ar9462_modes_fast_clock_2p0[][3] = { {0x0000a254, 0x00000898, 0x00001130}, }; -static const u32 ar9462_pciephy_clkreq_enable_L1_2p0[][2] = { - /* Addr allmodes */ - {0x00018c00, 0x18253ede}, - {0x00018c04, 0x000801d8}, - {0x00018c08, 0x0003780c}, -}; - static const u32 ar9462_2p0_baseband_postamble[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a800d}, @@ -366,13 +359,6 @@ static const u32 ar9462_pciephy_clkreq_disable_L1_2p0[][2] = { {0x00018c08, 0x0003780c}, }; -static const u32 ar9462_pciephy_pll_on_clkreq_disable_L1_2p0[][2] = { - /* Addr allmodes */ - {0x00018c00, 0x18212ede}, - {0x00018c04, 0x000801d8}, - {0x00018c08, 0x0003780c}, -}; - static const u32 ar9462_2p0_radio_postamble_sys2ant[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x000160ac, 0xa4646c08, 0xa4646c08, 0x24645808, 0x24645808}, -- cgit v1.2.3-70-g09d2 From c6fc7e64e1a699b77681dd383d9a5a1ff9eb48e9 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Tue, 29 Oct 2013 11:52:06 +0530 Subject: ath9k: Remove pcieSerDesWrite This HW config option is always set to true and is not needed. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_hw.c | 20 +++++++++----------- drivers/net/wireless/ath/ath9k/hw.c | 1 - drivers/net/wireless/ath/ath9k/hw.h | 1 - 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 84b83e1e713..8d453de979c 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -754,6 +754,9 @@ static void ar9003_hw_init_mode_gain_regs(struct ath_hw *ah) static void ar9003_hw_configpcipowersave(struct ath_hw *ah, bool power_off) { + unsigned int i; + struct ar5416IniArray *array; + /* * Increase L1 Entry Latency. Some WB222 boards don't have * this change in eeprom/OTP. @@ -779,18 +782,13 @@ static void ar9003_hw_configpcipowersave(struct ath_hw *ah, * Configire PCIE after Ini init. SERDES values now come from ini file * This enables PCIe low power mode. */ - if (ah->config.pcieSerDesWrite) { - unsigned int i; - struct ar5416IniArray *array; - - array = power_off ? &ah->iniPcieSerdes : - &ah->iniPcieSerdesLowPower; + array = power_off ? &ah->iniPcieSerdes : + &ah->iniPcieSerdesLowPower; - for (i = 0; i < array->ia_rows; i++) { - REG_WRITE(ah, - INI_RA(array, i, 0), - INI_RA(array, i, 1)); - } + for (i = 0; i < array->ia_rows; i++) { + REG_WRITE(ah, + INI_RA(array, i, 0), + INI_RA(array, i, 1)); } } diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 54b04155e43..381fbe1d489 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -454,7 +454,6 @@ static void ath9k_hw_init_config(struct ath_hw *ah) } ah->config.rx_intr_mitigation = true; - ah->config.pcieSerDesWrite = true; /* * We need this for PCI devices only (Cardbus, PCI, miniPCI) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index ecc3a4efe18..e5084360098 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -283,7 +283,6 @@ struct ath9k_ops_config { int additional_swba_backoff; int ack_6mb; u32 cwm_ignore_extcca; - bool pcieSerDesWrite; u8 pcie_clock_req; u32 pcie_waen; u8 analog_shiftreg; -- cgit v1.2.3-70-g09d2 From 8fd007ac7c6ca63f7dbf7792cc1081855ef7fe4e Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Tue, 5 Nov 2013 05:54:59 +0530 Subject: ath9k: Apply CUS227 specific TX gain values CUS227, which is an AR9340 based card used in Qualcomm's Allplay platforms requires a custom TX gain array, based on the index 7. Add suport for this. Cc: Michael Larson Cc: Stephen Collmeyer Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_hw.c | 8 ++ drivers/net/wireless/ath/ath9k/ar9340_initvals.h | 102 +++++++++++++++++++++++ 2 files changed, 110 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 8d453de979c..33f63dc672e 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -585,6 +585,13 @@ static void ar9003_tx_gain_table_mode6(struct ath_hw *ah) ar9580_1p0_type6_tx_gain_table); } +static void ar9003_tx_gain_table_mode7(struct ath_hw *ah) +{ + if (AR_SREV_9340(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9340_cus227_tx_gain_table_1p0); +} + typedef void (*ath_txgain_tab)(struct ath_hw *ah); static void ar9003_tx_gain_table_apply(struct ath_hw *ah) @@ -597,6 +604,7 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah) ar9003_tx_gain_table_mode4, ar9003_tx_gain_table_mode5, ar9003_tx_gain_table_mode6, + ar9003_tx_gain_table_mode7, }; int idx = ar9003_hw_get_tx_gain_idx(ah); diff --git a/drivers/net/wireless/ath/ath9k/ar9340_initvals.h b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h index 25db9215985..182bf90ab80 100644 --- a/drivers/net/wireless/ath/ath9k/ar9340_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h @@ -1447,4 +1447,106 @@ static const u32 ar9340_1p0_soc_preamble[][2] = { {0x00007038, 0x000004c2}, }; +static const u32 ar9340_cus227_tx_gain_table_1p0[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, + {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, + {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x1c000223, 0x1c000223, 0x11000400, 0x11000400}, + {0x0000a518, 0x21002220, 0x21002220, 0x15000402, 0x15000402}, + {0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404}, + {0x0000a520, 0x2c022220, 0x2c022220, 0x1b000603, 0x1b000603}, + {0x0000a524, 0x30022222, 0x30022222, 0x1f000a02, 0x1f000a02}, + {0x0000a528, 0x35022225, 0x35022225, 0x23000a04, 0x23000a04}, + {0x0000a52c, 0x3b02222a, 0x3b02222a, 0x26000a20, 0x26000a20}, + {0x0000a530, 0x3f02222c, 0x3f02222c, 0x2a000e20, 0x2a000e20}, + {0x0000a534, 0x4202242a, 0x4202242a, 0x2e000e22, 0x2e000e22}, + {0x0000a538, 0x4702244a, 0x4702244a, 0x31000e24, 0x31000e24}, + {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x34001640, 0x34001640}, + {0x0000a540, 0x4e02246c, 0x4e02246c, 0x38001660, 0x38001660}, + {0x0000a544, 0x5302266c, 0x5302266c, 0x3b001861, 0x3b001861}, + {0x0000a548, 0x5702286c, 0x5702286c, 0x3e001a81, 0x3e001a81}, + {0x0000a54c, 0x5c02486b, 0x5c02486b, 0x42001a83, 0x42001a83}, + {0x0000a550, 0x61024a6c, 0x61024a6c, 0x44001c84, 0x44001c84}, + {0x0000a554, 0x66026a6c, 0x66026a6c, 0x48001ce3, 0x48001ce3}, + {0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x4c001ce5, 0x4c001ce5}, + {0x0000a55c, 0x7002708c, 0x7002708c, 0x50001ce9, 0x50001ce9}, + {0x0000a560, 0x7302b08a, 0x7302b08a, 0x54001ceb, 0x54001ceb}, + {0x0000a564, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec}, + {0x0000a568, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec}, + {0x0000a56c, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec}, + {0x0000a570, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec}, + {0x0000a574, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec}, + {0x0000a578, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec}, + {0x0000a57c, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec}, + {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, + {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, + {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, + {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200}, + {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x1c800223, 0x1c800223, 0x11800400, 0x11800400}, + {0x0000a598, 0x21820220, 0x21820220, 0x15800402, 0x15800402}, + {0x0000a59c, 0x27820223, 0x27820223, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1b800603, 0x1b800603}, + {0x0000a5a4, 0x2f822222, 0x2f822222, 0x1f800a02, 0x1f800a02}, + {0x0000a5a8, 0x34822225, 0x34822225, 0x23800a04, 0x23800a04}, + {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x26800a20, 0x26800a20}, + {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2a800e20, 0x2a800e20}, + {0x0000a5b4, 0x4282242a, 0x4282242a, 0x2e800e22, 0x2e800e22}, + {0x0000a5b8, 0x4782244a, 0x4782244a, 0x31800e24, 0x31800e24}, + {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x34801640, 0x34801640}, + {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x38801660, 0x38801660}, + {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3b801861, 0x3b801861}, + {0x0000a5c8, 0x5782286c, 0x5782286c, 0x3e801a81, 0x3e801a81}, + {0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x42801a83, 0x42801a83}, + {0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x44801c84, 0x44801c84}, + {0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x48801ce3, 0x48801ce3}, + {0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x4c801ce5, 0x4c801ce5}, + {0x0000a5dc, 0x7086308c, 0x7086308c, 0x50801ce9, 0x50801ce9}, + {0x0000a5e0, 0x738a308a, 0x738a308a, 0x54801ceb, 0x54801ceb}, + {0x0000a5e4, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x0000a5e8, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x0000a5ec, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x0000a5f0, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x0000a5f4, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x0000a5f8, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x0000a5fc, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000}, + {0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501}, + {0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501}, + {0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03}, + {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04}, + {0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04}, + {0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005}, + {0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x00016044, 0x056db2db, 0x056db2db, 0x03b6d2e4, 0x03b6d2e4}, + {0x00016048, 0x24925666, 0x24925666, 0x8e481266, 0x8e481266}, + {0x00016280, 0x01000015, 0x01000015, 0x01001015, 0x01001015}, + {0x00016288, 0x30318000, 0x30318000, 0x00318000, 0x00318000}, + {0x00016444, 0x056db2db, 0x056db2db, 0x03b6d2e4, 0x03b6d2e4}, + {0x00016448, 0x24925666, 0x24925666, 0x8e481266, 0x8e481266}, + {0x0000a3a4, 0x00000011, 0x00000011, 0x00000011, 0x00000011}, + {0x0000a3a8, 0x3c3c3c3c, 0x3c3c3c3c, 0x3c3c3c3c, 0x3c3c3c3c}, + {0x0000a3ac, 0x30303030, 0x30303030, 0x30303030, 0x30303030}, +}; + #endif /* INITVALS_9340_H */ -- cgit v1.2.3-70-g09d2 From 966fb5ec4246455ac82fc13f713c36636175a2f9 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 6 Nov 2013 10:43:27 +0530 Subject: ath9k: Update MAINTAINERS Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- MAINTAINERS | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 63f30484932..6d7cf3b5623 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1458,17 +1458,6 @@ T: git git://github.com/kvalo/ath.git S: Supported F: drivers/net/wireless/ath/ath6kl/ -ATHEROS ATH9K WIRELESS DRIVER -M: "Luis R. Rodriguez" -M: Jouni Malinen -M: Vasanthakumar Thiagarajan -M: Senthil Balasubramanian -L: linux-wireless@vger.kernel.org -L: ath9k-devel@lists.ath9k.org -W: http://wireless.kernel.org/en/users/Drivers/ath9k -S: Supported -F: drivers/net/wireless/ath/ath9k/ - WILOCITY WIL6210 WIRELESS DRIVER M: Vladimir Kondratiev L: linux-wireless@vger.kernel.org @@ -6916,6 +6905,14 @@ T: git git://linuxtv.org/anttip/media_tree.git S: Maintained F: drivers/media/tuners/qt1010* +QUALCOMM ATHEROS ATH9K WIRELESS DRIVER +M: QCA ath9k Development +L: linux-wireless@vger.kernel.org +L: ath9k-devel@lists.ath9k.org +W: http://wireless.kernel.org/en/users/Drivers/ath9k +S: Supported +F: drivers/net/wireless/ath/ath9k/ + QUALCOMM ATHEROS ATH10K WIRELESS DRIVER M: Kalle Valo L: ath10k@lists.infradead.org -- cgit v1.2.3-70-g09d2 From 26f2a64abdeb44e488e2334d28a380a3ed5a504d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 14 Nov 2013 15:31:18 +0530 Subject: ath9k: fix SC_OP_INVALID test in ath9k_tx99_init() SC_OP_INVALID is zero so the test is always false. We're supposed to be testing the lowest bit instead. Fixes: 89f927af7f33 ('ath9k: add TX99 support') Signed-off-by: Dan Carpenter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/tx99.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c index 6668197c277..c65c37fe101 100644 --- a/drivers/net/wireless/ath/ath9k/tx99.c +++ b/drivers/net/wireless/ath/ath9k/tx99.c @@ -99,7 +99,7 @@ static int ath9k_tx99_init(struct ath_softc *sc) struct ath_tx_control txctl; int r; - if (sc->sc_flags & SC_OP_INVALID) { + if (test_bit(SC_OP_INVALID, &sc->sc_flags)) { ath_err(common, "driver is in invalid state unable to use TX99"); return -EINVAL; -- cgit v1.2.3-70-g09d2 From 3b06c1d7af98f2fbc0c136b668568c873017bd54 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 15 Nov 2013 10:46:21 +0530 Subject: ath9k: Separate routines for PCOEM and SoC calibration Though there is some overlap between the calibration mechanisms of PC-OEM cards and SoC chip families, dumping both of them into a single function makes things hard to understand. ar9003_hw_init_cal() is unreadable with chip-specific segments scattered around. To make the logic understandable, use different functions for client cards and SoC chips. Some code is duplicated, but in the long run, it makes the code more maintanable. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_calib.c | 198 +++++++++++++++++++++++++- 1 file changed, 195 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 22934d3ca54..9f54cb58053 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -1040,8 +1040,196 @@ static void ar9003_hw_cl_cal_post_proc(struct ath_hw *ah, bool is_reusable) } } -static bool ar9003_hw_init_cal(struct ath_hw *ah, - struct ath9k_channel *chan) +static bool ar9003_hw_init_cal_pcoem(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_cal_data *caldata = ah->caldata; + bool txiqcal_done = false; + bool is_reusable = true, status = true; + bool run_rtt_cal = false, run_agc_cal, sep_iq_cal = false; + bool rtt = !!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT); + u32 rx_delay = 0; + u32 agc_ctrl = 0, agc_supp_cals = AR_PHY_AGC_CONTROL_OFFSET_CAL | + AR_PHY_AGC_CONTROL_FLTR_CAL | + AR_PHY_AGC_CONTROL_PKDET_CAL; + + /* Use chip chainmask only for calibration */ + ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask); + + if (rtt) { + if (!ar9003_hw_rtt_restore(ah, chan)) + run_rtt_cal = true; + + if (run_rtt_cal) + ath_dbg(common, CALIBRATE, "RTT calibration to be done\n"); + } + + run_agc_cal = run_rtt_cal; + + if (run_rtt_cal) { + ar9003_hw_rtt_enable(ah); + ar9003_hw_rtt_set_mask(ah, 0x00); + ar9003_hw_rtt_clear_hist(ah); + } + + if (rtt) { + if (!run_rtt_cal) { + agc_ctrl = REG_READ(ah, AR_PHY_AGC_CONTROL); + agc_supp_cals &= agc_ctrl; + agc_ctrl &= ~(AR_PHY_AGC_CONTROL_OFFSET_CAL | + AR_PHY_AGC_CONTROL_FLTR_CAL | + AR_PHY_AGC_CONTROL_PKDET_CAL); + REG_WRITE(ah, AR_PHY_AGC_CONTROL, agc_ctrl); + } else { + if (ah->ah_flags & AH_FASTCC) + run_agc_cal = true; + } + } + + if (ah->enabled_cals & TX_CL_CAL) { + if (caldata && test_bit(TXCLCAL_DONE, &caldata->cal_flags)) + REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, + AR_PHY_CL_CAL_ENABLE); + else { + REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, + AR_PHY_CL_CAL_ENABLE); + run_agc_cal = true; + } + } + + if ((IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan)) || + !(ah->enabled_cals & TX_IQ_CAL)) + goto skip_tx_iqcal; + + /* Do Tx IQ Calibration */ + REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1, + AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, + DELPT); + + /* + * For AR9485 or later chips, TxIQ cal runs as part of + * AGC calibration + */ + if (ah->enabled_cals & TX_IQ_ON_AGC_CAL) { + if (caldata && !test_bit(TXIQCAL_DONE, &caldata->cal_flags)) + REG_SET_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0, + AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL); + else + REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0, + AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL); + txiqcal_done = run_agc_cal = true; + } else if (caldata && !test_bit(TXIQCAL_DONE, &caldata->cal_flags)) { + run_agc_cal = true; + sep_iq_cal = true; + } + +skip_tx_iqcal: + if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal) + ar9003_mci_init_cal_req(ah, &is_reusable); + + if (sep_iq_cal) { + txiqcal_done = ar9003_hw_tx_iq_cal_run(ah); + REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); + udelay(5); + REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); + } + + if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE) { + rx_delay = REG_READ(ah, AR_PHY_RX_DELAY); + /* Disable BB_active */ + REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); + udelay(5); + REG_WRITE(ah, AR_PHY_RX_DELAY, AR_PHY_RX_DELAY_DELAY); + REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); + } + + if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) { + /* Calibrate the AGC */ + REG_WRITE(ah, AR_PHY_AGC_CONTROL, + REG_READ(ah, AR_PHY_AGC_CONTROL) | + AR_PHY_AGC_CONTROL_CAL); + + /* Poll for offset calibration complete */ + status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_CAL, + 0, AH_WAIT_TIMEOUT); + + ar9003_hw_do_manual_peak_cal(ah, chan, run_rtt_cal); + } + + if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE) { + REG_WRITE(ah, AR_PHY_RX_DELAY, rx_delay); + udelay(5); + } + + if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal) + ar9003_mci_init_cal_done(ah); + + if (rtt && !run_rtt_cal) { + agc_ctrl |= agc_supp_cals; + REG_WRITE(ah, AR_PHY_AGC_CONTROL, agc_ctrl); + } + + if (!status) { + if (run_rtt_cal) + ar9003_hw_rtt_disable(ah); + + ath_dbg(common, CALIBRATE, + "offset calibration failed to complete in %d ms; noisy environment?\n", + AH_WAIT_TIMEOUT / 1000); + return false; + } + + if (txiqcal_done) + ar9003_hw_tx_iq_cal_post_proc(ah, is_reusable); + else if (caldata && test_bit(TXIQCAL_DONE, &caldata->cal_flags)) + ar9003_hw_tx_iq_cal_reload(ah); + + ar9003_hw_cl_cal_post_proc(ah, is_reusable); + + if (run_rtt_cal && caldata) { + if (is_reusable) { + if (!ath9k_hw_rfbus_req(ah)) { + ath_err(ath9k_hw_common(ah), + "Could not stop baseband\n"); + } else { + ar9003_hw_rtt_fill_hist(ah); + + if (test_bit(SW_PKDET_DONE, &caldata->cal_flags)) + ar9003_hw_rtt_load_hist(ah); + } + + ath9k_hw_rfbus_done(ah); + } + + ar9003_hw_rtt_disable(ah); + } + + /* Revert chainmask to runtime parameters */ + ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); + + /* Initialize list pointers */ + ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; + + INIT_CAL(&ah->iq_caldata); + INSERT_CAL(ah, &ah->iq_caldata); + ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n"); + + /* Initialize current pointer to first element in list */ + ah->cal_list_curr = ah->cal_list; + + if (ah->cal_list_curr) + ath9k_hw_reset_calibration(ah, ah->cal_list_curr); + + if (caldata) + caldata->CalValid = 0; + + return true; +} + +static bool ar9003_hw_init_cal_soc(struct ath_hw *ah, + struct ath9k_channel *chan) { struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_cal_data *caldata = ah->caldata; @@ -1233,8 +1421,12 @@ void ar9003_hw_attach_calib_ops(struct ath_hw *ah) struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); struct ath_hw_ops *ops = ath9k_hw_ops(ah); + if (AR_SREV_9485(ah) || AR_SREV_9462(ah) || AR_SREV_9565(ah)) + priv_ops->init_cal = ar9003_hw_init_cal_pcoem; + else + priv_ops->init_cal = ar9003_hw_init_cal_soc; + priv_ops->init_cal_settings = ar9003_hw_init_cal_settings; - priv_ops->init_cal = ar9003_hw_init_cal; priv_ops->setup_calibration = ar9003_hw_setup_calibration; ops->calibrate = ar9003_hw_calibrate; -- cgit v1.2.3-70-g09d2 From a3640781d91334ba2a507b56cae18355fad8b479 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 15 Nov 2013 10:50:58 +0530 Subject: ath9k: Remove RTT/MCI code from SoC calibration RTT is enabled only for AR9462 and MCI for AR9462/AR9565. Also, manual peak calibration is not done for any of the SoC chips. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_calib.c | 70 +-------------------------- 1 file changed, 1 insertion(+), 69 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 9f54cb58053..28248248add 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -1235,46 +1235,12 @@ static bool ar9003_hw_init_cal_soc(struct ath_hw *ah, struct ath9k_hw_cal_data *caldata = ah->caldata; bool txiqcal_done = false; bool is_reusable = true, status = true; - bool run_rtt_cal = false, run_agc_cal, sep_iq_cal = false; - bool rtt = !!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT); + bool run_agc_cal = false, sep_iq_cal = false; u32 rx_delay = 0; - u32 agc_ctrl = 0, agc_supp_cals = AR_PHY_AGC_CONTROL_OFFSET_CAL | - AR_PHY_AGC_CONTROL_FLTR_CAL | - AR_PHY_AGC_CONTROL_PKDET_CAL; /* Use chip chainmask only for calibration */ ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask); - if (rtt) { - if (!ar9003_hw_rtt_restore(ah, chan)) - run_rtt_cal = true; - - if (run_rtt_cal) - ath_dbg(common, CALIBRATE, "RTT calibration to be done\n"); - } - - run_agc_cal = run_rtt_cal; - - if (run_rtt_cal) { - ar9003_hw_rtt_enable(ah); - ar9003_hw_rtt_set_mask(ah, 0x00); - ar9003_hw_rtt_clear_hist(ah); - } - - if (rtt) { - if (!run_rtt_cal) { - agc_ctrl = REG_READ(ah, AR_PHY_AGC_CONTROL); - agc_supp_cals &= agc_ctrl; - agc_ctrl &= ~(AR_PHY_AGC_CONTROL_OFFSET_CAL | - AR_PHY_AGC_CONTROL_FLTR_CAL | - AR_PHY_AGC_CONTROL_PKDET_CAL); - REG_WRITE(ah, AR_PHY_AGC_CONTROL, agc_ctrl); - } else { - if (ah->ah_flags & AH_FASTCC) - run_agc_cal = true; - } - } - if (ah->enabled_cals & TX_CL_CAL) { if (caldata && test_bit(TXCLCAL_DONE, &caldata->cal_flags)) REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, @@ -1313,9 +1279,6 @@ static bool ar9003_hw_init_cal_soc(struct ath_hw *ah, } skip_tx_iqcal: - if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal) - ar9003_mci_init_cal_req(ah, &is_reusable); - if (sep_iq_cal) { txiqcal_done = ar9003_hw_tx_iq_cal_run(ah); REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); @@ -1342,8 +1305,6 @@ skip_tx_iqcal: status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT); - - ar9003_hw_do_manual_peak_cal(ah, chan, run_rtt_cal); } if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE) { @@ -1351,18 +1312,7 @@ skip_tx_iqcal: udelay(5); } - if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal) - ar9003_mci_init_cal_done(ah); - - if (rtt && !run_rtt_cal) { - agc_ctrl |= agc_supp_cals; - REG_WRITE(ah, AR_PHY_AGC_CONTROL, agc_ctrl); - } - if (!status) { - if (run_rtt_cal) - ar9003_hw_rtt_disable(ah); - ath_dbg(common, CALIBRATE, "offset calibration failed to complete in %d ms; noisy environment?\n", AH_WAIT_TIMEOUT / 1000); @@ -1376,24 +1326,6 @@ skip_tx_iqcal: ar9003_hw_cl_cal_post_proc(ah, is_reusable); - if (run_rtt_cal && caldata) { - if (is_reusable) { - if (!ath9k_hw_rfbus_req(ah)) { - ath_err(ath9k_hw_common(ah), - "Could not stop baseband\n"); - } else { - ar9003_hw_rtt_fill_hist(ah); - - if (test_bit(SW_PKDET_DONE, &caldata->cal_flags)) - ar9003_hw_rtt_load_hist(ah); - } - - ath9k_hw_rfbus_done(ah); - } - - ar9003_hw_rtt_disable(ah); - } - /* Revert chainmask to runtime parameters */ ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); -- cgit v1.2.3-70-g09d2 From c20a2c5912755e8cb6c643fa0aa87e93e1b2c893 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 15 Nov 2013 11:05:38 +0530 Subject: ath9k: Remove unnecessary check TX IQ calibration is always enabled for SoC chips. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_calib.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 28248248add..347b002938e 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -1252,8 +1252,7 @@ static bool ar9003_hw_init_cal_soc(struct ath_hw *ah, } } - if ((IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan)) || - !(ah->enabled_cals & TX_IQ_CAL)) + if (IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan)) goto skip_tx_iqcal; /* Do Tx IQ Calibration */ -- cgit v1.2.3-70-g09d2 From 34d9b6893405c5afaf9d906062feae15ccfbcb28 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 15 Nov 2013 13:05:18 +0530 Subject: ath9k: Fix Carrier Leak calibration for SoC chips CL calibration is applicable for all chips and the enable/disable knob comes via the INI file. For PCOEM chips, the calibration data is reused when Fast Channel Change is used. Caldata reuse is not enabled for SoC chips, so remove the CL post processing code. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_calib.c | 27 ++------------------------- drivers/net/wireless/ath/ath9k/ar9003_phy.c | 9 +++++---- 2 files changed, 7 insertions(+), 29 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 347b002938e..58eacf12db8 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -1236,20 +1236,13 @@ static bool ar9003_hw_init_cal_soc(struct ath_hw *ah, bool txiqcal_done = false; bool is_reusable = true, status = true; bool run_agc_cal = false, sep_iq_cal = false; - u32 rx_delay = 0; /* Use chip chainmask only for calibration */ ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask); if (ah->enabled_cals & TX_CL_CAL) { - if (caldata && test_bit(TXCLCAL_DONE, &caldata->cal_flags)) - REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, - AR_PHY_CL_CAL_ENABLE); - else { - REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, - AR_PHY_CL_CAL_ENABLE); - run_agc_cal = true; - } + REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); + run_agc_cal = true; } if (IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan)) @@ -1285,15 +1278,6 @@ skip_tx_iqcal: REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); } - if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE) { - rx_delay = REG_READ(ah, AR_PHY_RX_DELAY); - /* Disable BB_active */ - REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); - udelay(5); - REG_WRITE(ah, AR_PHY_RX_DELAY, AR_PHY_RX_DELAY_DELAY); - REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); - } - if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) { /* Calibrate the AGC */ REG_WRITE(ah, AR_PHY_AGC_CONTROL, @@ -1306,11 +1290,6 @@ skip_tx_iqcal: 0, AH_WAIT_TIMEOUT); } - if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE) { - REG_WRITE(ah, AR_PHY_RX_DELAY, rx_delay); - udelay(5); - } - if (!status) { ath_dbg(common, CALIBRATE, "offset calibration failed to complete in %d ms; noisy environment?\n", @@ -1323,8 +1302,6 @@ skip_tx_iqcal: else if (caldata && test_bit(TXIQCAL_DONE, &caldata->cal_flags)) ar9003_hw_tx_iq_cal_reload(ah); - ar9003_hw_cl_cal_post_proc(ah, is_reusable); - /* Revert chainmask to runtime parameters */ ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index d39b79f5e84..39b71b3d691 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -641,11 +641,12 @@ static void ar9003_hw_override_ini(struct ath_hw *ah) else ah->enabled_cals &= ~TX_IQ_CAL; - if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE) - ah->enabled_cals |= TX_CL_CAL; - else - ah->enabled_cals &= ~TX_CL_CAL; } + + if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE) + ah->enabled_cals |= TX_CL_CAL; + else + ah->enabled_cals &= ~TX_CL_CAL; } static void ar9003_hw_prog_ini(struct ath_hw *ah, -- cgit v1.2.3-70-g09d2 From f28c785f37a977cfd5879f4bfec99838053373f8 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 15 Nov 2013 14:49:32 +0530 Subject: ath9k: Fix TX IQ calibration for SoC chips Since calibration data reuse is not enabled in SoC chips, simplify the IQ calibration code. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_calib.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 58eacf12db8..a18c3dd01a1 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -1255,22 +1255,19 @@ static bool ar9003_hw_init_cal_soc(struct ath_hw *ah, /* * For AR9485 or later chips, TxIQ cal runs as part of - * AGC calibration + * AGC calibration. Specifically, AR9550 in SoC chips. */ if (ah->enabled_cals & TX_IQ_ON_AGC_CAL) { - if (caldata && !test_bit(TXIQCAL_DONE, &caldata->cal_flags)) - REG_SET_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0, - AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL); - else - REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0, - AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL); - txiqcal_done = run_agc_cal = true; - } else if (caldata && !test_bit(TXIQCAL_DONE, &caldata->cal_flags)) { + txiqcal_done = true; run_agc_cal = true; + } else { sep_iq_cal = true; + run_agc_cal = true; } -skip_tx_iqcal: + /* + * In the SoC family, this will run for AR9300, AR9331 and AR9340. + */ if (sep_iq_cal) { txiqcal_done = ar9003_hw_tx_iq_cal_run(ah); REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); @@ -1278,6 +1275,7 @@ skip_tx_iqcal: REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); } +skip_tx_iqcal: if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) { /* Calibrate the AGC */ REG_WRITE(ah, AR_PHY_AGC_CONTROL, @@ -1299,8 +1297,6 @@ skip_tx_iqcal: if (txiqcal_done) ar9003_hw_tx_iq_cal_post_proc(ah, is_reusable); - else if (caldata && test_bit(TXIQCAL_DONE, &caldata->cal_flags)) - ar9003_hw_tx_iq_cal_reload(ah); /* Revert chainmask to runtime parameters */ ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); -- cgit v1.2.3-70-g09d2 From bf3dac5a6fcf33a80c99e7b7406f8e5af99e2a70 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 11 Nov 2013 22:23:33 +0100 Subject: ath9k: use a timer to put hardware into full sleep When operating in client mode, the short period of time between scanning and associating is often enough to put the hardware through several FULL-SLEEP <-> AWAKE transitions, each wakeup requiring a reset to fully recover the hardware. This is completely unnecessary and can easily be avoided by deferring the switch to full sleep. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 2 ++ drivers/net/wireless/ath/ath9k/init.c | 2 ++ drivers/net/wireless/ath/ath9k/main.c | 27 ++++++++++++++++++++++----- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index e1013425cc7..0783e50f44b 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -459,6 +459,7 @@ void ath_check_ani(struct ath_softc *sc); int ath_update_survey_stats(struct ath_softc *sc); void ath_update_survey_nf(struct ath_softc *sc, int channel); void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type); +void ath_ps_full_sleep(unsigned long data); /**********/ /* BTCOEX */ @@ -789,6 +790,7 @@ struct ath_softc { struct delayed_work tx_complete_work; struct delayed_work hw_pll_work; struct timer_list rx_poll_timer; + struct timer_list sleep_timer; #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT struct ath_btcoex btcoex; diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index fb55302c958..65a2add3b67 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -738,6 +738,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet, (unsigned long)sc); + setup_timer(&sc->sleep_timer, ath_ps_full_sleep, (unsigned long)sc); INIT_WORK(&sc->hw_reset_work, ath_reset_work); INIT_WORK(&sc->hw_check_work, ath_hw_check); INIT_WORK(&sc->paprd_work, ath_paprd_calibrate); @@ -1049,6 +1050,7 @@ static void ath9k_deinit_softc(struct ath_softc *sc) if (ATH_TXQ_SETUP(sc, i)) ath_tx_cleanupq(sc, &sc->tx.txq[i]); + del_timer_sync(&sc->sleep_timer); ath9k_hw_deinit(sc->sc_ah); if (sc->dfs_detector != NULL) sc->dfs_detector->exit(sc->dfs_detector); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index e54ffdd36e2..f86404a70a7 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -82,6 +82,22 @@ static bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode) return ret; } +void ath_ps_full_sleep(unsigned long data) +{ + struct ath_softc *sc = (struct ath_softc *) data; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + bool reset; + + spin_lock(&common->cc_lock); + ath_hw_cycle_counters_update(common); + spin_unlock(&common->cc_lock); + + ath9k_hw_setrxabort(sc->sc_ah, 1); + ath9k_hw_stopdmarecv(sc->sc_ah, &reset); + + ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP); +} + void ath9k_ps_wakeup(struct ath_softc *sc) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); @@ -92,6 +108,7 @@ void ath9k_ps_wakeup(struct ath_softc *sc) if (++sc->ps_usecount != 1) goto unlock; + del_timer_sync(&sc->sleep_timer); power_mode = sc->sc_ah->power_mode; ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); @@ -117,17 +134,17 @@ void ath9k_ps_restore(struct ath_softc *sc) struct ath_common *common = ath9k_hw_common(sc->sc_ah); enum ath9k_power_mode mode; unsigned long flags; - bool reset; spin_lock_irqsave(&sc->sc_pm_lock, flags); if (--sc->ps_usecount != 0) goto unlock; if (sc->ps_idle) { - ath9k_hw_setrxabort(sc->sc_ah, 1); - ath9k_hw_stopdmarecv(sc->sc_ah, &reset); - mode = ATH9K_PM_FULL_SLEEP; - } else if (sc->ps_enabled && + mod_timer(&sc->sleep_timer, jiffies + HZ / 10); + goto unlock; + } + + if (sc->ps_enabled && !(sc->ps_flags & (PS_WAIT_FOR_BEACON | PS_WAIT_FOR_CAB | PS_WAIT_FOR_PSPOLL_DATA | -- cgit v1.2.3-70-g09d2 From 10ffb6a77e617a8f5ded84b504550759ec4a8df0 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 11 Nov 2013 22:23:34 +0100 Subject: ath9k: optimize ath_drain_all_txq If the software has processed all packets, checking the hardware queue is unnecessary. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/xmit.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 95f6c5a8ee1..24846d91554 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1786,6 +1786,9 @@ bool ath_drain_all_txq(struct ath_softc *sc) if (!ATH_TXQ_SETUP(sc, i)) continue; + if (!sc->tx.txq[i].axq_depth) + continue; + if (ath9k_hw_numtxpending(ah, sc->tx.txq[i].axq_qnum)) npend |= BIT(i); } -- cgit v1.2.3-70-g09d2 From 10e2318103f5941aa70c318afe34bc41f1b98529 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 11 Nov 2013 22:23:35 +0100 Subject: ath9k: optimize ath9k_flush Instead of checking the queues in a loop with hardcoded sleep times inbetween, use a wait queue to trigger queue checks after the tx processing tasklet has run. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 + drivers/net/wireless/ath/ath9k/init.c | 1 + drivers/net/wireless/ath/ath9k/main.c | 46 ++++++++++++++++++---------------- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 0783e50f44b..5e5d5cb2458 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -754,6 +754,7 @@ struct ath_softc { struct work_struct hw_check_work; struct work_struct hw_reset_work; struct completion paprd_complete; + wait_queue_head_t tx_wait; unsigned int hw_busy_count; unsigned long sc_flags; diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 65a2add3b67..8f4c1674b76 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -691,6 +691,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, common = ath9k_hw_common(ah); sc->dfs_detector = dfs_pattern_detector_init(common, NL80211_DFS_UNSET); sc->tx99_power = MAX_RATE_POWER + 1; + init_waitqueue_head(&sc->tx_wait); if (!pdata) { ah->ah_flags |= AH_USE_EEPROM; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index f86404a70a7..b1dcf89138d 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -504,6 +504,8 @@ void ath9k_tasklet(unsigned long data) ath_tx_edma_tasklet(sc); else ath_tx_tasklet(sc); + + wake_up(&sc->tx_wait); } ath9k_btcoex_handle_interrupt(sc, status); @@ -1837,13 +1839,31 @@ static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class) mutex_unlock(&sc->mutex); } +static bool ath9k_has_tx_pending(struct ath_softc *sc) +{ + int i, npend; + + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { + if (!ATH_TXQ_SETUP(sc, i)) + continue; + + if (!sc->tx.txq[i].axq_depth) + continue; + + npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i]); + if (npend) + break; + } + + return !!npend; +} + static void ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop) { struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - int timeout = 200; /* ms */ - int i, j; + int timeout = HZ / 5; /* 200 ms */ bool drain_txq; mutex_lock(&sc->mutex); @@ -1861,25 +1881,9 @@ static void ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop) return; } - for (j = 0; j < timeout; j++) { - bool npend = false; - - if (j) - usleep_range(1000, 2000); - - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { - if (!ATH_TXQ_SETUP(sc, i)) - continue; - - npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i]); - - if (npend) - break; - } - - if (!npend) - break; - } + if (wait_event_timeout(sc->tx_wait, !ath9k_has_tx_pending(sc), + timeout) > 0) + drop = false; if (drop) { ath9k_ps_wakeup(sc); -- cgit v1.2.3-70-g09d2 From 09d8e315d90a70eb1096d68f27be04d6c43724f3 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 18 Nov 2013 20:14:43 +0100 Subject: ath9k_hw: fix TSF save/restore around chip reset A cold reset can be triggered because of DMA stop issues, and this leads to TSF being cleared on all chipsets. To properly deal with this, always save the TSF. Additionally, account for the time it takes to do the actual chip reset, which can be quite significant. On AR9344 it takes around 4.5 ms. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 381fbe1d489..02eff2a8a28 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include "hw.h" @@ -1855,10 +1856,12 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, struct ath9k_hw_cal_data *caldata, bool fastcc) { struct ath_common *common = ath9k_hw_common(ah); + struct timespec ts; u32 saveLedState; u32 saveDefAntenna; u32 macStaId1; u64 tsf = 0; + s64 usec = 0; int r; bool start_mci_reset = false; bool save_fullsleep = ah->chip_fullsleep; @@ -1901,10 +1904,10 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, macStaId1 = REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B; - /* For chips on which RTC reset is done, save TSF before it gets cleared */ - if (AR_SREV_9100(ah) || - (AR_SREV_9280(ah) && ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL))) - tsf = ath9k_hw_gettsf64(ah); + /* Save TSF before chip reset, a cold reset clears it */ + tsf = ath9k_hw_gettsf64(ah); + getrawmonotonic(&ts); + usec = ts.tv_sec * 1000 + ts.tv_nsec / 1000; saveLedState = REG_READ(ah, AR_CFG_LED) & (AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL | @@ -1937,8 +1940,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, } /* Restore TSF */ - if (tsf) - ath9k_hw_settsf64(ah, tsf); + getrawmonotonic(&ts); + usec = ts.tv_sec * 1000 + ts.tv_nsec / 1000 - usec; + ath9k_hw_settsf64(ah, tsf + usec); if (AR_SREV_9280_20_OR_LATER(ah)) REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE); -- cgit v1.2.3-70-g09d2 From af02efb32e34938aecce5362b0cdb70e4d18e846 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 18 Nov 2013 20:14:44 +0100 Subject: ath9k_hw: allow fast channel change when only CHANNEL_HT changes The CHANNEL_HT flag is insignificant for fast channel change conditions, since it does not affect any important part of the hardware reset / channel setup. Scanning usually runs with HT disabled, so this change will slightly improve scan time on many chipsets. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 02eff2a8a28..fe3537f6ec5 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1502,8 +1502,9 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, int r; if (pCap->hw_caps & ATH9K_HW_CAP_FCC_BAND_SWITCH) { - band_switch = IS_CHAN_5GHZ(ah->curchan) != IS_CHAN_5GHZ(chan); - mode_diff = (chan->channelFlags != ah->curchan->channelFlags); + u32 flags_diff = chan->channelFlags ^ ah->curchan->channelFlags; + band_switch = !!(flags_diff & CHANNEL_5GHZ); + mode_diff = !!(flags_diff & ~CHANNEL_HT); } for (qnum = 0; qnum < AR_NUM_QCU; qnum++) { @@ -1815,7 +1816,7 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan) * If cross-band fcc is not supoprted, bail out if channelFlags differ. */ if (!(pCap->hw_caps & ATH9K_HW_CAP_FCC_BAND_SWITCH) && - chan->channelFlags != ah->curchan->channelFlags) + ((chan->channelFlags ^ ah->curchan->channelFlags) & ~CHANNEL_HT)) goto fail; if (!ath9k_hw_check_alive(ah)) -- cgit v1.2.3-70-g09d2 From ffaa02fc1e5cec06e32a63e2dfdc7ce3555102ca Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Tue, 19 Nov 2013 09:15:01 +0530 Subject: ath9k: Cleanup IQ calibration for PCOEM chips Since IQ calibration is done as part of AGC calibration for AR9485 and above, remove the seperate IQ calibration code. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_calib.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index a18c3dd01a1..aa012726574 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -1047,7 +1047,7 @@ static bool ar9003_hw_init_cal_pcoem(struct ath_hw *ah, struct ath9k_hw_cal_data *caldata = ah->caldata; bool txiqcal_done = false; bool is_reusable = true, status = true; - bool run_rtt_cal = false, run_agc_cal, sep_iq_cal = false; + bool run_rtt_cal = false, run_agc_cal; bool rtt = !!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT); u32 rx_delay = 0; u32 agc_ctrl = 0, agc_supp_cals = AR_PHY_AGC_CONTROL_OFFSET_CAL | @@ -1119,22 +1119,12 @@ static bool ar9003_hw_init_cal_pcoem(struct ath_hw *ah, REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0, AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL); txiqcal_done = run_agc_cal = true; - } else if (caldata && !test_bit(TXIQCAL_DONE, &caldata->cal_flags)) { - run_agc_cal = true; - sep_iq_cal = true; } skip_tx_iqcal: if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal) ar9003_mci_init_cal_req(ah, &is_reusable); - if (sep_iq_cal) { - txiqcal_done = ar9003_hw_tx_iq_cal_run(ah); - REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); - udelay(5); - REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); - } - if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE) { rx_delay = REG_READ(ah, AR_PHY_RX_DELAY); /* Disable BB_active */ -- cgit v1.2.3-70-g09d2 From ae4a9a1062d5d9d9a8121590544c01eb65ea760a Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Tue, 19 Nov 2013 12:01:09 +0530 Subject: ath9k: Add initvals for AR9565 1.1 The initialization arrays for v1.1 AR9565 are mostly the same as v1.0/v1.0.1 except for radio_postamble. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- .../net/wireless/ath/ath9k/ar9565_1p1_initvals.h | 64 ++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 drivers/net/wireless/ath/ath9k/ar9565_1p1_initvals.h diff --git a/drivers/net/wireless/ath/ath9k/ar9565_1p1_initvals.h b/drivers/net/wireless/ath/ath9k/ar9565_1p1_initvals.h new file mode 100644 index 00000000000..56810539971 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9565_1p1_initvals.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2010-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros Inc. + * + * 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. + */ + +#ifndef INITVALS_9565_1P1_H +#define INITVALS_9565_1P1_H + +/* AR9565 1.1 */ + +#define ar9565_1p1_mac_core ar9565_1p0_mac_core + +#define ar9565_1p1_mac_postamble ar9565_1p0_mac_postamble + +#define ar9565_1p1_baseband_core ar9565_1p0_baseband_core + +#define ar9565_1p1_baseband_postamble ar9565_1p0_baseband_postamble + +#define ar9565_1p1_radio_core ar9565_1p0_radio_core + +#define ar9565_1p1_soc_preamble ar9565_1p0_soc_preamble + +#define ar9565_1p1_soc_postamble ar9565_1p0_soc_postamble + +#define ar9565_1p1_Common_rx_gain_table ar9565_1p0_Common_rx_gain_table + +#define ar9565_1p1_Modes_lowest_ob_db_tx_gain_table ar9565_1p0_Modes_lowest_ob_db_tx_gain_table + +#define ar9565_1p1_pciephy_clkreq_disable_L1 ar9565_1p0_pciephy_clkreq_disable_L1 + +#define ar9565_1p1_modes_fast_clock ar9565_1p0_modes_fast_clock + +#define ar9565_1p1_common_wo_xlna_rx_gain_table ar9565_1p0_common_wo_xlna_rx_gain_table + +#define ar9565_1p1_modes_low_ob_db_tx_gain_table ar9565_1p0_modes_low_ob_db_tx_gain_table + +#define ar9565_1p1_modes_high_ob_db_tx_gain_table ar9565_1p0_modes_high_ob_db_tx_gain_table + +#define ar9565_1p1_modes_high_power_tx_gain_table ar9565_1p0_modes_high_power_tx_gain_table + +#define ar9565_1p1_baseband_core_txfir_coeff_japan_2484 ar9565_1p0_baseband_core_txfir_coeff_japan_2484 + +static const u32 ar9565_1p1_radio_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0001609c, 0x0b8ee524, 0x0b8ee524, 0x0b8ee524, 0x0b8ee524}, + {0x000160ac, 0xa4646c08, 0xa4646c08, 0x24645808, 0x24645808}, + {0x000160b0, 0x01d67f70, 0x01d67f70, 0x01d67f70, 0x01d67f70}, + {0x0001610c, 0x40000000, 0x40000000, 0x40000000, 0x40000000}, + {0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, +}; + +#endif /* INITVALS_9565_1P1_H */ -- cgit v1.2.3-70-g09d2 From 8af45965932781c1e9736a0609c8ed229b534a64 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Tue, 19 Nov 2013 12:06:08 +0530 Subject: ath9k: Add version macros for AR9565 1.1 Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/reg.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index a13b2d143d9..259a4b30770 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -809,6 +809,8 @@ #define AR_SREV_REVISION_9462_21 3 #define AR_SREV_VERSION_9565 0x2C0 #define AR_SREV_REVISION_9565_10 0 +#define AR_SREV_REVISION_9565_101 1 +#define AR_SREV_REVISION_9565_11 2 #define AR_SREV_VERSION_9550 0x400 #define AR_SREV_5416(_ah) \ @@ -927,10 +929,18 @@ #define AR_SREV_9565(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565)) - #define AR_SREV_9565_10(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565) && \ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9565_10)) +#define AR_SREV_9565_101(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565) && \ + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9565_101)) +#define AR_SREV_9565_11(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565) && \ + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9565_11)) +#define AR_SREV_9565_11_OR_LATER(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565) && \ + ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9565_11)) #define AR_SREV_9550(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9550)) -- cgit v1.2.3-70-g09d2 From 3777f7d121ffb8f75d7e98862f73ae8c2f2fa09a Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Tue, 19 Nov 2013 12:11:13 +0530 Subject: ath9k: Attach INI arrays for AR9565 v1.1 Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_hw.c | 54 ++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 33f63dc672e..568f3138188 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -26,6 +26,7 @@ #include "ar9462_2p0_initvals.h" #include "ar9462_2p1_initvals.h" #include "ar9565_1p0_initvals.h" +#include "ar9565_1p1_initvals.h" /* General hardware code for the AR9003 hadware family */ @@ -335,6 +336,41 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) INIT_INI_ARRAY(&ah->iniModesFastClock, ar9580_1p0_modes_fast_clock); + } else if (AR_SREV_9565_11_OR_LATER(ah)) { + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], + ar9565_1p1_mac_core); + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], + ar9565_1p1_mac_postamble); + + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], + ar9565_1p1_baseband_core); + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], + ar9565_1p1_baseband_postamble); + + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], + ar9565_1p1_radio_core); + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], + ar9565_1p1_radio_postamble); + + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], + ar9565_1p1_soc_preamble); + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], + ar9565_1p1_soc_postamble); + + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9565_1p1_Common_rx_gain_table); + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9565_1p1_Modes_lowest_ob_db_tx_gain_table); + + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9565_1p1_pciephy_clkreq_disable_L1); + INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, + ar9565_1p1_pciephy_clkreq_disable_L1); + + INIT_INI_ARRAY(&ah->iniModesFastClock, + ar9565_1p1_modes_fast_clock); + INIT_INI_ARRAY(&ah->iniCckfirJapan2484, + ar9565_1p1_baseband_core_txfir_coeff_japan_2484); } else if (AR_SREV_9565(ah)) { INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], ar9565_1p0_mac_core); @@ -445,6 +481,9 @@ static void ar9003_tx_gain_table_mode0(struct ath_hw *ah) else if (AR_SREV_9462_20(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9462_modes_low_ob_db_tx_gain_table_2p0); + else if (AR_SREV_9565_11(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9565_1p1_modes_low_ob_db_tx_gain_table); else if (AR_SREV_9565(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9565_1p0_modes_low_ob_db_tx_gain_table); @@ -479,6 +518,9 @@ static void ar9003_tx_gain_table_mode1(struct ath_hw *ah) else if (AR_SREV_9462_20(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9462_modes_high_ob_db_tx_gain_table_2p0); + else if (AR_SREV_9565_11(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9565_1p1_modes_high_ob_db_tx_gain_table); else if (AR_SREV_9565(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9565_1p0_modes_high_ob_db_tx_gain_table); @@ -504,6 +546,9 @@ static void ar9003_tx_gain_table_mode2(struct ath_hw *ah) else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9580_1p0_low_ob_db_tx_gain_table); + else if (AR_SREV_9565_11(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9565_1p1_modes_low_ob_db_tx_gain_table); else if (AR_SREV_9565(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9565_1p0_modes_low_ob_db_tx_gain_table); @@ -529,6 +574,9 @@ static void ar9003_tx_gain_table_mode3(struct ath_hw *ah) else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9580_1p0_high_power_tx_gain_table); + else if (AR_SREV_9565_11(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9565_1p1_modes_high_power_tx_gain_table); else if (AR_SREV_9565(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9565_1p0_modes_high_power_tx_gain_table); @@ -642,6 +690,9 @@ static void ar9003_rx_gain_table_mode0(struct ath_hw *ah) else if (AR_SREV_9462_20(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9462_common_rx_gain_table_2p0); + else if (AR_SREV_9565_11(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9565_1p1_Common_rx_gain_table); else if (AR_SREV_9565(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9565_1p0_Common_rx_gain_table); @@ -678,6 +729,9 @@ static void ar9003_rx_gain_table_mode1(struct ath_hw *ah) } else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9580_1p0_wo_xlna_rx_gain_table); + else if (AR_SREV_9565_11(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9565_1p1_common_wo_xlna_rx_gain_table); else if (AR_SREV_9565(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9565_1p0_common_wo_xlna_rx_gain_table); -- cgit v1.2.3-70-g09d2 From dbb3e2fb4ab59e1b2c1d4d3a9b0ed4034ee349b9 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Tue, 26 Nov 2013 15:04:55 +0530 Subject: ath9k: Remove duplicate initvals for AR9462 v2.1 The initvals for AR9462 v2.1 are very similar to v2.0. Identify duplicate arrays and reuse the values from v2.0 to reduce module size. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_hw.c | 24 +- .../net/wireless/ath/ath9k/ar9462_2p0_initvals.h | 18 +- .../net/wireless/ath/ath9k/ar9462_2p1_initvals.h | 1566 +------------------- .../net/wireless/ath/ath9k/ar9580_1p0_initvals.h | 2 +- 4 files changed, 60 insertions(+), 1550 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 568f3138188..d3eca0cec9c 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -252,18 +252,18 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ar9462_2p0_soc_postamble); INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9462_common_rx_gain_table_2p0); + ar9462_2p0_common_rx_gain); /* Awake -> Sleep Setting */ INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9462_pciephy_clkreq_disable_L1_2p0); + ar9462_2p0_pciephy_clkreq_disable_L1); /* Sleep -> Awake Setting */ INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, - ar9462_pciephy_clkreq_disable_L1_2p0); + ar9462_2p0_pciephy_clkreq_disable_L1); /* Fast clock modal settings */ INIT_INI_ARRAY(&ah->iniModesFastClock, - ar9462_modes_fast_clock_2p0); + ar9462_2p0_modes_fast_clock); INIT_INI_ARRAY(&ah->iniCckfirJapan2484, ar9462_2p0_baseband_core_txfir_coeff_japan_2484); @@ -480,7 +480,7 @@ static void ar9003_tx_gain_table_mode0(struct ath_hw *ah) ar9462_2p1_modes_low_ob_db_tx_gain); else if (AR_SREV_9462_20(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9462_modes_low_ob_db_tx_gain_table_2p0); + ar9462_2p0_modes_low_ob_db_tx_gain); else if (AR_SREV_9565_11(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9565_1p1_modes_low_ob_db_tx_gain_table); @@ -517,7 +517,7 @@ static void ar9003_tx_gain_table_mode1(struct ath_hw *ah) ar9462_2p1_modes_high_ob_db_tx_gain); else if (AR_SREV_9462_20(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9462_modes_high_ob_db_tx_gain_table_2p0); + ar9462_2p0_modes_high_ob_db_tx_gain); else if (AR_SREV_9565_11(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9565_1p1_modes_high_ob_db_tx_gain_table); @@ -598,7 +598,7 @@ static void ar9003_tx_gain_table_mode4(struct ath_hw *ah) ar9462_2p1_modes_mix_ob_db_tx_gain); else if (AR_SREV_9462_20(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9462_modes_mix_ob_db_tx_gain_table_2p0); + ar9462_2p0_modes_mix_ob_db_tx_gain); else INIT_INI_ARRAY(&ah->iniModesTxGain, ar9300Modes_mixed_ob_db_tx_gain_table_2p2); @@ -689,7 +689,7 @@ static void ar9003_rx_gain_table_mode0(struct ath_hw *ah) ar9462_2p1_common_rx_gain); else if (AR_SREV_9462_20(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9462_common_rx_gain_table_2p0); + ar9462_2p0_common_rx_gain); else if (AR_SREV_9565_11(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9565_1p1_Common_rx_gain_table); @@ -720,7 +720,7 @@ static void ar9003_rx_gain_table_mode1(struct ath_hw *ah) ar9462_2p1_common_wo_xlna_rx_gain); else if (AR_SREV_9462_20(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9462_common_wo_xlna_rx_gain_table_2p0); + ar9462_2p0_common_wo_xlna_rx_gain); else if (AR_SREV_9550(ah)) { INIT_INI_ARRAY(&ah->iniModesRxGain, ar955x_1p0_common_wo_xlna_rx_gain_table); @@ -753,7 +753,7 @@ static void ar9003_rx_gain_table_mode2(struct ath_hw *ah) ar9462_2p1_baseband_postamble_5g_xlna); } else if (AR_SREV_9462_20(ah)) { INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9462_common_mixed_rx_gain_table_2p0); + ar9462_2p0_common_mixed_rx_gain); INIT_INI_ARRAY(&ah->ini_modes_rxgain_bb_core, ar9462_2p0_baseband_core_mix_rxgain); INIT_INI_ARRAY(&ah->ini_modes_rxgain_bb_postamble, @@ -767,12 +767,12 @@ static void ar9003_rx_gain_table_mode3(struct ath_hw *ah) { if (AR_SREV_9462_21(ah)) { INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9462_2p1_common_5g_xlna_only_rx_gain); + ar9462_2p1_common_5g_xlna_only_rxgain); INIT_INI_ARRAY(&ah->ini_modes_rxgain_5g_xlna, ar9462_2p1_baseband_postamble_5g_xlna); } else if (AR_SREV_9462_20(ah)) { INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9462_2p0_5g_xlna_only_rxgain); + ar9462_2p0_common_5g_xlna_only_rxgain); INIT_INI_ARRAY(&ah->ini_modes_rxgain_5g_xlna, ar9462_2p0_baseband_postamble_5g_xlna); } diff --git a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h index 5a10dcf2adf..73909438436 100644 --- a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h @@ -20,7 +20,7 @@ /* AR9462 2.0 */ -static const u32 ar9462_modes_fast_clock_2p0[][3] = { +static const u32 ar9462_2p0_modes_fast_clock[][3] = { /* Addr 5G_HT20 5G_HT40 */ {0x00001030, 0x00000268, 0x000004d0}, {0x00001070, 0x0000018c, 0x00000318}, @@ -92,7 +92,7 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = { {0x0000b284, 0x00000000, 0x00000000, 0x00000550, 0x00000550}, }; -static const u32 ar9462_common_rx_gain_table_2p0[][2] = { +static const u32 ar9462_2p0_common_rx_gain[][2] = { /* Addr allmodes */ {0x0000a000, 0x00010000}, {0x0000a004, 0x00030002}, @@ -352,7 +352,7 @@ static const u32 ar9462_common_rx_gain_table_2p0[][2] = { {0x0000b1fc, 0x00000196}, }; -static const u32 ar9462_pciephy_clkreq_disable_L1_2p0[][2] = { +static const u32 ar9462_2p0_pciephy_clkreq_disable_L1[][2] = { /* Addr allmodes */ {0x00018c00, 0x18213ede}, {0x00018c04, 0x000801d8}, @@ -366,7 +366,7 @@ static const u32 ar9462_2p0_radio_postamble_sys2ant[][5] = { {0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, }; -static const u32 ar9462_common_wo_xlna_rx_gain_table_2p0[][2] = { +static const u32 ar9462_2p0_common_wo_xlna_rx_gain[][2] = { /* Addr allmodes */ {0x0000a000, 0x00010000}, {0x0000a004, 0x00030002}, @@ -633,7 +633,7 @@ static const u32 ar9462_2p0_baseband_core_txfir_coeff_japan_2484[][2] = { {0x0000a3a0, 0xca9228ee}, }; -static const u32 ar9462_modes_low_ob_db_tx_gain_table_2p0[][5] = { +static const u32 ar9462_2p0_modes_low_ob_db_tx_gain[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002}, {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, @@ -865,7 +865,7 @@ static const u32 ar9462_2p0_radio_postamble[][5] = { {0x0001650c, 0x48000000, 0x40000000, 0x40000000, 0x40000000}, }; -static const u32 ar9462_modes_mix_ob_db_tx_gain_table_2p0[][5] = { +static const u32 ar9462_2p0_modes_mix_ob_db_tx_gain[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002}, {0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, @@ -928,7 +928,7 @@ static const u32 ar9462_modes_mix_ob_db_tx_gain_table_2p0[][5] = { {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, }; -static const u32 ar9462_modes_high_ob_db_tx_gain_table_2p0[][5] = { +static const u32 ar9462_2p0_modes_high_ob_db_tx_gain[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002}, {0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, @@ -1238,7 +1238,7 @@ static const u32 ar9462_2p0_mac_postamble[][5] = { {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, }; -static const u32 ar9462_common_mixed_rx_gain_table_2p0[][2] = { +static const u32 ar9462_2p0_common_mixed_rx_gain[][2] = { /* Addr allmodes */ {0x0000a000, 0x00010000}, {0x0000a004, 0x00030002}, @@ -1503,7 +1503,7 @@ static const u32 ar9462_2p0_baseband_postamble_5g_xlna[][5] = { {0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c282}, }; -static const u32 ar9462_2p0_5g_xlna_only_rxgain[][2] = { +static const u32 ar9462_2p0_common_5g_xlna_only_rxgain[][2] = { /* Addr allmodes */ {0x0000a000, 0x00010000}, {0x0000a004, 0x00030002}, diff --git a/drivers/net/wireless/ath/ath9k/ar9462_2p1_initvals.h b/drivers/net/wireless/ath/ath9k/ar9462_2p1_initvals.h index 0fcce0739a4..dc3adda46e8 100644 --- a/drivers/net/wireless/ath/ath9k/ar9462_2p1_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9462_2p1_initvals.h @@ -20,6 +20,44 @@ /* AR9462 2.1 */ +#define ar9462_2p1_mac_postamble ar9462_2p0_mac_postamble + +#define ar9462_2p1_baseband_core ar9462_2p0_baseband_core + +#define ar9462_2p1_radio_core ar9462_2p0_radio_core + +#define ar9462_2p1_radio_postamble ar9462_2p0_radio_postamble + +#define ar9462_2p1_soc_postamble ar9462_2p0_soc_postamble + +#define ar9462_2p1_radio_postamble_sys2ant ar9462_2p0_radio_postamble_sys2ant + +#define ar9462_2p1_common_rx_gain ar9462_2p0_common_rx_gain + +#define ar9462_2p1_common_mixed_rx_gain ar9462_2p0_common_mixed_rx_gain + +#define ar9462_2p1_common_5g_xlna_only_rxgain ar9462_2p0_common_5g_xlna_only_rxgain + +#define ar9462_2p1_baseband_core_mix_rxgain ar9462_2p0_baseband_core_mix_rxgain + +#define ar9462_2p1_baseband_postamble_mix_rxgain ar9462_2p0_baseband_postamble_mix_rxgain + +#define ar9462_2p1_baseband_postamble_5g_xlna ar9462_2p0_baseband_postamble_5g_xlna + +#define ar9462_2p1_common_wo_xlna_rx_gain ar9462_2p0_common_wo_xlna_rx_gain + +#define ar9462_2p1_modes_low_ob_db_tx_gain ar9462_2p0_modes_low_ob_db_tx_gain + +#define ar9462_2p1_modes_high_ob_db_tx_gain ar9462_2p0_modes_high_ob_db_tx_gain + +#define ar9462_2p1_modes_mix_ob_db_tx_gain ar9462_2p0_modes_mix_ob_db_tx_gain + +#define ar9462_2p1_modes_fast_clock ar9462_2p0_modes_fast_clock + +#define ar9462_2p1_baseband_core_txfir_coeff_japan_2484 ar9462_2p0_baseband_core_txfir_coeff_japan_2484 + +#define ar9462_2p1_pciephy_clkreq_disable_L1 ar9462_2p0_pciephy_clkreq_disable_L1 + static const u32 ar9462_2p1_mac_core[][2] = { /* Addr allmodes */ {0x00000008, 0x00000000}, @@ -183,168 +221,6 @@ static const u32 ar9462_2p1_mac_core[][2] = { {0x000083d0, 0x000301ff}, }; -static const u32 ar9462_2p1_mac_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, - {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c}, - {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, - {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, - {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, - {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, - {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, - {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, -}; - -static const u32 ar9462_2p1_baseband_core[][2] = { - /* Addr allmodes */ - {0x00009800, 0xafe68e30}, - {0x00009804, 0xfd14e000}, - {0x00009808, 0x9c0a9f6b}, - {0x0000980c, 0x04900000}, - {0x00009814, 0x9280c00a}, - {0x00009818, 0x00000000}, - {0x0000981c, 0x00020028}, - {0x00009834, 0x6400a290}, - {0x00009838, 0x0108ecff}, - {0x0000983c, 0x0d000600}, - {0x00009880, 0x201fff00}, - {0x00009884, 0x00001042}, - {0x000098a4, 0x00200400}, - {0x000098b0, 0x32440bbe}, - {0x000098d0, 0x004b6a8e}, - {0x000098d4, 0x00000820}, - {0x000098dc, 0x00000000}, - {0x000098e4, 0x01ffffff}, - {0x000098e8, 0x01ffffff}, - {0x000098ec, 0x01ffffff}, - {0x000098f0, 0x00000000}, - {0x000098f4, 0x00000000}, - {0x00009bf0, 0x80000000}, - {0x00009c04, 0xff55ff55}, - {0x00009c08, 0x0320ff55}, - {0x00009c0c, 0x00000000}, - {0x00009c10, 0x00000000}, - {0x00009c14, 0x00046384}, - {0x00009c18, 0x05b6b440}, - {0x00009c1c, 0x00b6b440}, - {0x00009d00, 0xc080a333}, - {0x00009d04, 0x40206c10}, - {0x00009d08, 0x009c4060}, - {0x00009d0c, 0x9883800a}, - {0x00009d10, 0x01834061}, - {0x00009d14, 0x00c0040b}, - {0x00009d18, 0x00000000}, - {0x00009e08, 0x0038230c}, - {0x00009e24, 0x990bb515}, - {0x00009e28, 0x0c6f0000}, - {0x00009e30, 0x06336f77}, - {0x00009e34, 0x6af6532f}, - {0x00009e38, 0x0cc80c00}, - {0x00009e40, 0x15262820}, - {0x00009e4c, 0x00001004}, - {0x00009e50, 0x00ff03f1}, - {0x00009e54, 0xe4c555c2}, - {0x00009e58, 0xfd857722}, - {0x00009e5c, 0xe9198724}, - {0x00009fc0, 0x803e4788}, - {0x00009fc4, 0x0001efb5}, - {0x00009fcc, 0x40000014}, - {0x00009fd0, 0x0a193b93}, - {0x0000a20c, 0x00000000}, - {0x0000a220, 0x00000000}, - {0x0000a224, 0x00000000}, - {0x0000a228, 0x10002310}, - {0x0000a23c, 0x00000000}, - {0x0000a244, 0x0c000000}, - {0x0000a2a0, 0x00000001}, - {0x0000a2c0, 0x00000001}, - {0x0000a2c8, 0x00000000}, - {0x0000a2cc, 0x18c43433}, - {0x0000a2d4, 0x00000000}, - {0x0000a2ec, 0x00000000}, - {0x0000a2f0, 0x00000000}, - {0x0000a2f4, 0x00000000}, - {0x0000a2f8, 0x00000000}, - {0x0000a344, 0x00000000}, - {0x0000a34c, 0x00000000}, - {0x0000a350, 0x0000a000}, - {0x0000a364, 0x00000000}, - {0x0000a370, 0x00000000}, - {0x0000a390, 0x00000001}, - {0x0000a394, 0x00000444}, - {0x0000a398, 0x001f0e0f}, - {0x0000a39c, 0x0075393f}, - {0x0000a3a0, 0xb79f6427}, - {0x0000a3c0, 0x20202020}, - {0x0000a3c4, 0x22222220}, - {0x0000a3c8, 0x20200020}, - {0x0000a3cc, 0x20202020}, - {0x0000a3d0, 0x20202020}, - {0x0000a3d4, 0x20202020}, - {0x0000a3d8, 0x20202020}, - {0x0000a3dc, 0x20202020}, - {0x0000a3e0, 0x20202020}, - {0x0000a3e4, 0x20202020}, - {0x0000a3e8, 0x20202020}, - {0x0000a3ec, 0x20202020}, - {0x0000a3f0, 0x00000000}, - {0x0000a3f4, 0x00000006}, - {0x0000a3f8, 0x0c9bd380}, - {0x0000a3fc, 0x000f0f01}, - {0x0000a400, 0x8fa91f01}, - {0x0000a404, 0x00000000}, - {0x0000a408, 0x0e79e5c6}, - {0x0000a40c, 0x00820820}, - {0x0000a414, 0x1ce739ce}, - {0x0000a418, 0x2d001dce}, - {0x0000a434, 0x00000000}, - {0x0000a438, 0x00001801}, - {0x0000a43c, 0x00100000}, - {0x0000a444, 0x00000000}, - {0x0000a448, 0x05000080}, - {0x0000a44c, 0x00000001}, - {0x0000a450, 0x00010000}, - {0x0000a454, 0x07000000}, - {0x0000a644, 0xbfad9d74}, - {0x0000a648, 0x0048060a}, - {0x0000a64c, 0x00002037}, - {0x0000a670, 0x03020100}, - {0x0000a674, 0x09080504}, - {0x0000a678, 0x0d0c0b0a}, - {0x0000a67c, 0x13121110}, - {0x0000a680, 0x31301514}, - {0x0000a684, 0x35343332}, - {0x0000a688, 0x00000036}, - {0x0000a690, 0x00000838}, - {0x0000a6b0, 0x0000000a}, - {0x0000a6b4, 0x00512c01}, - {0x0000a7c0, 0x00000000}, - {0x0000a7c4, 0xfffffffc}, - {0x0000a7c8, 0x00000000}, - {0x0000a7cc, 0x00000000}, - {0x0000a7d0, 0x00000000}, - {0x0000a7d4, 0x00000004}, - {0x0000a7dc, 0x00000000}, - {0x0000a7f0, 0x80000000}, - {0x0000a8d0, 0x004b6a8e}, - {0x0000a8d4, 0x00000820}, - {0x0000a8dc, 0x00000000}, - {0x0000a8f0, 0x00000000}, - {0x0000a8f4, 0x00000000}, - {0x0000abf0, 0x80000000}, - {0x0000b2d0, 0x00000080}, - {0x0000b2d4, 0x00000000}, - {0x0000b2ec, 0x00000000}, - {0x0000b2f0, 0x00000000}, - {0x0000b2f4, 0x00000000}, - {0x0000b2f8, 0x00000000}, - {0x0000b408, 0x0e79e5c0}, - {0x0000b40c, 0x00820820}, - {0x0000b420, 0x00000000}, - {0x0000b6b0, 0x0000000a}, - {0x0000b6b4, 0x00000001}, -}; - static const u32 ar9462_2p1_baseband_postamble[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a800d}, @@ -404,72 +280,6 @@ static const u32 ar9462_2p1_baseband_postamble[][5] = { {0x0000b284, 0x00000000, 0x00000000, 0x00000550, 0x00000550}, }; -static const u32 ar9462_2p1_radio_core[][2] = { - /* Addr allmodes */ - {0x00016000, 0x36db6db6}, - {0x00016004, 0x6db6db40}, - {0x00016008, 0x73f00000}, - {0x0001600c, 0x00000000}, - {0x00016010, 0x6d820001}, - {0x00016040, 0x7f80fff8}, - {0x0001604c, 0x2699e04f}, - {0x00016050, 0x6db6db6c}, - {0x00016058, 0x6c200000}, - {0x00016080, 0x000c0000}, - {0x00016084, 0x9a68048c}, - {0x00016088, 0x54214514}, - {0x0001608c, 0x1203040b}, - {0x00016090, 0x24926490}, - {0x00016098, 0xd2888888}, - {0x000160a0, 0x0a108ffe}, - {0x000160a4, 0x812fc491}, - {0x000160a8, 0x423c8000}, - {0x000160b4, 0x92000000}, - {0x000160b8, 0x0285dddc}, - {0x000160bc, 0x02908888}, - {0x000160c0, 0x00adb6d0}, - {0x000160c4, 0x6db6db60}, - {0x000160c8, 0x6db6db6c}, - {0x000160cc, 0x0de6c1b0}, - {0x00016100, 0x3fffbe04}, - {0x00016104, 0xfff80000}, - {0x00016108, 0x00200400}, - {0x00016110, 0x00000000}, - {0x00016144, 0x02084080}, - {0x00016148, 0x000080c0}, - {0x00016280, 0x050a0001}, - {0x00016284, 0x3d841418}, - {0x00016288, 0x00000000}, - {0x0001628c, 0xe3000000}, - {0x00016290, 0xa1005080}, - {0x00016294, 0x00000020}, - {0x00016298, 0x54a82900}, - {0x00016340, 0x121e4276}, - {0x00016344, 0x00300000}, - {0x00016400, 0x36db6db6}, - {0x00016404, 0x6db6db40}, - {0x00016408, 0x73f00000}, - {0x0001640c, 0x00000000}, - {0x00016410, 0x6c800001}, - {0x00016440, 0x7f80fff8}, - {0x0001644c, 0x4699e04f}, - {0x00016450, 0x6db6db6c}, - {0x00016500, 0x3fffbe04}, - {0x00016504, 0xfff80000}, - {0x00016508, 0x00200400}, - {0x00016510, 0x00000000}, - {0x00016544, 0x02084080}, - {0x00016548, 0x000080c0}, -}; - -static const u32 ar9462_2p1_radio_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0001609c, 0x0b8ee524, 0x0b8ee524, 0x0b8ee524, 0x0b8ee524}, - {0x000160b0, 0x01d67f70, 0x01d67f70, 0x01d67f70, 0x01d67f70}, - {0x0001610c, 0x48000000, 0x40000000, 0x40000000, 0x40000000}, - {0x0001650c, 0x48000000, 0x40000000, 0x40000000, 0x40000000}, -}; - static const u32 ar9462_2p1_soc_preamble[][2] = { /* Addr allmodes */ {0x000040a4, 0x00a0c9c9}, @@ -478,1304 +288,4 @@ static const u32 ar9462_2p1_soc_preamble[][2] = { {0x00007038, 0x000004c2}, }; -static const u32 ar9462_2p1_soc_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00007010, 0x00000033, 0x00000033, 0x00000033, 0x00000033}, -}; - -static const u32 ar9462_2p1_radio_postamble_sys2ant[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x000160ac, 0xa4646c08, 0xa4646c08, 0x24645808, 0x24645808}, - {0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, - {0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, -}; - -static const u32 ar9462_2p1_common_rx_gain[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x00010000}, - {0x0000a004, 0x00030002}, - {0x0000a008, 0x00050004}, - {0x0000a00c, 0x00810080}, - {0x0000a010, 0x00830082}, - {0x0000a014, 0x01810180}, - {0x0000a018, 0x01830182}, - {0x0000a01c, 0x01850184}, - {0x0000a020, 0x01890188}, - {0x0000a024, 0x018b018a}, - {0x0000a028, 0x018d018c}, - {0x0000a02c, 0x01910190}, - {0x0000a030, 0x01930192}, - {0x0000a034, 0x01950194}, - {0x0000a038, 0x038a0196}, - {0x0000a03c, 0x038c038b}, - {0x0000a040, 0x0390038d}, - {0x0000a044, 0x03920391}, - {0x0000a048, 0x03940393}, - {0x0000a04c, 0x03960395}, - {0x0000a050, 0x00000000}, - {0x0000a054, 0x00000000}, - {0x0000a058, 0x00000000}, - {0x0000a05c, 0x00000000}, - {0x0000a060, 0x00000000}, - {0x0000a064, 0x00000000}, - {0x0000a068, 0x00000000}, - {0x0000a06c, 0x00000000}, - {0x0000a070, 0x00000000}, - {0x0000a074, 0x00000000}, - {0x0000a078, 0x00000000}, - {0x0000a07c, 0x00000000}, - {0x0000a080, 0x22222229}, - {0x0000a084, 0x1d1d1d1d}, - {0x0000a088, 0x1d1d1d1d}, - {0x0000a08c, 0x1d1d1d1d}, - {0x0000a090, 0x171d1d1d}, - {0x0000a094, 0x11111717}, - {0x0000a098, 0x00030311}, - {0x0000a09c, 0x00000000}, - {0x0000a0a0, 0x00000000}, - {0x0000a0a4, 0x00000000}, - {0x0000a0a8, 0x00000000}, - {0x0000a0ac, 0x00000000}, - {0x0000a0b0, 0x00000000}, - {0x0000a0b4, 0x00000000}, - {0x0000a0b8, 0x00000000}, - {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x001f0000}, - {0x0000a0c4, 0x01000101}, - {0x0000a0c8, 0x011e011f}, - {0x0000a0cc, 0x011c011d}, - {0x0000a0d0, 0x02030204}, - {0x0000a0d4, 0x02010202}, - {0x0000a0d8, 0x021f0200}, - {0x0000a0dc, 0x0302021e}, - {0x0000a0e0, 0x03000301}, - {0x0000a0e4, 0x031e031f}, - {0x0000a0e8, 0x0402031d}, - {0x0000a0ec, 0x04000401}, - {0x0000a0f0, 0x041e041f}, - {0x0000a0f4, 0x0502041d}, - {0x0000a0f8, 0x05000501}, - {0x0000a0fc, 0x051e051f}, - {0x0000a100, 0x06010602}, - {0x0000a104, 0x061f0600}, - {0x0000a108, 0x061d061e}, - {0x0000a10c, 0x07020703}, - {0x0000a110, 0x07000701}, - {0x0000a114, 0x00000000}, - {0x0000a118, 0x00000000}, - {0x0000a11c, 0x00000000}, - {0x0000a120, 0x00000000}, - {0x0000a124, 0x00000000}, - {0x0000a128, 0x00000000}, - {0x0000a12c, 0x00000000}, - {0x0000a130, 0x00000000}, - {0x0000a134, 0x00000000}, - {0x0000a138, 0x00000000}, - {0x0000a13c, 0x00000000}, - {0x0000a140, 0x001f0000}, - {0x0000a144, 0x01000101}, - {0x0000a148, 0x011e011f}, - {0x0000a14c, 0x011c011d}, - {0x0000a150, 0x02030204}, - {0x0000a154, 0x02010202}, - {0x0000a158, 0x021f0200}, - {0x0000a15c, 0x0302021e}, - {0x0000a160, 0x03000301}, - {0x0000a164, 0x031e031f}, - {0x0000a168, 0x0402031d}, - {0x0000a16c, 0x04000401}, - {0x0000a170, 0x041e041f}, - {0x0000a174, 0x0502041d}, - {0x0000a178, 0x05000501}, - {0x0000a17c, 0x051e051f}, - {0x0000a180, 0x06010602}, - {0x0000a184, 0x061f0600}, - {0x0000a188, 0x061d061e}, - {0x0000a18c, 0x07020703}, - {0x0000a190, 0x07000701}, - {0x0000a194, 0x00000000}, - {0x0000a198, 0x00000000}, - {0x0000a19c, 0x00000000}, - {0x0000a1a0, 0x00000000}, - {0x0000a1a4, 0x00000000}, - {0x0000a1a8, 0x00000000}, - {0x0000a1ac, 0x00000000}, - {0x0000a1b0, 0x00000000}, - {0x0000a1b4, 0x00000000}, - {0x0000a1b8, 0x00000000}, - {0x0000a1bc, 0x00000000}, - {0x0000a1c0, 0x00000000}, - {0x0000a1c4, 0x00000000}, - {0x0000a1c8, 0x00000000}, - {0x0000a1cc, 0x00000000}, - {0x0000a1d0, 0x00000000}, - {0x0000a1d4, 0x00000000}, - {0x0000a1d8, 0x00000000}, - {0x0000a1dc, 0x00000000}, - {0x0000a1e0, 0x00000000}, - {0x0000a1e4, 0x00000000}, - {0x0000a1e8, 0x00000000}, - {0x0000a1ec, 0x00000000}, - {0x0000a1f0, 0x00000396}, - {0x0000a1f4, 0x00000396}, - {0x0000a1f8, 0x00000396}, - {0x0000a1fc, 0x00000196}, - {0x0000b000, 0x00010000}, - {0x0000b004, 0x00030002}, - {0x0000b008, 0x00050004}, - {0x0000b00c, 0x00810080}, - {0x0000b010, 0x00830082}, - {0x0000b014, 0x01810180}, - {0x0000b018, 0x01830182}, - {0x0000b01c, 0x01850184}, - {0x0000b020, 0x02810280}, - {0x0000b024, 0x02830282}, - {0x0000b028, 0x02850284}, - {0x0000b02c, 0x02890288}, - {0x0000b030, 0x028b028a}, - {0x0000b034, 0x0388028c}, - {0x0000b038, 0x038a0389}, - {0x0000b03c, 0x038c038b}, - {0x0000b040, 0x0390038d}, - {0x0000b044, 0x03920391}, - {0x0000b048, 0x03940393}, - {0x0000b04c, 0x03960395}, - {0x0000b050, 0x00000000}, - {0x0000b054, 0x00000000}, - {0x0000b058, 0x00000000}, - {0x0000b05c, 0x00000000}, - {0x0000b060, 0x00000000}, - {0x0000b064, 0x00000000}, - {0x0000b068, 0x00000000}, - {0x0000b06c, 0x00000000}, - {0x0000b070, 0x00000000}, - {0x0000b074, 0x00000000}, - {0x0000b078, 0x00000000}, - {0x0000b07c, 0x00000000}, - {0x0000b080, 0x2a2d2f32}, - {0x0000b084, 0x21232328}, - {0x0000b088, 0x19191c1e}, - {0x0000b08c, 0x12141417}, - {0x0000b090, 0x07070e0e}, - {0x0000b094, 0x03030305}, - {0x0000b098, 0x00000003}, - {0x0000b09c, 0x00000000}, - {0x0000b0a0, 0x00000000}, - {0x0000b0a4, 0x00000000}, - {0x0000b0a8, 0x00000000}, - {0x0000b0ac, 0x00000000}, - {0x0000b0b0, 0x00000000}, - {0x0000b0b4, 0x00000000}, - {0x0000b0b8, 0x00000000}, - {0x0000b0bc, 0x00000000}, - {0x0000b0c0, 0x003f0020}, - {0x0000b0c4, 0x00400041}, - {0x0000b0c8, 0x0140005f}, - {0x0000b0cc, 0x0160015f}, - {0x0000b0d0, 0x017e017f}, - {0x0000b0d4, 0x02410242}, - {0x0000b0d8, 0x025f0240}, - {0x0000b0dc, 0x027f0260}, - {0x0000b0e0, 0x0341027e}, - {0x0000b0e4, 0x035f0340}, - {0x0000b0e8, 0x037f0360}, - {0x0000b0ec, 0x04400441}, - {0x0000b0f0, 0x0460045f}, - {0x0000b0f4, 0x0541047f}, - {0x0000b0f8, 0x055f0540}, - {0x0000b0fc, 0x057f0560}, - {0x0000b100, 0x06400641}, - {0x0000b104, 0x0660065f}, - {0x0000b108, 0x067e067f}, - {0x0000b10c, 0x07410742}, - {0x0000b110, 0x075f0740}, - {0x0000b114, 0x077f0760}, - {0x0000b118, 0x07800781}, - {0x0000b11c, 0x07a0079f}, - {0x0000b120, 0x07c107bf}, - {0x0000b124, 0x000007c0}, - {0x0000b128, 0x00000000}, - {0x0000b12c, 0x00000000}, - {0x0000b130, 0x00000000}, - {0x0000b134, 0x00000000}, - {0x0000b138, 0x00000000}, - {0x0000b13c, 0x00000000}, - {0x0000b140, 0x003f0020}, - {0x0000b144, 0x00400041}, - {0x0000b148, 0x0140005f}, - {0x0000b14c, 0x0160015f}, - {0x0000b150, 0x017e017f}, - {0x0000b154, 0x02410242}, - {0x0000b158, 0x025f0240}, - {0x0000b15c, 0x027f0260}, - {0x0000b160, 0x0341027e}, - {0x0000b164, 0x035f0340}, - {0x0000b168, 0x037f0360}, - {0x0000b16c, 0x04400441}, - {0x0000b170, 0x0460045f}, - {0x0000b174, 0x0541047f}, - {0x0000b178, 0x055f0540}, - {0x0000b17c, 0x057f0560}, - {0x0000b180, 0x06400641}, - {0x0000b184, 0x0660065f}, - {0x0000b188, 0x067e067f}, - {0x0000b18c, 0x07410742}, - {0x0000b190, 0x075f0740}, - {0x0000b194, 0x077f0760}, - {0x0000b198, 0x07800781}, - {0x0000b19c, 0x07a0079f}, - {0x0000b1a0, 0x07c107bf}, - {0x0000b1a4, 0x000007c0}, - {0x0000b1a8, 0x00000000}, - {0x0000b1ac, 0x00000000}, - {0x0000b1b0, 0x00000000}, - {0x0000b1b4, 0x00000000}, - {0x0000b1b8, 0x00000000}, - {0x0000b1bc, 0x00000000}, - {0x0000b1c0, 0x00000000}, - {0x0000b1c4, 0x00000000}, - {0x0000b1c8, 0x00000000}, - {0x0000b1cc, 0x00000000}, - {0x0000b1d0, 0x00000000}, - {0x0000b1d4, 0x00000000}, - {0x0000b1d8, 0x00000000}, - {0x0000b1dc, 0x00000000}, - {0x0000b1e0, 0x00000000}, - {0x0000b1e4, 0x00000000}, - {0x0000b1e8, 0x00000000}, - {0x0000b1ec, 0x00000000}, - {0x0000b1f0, 0x00000396}, - {0x0000b1f4, 0x00000396}, - {0x0000b1f8, 0x00000396}, - {0x0000b1fc, 0x00000196}, -}; - -static const u32 ar9462_2p1_common_mixed_rx_gain[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x00010000}, - {0x0000a004, 0x00030002}, - {0x0000a008, 0x00050004}, - {0x0000a00c, 0x00810080}, - {0x0000a010, 0x00830082}, - {0x0000a014, 0x01810180}, - {0x0000a018, 0x01830182}, - {0x0000a01c, 0x01850184}, - {0x0000a020, 0x01890188}, - {0x0000a024, 0x018b018a}, - {0x0000a028, 0x018d018c}, - {0x0000a02c, 0x03820190}, - {0x0000a030, 0x03840383}, - {0x0000a034, 0x03880385}, - {0x0000a038, 0x038a0389}, - {0x0000a03c, 0x038c038b}, - {0x0000a040, 0x0390038d}, - {0x0000a044, 0x03920391}, - {0x0000a048, 0x03940393}, - {0x0000a04c, 0x03960395}, - {0x0000a050, 0x00000000}, - {0x0000a054, 0x00000000}, - {0x0000a058, 0x00000000}, - {0x0000a05c, 0x00000000}, - {0x0000a060, 0x00000000}, - {0x0000a064, 0x00000000}, - {0x0000a068, 0x00000000}, - {0x0000a06c, 0x00000000}, - {0x0000a070, 0x00000000}, - {0x0000a074, 0x00000000}, - {0x0000a078, 0x00000000}, - {0x0000a07c, 0x00000000}, - {0x0000a080, 0x29292929}, - {0x0000a084, 0x29292929}, - {0x0000a088, 0x29292929}, - {0x0000a08c, 0x29292929}, - {0x0000a090, 0x22292929}, - {0x0000a094, 0x1d1d2222}, - {0x0000a098, 0x0c111117}, - {0x0000a09c, 0x00030303}, - {0x0000a0a0, 0x00000000}, - {0x0000a0a4, 0x00000000}, - {0x0000a0a8, 0x00000000}, - {0x0000a0ac, 0x00000000}, - {0x0000a0b0, 0x00000000}, - {0x0000a0b4, 0x00000000}, - {0x0000a0b8, 0x00000000}, - {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x001f0000}, - {0x0000a0c4, 0x01000101}, - {0x0000a0c8, 0x011e011f}, - {0x0000a0cc, 0x011c011d}, - {0x0000a0d0, 0x02030204}, - {0x0000a0d4, 0x02010202}, - {0x0000a0d8, 0x021f0200}, - {0x0000a0dc, 0x0302021e}, - {0x0000a0e0, 0x03000301}, - {0x0000a0e4, 0x031e031f}, - {0x0000a0e8, 0x0402031d}, - {0x0000a0ec, 0x04000401}, - {0x0000a0f0, 0x041e041f}, - {0x0000a0f4, 0x0502041d}, - {0x0000a0f8, 0x05000501}, - {0x0000a0fc, 0x051e051f}, - {0x0000a100, 0x06010602}, - {0x0000a104, 0x061f0600}, - {0x0000a108, 0x061d061e}, - {0x0000a10c, 0x07020703}, - {0x0000a110, 0x07000701}, - {0x0000a114, 0x00000000}, - {0x0000a118, 0x00000000}, - {0x0000a11c, 0x00000000}, - {0x0000a120, 0x00000000}, - {0x0000a124, 0x00000000}, - {0x0000a128, 0x00000000}, - {0x0000a12c, 0x00000000}, - {0x0000a130, 0x00000000}, - {0x0000a134, 0x00000000}, - {0x0000a138, 0x00000000}, - {0x0000a13c, 0x00000000}, - {0x0000a140, 0x001f0000}, - {0x0000a144, 0x01000101}, - {0x0000a148, 0x011e011f}, - {0x0000a14c, 0x011c011d}, - {0x0000a150, 0x02030204}, - {0x0000a154, 0x02010202}, - {0x0000a158, 0x021f0200}, - {0x0000a15c, 0x0302021e}, - {0x0000a160, 0x03000301}, - {0x0000a164, 0x031e031f}, - {0x0000a168, 0x0402031d}, - {0x0000a16c, 0x04000401}, - {0x0000a170, 0x041e041f}, - {0x0000a174, 0x0502041d}, - {0x0000a178, 0x05000501}, - {0x0000a17c, 0x051e051f}, - {0x0000a180, 0x06010602}, - {0x0000a184, 0x061f0600}, - {0x0000a188, 0x061d061e}, - {0x0000a18c, 0x07020703}, - {0x0000a190, 0x07000701}, - {0x0000a194, 0x00000000}, - {0x0000a198, 0x00000000}, - {0x0000a19c, 0x00000000}, - {0x0000a1a0, 0x00000000}, - {0x0000a1a4, 0x00000000}, - {0x0000a1a8, 0x00000000}, - {0x0000a1ac, 0x00000000}, - {0x0000a1b0, 0x00000000}, - {0x0000a1b4, 0x00000000}, - {0x0000a1b8, 0x00000000}, - {0x0000a1bc, 0x00000000}, - {0x0000a1c0, 0x00000000}, - {0x0000a1c4, 0x00000000}, - {0x0000a1c8, 0x00000000}, - {0x0000a1cc, 0x00000000}, - {0x0000a1d0, 0x00000000}, - {0x0000a1d4, 0x00000000}, - {0x0000a1d8, 0x00000000}, - {0x0000a1dc, 0x00000000}, - {0x0000a1e0, 0x00000000}, - {0x0000a1e4, 0x00000000}, - {0x0000a1e8, 0x00000000}, - {0x0000a1ec, 0x00000000}, - {0x0000a1f0, 0x00000396}, - {0x0000a1f4, 0x00000396}, - {0x0000a1f8, 0x00000396}, - {0x0000a1fc, 0x00000196}, - {0x0000b000, 0x00010000}, - {0x0000b004, 0x00030002}, - {0x0000b008, 0x00050004}, - {0x0000b00c, 0x00810080}, - {0x0000b010, 0x00830082}, - {0x0000b014, 0x01810180}, - {0x0000b018, 0x01830182}, - {0x0000b01c, 0x01850184}, - {0x0000b020, 0x02810280}, - {0x0000b024, 0x02830282}, - {0x0000b028, 0x02850284}, - {0x0000b02c, 0x02890288}, - {0x0000b030, 0x028b028a}, - {0x0000b034, 0x0388028c}, - {0x0000b038, 0x038a0389}, - {0x0000b03c, 0x038c038b}, - {0x0000b040, 0x0390038d}, - {0x0000b044, 0x03920391}, - {0x0000b048, 0x03940393}, - {0x0000b04c, 0x03960395}, - {0x0000b050, 0x00000000}, - {0x0000b054, 0x00000000}, - {0x0000b058, 0x00000000}, - {0x0000b05c, 0x00000000}, - {0x0000b060, 0x00000000}, - {0x0000b064, 0x00000000}, - {0x0000b068, 0x00000000}, - {0x0000b06c, 0x00000000}, - {0x0000b070, 0x00000000}, - {0x0000b074, 0x00000000}, - {0x0000b078, 0x00000000}, - {0x0000b07c, 0x00000000}, - {0x0000b080, 0x2a2d2f32}, - {0x0000b084, 0x21232328}, - {0x0000b088, 0x19191c1e}, - {0x0000b08c, 0x12141417}, - {0x0000b090, 0x07070e0e}, - {0x0000b094, 0x03030305}, - {0x0000b098, 0x00000003}, - {0x0000b09c, 0x00000000}, - {0x0000b0a0, 0x00000000}, - {0x0000b0a4, 0x00000000}, - {0x0000b0a8, 0x00000000}, - {0x0000b0ac, 0x00000000}, - {0x0000b0b0, 0x00000000}, - {0x0000b0b4, 0x00000000}, - {0x0000b0b8, 0x00000000}, - {0x0000b0bc, 0x00000000}, - {0x0000b0c0, 0x003f0020}, - {0x0000b0c4, 0x00400041}, - {0x0000b0c8, 0x0140005f}, - {0x0000b0cc, 0x0160015f}, - {0x0000b0d0, 0x017e017f}, - {0x0000b0d4, 0x02410242}, - {0x0000b0d8, 0x025f0240}, - {0x0000b0dc, 0x027f0260}, - {0x0000b0e0, 0x0341027e}, - {0x0000b0e4, 0x035f0340}, - {0x0000b0e8, 0x037f0360}, - {0x0000b0ec, 0x04400441}, - {0x0000b0f0, 0x0460045f}, - {0x0000b0f4, 0x0541047f}, - {0x0000b0f8, 0x055f0540}, - {0x0000b0fc, 0x057f0560}, - {0x0000b100, 0x06400641}, - {0x0000b104, 0x0660065f}, - {0x0000b108, 0x067e067f}, - {0x0000b10c, 0x07410742}, - {0x0000b110, 0x075f0740}, - {0x0000b114, 0x077f0760}, - {0x0000b118, 0x07800781}, - {0x0000b11c, 0x07a0079f}, - {0x0000b120, 0x07c107bf}, - {0x0000b124, 0x000007c0}, - {0x0000b128, 0x00000000}, - {0x0000b12c, 0x00000000}, - {0x0000b130, 0x00000000}, - {0x0000b134, 0x00000000}, - {0x0000b138, 0x00000000}, - {0x0000b13c, 0x00000000}, - {0x0000b140, 0x003f0020}, - {0x0000b144, 0x00400041}, - {0x0000b148, 0x0140005f}, - {0x0000b14c, 0x0160015f}, - {0x0000b150, 0x017e017f}, - {0x0000b154, 0x02410242}, - {0x0000b158, 0x025f0240}, - {0x0000b15c, 0x027f0260}, - {0x0000b160, 0x0341027e}, - {0x0000b164, 0x035f0340}, - {0x0000b168, 0x037f0360}, - {0x0000b16c, 0x04400441}, - {0x0000b170, 0x0460045f}, - {0x0000b174, 0x0541047f}, - {0x0000b178, 0x055f0540}, - {0x0000b17c, 0x057f0560}, - {0x0000b180, 0x06400641}, - {0x0000b184, 0x0660065f}, - {0x0000b188, 0x067e067f}, - {0x0000b18c, 0x07410742}, - {0x0000b190, 0x075f0740}, - {0x0000b194, 0x077f0760}, - {0x0000b198, 0x07800781}, - {0x0000b19c, 0x07a0079f}, - {0x0000b1a0, 0x07c107bf}, - {0x0000b1a4, 0x000007c0}, - {0x0000b1a8, 0x00000000}, - {0x0000b1ac, 0x00000000}, - {0x0000b1b0, 0x00000000}, - {0x0000b1b4, 0x00000000}, - {0x0000b1b8, 0x00000000}, - {0x0000b1bc, 0x00000000}, - {0x0000b1c0, 0x00000000}, - {0x0000b1c4, 0x00000000}, - {0x0000b1c8, 0x00000000}, - {0x0000b1cc, 0x00000000}, - {0x0000b1d0, 0x00000000}, - {0x0000b1d4, 0x00000000}, - {0x0000b1d8, 0x00000000}, - {0x0000b1dc, 0x00000000}, - {0x0000b1e0, 0x00000000}, - {0x0000b1e4, 0x00000000}, - {0x0000b1e8, 0x00000000}, - {0x0000b1ec, 0x00000000}, - {0x0000b1f0, 0x00000396}, - {0x0000b1f4, 0x00000396}, - {0x0000b1f8, 0x00000396}, - {0x0000b1fc, 0x00000196}, -}; - -static const u32 ar9462_2p1_baseband_core_mix_rxgain[][2] = { - /* Addr allmodes */ - {0x00009fd0, 0x0a2d6b93}, -}; - -static const u32 ar9462_2p1_baseband_postamble_mix_rxgain[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00009820, 0x206a022e, 0x206a022e, 0x206a01ae, 0x206a01ae}, - {0x00009824, 0x63c640de, 0x5ac640d0, 0x63c640da, 0x63c640da}, - {0x00009828, 0x0796be89, 0x0696b081, 0x0916be81, 0x0916be81}, - {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000d8, 0x6c4000d8}, - {0x00009e10, 0x92c88d2e, 0x7ec88d2e, 0x7ec86d2e, 0x7ec86d2e}, - {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3236605e, 0x32395c5e}, -}; - -static const u32 ar9462_2p1_baseband_postamble_5g_xlna[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c282}, -}; - -static const u32 ar9462_2p1_common_wo_xlna_rx_gain[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x00010000}, - {0x0000a004, 0x00030002}, - {0x0000a008, 0x00050004}, - {0x0000a00c, 0x00810080}, - {0x0000a010, 0x00830082}, - {0x0000a014, 0x01810180}, - {0x0000a018, 0x01830182}, - {0x0000a01c, 0x01850184}, - {0x0000a020, 0x01890188}, - {0x0000a024, 0x018b018a}, - {0x0000a028, 0x018d018c}, - {0x0000a02c, 0x03820190}, - {0x0000a030, 0x03840383}, - {0x0000a034, 0x03880385}, - {0x0000a038, 0x038a0389}, - {0x0000a03c, 0x038c038b}, - {0x0000a040, 0x0390038d}, - {0x0000a044, 0x03920391}, - {0x0000a048, 0x03940393}, - {0x0000a04c, 0x03960395}, - {0x0000a050, 0x00000000}, - {0x0000a054, 0x00000000}, - {0x0000a058, 0x00000000}, - {0x0000a05c, 0x00000000}, - {0x0000a060, 0x00000000}, - {0x0000a064, 0x00000000}, - {0x0000a068, 0x00000000}, - {0x0000a06c, 0x00000000}, - {0x0000a070, 0x00000000}, - {0x0000a074, 0x00000000}, - {0x0000a078, 0x00000000}, - {0x0000a07c, 0x00000000}, - {0x0000a080, 0x29292929}, - {0x0000a084, 0x29292929}, - {0x0000a088, 0x29292929}, - {0x0000a08c, 0x29292929}, - {0x0000a090, 0x22292929}, - {0x0000a094, 0x1d1d2222}, - {0x0000a098, 0x0c111117}, - {0x0000a09c, 0x00030303}, - {0x0000a0a0, 0x00000000}, - {0x0000a0a4, 0x00000000}, - {0x0000a0a8, 0x00000000}, - {0x0000a0ac, 0x00000000}, - {0x0000a0b0, 0x00000000}, - {0x0000a0b4, 0x00000000}, - {0x0000a0b8, 0x00000000}, - {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x001f0000}, - {0x0000a0c4, 0x01000101}, - {0x0000a0c8, 0x011e011f}, - {0x0000a0cc, 0x011c011d}, - {0x0000a0d0, 0x02030204}, - {0x0000a0d4, 0x02010202}, - {0x0000a0d8, 0x021f0200}, - {0x0000a0dc, 0x0302021e}, - {0x0000a0e0, 0x03000301}, - {0x0000a0e4, 0x031e031f}, - {0x0000a0e8, 0x0402031d}, - {0x0000a0ec, 0x04000401}, - {0x0000a0f0, 0x041e041f}, - {0x0000a0f4, 0x0502041d}, - {0x0000a0f8, 0x05000501}, - {0x0000a0fc, 0x051e051f}, - {0x0000a100, 0x06010602}, - {0x0000a104, 0x061f0600}, - {0x0000a108, 0x061d061e}, - {0x0000a10c, 0x07020703}, - {0x0000a110, 0x07000701}, - {0x0000a114, 0x00000000}, - {0x0000a118, 0x00000000}, - {0x0000a11c, 0x00000000}, - {0x0000a120, 0x00000000}, - {0x0000a124, 0x00000000}, - {0x0000a128, 0x00000000}, - {0x0000a12c, 0x00000000}, - {0x0000a130, 0x00000000}, - {0x0000a134, 0x00000000}, - {0x0000a138, 0x00000000}, - {0x0000a13c, 0x00000000}, - {0x0000a140, 0x001f0000}, - {0x0000a144, 0x01000101}, - {0x0000a148, 0x011e011f}, - {0x0000a14c, 0x011c011d}, - {0x0000a150, 0x02030204}, - {0x0000a154, 0x02010202}, - {0x0000a158, 0x021f0200}, - {0x0000a15c, 0x0302021e}, - {0x0000a160, 0x03000301}, - {0x0000a164, 0x031e031f}, - {0x0000a168, 0x0402031d}, - {0x0000a16c, 0x04000401}, - {0x0000a170, 0x041e041f}, - {0x0000a174, 0x0502041d}, - {0x0000a178, 0x05000501}, - {0x0000a17c, 0x051e051f}, - {0x0000a180, 0x06010602}, - {0x0000a184, 0x061f0600}, - {0x0000a188, 0x061d061e}, - {0x0000a18c, 0x07020703}, - {0x0000a190, 0x07000701}, - {0x0000a194, 0x00000000}, - {0x0000a198, 0x00000000}, - {0x0000a19c, 0x00000000}, - {0x0000a1a0, 0x00000000}, - {0x0000a1a4, 0x00000000}, - {0x0000a1a8, 0x00000000}, - {0x0000a1ac, 0x00000000}, - {0x0000a1b0, 0x00000000}, - {0x0000a1b4, 0x00000000}, - {0x0000a1b8, 0x00000000}, - {0x0000a1bc, 0x00000000}, - {0x0000a1c0, 0x00000000}, - {0x0000a1c4, 0x00000000}, - {0x0000a1c8, 0x00000000}, - {0x0000a1cc, 0x00000000}, - {0x0000a1d0, 0x00000000}, - {0x0000a1d4, 0x00000000}, - {0x0000a1d8, 0x00000000}, - {0x0000a1dc, 0x00000000}, - {0x0000a1e0, 0x00000000}, - {0x0000a1e4, 0x00000000}, - {0x0000a1e8, 0x00000000}, - {0x0000a1ec, 0x00000000}, - {0x0000a1f0, 0x00000396}, - {0x0000a1f4, 0x00000396}, - {0x0000a1f8, 0x00000396}, - {0x0000a1fc, 0x00000196}, - {0x0000b000, 0x00010000}, - {0x0000b004, 0x00030002}, - {0x0000b008, 0x00050004}, - {0x0000b00c, 0x00810080}, - {0x0000b010, 0x00830082}, - {0x0000b014, 0x01810180}, - {0x0000b018, 0x01830182}, - {0x0000b01c, 0x01850184}, - {0x0000b020, 0x02810280}, - {0x0000b024, 0x02830282}, - {0x0000b028, 0x02850284}, - {0x0000b02c, 0x02890288}, - {0x0000b030, 0x028b028a}, - {0x0000b034, 0x0388028c}, - {0x0000b038, 0x038a0389}, - {0x0000b03c, 0x038c038b}, - {0x0000b040, 0x0390038d}, - {0x0000b044, 0x03920391}, - {0x0000b048, 0x03940393}, - {0x0000b04c, 0x03960395}, - {0x0000b050, 0x00000000}, - {0x0000b054, 0x00000000}, - {0x0000b058, 0x00000000}, - {0x0000b05c, 0x00000000}, - {0x0000b060, 0x00000000}, - {0x0000b064, 0x00000000}, - {0x0000b068, 0x00000000}, - {0x0000b06c, 0x00000000}, - {0x0000b070, 0x00000000}, - {0x0000b074, 0x00000000}, - {0x0000b078, 0x00000000}, - {0x0000b07c, 0x00000000}, - {0x0000b080, 0x32323232}, - {0x0000b084, 0x2f2f3232}, - {0x0000b088, 0x23282a2d}, - {0x0000b08c, 0x1c1e2123}, - {0x0000b090, 0x14171919}, - {0x0000b094, 0x0e0e1214}, - {0x0000b098, 0x03050707}, - {0x0000b09c, 0x00030303}, - {0x0000b0a0, 0x00000000}, - {0x0000b0a4, 0x00000000}, - {0x0000b0a8, 0x00000000}, - {0x0000b0ac, 0x00000000}, - {0x0000b0b0, 0x00000000}, - {0x0000b0b4, 0x00000000}, - {0x0000b0b8, 0x00000000}, - {0x0000b0bc, 0x00000000}, - {0x0000b0c0, 0x003f0020}, - {0x0000b0c4, 0x00400041}, - {0x0000b0c8, 0x0140005f}, - {0x0000b0cc, 0x0160015f}, - {0x0000b0d0, 0x017e017f}, - {0x0000b0d4, 0x02410242}, - {0x0000b0d8, 0x025f0240}, - {0x0000b0dc, 0x027f0260}, - {0x0000b0e0, 0x0341027e}, - {0x0000b0e4, 0x035f0340}, - {0x0000b0e8, 0x037f0360}, - {0x0000b0ec, 0x04400441}, - {0x0000b0f0, 0x0460045f}, - {0x0000b0f4, 0x0541047f}, - {0x0000b0f8, 0x055f0540}, - {0x0000b0fc, 0x057f0560}, - {0x0000b100, 0x06400641}, - {0x0000b104, 0x0660065f}, - {0x0000b108, 0x067e067f}, - {0x0000b10c, 0x07410742}, - {0x0000b110, 0x075f0740}, - {0x0000b114, 0x077f0760}, - {0x0000b118, 0x07800781}, - {0x0000b11c, 0x07a0079f}, - {0x0000b120, 0x07c107bf}, - {0x0000b124, 0x000007c0}, - {0x0000b128, 0x00000000}, - {0x0000b12c, 0x00000000}, - {0x0000b130, 0x00000000}, - {0x0000b134, 0x00000000}, - {0x0000b138, 0x00000000}, - {0x0000b13c, 0x00000000}, - {0x0000b140, 0x003f0020}, - {0x0000b144, 0x00400041}, - {0x0000b148, 0x0140005f}, - {0x0000b14c, 0x0160015f}, - {0x0000b150, 0x017e017f}, - {0x0000b154, 0x02410242}, - {0x0000b158, 0x025f0240}, - {0x0000b15c, 0x027f0260}, - {0x0000b160, 0x0341027e}, - {0x0000b164, 0x035f0340}, - {0x0000b168, 0x037f0360}, - {0x0000b16c, 0x04400441}, - {0x0000b170, 0x0460045f}, - {0x0000b174, 0x0541047f}, - {0x0000b178, 0x055f0540}, - {0x0000b17c, 0x057f0560}, - {0x0000b180, 0x06400641}, - {0x0000b184, 0x0660065f}, - {0x0000b188, 0x067e067f}, - {0x0000b18c, 0x07410742}, - {0x0000b190, 0x075f0740}, - {0x0000b194, 0x077f0760}, - {0x0000b198, 0x07800781}, - {0x0000b19c, 0x07a0079f}, - {0x0000b1a0, 0x07c107bf}, - {0x0000b1a4, 0x000007c0}, - {0x0000b1a8, 0x00000000}, - {0x0000b1ac, 0x00000000}, - {0x0000b1b0, 0x00000000}, - {0x0000b1b4, 0x00000000}, - {0x0000b1b8, 0x00000000}, - {0x0000b1bc, 0x00000000}, - {0x0000b1c0, 0x00000000}, - {0x0000b1c4, 0x00000000}, - {0x0000b1c8, 0x00000000}, - {0x0000b1cc, 0x00000000}, - {0x0000b1d0, 0x00000000}, - {0x0000b1d4, 0x00000000}, - {0x0000b1d8, 0x00000000}, - {0x0000b1dc, 0x00000000}, - {0x0000b1e0, 0x00000000}, - {0x0000b1e4, 0x00000000}, - {0x0000b1e8, 0x00000000}, - {0x0000b1ec, 0x00000000}, - {0x0000b1f0, 0x00000396}, - {0x0000b1f4, 0x00000396}, - {0x0000b1f8, 0x00000396}, - {0x0000b1fc, 0x00000196}, -}; - -static const u32 ar9462_2p1_common_5g_xlna_only_rx_gain[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x00010000}, - {0x0000a004, 0x00030002}, - {0x0000a008, 0x00050004}, - {0x0000a00c, 0x00810080}, - {0x0000a010, 0x00830082}, - {0x0000a014, 0x01810180}, - {0x0000a018, 0x01830182}, - {0x0000a01c, 0x01850184}, - {0x0000a020, 0x01890188}, - {0x0000a024, 0x018b018a}, - {0x0000a028, 0x018d018c}, - {0x0000a02c, 0x03820190}, - {0x0000a030, 0x03840383}, - {0x0000a034, 0x03880385}, - {0x0000a038, 0x038a0389}, - {0x0000a03c, 0x038c038b}, - {0x0000a040, 0x0390038d}, - {0x0000a044, 0x03920391}, - {0x0000a048, 0x03940393}, - {0x0000a04c, 0x03960395}, - {0x0000a050, 0x00000000}, - {0x0000a054, 0x00000000}, - {0x0000a058, 0x00000000}, - {0x0000a05c, 0x00000000}, - {0x0000a060, 0x00000000}, - {0x0000a064, 0x00000000}, - {0x0000a068, 0x00000000}, - {0x0000a06c, 0x00000000}, - {0x0000a070, 0x00000000}, - {0x0000a074, 0x00000000}, - {0x0000a078, 0x00000000}, - {0x0000a07c, 0x00000000}, - {0x0000a080, 0x29292929}, - {0x0000a084, 0x29292929}, - {0x0000a088, 0x29292929}, - {0x0000a08c, 0x29292929}, - {0x0000a090, 0x22292929}, - {0x0000a094, 0x1d1d2222}, - {0x0000a098, 0x0c111117}, - {0x0000a09c, 0x00030303}, - {0x0000a0a0, 0x00000000}, - {0x0000a0a4, 0x00000000}, - {0x0000a0a8, 0x00000000}, - {0x0000a0ac, 0x00000000}, - {0x0000a0b0, 0x00000000}, - {0x0000a0b4, 0x00000000}, - {0x0000a0b8, 0x00000000}, - {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x001f0000}, - {0x0000a0c4, 0x01000101}, - {0x0000a0c8, 0x011e011f}, - {0x0000a0cc, 0x011c011d}, - {0x0000a0d0, 0x02030204}, - {0x0000a0d4, 0x02010202}, - {0x0000a0d8, 0x021f0200}, - {0x0000a0dc, 0x0302021e}, - {0x0000a0e0, 0x03000301}, - {0x0000a0e4, 0x031e031f}, - {0x0000a0e8, 0x0402031d}, - {0x0000a0ec, 0x04000401}, - {0x0000a0f0, 0x041e041f}, - {0x0000a0f4, 0x0502041d}, - {0x0000a0f8, 0x05000501}, - {0x0000a0fc, 0x051e051f}, - {0x0000a100, 0x06010602}, - {0x0000a104, 0x061f0600}, - {0x0000a108, 0x061d061e}, - {0x0000a10c, 0x07020703}, - {0x0000a110, 0x07000701}, - {0x0000a114, 0x00000000}, - {0x0000a118, 0x00000000}, - {0x0000a11c, 0x00000000}, - {0x0000a120, 0x00000000}, - {0x0000a124, 0x00000000}, - {0x0000a128, 0x00000000}, - {0x0000a12c, 0x00000000}, - {0x0000a130, 0x00000000}, - {0x0000a134, 0x00000000}, - {0x0000a138, 0x00000000}, - {0x0000a13c, 0x00000000}, - {0x0000a140, 0x001f0000}, - {0x0000a144, 0x01000101}, - {0x0000a148, 0x011e011f}, - {0x0000a14c, 0x011c011d}, - {0x0000a150, 0x02030204}, - {0x0000a154, 0x02010202}, - {0x0000a158, 0x021f0200}, - {0x0000a15c, 0x0302021e}, - {0x0000a160, 0x03000301}, - {0x0000a164, 0x031e031f}, - {0x0000a168, 0x0402031d}, - {0x0000a16c, 0x04000401}, - {0x0000a170, 0x041e041f}, - {0x0000a174, 0x0502041d}, - {0x0000a178, 0x05000501}, - {0x0000a17c, 0x051e051f}, - {0x0000a180, 0x06010602}, - {0x0000a184, 0x061f0600}, - {0x0000a188, 0x061d061e}, - {0x0000a18c, 0x07020703}, - {0x0000a190, 0x07000701}, - {0x0000a194, 0x00000000}, - {0x0000a198, 0x00000000}, - {0x0000a19c, 0x00000000}, - {0x0000a1a0, 0x00000000}, - {0x0000a1a4, 0x00000000}, - {0x0000a1a8, 0x00000000}, - {0x0000a1ac, 0x00000000}, - {0x0000a1b0, 0x00000000}, - {0x0000a1b4, 0x00000000}, - {0x0000a1b8, 0x00000000}, - {0x0000a1bc, 0x00000000}, - {0x0000a1c0, 0x00000000}, - {0x0000a1c4, 0x00000000}, - {0x0000a1c8, 0x00000000}, - {0x0000a1cc, 0x00000000}, - {0x0000a1d0, 0x00000000}, - {0x0000a1d4, 0x00000000}, - {0x0000a1d8, 0x00000000}, - {0x0000a1dc, 0x00000000}, - {0x0000a1e0, 0x00000000}, - {0x0000a1e4, 0x00000000}, - {0x0000a1e8, 0x00000000}, - {0x0000a1ec, 0x00000000}, - {0x0000a1f0, 0x00000396}, - {0x0000a1f4, 0x00000396}, - {0x0000a1f8, 0x00000396}, - {0x0000a1fc, 0x00000196}, - {0x0000b000, 0x00010000}, - {0x0000b004, 0x00030002}, - {0x0000b008, 0x00050004}, - {0x0000b00c, 0x00810080}, - {0x0000b010, 0x00830082}, - {0x0000b014, 0x01810180}, - {0x0000b018, 0x01830182}, - {0x0000b01c, 0x01850184}, - {0x0000b020, 0x02810280}, - {0x0000b024, 0x02830282}, - {0x0000b028, 0x02850284}, - {0x0000b02c, 0x02890288}, - {0x0000b030, 0x028b028a}, - {0x0000b034, 0x0388028c}, - {0x0000b038, 0x038a0389}, - {0x0000b03c, 0x038c038b}, - {0x0000b040, 0x0390038d}, - {0x0000b044, 0x03920391}, - {0x0000b048, 0x03940393}, - {0x0000b04c, 0x03960395}, - {0x0000b050, 0x00000000}, - {0x0000b054, 0x00000000}, - {0x0000b058, 0x00000000}, - {0x0000b05c, 0x00000000}, - {0x0000b060, 0x00000000}, - {0x0000b064, 0x00000000}, - {0x0000b068, 0x00000000}, - {0x0000b06c, 0x00000000}, - {0x0000b070, 0x00000000}, - {0x0000b074, 0x00000000}, - {0x0000b078, 0x00000000}, - {0x0000b07c, 0x00000000}, - {0x0000b080, 0x2a2d2f32}, - {0x0000b084, 0x21232328}, - {0x0000b088, 0x19191c1e}, - {0x0000b08c, 0x12141417}, - {0x0000b090, 0x07070e0e}, - {0x0000b094, 0x03030305}, - {0x0000b098, 0x00000003}, - {0x0000b09c, 0x00000000}, - {0x0000b0a0, 0x00000000}, - {0x0000b0a4, 0x00000000}, - {0x0000b0a8, 0x00000000}, - {0x0000b0ac, 0x00000000}, - {0x0000b0b0, 0x00000000}, - {0x0000b0b4, 0x00000000}, - {0x0000b0b8, 0x00000000}, - {0x0000b0bc, 0x00000000}, - {0x0000b0c0, 0x003f0020}, - {0x0000b0c4, 0x00400041}, - {0x0000b0c8, 0x0140005f}, - {0x0000b0cc, 0x0160015f}, - {0x0000b0d0, 0x017e017f}, - {0x0000b0d4, 0x02410242}, - {0x0000b0d8, 0x025f0240}, - {0x0000b0dc, 0x027f0260}, - {0x0000b0e0, 0x0341027e}, - {0x0000b0e4, 0x035f0340}, - {0x0000b0e8, 0x037f0360}, - {0x0000b0ec, 0x04400441}, - {0x0000b0f0, 0x0460045f}, - {0x0000b0f4, 0x0541047f}, - {0x0000b0f8, 0x055f0540}, - {0x0000b0fc, 0x057f0560}, - {0x0000b100, 0x06400641}, - {0x0000b104, 0x0660065f}, - {0x0000b108, 0x067e067f}, - {0x0000b10c, 0x07410742}, - {0x0000b110, 0x075f0740}, - {0x0000b114, 0x077f0760}, - {0x0000b118, 0x07800781}, - {0x0000b11c, 0x07a0079f}, - {0x0000b120, 0x07c107bf}, - {0x0000b124, 0x000007c0}, - {0x0000b128, 0x00000000}, - {0x0000b12c, 0x00000000}, - {0x0000b130, 0x00000000}, - {0x0000b134, 0x00000000}, - {0x0000b138, 0x00000000}, - {0x0000b13c, 0x00000000}, - {0x0000b140, 0x003f0020}, - {0x0000b144, 0x00400041}, - {0x0000b148, 0x0140005f}, - {0x0000b14c, 0x0160015f}, - {0x0000b150, 0x017e017f}, - {0x0000b154, 0x02410242}, - {0x0000b158, 0x025f0240}, - {0x0000b15c, 0x027f0260}, - {0x0000b160, 0x0341027e}, - {0x0000b164, 0x035f0340}, - {0x0000b168, 0x037f0360}, - {0x0000b16c, 0x04400441}, - {0x0000b170, 0x0460045f}, - {0x0000b174, 0x0541047f}, - {0x0000b178, 0x055f0540}, - {0x0000b17c, 0x057f0560}, - {0x0000b180, 0x06400641}, - {0x0000b184, 0x0660065f}, - {0x0000b188, 0x067e067f}, - {0x0000b18c, 0x07410742}, - {0x0000b190, 0x075f0740}, - {0x0000b194, 0x077f0760}, - {0x0000b198, 0x07800781}, - {0x0000b19c, 0x07a0079f}, - {0x0000b1a0, 0x07c107bf}, - {0x0000b1a4, 0x000007c0}, - {0x0000b1a8, 0x00000000}, - {0x0000b1ac, 0x00000000}, - {0x0000b1b0, 0x00000000}, - {0x0000b1b4, 0x00000000}, - {0x0000b1b8, 0x00000000}, - {0x0000b1bc, 0x00000000}, - {0x0000b1c0, 0x00000000}, - {0x0000b1c4, 0x00000000}, - {0x0000b1c8, 0x00000000}, - {0x0000b1cc, 0x00000000}, - {0x0000b1d0, 0x00000000}, - {0x0000b1d4, 0x00000000}, - {0x0000b1d8, 0x00000000}, - {0x0000b1dc, 0x00000000}, - {0x0000b1e0, 0x00000000}, - {0x0000b1e4, 0x00000000}, - {0x0000b1e8, 0x00000000}, - {0x0000b1ec, 0x00000000}, - {0x0000b1f0, 0x00000396}, - {0x0000b1f4, 0x00000396}, - {0x0000b1f8, 0x00000396}, - {0x0000b1fc, 0x00000196}, -}; - -static const u32 ar9462_2p1_modes_low_ob_db_tx_gain[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002}, - {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, - {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, - {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, - {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, - {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, - {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, - {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, - {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, - {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, - {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400}, - {0x0000a518, 0x21020220, 0x21020220, 0x16000402, 0x16000402}, - {0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404}, - {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603}, - {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02}, - {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04}, - {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20}, - {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20}, - {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22}, - {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24}, - {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640}, - {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660}, - {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861}, - {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81}, - {0x0000a54c, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83}, - {0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84}, - {0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3}, - {0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5}, - {0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9}, - {0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb}, - {0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a57c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000}, - {0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501}, - {0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501}, - {0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03}, - {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04}, - {0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04}, - {0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005}, - {0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, - {0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, - {0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, - {0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, - {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, - {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, - {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, - {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, - {0x00016044, 0x012482d4, 0x012482d4, 0x012482d4, 0x012482d4}, - {0x00016048, 0x64992060, 0x64992060, 0x64992060, 0x64992060}, - {0x00016054, 0x6db60000, 0x6db60000, 0x6db60000, 0x6db60000}, - {0x00016444, 0x012482d4, 0x012482d4, 0x012482d4, 0x012482d4}, - {0x00016448, 0x64992000, 0x64992000, 0x64992000, 0x64992000}, - {0x00016454, 0x6db60000, 0x6db60000, 0x6db60000, 0x6db60000}, -}; - -static const u32 ar9462_2p1_modes_high_ob_db_tx_gain[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002}, - {0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, - {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, - {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, - {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, - {0x0000a410, 0x000050da, 0x000050da, 0x000050de, 0x000050de}, - {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, - {0x0000a504, 0x06002223, 0x06002223, 0x04000002, 0x04000002}, - {0x0000a508, 0x0a022220, 0x0a022220, 0x08000004, 0x08000004}, - {0x0000a50c, 0x0f022223, 0x0f022223, 0x0b000200, 0x0b000200}, - {0x0000a510, 0x14022620, 0x14022620, 0x0f000202, 0x0f000202}, - {0x0000a514, 0x18022622, 0x18022622, 0x11000400, 0x11000400}, - {0x0000a518, 0x1b022822, 0x1b022822, 0x15000402, 0x15000402}, - {0x0000a51c, 0x20022842, 0x20022842, 0x19000404, 0x19000404}, - {0x0000a520, 0x22022c41, 0x22022c41, 0x1b000603, 0x1b000603}, - {0x0000a524, 0x28023042, 0x28023042, 0x1f000a02, 0x1f000a02}, - {0x0000a528, 0x2c023044, 0x2c023044, 0x23000a04, 0x23000a04}, - {0x0000a52c, 0x2f023644, 0x2f023644, 0x26000a20, 0x26000a20}, - {0x0000a530, 0x34025643, 0x34025643, 0x2a000e20, 0x2a000e20}, - {0x0000a534, 0x38025a44, 0x38025a44, 0x2e000e22, 0x2e000e22}, - {0x0000a538, 0x3b025e45, 0x3b025e45, 0x31000e24, 0x31000e24}, - {0x0000a53c, 0x41025e4a, 0x41025e4a, 0x34001640, 0x34001640}, - {0x0000a540, 0x48025e6c, 0x48025e6c, 0x38001660, 0x38001660}, - {0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3b001861, 0x3b001861}, - {0x0000a548, 0x55025eb3, 0x55025eb3, 0x3e001a81, 0x3e001a81}, - {0x0000a54c, 0x58025ef3, 0x58025ef3, 0x42001a83, 0x42001a83}, - {0x0000a550, 0x5d025ef6, 0x5d025ef6, 0x44001a84, 0x44001a84}, - {0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3}, - {0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5}, - {0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9}, - {0x0000a560, 0x70049f56, 0x70049f56, 0x54001ceb, 0x54001ceb}, - {0x0000a564, 0x751ffff6, 0x751ffff6, 0x56001eec, 0x56001eec}, - {0x0000a568, 0x751ffff6, 0x751ffff6, 0x58001ef0, 0x58001ef0}, - {0x0000a56c, 0x751ffff6, 0x751ffff6, 0x5a001ef4, 0x5a001ef4}, - {0x0000a570, 0x751ffff6, 0x751ffff6, 0x5c001ff6, 0x5c001ff6}, - {0x0000a574, 0x751ffff6, 0x751ffff6, 0x5c001ff6, 0x5c001ff6}, - {0x0000a578, 0x751ffff6, 0x751ffff6, 0x5c001ff6, 0x5c001ff6}, - {0x0000a57c, 0x751ffff6, 0x751ffff6, 0x5c001ff6, 0x5c001ff6}, - {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000}, - {0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000}, - {0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501}, - {0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501}, - {0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03}, - {0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04}, - {0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04}, - {0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000b2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, - {0x0000b2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, - {0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, - {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, - {0x00016044, 0x056d82e4, 0x056d82e4, 0x056d82e4, 0x056d82e4}, - {0x00016048, 0x8db49060, 0x8db49060, 0x8db49060, 0x8db49060}, - {0x00016054, 0x6db60000, 0x6db60000, 0x6db60000, 0x6db60000}, - {0x00016444, 0x056d82e4, 0x056d82e4, 0x056d82e4, 0x056d82e4}, - {0x00016448, 0x8db49000, 0x8db49000, 0x8db49000, 0x8db49000}, - {0x00016454, 0x6db60000, 0x6db60000, 0x6db60000, 0x6db60000}, -}; - -static const u32 ar9462_2p1_modes_mix_ob_db_tx_gain[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002}, - {0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, - {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, - {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, - {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, - {0x0000a410, 0x0000d0da, 0x0000d0da, 0x0000d0de, 0x0000d0de}, - {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, - {0x0000a504, 0x06002223, 0x06002223, 0x04000002, 0x04000002}, - {0x0000a508, 0x0a022220, 0x0a022220, 0x08000004, 0x08000004}, - {0x0000a50c, 0x0f022223, 0x0f022223, 0x0b000200, 0x0b000200}, - {0x0000a510, 0x14022620, 0x14022620, 0x0f000202, 0x0f000202}, - {0x0000a514, 0x18022622, 0x18022622, 0x12000400, 0x12000400}, - {0x0000a518, 0x1b022822, 0x1b022822, 0x16000402, 0x16000402}, - {0x0000a51c, 0x20022842, 0x20022842, 0x19000404, 0x19000404}, - {0x0000a520, 0x22022c41, 0x22022c41, 0x1c000603, 0x1c000603}, - {0x0000a524, 0x28023042, 0x28023042, 0x21000a02, 0x21000a02}, - {0x0000a528, 0x2c023044, 0x2c023044, 0x25000a04, 0x25000a04}, - {0x0000a52c, 0x2f023644, 0x2f023644, 0x28000a20, 0x28000a20}, - {0x0000a530, 0x34025643, 0x34025643, 0x2c000e20, 0x2c000e20}, - {0x0000a534, 0x38025a44, 0x38025a44, 0x30000e22, 0x30000e22}, - {0x0000a538, 0x3b025e45, 0x3b025e45, 0x34000e24, 0x34000e24}, - {0x0000a53c, 0x41025e4a, 0x41025e4a, 0x38001640, 0x38001640}, - {0x0000a540, 0x48025e6c, 0x48025e6c, 0x3c001660, 0x3c001660}, - {0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3f001861, 0x3f001861}, - {0x0000a548, 0x55025eb3, 0x55025eb3, 0x43001a81, 0x43001a81}, - {0x0000a54c, 0x58025ef3, 0x58025ef3, 0x47001a83, 0x47001a83}, - {0x0000a550, 0x5d025ef6, 0x5d025ef6, 0x4a001c84, 0x4a001c84}, - {0x0000a554, 0x62025f56, 0x62025f56, 0x4e001ce3, 0x4e001ce3}, - {0x0000a558, 0x66027f56, 0x66027f56, 0x52001ce5, 0x52001ce5}, - {0x0000a55c, 0x6a029f56, 0x6a029f56, 0x56001ce9, 0x56001ce9}, - {0x0000a560, 0x70049f56, 0x70049f56, 0x5a001ceb, 0x5a001ceb}, - {0x0000a564, 0x751ffff6, 0x751ffff6, 0x5c001eec, 0x5c001eec}, - {0x0000a568, 0x751ffff6, 0x751ffff6, 0x5e001ef0, 0x5e001ef0}, - {0x0000a56c, 0x751ffff6, 0x751ffff6, 0x60001ef4, 0x60001ef4}, - {0x0000a570, 0x751ffff6, 0x751ffff6, 0x62001ff6, 0x62001ff6}, - {0x0000a574, 0x751ffff6, 0x751ffff6, 0x62001ff6, 0x62001ff6}, - {0x0000a578, 0x751ffff6, 0x751ffff6, 0x62001ff6, 0x62001ff6}, - {0x0000a57c, 0x751ffff6, 0x751ffff6, 0x62001ff6, 0x62001ff6}, - {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000}, - {0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000}, - {0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501}, - {0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501}, - {0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03}, - {0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04}, - {0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04}, - {0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000b2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, - {0x0000b2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, - {0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, - {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, -}; - -static const u32 ar9462_2p1_modes_fast_clock[][3] = { - /* Addr 5G_HT20 5G_HT40 */ - {0x00001030, 0x00000268, 0x000004d0}, - {0x00001070, 0x0000018c, 0x00000318}, - {0x000010b0, 0x00000fd0, 0x00001fa0}, - {0x00008014, 0x044c044c, 0x08980898}, - {0x0000801c, 0x148ec02b, 0x148ec057}, - {0x00008318, 0x000044c0, 0x00008980}, - {0x00009e00, 0x0372131c, 0x0372131c}, - {0x0000a230, 0x0000400b, 0x00004016}, - {0x0000a254, 0x00000898, 0x00001130}, -}; - -static const u32 ar9462_2p1_baseband_core_txfir_coeff_japan_2484[][2] = { - /* Addr allmodes */ - {0x0000a398, 0x00000000}, - {0x0000a39c, 0x6f7f0301}, - {0x0000a3a0, 0xca9228ee}, -}; - -static const u32 ar9462_2p1_pciephy_clkreq_disable_L1[][2] = { - /* Addr allmodes */ - {0x00018c00, 0x18213ede}, - {0x00018c04, 0x000801d8}, - {0x00018c08, 0x0003780c}, -}; - #endif /* INITVALS_9462_2P1_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h index bdee2ed6721..d17b7ca7261 100644 --- a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h @@ -771,7 +771,7 @@ static const u32 ar9580_1p0_soc_preamble[][2] = { {0x00007048, 0x00000008}, }; -#define ar9580_1p0_rx_gain_table ar9462_common_rx_gain_table_2p0 +#define ar9580_1p0_rx_gain_table ar9462_2p0_common_rx_gain static const u32 ar9580_1p0_radio_core[][2] = { /* Addr allmodes */ -- cgit v1.2.3-70-g09d2 From 879fb289ef8436a4672328cc81a1eafd7c9d622a Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 27 Nov 2013 13:10:46 +0530 Subject: ath9k: Update initvals for AR9300 v2.2 Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- .../net/wireless/ath/ath9k/ar9003_2p2_initvals.h | 24 +++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h index 7546b9a7dcb..15533953e0a 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h @@ -352,7 +352,7 @@ static const u32 ar9300_2p2_baseband_postamble[][5] = { {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110}, {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222}, {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, - {0x0000a2d0, 0x00041981, 0x00041981, 0x00041981, 0x00041982}, + {0x0000a2d0, 0x00041983, 0x00041983, 0x00041981, 0x00041982}, {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b}, {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, @@ -378,9 +378,9 @@ static const u32 ar9300_2p2_baseband_core[][2] = { {0x00009814, 0x9280c00a}, {0x00009818, 0x00000000}, {0x0000981c, 0x00020028}, - {0x00009834, 0x6400a290}, + {0x00009834, 0x6400a190}, {0x00009838, 0x0108ecff}, - {0x0000983c, 0x0d000600}, + {0x0000983c, 0x14000600}, {0x00009880, 0x201fff00}, {0x00009884, 0x00001042}, {0x000098a4, 0x00200400}, @@ -401,7 +401,7 @@ static const u32 ar9300_2p2_baseband_core[][2] = { {0x00009d04, 0x40206c10}, {0x00009d08, 0x009c4060}, {0x00009d0c, 0x9883800a}, - {0x00009d10, 0x01834061}, + {0x00009d10, 0x01884061}, {0x00009d14, 0x00c0040b}, {0x00009d18, 0x00000000}, {0x00009e08, 0x0038230c}, @@ -459,7 +459,7 @@ static const u32 ar9300_2p2_baseband_core[][2] = { {0x0000a3e8, 0x20202020}, {0x0000a3ec, 0x20202020}, {0x0000a3f0, 0x00000000}, - {0x0000a3f4, 0x00000246}, + {0x0000a3f4, 0x00000000}, {0x0000a3f8, 0x0c9bd380}, {0x0000a3fc, 0x000f0f01}, {0x0000a400, 0x8fa91f01}, @@ -644,7 +644,7 @@ static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = { {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, - {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, + {0x0000a410, 0x000050d4, 0x000050d4, 0x000050d9, 0x000050d9}, {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004}, @@ -1086,8 +1086,8 @@ static const u32 ar9300Common_rx_gain_table_2p2[][2] = { {0x0000b074, 0x00000000}, {0x0000b078, 0x00000000}, {0x0000b07c, 0x00000000}, - {0x0000b080, 0x2a2d2f32}, - {0x0000b084, 0x21232328}, + {0x0000b080, 0x23232323}, + {0x0000b084, 0x21232323}, {0x0000b088, 0x19191c1e}, {0x0000b08c, 0x12141417}, {0x0000b090, 0x07070e0e}, @@ -1385,9 +1385,9 @@ static const u32 ar9300_2p2_mac_core[][2] = { {0x000081f8, 0x00000000}, {0x000081fc, 0x00000000}, {0x00008240, 0x00100000}, - {0x00008244, 0x0010f424}, + {0x00008244, 0x0010f400}, {0x00008248, 0x00000800}, - {0x0000824c, 0x0001e848}, + {0x0000824c, 0x0001e800}, {0x00008250, 0x00000000}, {0x00008254, 0x00000000}, {0x00008258, 0x00000000}, @@ -1726,14 +1726,14 @@ static const u32 ar9300PciePhy_pll_on_clkreq_disable_L1_2p2[][2] = { static const u32 ar9300PciePhy_clkreq_enable_L1_2p2[][2] = { /* Addr allmodes */ - {0x00004040, 0x08253e5e}, + {0x00004040, 0x0825365e}, {0x00004040, 0x0008003b}, {0x00004044, 0x00000000}, }; static const u32 ar9300PciePhy_clkreq_disable_L1_2p2[][2] = { /* Addr allmodes */ - {0x00004040, 0x08213e5e}, + {0x00004040, 0x0821365e}, {0x00004040, 0x0008003b}, {0x00004044, 0x00000000}, }; -- cgit v1.2.3-70-g09d2 From 2d9507c899ab196b3110abd380a417b126b87d5c Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Tue, 26 Nov 2013 22:00:29 +0530 Subject: ath9k: Update initvals for AR9580 v1.0 Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- .../net/wireless/ath/ath9k/ar9580_1p0_initvals.h | 559 ++++++++++++++------- 1 file changed, 386 insertions(+), 173 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h index d17b7ca7261..2ae380b70c0 100644 --- a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h @@ -20,18 +20,34 @@ /* AR9580 1.0 */ +#define ar9580_1p0_soc_preamble ar9300_2p2_soc_preamble + +#define ar9580_1p0_soc_postamble ar9300_2p2_soc_postamble + +#define ar9580_1p0_radio_core ar9300_2p2_radio_core + +#define ar9580_1p0_mac_postamble ar9300_2p2_mac_postamble + +#define ar9580_1p0_wo_xlna_rx_gain_table ar9300Common_wo_xlna_rx_gain_table_2p2 + +#define ar9580_1p0_type5_tx_gain_table ar9300Modes_type5_tx_gain_table_2p2 + +#define ar9580_1p0_high_ob_db_tx_gain_table ar9300Modes_high_ob_db_tx_gain_table_2p2 + #define ar9580_1p0_modes_fast_clock ar9300Modes_fast_clock_2p2 +#define ar9580_1p0_baseband_core_txfir_coeff_japan_2484 ar9462_2p0_baseband_core_txfir_coeff_japan_2484 + static const u32 ar9580_1p0_radio_postamble[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x0001609c, 0x0dd08f29, 0x0dd08f29, 0x0b283f31, 0x0b283f31}, {0x000160ac, 0xa4653c00, 0xa4653c00, 0x24652800, 0x24652800}, {0x000160b0, 0x03284f3e, 0x03284f3e, 0x05d08f20, 0x05d08f20}, - {0x0001610c, 0x08000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0001610c, 0xc8000000, 0xc0000000, 0xc0000000, 0xc0000000}, {0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, - {0x0001650c, 0x08000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0001650c, 0xc8000000, 0xc0000000, 0xc0000000, 0xc0000000}, {0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, - {0x0001690c, 0x08000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0001690c, 0xc8000000, 0xc0000000, 0xc0000000, 0xc0000000}, {0x00016940, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, }; @@ -44,9 +60,9 @@ static const u32 ar9580_1p0_baseband_core[][2] = { {0x00009814, 0x3280c00a}, {0x00009818, 0x00000000}, {0x0000981c, 0x00020028}, - {0x00009834, 0x6400a290}, + {0x00009834, 0x6400a190}, {0x00009838, 0x0108ecff}, - {0x0000983c, 0x0d000600}, + {0x0000983c, 0x14000600}, {0x00009880, 0x201fff00}, {0x00009884, 0x00001042}, {0x000098a4, 0x00200400}, @@ -67,7 +83,7 @@ static const u32 ar9580_1p0_baseband_core[][2] = { {0x00009d04, 0x40206c10}, {0x00009d08, 0x009c4060}, {0x00009d0c, 0x9883800a}, - {0x00009d10, 0x01834061}, + {0x00009d10, 0x01884061}, {0x00009d14, 0x00c0040b}, {0x00009d18, 0x00000000}, {0x00009e08, 0x0038230c}, @@ -198,8 +214,6 @@ static const u32 ar9580_1p0_baseband_core[][2] = { {0x0000c420, 0x00000000}, }; -#define ar9580_1p0_mac_postamble ar9300_2p2_mac_postamble - static const u32 ar9580_1p0_low_ob_db_tx_gain_table[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, @@ -306,7 +320,112 @@ static const u32 ar9580_1p0_low_ob_db_tx_gain_table[][5] = { {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, }; -#define ar9580_1p0_high_power_tx_gain_table ar9580_1p0_low_ob_db_tx_gain_table +static const u32 ar9580_1p0_high_power_tx_gain_table[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800}, + {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, + {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, + {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x15000028, 0x15000028, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x1b00002b, 0x1b00002b, 0x12000400, 0x12000400}, + {0x0000a518, 0x1f020028, 0x1f020028, 0x16000402, 0x16000402}, + {0x0000a51c, 0x2502002b, 0x2502002b, 0x19000404, 0x19000404}, + {0x0000a520, 0x2a04002a, 0x2a04002a, 0x1c000603, 0x1c000603}, + {0x0000a524, 0x2e06002a, 0x2e06002a, 0x21000a02, 0x21000a02}, + {0x0000a528, 0x3302202d, 0x3302202d, 0x25000a04, 0x25000a04}, + {0x0000a52c, 0x3804202c, 0x3804202c, 0x28000a20, 0x28000a20}, + {0x0000a530, 0x3c06202c, 0x3c06202c, 0x2c000e20, 0x2c000e20}, + {0x0000a534, 0x4108202d, 0x4108202d, 0x30000e22, 0x30000e22}, + {0x0000a538, 0x4506402d, 0x4506402d, 0x34000e24, 0x34000e24}, + {0x0000a53c, 0x4906222d, 0x4906222d, 0x38001640, 0x38001640}, + {0x0000a540, 0x4d062231, 0x4d062231, 0x3c001660, 0x3c001660}, + {0x0000a544, 0x50082231, 0x50082231, 0x3f001861, 0x3f001861}, + {0x0000a548, 0x5608422e, 0x5608422e, 0x43001a81, 0x43001a81}, + {0x0000a54c, 0x5e08442e, 0x5e08442e, 0x47001a83, 0x47001a83}, + {0x0000a550, 0x620a4431, 0x620a4431, 0x4a001c84, 0x4a001c84}, + {0x0000a554, 0x640a4432, 0x640a4432, 0x4e001ce3, 0x4e001ce3}, + {0x0000a558, 0x680a4434, 0x680a4434, 0x52001ce5, 0x52001ce5}, + {0x0000a55c, 0x6c0a6434, 0x6c0a6434, 0x56001ce9, 0x56001ce9}, + {0x0000a560, 0x6f0a6633, 0x6f0a6633, 0x5a001ceb, 0x5a001ceb}, + {0x0000a564, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a568, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a56c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a570, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a574, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a578, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a57c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, + {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, + {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, + {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200}, + {0x0000a590, 0x15800028, 0x15800028, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x1b80002b, 0x1b80002b, 0x12800400, 0x12800400}, + {0x0000a598, 0x1f820028, 0x1f820028, 0x16800402, 0x16800402}, + {0x0000a59c, 0x2582002b, 0x2582002b, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x2a84002a, 0x2a84002a, 0x1c800603, 0x1c800603}, + {0x0000a5a4, 0x2e86002a, 0x2e86002a, 0x21800a02, 0x21800a02}, + {0x0000a5a8, 0x3382202d, 0x3382202d, 0x25800a04, 0x25800a04}, + {0x0000a5ac, 0x3884202c, 0x3884202c, 0x28800a20, 0x28800a20}, + {0x0000a5b0, 0x3c86202c, 0x3c86202c, 0x2c800e20, 0x2c800e20}, + {0x0000a5b4, 0x4188202d, 0x4188202d, 0x30800e22, 0x30800e22}, + {0x0000a5b8, 0x4586402d, 0x4586402d, 0x34800e24, 0x34800e24}, + {0x0000a5bc, 0x4986222d, 0x4986222d, 0x38801640, 0x38801640}, + {0x0000a5c0, 0x4d862231, 0x4d862231, 0x3c801660, 0x3c801660}, + {0x0000a5c4, 0x50882231, 0x50882231, 0x3f801861, 0x3f801861}, + {0x0000a5c8, 0x5688422e, 0x5688422e, 0x43801a81, 0x43801a81}, + {0x0000a5cc, 0x5a88442e, 0x5a88442e, 0x47801a83, 0x47801a83}, + {0x0000a5d0, 0x5e8a4431, 0x5e8a4431, 0x4a801c84, 0x4a801c84}, + {0x0000a5d4, 0x648a4432, 0x648a4432, 0x4e801ce3, 0x4e801ce3}, + {0x0000a5d8, 0x688a4434, 0x688a4434, 0x52801ce5, 0x52801ce5}, + {0x0000a5dc, 0x6c8a6434, 0x6c8a6434, 0x56801ce9, 0x56801ce9}, + {0x0000a5e0, 0x6f8a6633, 0x6f8a6633, 0x5a801ceb, 0x5a801ceb}, + {0x0000a5e4, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, + {0x0000a5e8, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, + {0x0000a5ec, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, + {0x0000a5f0, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, + {0x0000a5f4, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, + {0x0000a5f8, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, + {0x0000a5fc, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, + {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a608, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, + {0x0000a60c, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, + {0x0000a610, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, + {0x0000a614, 0x01804601, 0x01804601, 0x01404000, 0x01404000}, + {0x0000a618, 0x01804601, 0x01804601, 0x01404501, 0x01404501}, + {0x0000a61c, 0x01804601, 0x01804601, 0x02008501, 0x02008501}, + {0x0000a620, 0x03408d02, 0x03408d02, 0x0280ca03, 0x0280ca03}, + {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04}, + {0x0000a628, 0x03410d04, 0x03410d04, 0x04014c04, 0x04014c04}, + {0x0000a62c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, + {0x0000a630, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, + {0x0000a634, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, + {0x0000a638, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, + {0x0000a63c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, + {0x0000b2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, + {0x0000b2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, + {0x0000b2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800}, + {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000c2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, + {0x0000c2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, + {0x0000c2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800}, + {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, + {0x00016048, 0x65240001, 0x65240001, 0x66480001, 0x66480001}, + {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, + {0x00016288, 0x05a2040a, 0x05a2040a, 0x05a20408, 0x05a20408}, + {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, + {0x00016448, 0x65240001, 0x65240001, 0x66480001, 0x66480001}, + {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, + {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, + {0x00016848, 0x65240001, 0x65240001, 0x66480001, 0x66480001}, + {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, +}; static const u32 ar9580_1p0_lowest_ob_db_tx_gain_table[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ @@ -414,8 +533,6 @@ static const u32 ar9580_1p0_lowest_ob_db_tx_gain_table[][5] = { {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, }; -#define ar9580_1p0_baseband_core_txfir_coeff_japan_2484 ar9462_2p0_baseband_core_txfir_coeff_japan_2484 - static const u32 ar9580_1p0_mac_core[][2] = { /* Addr allmodes */ {0x00000008, 0x00000000}, @@ -679,14 +796,6 @@ static const u32 ar9580_1p0_mixed_ob_db_tx_gain_table[][5] = { {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, }; -#define ar9580_1p0_wo_xlna_rx_gain_table ar9300Common_wo_xlna_rx_gain_table_2p2 - -#define ar9580_1p0_soc_postamble ar9300_2p2_soc_postamble - -#define ar9580_1p0_high_ob_db_tx_gain_table ar9300Modes_high_ob_db_tx_gain_table_2p2 - -#define ar9580_1p0_type5_tx_gain_table ar9300Modes_type5_tx_gain_table_2p2 - static const u32 ar9580_1p0_type6_tx_gain_table[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x0000a2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, @@ -761,160 +870,264 @@ static const u32 ar9580_1p0_type6_tx_gain_table[][5] = { {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, }; -static const u32 ar9580_1p0_soc_preamble[][2] = { - /* Addr allmodes */ - {0x000040a4, 0x00a0c1c9}, - {0x00007008, 0x00000000}, - {0x00007020, 0x00000000}, - {0x00007034, 0x00000002}, - {0x00007038, 0x000004c2}, - {0x00007048, 0x00000008}, -}; - -#define ar9580_1p0_rx_gain_table ar9462_2p0_common_rx_gain - -static const u32 ar9580_1p0_radio_core[][2] = { +static const u32 ar9580_1p0_rx_gain_table[][2] = { /* Addr allmodes */ - {0x00016000, 0x36db6db6}, - {0x00016004, 0x6db6db40}, - {0x00016008, 0x73f00000}, - {0x0001600c, 0x00000000}, - {0x00016040, 0x7f80fff8}, - {0x0001604c, 0x76d005b5}, - {0x00016050, 0x556cf031}, - {0x00016054, 0x13449440}, - {0x00016058, 0x0c51c92c}, - {0x0001605c, 0x3db7fffc}, - {0x00016060, 0xfffffffc}, - {0x00016064, 0x000f0278}, - {0x0001606c, 0x6db60000}, - {0x00016080, 0x00000000}, - {0x00016084, 0x0e48048c}, - {0x00016088, 0x54214514}, - {0x0001608c, 0x119f481e}, - {0x00016090, 0x24926490}, - {0x00016098, 0xd2888888}, - {0x000160a0, 0x0a108ffe}, - {0x000160a4, 0x812fc370}, - {0x000160a8, 0x423c8000}, - {0x000160b4, 0x92480080}, - {0x000160c0, 0x00adb6d0}, - {0x000160c4, 0x6db6db60}, - {0x000160c8, 0x6db6db6c}, - {0x000160cc, 0x01e6c000}, - {0x00016100, 0x3fffbe01}, - {0x00016104, 0xfff80000}, - {0x00016108, 0x00080010}, - {0x00016144, 0x02084080}, - {0x00016148, 0x00000000}, - {0x00016280, 0x058a0001}, - {0x00016284, 0x3d840208}, - {0x00016288, 0x05a20408}, - {0x0001628c, 0x00038c07}, - {0x00016290, 0x00000004}, - {0x00016294, 0x458aa14f}, - {0x00016380, 0x00000000}, - {0x00016384, 0x00000000}, - {0x00016388, 0x00800700}, - {0x0001638c, 0x00800700}, - {0x00016390, 0x00800700}, - {0x00016394, 0x00000000}, - {0x00016398, 0x00000000}, - {0x0001639c, 0x00000000}, - {0x000163a0, 0x00000001}, - {0x000163a4, 0x00000001}, - {0x000163a8, 0x00000000}, - {0x000163ac, 0x00000000}, - {0x000163b0, 0x00000000}, - {0x000163b4, 0x00000000}, - {0x000163b8, 0x00000000}, - {0x000163bc, 0x00000000}, - {0x000163c0, 0x000000a0}, - {0x000163c4, 0x000c0000}, - {0x000163c8, 0x14021402}, - {0x000163cc, 0x00001402}, - {0x000163d0, 0x00000000}, - {0x000163d4, 0x00000000}, - {0x00016400, 0x36db6db6}, - {0x00016404, 0x6db6db40}, - {0x00016408, 0x73f00000}, - {0x0001640c, 0x00000000}, - {0x00016440, 0x7f80fff8}, - {0x0001644c, 0x76d005b5}, - {0x00016450, 0x556cf031}, - {0x00016454, 0x13449440}, - {0x00016458, 0x0c51c92c}, - {0x0001645c, 0x3db7fffc}, - {0x00016460, 0xfffffffc}, - {0x00016464, 0x000f0278}, - {0x0001646c, 0x6db60000}, - {0x00016500, 0x3fffbe01}, - {0x00016504, 0xfff80000}, - {0x00016508, 0x00080010}, - {0x00016544, 0x02084080}, - {0x00016548, 0x00000000}, - {0x00016780, 0x00000000}, - {0x00016784, 0x00000000}, - {0x00016788, 0x00800700}, - {0x0001678c, 0x00800700}, - {0x00016790, 0x00800700}, - {0x00016794, 0x00000000}, - {0x00016798, 0x00000000}, - {0x0001679c, 0x00000000}, - {0x000167a0, 0x00000001}, - {0x000167a4, 0x00000001}, - {0x000167a8, 0x00000000}, - {0x000167ac, 0x00000000}, - {0x000167b0, 0x00000000}, - {0x000167b4, 0x00000000}, - {0x000167b8, 0x00000000}, - {0x000167bc, 0x00000000}, - {0x000167c0, 0x000000a0}, - {0x000167c4, 0x000c0000}, - {0x000167c8, 0x14021402}, - {0x000167cc, 0x00001402}, - {0x000167d0, 0x00000000}, - {0x000167d4, 0x00000000}, - {0x00016800, 0x36db6db6}, - {0x00016804, 0x6db6db40}, - {0x00016808, 0x73f00000}, - {0x0001680c, 0x00000000}, - {0x00016840, 0x7f80fff8}, - {0x0001684c, 0x76d005b5}, - {0x00016850, 0x556cf031}, - {0x00016854, 0x13449440}, - {0x00016858, 0x0c51c92c}, - {0x0001685c, 0x3db7fffc}, - {0x00016860, 0xfffffffc}, - {0x00016864, 0x000f0278}, - {0x0001686c, 0x6db60000}, - {0x00016900, 0x3fffbe01}, - {0x00016904, 0xfff80000}, - {0x00016908, 0x00080010}, - {0x00016944, 0x02084080}, - {0x00016948, 0x00000000}, - {0x00016b80, 0x00000000}, - {0x00016b84, 0x00000000}, - {0x00016b88, 0x00800700}, - {0x00016b8c, 0x00800700}, - {0x00016b90, 0x00800700}, - {0x00016b94, 0x00000000}, - {0x00016b98, 0x00000000}, - {0x00016b9c, 0x00000000}, - {0x00016ba0, 0x00000001}, - {0x00016ba4, 0x00000001}, - {0x00016ba8, 0x00000000}, - {0x00016bac, 0x00000000}, - {0x00016bb0, 0x00000000}, - {0x00016bb4, 0x00000000}, - {0x00016bb8, 0x00000000}, - {0x00016bbc, 0x00000000}, - {0x00016bc0, 0x000000a0}, - {0x00016bc4, 0x000c0000}, - {0x00016bc8, 0x14021402}, - {0x00016bcc, 0x00001402}, - {0x00016bd0, 0x00000000}, - {0x00016bd4, 0x00000000}, + {0x0000a000, 0x00010000}, + {0x0000a004, 0x00030002}, + {0x0000a008, 0x00050004}, + {0x0000a00c, 0x00810080}, + {0x0000a010, 0x00830082}, + {0x0000a014, 0x01810180}, + {0x0000a018, 0x01830182}, + {0x0000a01c, 0x01850184}, + {0x0000a020, 0x01890188}, + {0x0000a024, 0x018b018a}, + {0x0000a028, 0x018d018c}, + {0x0000a02c, 0x01910190}, + {0x0000a030, 0x01930192}, + {0x0000a034, 0x01950194}, + {0x0000a038, 0x038a0196}, + {0x0000a03c, 0x038c038b}, + {0x0000a040, 0x0390038d}, + {0x0000a044, 0x03920391}, + {0x0000a048, 0x03940393}, + {0x0000a04c, 0x03960395}, + {0x0000a050, 0x00000000}, + {0x0000a054, 0x00000000}, + {0x0000a058, 0x00000000}, + {0x0000a05c, 0x00000000}, + {0x0000a060, 0x00000000}, + {0x0000a064, 0x00000000}, + {0x0000a068, 0x00000000}, + {0x0000a06c, 0x00000000}, + {0x0000a070, 0x00000000}, + {0x0000a074, 0x00000000}, + {0x0000a078, 0x00000000}, + {0x0000a07c, 0x00000000}, + {0x0000a080, 0x22222229}, + {0x0000a084, 0x1d1d1d1d}, + {0x0000a088, 0x1d1d1d1d}, + {0x0000a08c, 0x1d1d1d1d}, + {0x0000a090, 0x171d1d1d}, + {0x0000a094, 0x11111717}, + {0x0000a098, 0x00030311}, + {0x0000a09c, 0x00000000}, + {0x0000a0a0, 0x00000000}, + {0x0000a0a4, 0x00000000}, + {0x0000a0a8, 0x00000000}, + {0x0000a0ac, 0x00000000}, + {0x0000a0b0, 0x00000000}, + {0x0000a0b4, 0x00000000}, + {0x0000a0b8, 0x00000000}, + {0x0000a0bc, 0x00000000}, + {0x0000a0c0, 0x001f0000}, + {0x0000a0c4, 0x01000101}, + {0x0000a0c8, 0x011e011f}, + {0x0000a0cc, 0x011c011d}, + {0x0000a0d0, 0x02030204}, + {0x0000a0d4, 0x02010202}, + {0x0000a0d8, 0x021f0200}, + {0x0000a0dc, 0x0302021e}, + {0x0000a0e0, 0x03000301}, + {0x0000a0e4, 0x031e031f}, + {0x0000a0e8, 0x0402031d}, + {0x0000a0ec, 0x04000401}, + {0x0000a0f0, 0x041e041f}, + {0x0000a0f4, 0x0502041d}, + {0x0000a0f8, 0x05000501}, + {0x0000a0fc, 0x051e051f}, + {0x0000a100, 0x06010602}, + {0x0000a104, 0x061f0600}, + {0x0000a108, 0x061d061e}, + {0x0000a10c, 0x07020703}, + {0x0000a110, 0x07000701}, + {0x0000a114, 0x00000000}, + {0x0000a118, 0x00000000}, + {0x0000a11c, 0x00000000}, + {0x0000a120, 0x00000000}, + {0x0000a124, 0x00000000}, + {0x0000a128, 0x00000000}, + {0x0000a12c, 0x00000000}, + {0x0000a130, 0x00000000}, + {0x0000a134, 0x00000000}, + {0x0000a138, 0x00000000}, + {0x0000a13c, 0x00000000}, + {0x0000a140, 0x001f0000}, + {0x0000a144, 0x01000101}, + {0x0000a148, 0x011e011f}, + {0x0000a14c, 0x011c011d}, + {0x0000a150, 0x02030204}, + {0x0000a154, 0x02010202}, + {0x0000a158, 0x021f0200}, + {0x0000a15c, 0x0302021e}, + {0x0000a160, 0x03000301}, + {0x0000a164, 0x031e031f}, + {0x0000a168, 0x0402031d}, + {0x0000a16c, 0x04000401}, + {0x0000a170, 0x041e041f}, + {0x0000a174, 0x0502041d}, + {0x0000a178, 0x05000501}, + {0x0000a17c, 0x051e051f}, + {0x0000a180, 0x06010602}, + {0x0000a184, 0x061f0600}, + {0x0000a188, 0x061d061e}, + {0x0000a18c, 0x07020703}, + {0x0000a190, 0x07000701}, + {0x0000a194, 0x00000000}, + {0x0000a198, 0x00000000}, + {0x0000a19c, 0x00000000}, + {0x0000a1a0, 0x00000000}, + {0x0000a1a4, 0x00000000}, + {0x0000a1a8, 0x00000000}, + {0x0000a1ac, 0x00000000}, + {0x0000a1b0, 0x00000000}, + {0x0000a1b4, 0x00000000}, + {0x0000a1b8, 0x00000000}, + {0x0000a1bc, 0x00000000}, + {0x0000a1c0, 0x00000000}, + {0x0000a1c4, 0x00000000}, + {0x0000a1c8, 0x00000000}, + {0x0000a1cc, 0x00000000}, + {0x0000a1d0, 0x00000000}, + {0x0000a1d4, 0x00000000}, + {0x0000a1d8, 0x00000000}, + {0x0000a1dc, 0x00000000}, + {0x0000a1e0, 0x00000000}, + {0x0000a1e4, 0x00000000}, + {0x0000a1e8, 0x00000000}, + {0x0000a1ec, 0x00000000}, + {0x0000a1f0, 0x00000396}, + {0x0000a1f4, 0x00000396}, + {0x0000a1f8, 0x00000396}, + {0x0000a1fc, 0x00000196}, + {0x0000b000, 0x00010000}, + {0x0000b004, 0x00030002}, + {0x0000b008, 0x00050004}, + {0x0000b00c, 0x00810080}, + {0x0000b010, 0x00830082}, + {0x0000b014, 0x01810180}, + {0x0000b018, 0x01830182}, + {0x0000b01c, 0x01850184}, + {0x0000b020, 0x02810280}, + {0x0000b024, 0x02830282}, + {0x0000b028, 0x02850284}, + {0x0000b02c, 0x02890288}, + {0x0000b030, 0x028b028a}, + {0x0000b034, 0x0388028c}, + {0x0000b038, 0x038a0389}, + {0x0000b03c, 0x038c038b}, + {0x0000b040, 0x0390038d}, + {0x0000b044, 0x03920391}, + {0x0000b048, 0x03940393}, + {0x0000b04c, 0x03960395}, + {0x0000b050, 0x00000000}, + {0x0000b054, 0x00000000}, + {0x0000b058, 0x00000000}, + {0x0000b05c, 0x00000000}, + {0x0000b060, 0x00000000}, + {0x0000b064, 0x00000000}, + {0x0000b068, 0x00000000}, + {0x0000b06c, 0x00000000}, + {0x0000b070, 0x00000000}, + {0x0000b074, 0x00000000}, + {0x0000b078, 0x00000000}, + {0x0000b07c, 0x00000000}, + {0x0000b080, 0x23232323}, + {0x0000b084, 0x21232323}, + {0x0000b088, 0x19191c1e}, + {0x0000b08c, 0x12141417}, + {0x0000b090, 0x07070e0e}, + {0x0000b094, 0x03030305}, + {0x0000b098, 0x00000003}, + {0x0000b09c, 0x00000000}, + {0x0000b0a0, 0x00000000}, + {0x0000b0a4, 0x00000000}, + {0x0000b0a8, 0x00000000}, + {0x0000b0ac, 0x00000000}, + {0x0000b0b0, 0x00000000}, + {0x0000b0b4, 0x00000000}, + {0x0000b0b8, 0x00000000}, + {0x0000b0bc, 0x00000000}, + {0x0000b0c0, 0x003f0020}, + {0x0000b0c4, 0x00400041}, + {0x0000b0c8, 0x0140005f}, + {0x0000b0cc, 0x0160015f}, + {0x0000b0d0, 0x017e017f}, + {0x0000b0d4, 0x02410242}, + {0x0000b0d8, 0x025f0240}, + {0x0000b0dc, 0x027f0260}, + {0x0000b0e0, 0x0341027e}, + {0x0000b0e4, 0x035f0340}, + {0x0000b0e8, 0x037f0360}, + {0x0000b0ec, 0x04400441}, + {0x0000b0f0, 0x0460045f}, + {0x0000b0f4, 0x0541047f}, + {0x0000b0f8, 0x055f0540}, + {0x0000b0fc, 0x057f0560}, + {0x0000b100, 0x06400641}, + {0x0000b104, 0x0660065f}, + {0x0000b108, 0x067e067f}, + {0x0000b10c, 0x07410742}, + {0x0000b110, 0x075f0740}, + {0x0000b114, 0x077f0760}, + {0x0000b118, 0x07800781}, + {0x0000b11c, 0x07a0079f}, + {0x0000b120, 0x07c107bf}, + {0x0000b124, 0x000007c0}, + {0x0000b128, 0x00000000}, + {0x0000b12c, 0x00000000}, + {0x0000b130, 0x00000000}, + {0x0000b134, 0x00000000}, + {0x0000b138, 0x00000000}, + {0x0000b13c, 0x00000000}, + {0x0000b140, 0x003f0020}, + {0x0000b144, 0x00400041}, + {0x0000b148, 0x0140005f}, + {0x0000b14c, 0x0160015f}, + {0x0000b150, 0x017e017f}, + {0x0000b154, 0x02410242}, + {0x0000b158, 0x025f0240}, + {0x0000b15c, 0x027f0260}, + {0x0000b160, 0x0341027e}, + {0x0000b164, 0x035f0340}, + {0x0000b168, 0x037f0360}, + {0x0000b16c, 0x04400441}, + {0x0000b170, 0x0460045f}, + {0x0000b174, 0x0541047f}, + {0x0000b178, 0x055f0540}, + {0x0000b17c, 0x057f0560}, + {0x0000b180, 0x06400641}, + {0x0000b184, 0x0660065f}, + {0x0000b188, 0x067e067f}, + {0x0000b18c, 0x07410742}, + {0x0000b190, 0x075f0740}, + {0x0000b194, 0x077f0760}, + {0x0000b198, 0x07800781}, + {0x0000b19c, 0x07a0079f}, + {0x0000b1a0, 0x07c107bf}, + {0x0000b1a4, 0x000007c0}, + {0x0000b1a8, 0x00000000}, + {0x0000b1ac, 0x00000000}, + {0x0000b1b0, 0x00000000}, + {0x0000b1b4, 0x00000000}, + {0x0000b1b8, 0x00000000}, + {0x0000b1bc, 0x00000000}, + {0x0000b1c0, 0x00000000}, + {0x0000b1c4, 0x00000000}, + {0x0000b1c8, 0x00000000}, + {0x0000b1cc, 0x00000000}, + {0x0000b1d0, 0x00000000}, + {0x0000b1d4, 0x00000000}, + {0x0000b1d8, 0x00000000}, + {0x0000b1dc, 0x00000000}, + {0x0000b1e0, 0x00000000}, + {0x0000b1e4, 0x00000000}, + {0x0000b1e8, 0x00000000}, + {0x0000b1ec, 0x00000000}, + {0x0000b1f0, 0x00000396}, + {0x0000b1f4, 0x00000396}, + {0x0000b1f8, 0x00000396}, + {0x0000b1fc, 0x00000196}, }; static const u32 ar9580_1p0_baseband_postamble[][5] = { @@ -956,7 +1169,7 @@ static const u32 ar9580_1p0_baseband_postamble[][5] = { {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110}, {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222}, {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, - {0x0000a2d0, 0x00041981, 0x00041981, 0x00041981, 0x00041982}, + {0x0000a2d0, 0x00041983, 0x00041983, 0x00041981, 0x00041982}, {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b}, {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, -- cgit v1.2.3-70-g09d2 From 40cc87de93ebb9122f6fcddd799ea18145f0bdab Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 2 Dec 2013 09:27:24 +0530 Subject: ath9k: Update AR9340 initvals * Baseband updates * Remove ar9340Common_rx_gain_table_1p0 since it is a duplicate. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9340_initvals.h | 286 ++--------------------- 1 file changed, 14 insertions(+), 272 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9340_initvals.h b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h index 182bf90ab80..d2d789bdb7f 100644 --- a/drivers/net/wireless/ath/ath9k/ar9340_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h @@ -18,6 +18,16 @@ #ifndef INITVALS_9340_H #define INITVALS_9340_H +#define ar9340_1p0_mac_postamble ar9300_2p2_mac_postamble + +#define ar9340_1p0_soc_postamble ar9300_2p2_soc_postamble + +#define ar9340Modes_fast_clock_1p0 ar9300Modes_fast_clock_2p2 + +#define ar9340Common_rx_gain_table_1p0 ar9300Common_rx_gain_table_2p2 + +#define ar9340Common_wo_xlna_rx_gain_table_1p0 ar9300Common_wo_xlna_rx_gain_table_2p2 + static const u32 ar9340_1p0_radio_postamble[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x000160ac, 0xa4646800, 0xa4646800, 0xa4646800, 0xa4646800}, @@ -100,8 +110,6 @@ static const u32 ar9340Modes_lowest_ob_db_tx_gain_table_1p0[][5] = { {0x00016448, 0x24925266, 0x24925266, 0x24925266, 0x24925266}, }; -#define ar9340Modes_fast_clock_1p0 ar9300Modes_fast_clock_2p2 - static const u32 ar9340_1p0_radio_core[][2] = { /* Addr allmodes */ {0x00016000, 0x36db6db6}, @@ -215,16 +223,12 @@ static const u32 ar9340_1p0_radio_core_40M[][2] = { {0x0000824c, 0x0001e800}, }; -#define ar9340_1p0_mac_postamble ar9300_2p2_mac_postamble - -#define ar9340_1p0_soc_postamble ar9300_2p2_soc_postamble - static const u32 ar9340_1p0_baseband_postamble[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011}, {0x00009820, 0x206a022e, 0x206a022e, 0x206a022e, 0x206a022e}, {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, - {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, + {0x00009828, 0x06903081, 0x06903081, 0x09103881, 0x09103881}, {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c}, {0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4}, @@ -340,9 +344,9 @@ static const u32 ar9340_1p0_baseband_core[][2] = { {0x0000a370, 0x00000000}, {0x0000a390, 0x00000001}, {0x0000a394, 0x00000444}, - {0x0000a398, 0x001f0e0f}, - {0x0000a39c, 0x0075393f}, - {0x0000a3a0, 0xb79f6427}, + {0x0000a398, 0x00000000}, + {0x0000a39c, 0x210d0401}, + {0x0000a3a0, 0xab9a7144}, {0x0000a3a4, 0x00000000}, {0x0000a3a8, 0xaaaaaaaa}, {0x0000a3ac, 0x3c466478}, @@ -714,266 +718,6 @@ static const u32 ar9340Modes_ub124_tx_gain_table_1p0[][5] = { {0x0000b2e8, 0xfffe0000, 0xfffe0000, 0xfffc0000, 0xfffc0000}, }; -static const u32 ar9340Common_rx_gain_table_1p0[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x00010000}, - {0x0000a004, 0x00030002}, - {0x0000a008, 0x00050004}, - {0x0000a00c, 0x00810080}, - {0x0000a010, 0x00830082}, - {0x0000a014, 0x01810180}, - {0x0000a018, 0x01830182}, - {0x0000a01c, 0x01850184}, - {0x0000a020, 0x01890188}, - {0x0000a024, 0x018b018a}, - {0x0000a028, 0x018d018c}, - {0x0000a02c, 0x01910190}, - {0x0000a030, 0x01930192}, - {0x0000a034, 0x01950194}, - {0x0000a038, 0x038a0196}, - {0x0000a03c, 0x038c038b}, - {0x0000a040, 0x0390038d}, - {0x0000a044, 0x03920391}, - {0x0000a048, 0x03940393}, - {0x0000a04c, 0x03960395}, - {0x0000a050, 0x00000000}, - {0x0000a054, 0x00000000}, - {0x0000a058, 0x00000000}, - {0x0000a05c, 0x00000000}, - {0x0000a060, 0x00000000}, - {0x0000a064, 0x00000000}, - {0x0000a068, 0x00000000}, - {0x0000a06c, 0x00000000}, - {0x0000a070, 0x00000000}, - {0x0000a074, 0x00000000}, - {0x0000a078, 0x00000000}, - {0x0000a07c, 0x00000000}, - {0x0000a080, 0x22222229}, - {0x0000a084, 0x1d1d1d1d}, - {0x0000a088, 0x1d1d1d1d}, - {0x0000a08c, 0x1d1d1d1d}, - {0x0000a090, 0x171d1d1d}, - {0x0000a094, 0x11111717}, - {0x0000a098, 0x00030311}, - {0x0000a09c, 0x00000000}, - {0x0000a0a0, 0x00000000}, - {0x0000a0a4, 0x00000000}, - {0x0000a0a8, 0x00000000}, - {0x0000a0ac, 0x00000000}, - {0x0000a0b0, 0x00000000}, - {0x0000a0b4, 0x00000000}, - {0x0000a0b8, 0x00000000}, - {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x001f0000}, - {0x0000a0c4, 0x01000101}, - {0x0000a0c8, 0x011e011f}, - {0x0000a0cc, 0x011c011d}, - {0x0000a0d0, 0x02030204}, - {0x0000a0d4, 0x02010202}, - {0x0000a0d8, 0x021f0200}, - {0x0000a0dc, 0x0302021e}, - {0x0000a0e0, 0x03000301}, - {0x0000a0e4, 0x031e031f}, - {0x0000a0e8, 0x0402031d}, - {0x0000a0ec, 0x04000401}, - {0x0000a0f0, 0x041e041f}, - {0x0000a0f4, 0x0502041d}, - {0x0000a0f8, 0x05000501}, - {0x0000a0fc, 0x051e051f}, - {0x0000a100, 0x06010602}, - {0x0000a104, 0x061f0600}, - {0x0000a108, 0x061d061e}, - {0x0000a10c, 0x07020703}, - {0x0000a110, 0x07000701}, - {0x0000a114, 0x00000000}, - {0x0000a118, 0x00000000}, - {0x0000a11c, 0x00000000}, - {0x0000a120, 0x00000000}, - {0x0000a124, 0x00000000}, - {0x0000a128, 0x00000000}, - {0x0000a12c, 0x00000000}, - {0x0000a130, 0x00000000}, - {0x0000a134, 0x00000000}, - {0x0000a138, 0x00000000}, - {0x0000a13c, 0x00000000}, - {0x0000a140, 0x001f0000}, - {0x0000a144, 0x01000101}, - {0x0000a148, 0x011e011f}, - {0x0000a14c, 0x011c011d}, - {0x0000a150, 0x02030204}, - {0x0000a154, 0x02010202}, - {0x0000a158, 0x021f0200}, - {0x0000a15c, 0x0302021e}, - {0x0000a160, 0x03000301}, - {0x0000a164, 0x031e031f}, - {0x0000a168, 0x0402031d}, - {0x0000a16c, 0x04000401}, - {0x0000a170, 0x041e041f}, - {0x0000a174, 0x0502041d}, - {0x0000a178, 0x05000501}, - {0x0000a17c, 0x051e051f}, - {0x0000a180, 0x06010602}, - {0x0000a184, 0x061f0600}, - {0x0000a188, 0x061d061e}, - {0x0000a18c, 0x07020703}, - {0x0000a190, 0x07000701}, - {0x0000a194, 0x00000000}, - {0x0000a198, 0x00000000}, - {0x0000a19c, 0x00000000}, - {0x0000a1a0, 0x00000000}, - {0x0000a1a4, 0x00000000}, - {0x0000a1a8, 0x00000000}, - {0x0000a1ac, 0x00000000}, - {0x0000a1b0, 0x00000000}, - {0x0000a1b4, 0x00000000}, - {0x0000a1b8, 0x00000000}, - {0x0000a1bc, 0x00000000}, - {0x0000a1c0, 0x00000000}, - {0x0000a1c4, 0x00000000}, - {0x0000a1c8, 0x00000000}, - {0x0000a1cc, 0x00000000}, - {0x0000a1d0, 0x00000000}, - {0x0000a1d4, 0x00000000}, - {0x0000a1d8, 0x00000000}, - {0x0000a1dc, 0x00000000}, - {0x0000a1e0, 0x00000000}, - {0x0000a1e4, 0x00000000}, - {0x0000a1e8, 0x00000000}, - {0x0000a1ec, 0x00000000}, - {0x0000a1f0, 0x00000396}, - {0x0000a1f4, 0x00000396}, - {0x0000a1f8, 0x00000396}, - {0x0000a1fc, 0x00000196}, - {0x0000b000, 0x00010000}, - {0x0000b004, 0x00030002}, - {0x0000b008, 0x00050004}, - {0x0000b00c, 0x00810080}, - {0x0000b010, 0x00830082}, - {0x0000b014, 0x01810180}, - {0x0000b018, 0x01830182}, - {0x0000b01c, 0x01850184}, - {0x0000b020, 0x02810280}, - {0x0000b024, 0x02830282}, - {0x0000b028, 0x02850284}, - {0x0000b02c, 0x02890288}, - {0x0000b030, 0x028b028a}, - {0x0000b034, 0x0388028c}, - {0x0000b038, 0x038a0389}, - {0x0000b03c, 0x038c038b}, - {0x0000b040, 0x0390038d}, - {0x0000b044, 0x03920391}, - {0x0000b048, 0x03940393}, - {0x0000b04c, 0x03960395}, - {0x0000b050, 0x00000000}, - {0x0000b054, 0x00000000}, - {0x0000b058, 0x00000000}, - {0x0000b05c, 0x00000000}, - {0x0000b060, 0x00000000}, - {0x0000b064, 0x00000000}, - {0x0000b068, 0x00000000}, - {0x0000b06c, 0x00000000}, - {0x0000b070, 0x00000000}, - {0x0000b074, 0x00000000}, - {0x0000b078, 0x00000000}, - {0x0000b07c, 0x00000000}, - {0x0000b080, 0x23232323}, - {0x0000b084, 0x21232323}, - {0x0000b088, 0x19191c1e}, - {0x0000b08c, 0x12141417}, - {0x0000b090, 0x07070e0e}, - {0x0000b094, 0x03030305}, - {0x0000b098, 0x00000003}, - {0x0000b09c, 0x00000000}, - {0x0000b0a0, 0x00000000}, - {0x0000b0a4, 0x00000000}, - {0x0000b0a8, 0x00000000}, - {0x0000b0ac, 0x00000000}, - {0x0000b0b0, 0x00000000}, - {0x0000b0b4, 0x00000000}, - {0x0000b0b8, 0x00000000}, - {0x0000b0bc, 0x00000000}, - {0x0000b0c0, 0x003f0020}, - {0x0000b0c4, 0x00400041}, - {0x0000b0c8, 0x0140005f}, - {0x0000b0cc, 0x0160015f}, - {0x0000b0d0, 0x017e017f}, - {0x0000b0d4, 0x02410242}, - {0x0000b0d8, 0x025f0240}, - {0x0000b0dc, 0x027f0260}, - {0x0000b0e0, 0x0341027e}, - {0x0000b0e4, 0x035f0340}, - {0x0000b0e8, 0x037f0360}, - {0x0000b0ec, 0x04400441}, - {0x0000b0f0, 0x0460045f}, - {0x0000b0f4, 0x0541047f}, - {0x0000b0f8, 0x055f0540}, - {0x0000b0fc, 0x057f0560}, - {0x0000b100, 0x06400641}, - {0x0000b104, 0x0660065f}, - {0x0000b108, 0x067e067f}, - {0x0000b10c, 0x07410742}, - {0x0000b110, 0x075f0740}, - {0x0000b114, 0x077f0760}, - {0x0000b118, 0x07800781}, - {0x0000b11c, 0x07a0079f}, - {0x0000b120, 0x07c107bf}, - {0x0000b124, 0x000007c0}, - {0x0000b128, 0x00000000}, - {0x0000b12c, 0x00000000}, - {0x0000b130, 0x00000000}, - {0x0000b134, 0x00000000}, - {0x0000b138, 0x00000000}, - {0x0000b13c, 0x00000000}, - {0x0000b140, 0x003f0020}, - {0x0000b144, 0x00400041}, - {0x0000b148, 0x0140005f}, - {0x0000b14c, 0x0160015f}, - {0x0000b150, 0x017e017f}, - {0x0000b154, 0x02410242}, - {0x0000b158, 0x025f0240}, - {0x0000b15c, 0x027f0260}, - {0x0000b160, 0x0341027e}, - {0x0000b164, 0x035f0340}, - {0x0000b168, 0x037f0360}, - {0x0000b16c, 0x04400441}, - {0x0000b170, 0x0460045f}, - {0x0000b174, 0x0541047f}, - {0x0000b178, 0x055f0540}, - {0x0000b17c, 0x057f0560}, - {0x0000b180, 0x06400641}, - {0x0000b184, 0x0660065f}, - {0x0000b188, 0x067e067f}, - {0x0000b18c, 0x07410742}, - {0x0000b190, 0x075f0740}, - {0x0000b194, 0x077f0760}, - {0x0000b198, 0x07800781}, - {0x0000b19c, 0x07a0079f}, - {0x0000b1a0, 0x07c107bf}, - {0x0000b1a4, 0x000007c0}, - {0x0000b1a8, 0x00000000}, - {0x0000b1ac, 0x00000000}, - {0x0000b1b0, 0x00000000}, - {0x0000b1b4, 0x00000000}, - {0x0000b1b8, 0x00000000}, - {0x0000b1bc, 0x00000000}, - {0x0000b1c0, 0x00000000}, - {0x0000b1c4, 0x00000000}, - {0x0000b1c8, 0x00000000}, - {0x0000b1cc, 0x00000000}, - {0x0000b1d0, 0x00000000}, - {0x0000b1d4, 0x00000000}, - {0x0000b1d8, 0x00000000}, - {0x0000b1dc, 0x00000000}, - {0x0000b1e0, 0x00000000}, - {0x0000b1e4, 0x00000000}, - {0x0000b1e8, 0x00000000}, - {0x0000b1ec, 0x00000000}, - {0x0000b1f0, 0x00000396}, - {0x0000b1f4, 0x00000396}, - {0x0000b1f8, 0x00000396}, - {0x0000b1fc, 0x00000196}, -}; - static const u32 ar9340Modes_low_ob_db_tx_gain_table_1p0[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, @@ -1437,8 +1181,6 @@ static const u32 ar9340_1p0_mac_core[][2] = { {0x000083d0, 0x000101ff}, }; -#define ar9340Common_wo_xlna_rx_gain_table_1p0 ar9300Common_wo_xlna_rx_gain_table_2p2 - static const u32 ar9340_1p0_soc_preamble[][2] = { /* Addr allmodes */ {0x00007008, 0x00000000}, -- cgit v1.2.3-70-g09d2 From 2c8672c13a206fdf1df1f9c5c57f361a7d3f5594 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 2 Dec 2013 09:56:31 +0530 Subject: ath9k: Fix initvals for freq 2484 This is missing for AR9300, AR9580 and AR9340. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h | 7 +++++++ drivers/net/wireless/ath/ath9k/ar9003_hw.c | 12 +++++++++--- drivers/net/wireless/ath/ath9k/ar9340_initvals.h | 2 ++ drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h | 2 +- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h index 15533953e0a..e7cdf1100f5 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h @@ -1738,4 +1738,11 @@ static const u32 ar9300PciePhy_clkreq_disable_L1_2p2[][2] = { {0x00004044, 0x00000000}, }; +static const u32 ar9300_2p2_baseband_core_txfir_coeff_japan_2484[][2] = { + /* Addr allmodes */ + {0x0000a398, 0x00000000}, + {0x0000a39c, 0x6f7f0301}, + {0x0000a3a0, 0xca9228ee}, +}; + #endif /* INITVALS_9003_2P2_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index d3eca0cec9c..d8c1eee8ea5 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -149,7 +149,9 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ar9340Modes_high_ob_db_tx_gain_table_1p0); INIT_INI_ARRAY(&ah->iniModesFastClock, - ar9340Modes_fast_clock_1p0); + ar9340Modes_fast_clock_1p0); + INIT_INI_ARRAY(&ah->iniCckfirJapan2484, + ar9340_1p0_baseband_core_txfir_coeff_japan_2484); if (!ah->is_clk_25mhz) INIT_INI_ARRAY(&ah->iniAdditional, @@ -335,7 +337,9 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ar9580_1p0_low_ob_db_tx_gain_table); INIT_INI_ARRAY(&ah->iniModesFastClock, - ar9580_1p0_modes_fast_clock); + ar9580_1p0_modes_fast_clock); + INIT_INI_ARRAY(&ah->iniCckfirJapan2484, + ar9580_1p0_baseband_core_txfir_coeff_japan_2484); } else if (AR_SREV_9565_11_OR_LATER(ah)) { INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], ar9565_1p1_mac_core); @@ -451,7 +455,9 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) /* Fast clock modal settings */ INIT_INI_ARRAY(&ah->iniModesFastClock, - ar9300Modes_fast_clock_2p2); + ar9300Modes_fast_clock_2p2); + INIT_INI_ARRAY(&ah->iniCckfirJapan2484, + ar9300_2p2_baseband_core_txfir_coeff_japan_2484); } } diff --git a/drivers/net/wireless/ath/ath9k/ar9340_initvals.h b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h index d2d789bdb7f..7f22cb2a494 100644 --- a/drivers/net/wireless/ath/ath9k/ar9340_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h @@ -28,6 +28,8 @@ #define ar9340Common_wo_xlna_rx_gain_table_1p0 ar9300Common_wo_xlna_rx_gain_table_2p2 +#define ar9340_1p0_baseband_core_txfir_coeff_japan_2484 ar9300_2p2_baseband_core_txfir_coeff_japan_2484 + static const u32 ar9340_1p0_radio_postamble[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x000160ac, 0xa4646800, 0xa4646800, 0xa4646800, 0xa4646800}, diff --git a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h index 2ae380b70c0..75bef1179d0 100644 --- a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h @@ -36,7 +36,7 @@ #define ar9580_1p0_modes_fast_clock ar9300Modes_fast_clock_2p2 -#define ar9580_1p0_baseband_core_txfir_coeff_japan_2484 ar9462_2p0_baseband_core_txfir_coeff_japan_2484 +#define ar9580_1p0_baseband_core_txfir_coeff_japan_2484 ar9300_2p2_baseband_core_txfir_coeff_japan_2484 static const u32 ar9580_1p0_radio_postamble[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ -- cgit v1.2.3-70-g09d2 From 1e86d69662d7d86360624f74bbe1b5fa1b8ffb13 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Fri, 29 Nov 2013 11:48:13 +0100 Subject: brcmfmac: Update fwsignal to fix out of order tx. When using fwsignal it is possible that tx packets get delivered out of order. This patch fixes that by reordering suppressed packets and tracking generation bit and sequence number per packet. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c | 167 ++++++++++++++++++--- 1 file changed, 146 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c index d0cd0bf95c5..784cf94072e 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c @@ -105,6 +105,9 @@ static struct { }; #undef BRCMF_FWS_TLV_DEF +#define BRCMF_FWS_TYPE_SEQ_LEN 2 + + static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id) { int i; @@ -147,8 +150,15 @@ static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id) #define BRCMF_FWS_HTOD_FLAG_PKTFROMHOST 0x01 #define BRCMF_FWS_HTOD_FLAG_PKT_REQUESTED 0x02 -#define BRCMF_FWS_RET_OK_NOSCHEDULE 0 -#define BRCMF_FWS_RET_OK_SCHEDULE 1 +#define BRCMF_FWS_RET_OK_NOSCHEDULE 0 +#define BRCMF_FWS_RET_OK_SCHEDULE 1 + +#define BRCMF_FWS_MODE_REUSESEQ_SHIFT 3 /* seq reuse */ +#define BRCMF_FWS_MODE_SET_REUSESEQ(x, val) ((x) = \ + ((x) & ~(1 << BRCMF_FWS_MODE_REUSESEQ_SHIFT)) | \ + (((val) & 1) << BRCMF_FWS_MODE_REUSESEQ_SHIFT)) +#define BRCMF_FWS_MODE_GET_REUSESEQ(x) \ + (((x) >> BRCMF_FWS_MODE_REUSESEQ_SHIFT) & 1) /** * enum brcmf_fws_skb_state - indicates processing state of skb. @@ -171,6 +181,7 @@ enum brcmf_fws_skb_state { * @bus_flags: 2 bytes reserved for bus specific parameters * @if_flags: holds interface index and packet related flags. * @htod: host to device packet identifier (used in PKTTAG tlv). + * @htod_seq: this 16-bit is original seq number for every suppress packet. * @state: transmit state of the packet. * @mac: descriptor related to destination for this packet. * @@ -181,6 +192,7 @@ struct brcmf_skbuff_cb { u16 bus_flags; u16 if_flags; u32 htod; + u16 htod_seq; enum brcmf_fws_skb_state state; struct brcmf_fws_mac_descriptor *mac; }; @@ -257,6 +269,22 @@ struct brcmf_skbuff_cb { BRCMF_SKB_HTOD_TAG_ ## field ## _MASK, \ BRCMF_SKB_HTOD_TAG_ ## field ## _SHIFT) +#define BRCMF_SKB_HTOD_SEQ_FROMFW_MASK 0x2000 +#define BRCMF_SKB_HTOD_SEQ_FROMFW_SHIFT 13 +#define BRCMF_SKB_HTOD_SEQ_FROMDRV_MASK 0x1000 +#define BRCMF_SKB_HTOD_SEQ_FROMDRV_SHIFT 12 +#define BRCMF_SKB_HTOD_SEQ_NR_MASK 0x0fff +#define BRCMF_SKB_HTOD_SEQ_NR_SHIFT 0 + +#define brcmf_skb_htod_seq_set_field(skb, field, value) \ + brcmu_maskset16(&(brcmf_skbcb(skb)->htod_seq), \ + BRCMF_SKB_HTOD_SEQ_ ## field ## _MASK, \ + BRCMF_SKB_HTOD_SEQ_ ## field ## _SHIFT, (value)) +#define brcmf_skb_htod_seq_get_field(skb, field) \ + brcmu_maskget16(brcmf_skbcb(skb)->htod_seq, \ + BRCMF_SKB_HTOD_SEQ_ ## field ## _MASK, \ + BRCMF_SKB_HTOD_SEQ_ ## field ## _SHIFT) + #define BRCMF_FWS_TXSTAT_GENERATION_MASK 0x80000000 #define BRCMF_FWS_TXSTAT_GENERATION_SHIFT 31 #define BRCMF_FWS_TXSTAT_FLAGS_MASK 0x78000000 @@ -265,8 +293,8 @@ struct brcmf_skbuff_cb { #define BRCMF_FWS_TXSTAT_FIFO_SHIFT 24 #define BRCMF_FWS_TXSTAT_HSLOT_MASK 0x00FFFF00 #define BRCMF_FWS_TXSTAT_HSLOT_SHIFT 8 -#define BRCMF_FWS_TXSTAT_PKTID_MASK 0x00FFFFFF -#define BRCMF_FWS_TXSTAT_PKTID_SHIFT 0 +#define BRCMF_FWS_TXSTAT_FREERUN_MASK 0x000000FF +#define BRCMF_FWS_TXSTAT_FREERUN_SHIFT 0 #define brcmf_txstatus_get_field(txs, field) \ brcmu_maskget32(txs, BRCMF_FWS_TXSTAT_ ## field ## _MASK, \ @@ -443,6 +471,7 @@ struct brcmf_fws_info { unsigned long borrow_defer_timestamp; bool bus_flow_blocked; bool creditmap_received; + u8 mode; }; /* @@ -812,13 +841,16 @@ static int brcmf_fws_hdrpush(struct brcmf_fws_info *fws, struct sk_buff *skb) u16 data_offset = 0; u8 fillers; __le32 pkttag = cpu_to_le32(brcmf_skbcb(skb)->htod); + __le16 pktseq = cpu_to_le16(brcmf_skbcb(skb)->htod_seq); - brcmf_dbg(TRACE, "enter: %s, idx=%d pkttag=0x%08X, hslot=%d\n", + brcmf_dbg(TRACE, "enter: %s, idx=%d hslot=%d htod %X seq %X\n", entry->name, brcmf_skb_if_flags_get_field(skb, INDEX), - le32_to_cpu(pkttag), (le32_to_cpu(pkttag) >> 8) & 0xffff); + (le32_to_cpu(pkttag) >> 8) & 0xffff, + brcmf_skbcb(skb)->htod, brcmf_skbcb(skb)->htod_seq); if (entry->send_tim_signal) data_offset += 2 + BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN; - + if (BRCMF_FWS_MODE_GET_REUSESEQ(fws->mode)) + data_offset += BRCMF_FWS_TYPE_SEQ_LEN; /* +2 is for Type[1] and Len[1] in TLV, plus TIM signal */ data_offset += 2 + BRCMF_FWS_TYPE_PKTTAG_LEN; fillers = round_up(data_offset, 4) - data_offset; @@ -830,7 +862,12 @@ static int brcmf_fws_hdrpush(struct brcmf_fws_info *fws, struct sk_buff *skb) wlh[0] = BRCMF_FWS_TYPE_PKTTAG; wlh[1] = BRCMF_FWS_TYPE_PKTTAG_LEN; memcpy(&wlh[2], &pkttag, sizeof(pkttag)); - wlh += BRCMF_FWS_TYPE_PKTTAG_LEN + 2; + if (BRCMF_FWS_MODE_GET_REUSESEQ(fws->mode)) { + wlh[1] += BRCMF_FWS_TYPE_SEQ_LEN; + memcpy(&wlh[2 + BRCMF_FWS_TYPE_PKTTAG_LEN], &pktseq, + sizeof(pktseq)); + } + wlh += wlh[1] + 2; if (entry->send_tim_signal) { entry->send_tim_signal = 0; @@ -875,6 +912,7 @@ static bool brcmf_fws_tim_update(struct brcmf_fws_info *fws, /* create a dummy packet and sent that. The traffic */ /* bitmap info will automatically be attached to that packet */ len = BRCMF_FWS_TYPE_PKTTAG_LEN + 2 + + BRCMF_FWS_TYPE_SEQ_LEN + BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN + 2 + 4 + fws->drvr->hdrlen; skb = brcmu_pkt_buf_get_skb(len); @@ -884,6 +922,8 @@ static bool brcmf_fws_tim_update(struct brcmf_fws_info *fws, skcb = brcmf_skbcb(skb); skcb->mac = entry; skcb->state = BRCMF_FWS_SKBSTATE_TIM; + skcb->htod = 0; + skcb->htod_seq = 0; bus = fws->drvr->bus_if; err = brcmf_fws_hdrpush(fws, skb); if (err == 0) { @@ -1172,8 +1212,13 @@ static int brcmf_fws_enq(struct brcmf_fws_info *fws, { int prec = 2 * fifo; u32 *qfull_stat = &fws->stats.delayq_full_error; - struct brcmf_fws_mac_descriptor *entry; + struct pktq *pq; + struct sk_buff_head *queue; + struct sk_buff *p_head; + struct sk_buff *p_tail; + u32 fr_new; + u32 fr_compare; entry = brcmf_skbcb(p)->mac; if (entry == NULL) { @@ -1185,9 +1230,55 @@ static int brcmf_fws_enq(struct brcmf_fws_info *fws, if (state == BRCMF_FWS_SKBSTATE_SUPPRESSED) { prec += 1; qfull_stat = &fws->stats.supprq_full_error; - } - if (brcmu_pktq_penq(&entry->psq, prec, p) == NULL) { + /* Fix out of order delivery of frames. Dont assume frame */ + /* can be inserted at the end, but look for correct position */ + pq = &entry->psq; + if (pktq_full(pq) || pktq_pfull(pq, prec)) { + *qfull_stat += 1; + return -ENFILE; + } + queue = &pq->q[prec].skblist; + + p_head = skb_peek(queue); + p_tail = skb_peek_tail(queue); + fr_new = brcmf_skb_htod_tag_get_field(p, FREERUN); + + while (p_head != p_tail) { + fr_compare = brcmf_skb_htod_tag_get_field(p_tail, + FREERUN); + /* be sure to handle wrap of 256 */ + if (((fr_new > fr_compare) && + ((fr_new - fr_compare) < 128)) || + ((fr_new < fr_compare) && + ((fr_compare - fr_new) > 128))) + break; + p_tail = skb_queue_prev(queue, p_tail); + } + /* Position found. Determine what to do */ + if (p_tail == NULL) { + /* empty list */ + __skb_queue_tail(queue, p); + } else { + fr_compare = brcmf_skb_htod_tag_get_field(p_tail, + FREERUN); + if (((fr_new > fr_compare) && + ((fr_new - fr_compare) < 128)) || + ((fr_new < fr_compare) && + ((fr_compare - fr_new) > 128))) { + /* After tail */ + __skb_queue_after(queue, p_tail, p); + } else { + /* Before tail */ + __skb_insert(p, p_tail->prev, p_tail, queue); + } + } + + /* Complete the counters and statistics */ + pq->len++; + if (pq->hi_prec < prec) + pq->hi_prec = (u8) prec; + } else if (brcmu_pktq_penq(&entry->psq, prec, p) == NULL) { *qfull_stat += 1; return -ENFILE; } @@ -1277,7 +1368,8 @@ done: } static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo, - struct sk_buff *skb, u32 genbit) + struct sk_buff *skb, u32 genbit, + u16 seq) { struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac; u32 hslot; @@ -1298,6 +1390,14 @@ static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo, ret = brcmf_proto_hdrpull(fws->drvr, false, &ifidx, skb); if (ret == 0) + brcmf_skb_htod_tag_set_field(skb, GENERATION, genbit); + brcmf_skbcb(skb)->htod_seq = seq; + if (brcmf_skb_htod_seq_get_field(skb, FROMFW)) { + brcmf_skb_htod_seq_set_field(skb, FROMDRV, 1); + brcmf_skb_htod_seq_set_field(skb, FROMFW, 0); + } else { + brcmf_skb_htod_seq_set_field(skb, FROMDRV, 0); + } ret = brcmf_fws_enq(fws, BRCMF_FWS_SKBSTATE_SUPPRESSED, fifo, skb); if (ret != 0) { @@ -1317,7 +1417,7 @@ static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo, static int brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot, - u32 genbit) + u32 genbit, u16 seq) { u32 fifo; int ret; @@ -1360,8 +1460,8 @@ brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot, if (entry->suppressed && entry->suppr_transit_count) entry->suppr_transit_count--; - brcmf_dbg(DATA, "%s flags %X htod %X\n", entry->name, skcb->if_flags, - skcb->htod); + brcmf_dbg(DATA, "%s flags %d htod %X seq %X\n", entry->name, flags, + skcb->htod, seq); /* pick up the implicit credit from this packet */ fifo = brcmf_skb_htod_tag_get_field(skb, FIFO); @@ -1374,7 +1474,8 @@ brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot, brcmf_fws_macdesc_return_req_credit(skb); if (!remove_from_hanger) - ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, genbit); + ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, genbit, + seq); if (remove_from_hanger || ret) brcmf_txfinalize(fws->drvr, skb, true); @@ -1406,10 +1507,12 @@ static int brcmf_fws_fifocreditback_indicate(struct brcmf_fws_info *fws, static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data) { __le32 status_le; + __le16 seq_le; u32 status; u32 hslot; u32 genbit; u8 flags; + u16 seq; fws->stats.txs_indicate++; memcpy(&status_le, data, sizeof(status_le)); @@ -1417,9 +1520,16 @@ static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data) flags = brcmf_txstatus_get_field(status, FLAGS); hslot = brcmf_txstatus_get_field(status, HSLOT); genbit = brcmf_txstatus_get_field(status, GENERATION); + if (BRCMF_FWS_MODE_GET_REUSESEQ(fws->mode)) { + memcpy(&seq_le, &data[BRCMF_FWS_TYPE_PKTTAG_LEN], + sizeof(seq_le)); + seq = le16_to_cpu(seq_le); + } else { + seq = 0; + } brcmf_fws_lock(fws); - brcmf_fws_txs_process(fws, flags, hslot, genbit); + brcmf_fws_txs_process(fws, flags, hslot, genbit, seq); brcmf_fws_unlock(fws); return BRCMF_FWS_RET_OK_NOSCHEDULE; } @@ -1610,8 +1720,8 @@ static void brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo, struct brcmf_fws_mac_descriptor *entry = skcb->mac; u8 flags; - brcmf_skb_if_flags_set_field(p, TRANSMIT, 1); - brcmf_skb_htod_tag_set_field(p, GENERATION, entry->generation); + if (skcb->state != BRCMF_FWS_SKBSTATE_SUPPRESSED) + brcmf_skb_htod_tag_set_field(p, GENERATION, entry->generation); flags = BRCMF_FWS_HTOD_FLAG_PKTFROMHOST; if (brcmf_skb_if_flags_get_field(p, REQUESTED)) { /* @@ -1652,7 +1762,7 @@ static void brcmf_fws_rollback_toq(struct brcmf_fws_info *fws, fws->stats.rollback_failed++; hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT); brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED, - hslot, 0); + hslot, 0, 0); } else { fws->stats.rollback_success++; brcmf_fws_return_credits(fws, fifo, 1); @@ -1732,6 +1842,8 @@ static int brcmf_fws_assign_htod(struct brcmf_fws_info *fws, struct sk_buff *p, struct brcmf_skbuff_cb *skcb = brcmf_skbcb(p); int rc, hslot; + skcb->htod = 0; + skcb->htod_seq = 0; hslot = brcmf_fws_hanger_get_free_slot(&fws->hanger); brcmf_skb_htod_tag_set_field(p, HSLOT, hslot); brcmf_skb_htod_tag_set_field(p, FREERUN, skcb->mac->seq[fifo]); @@ -1908,6 +2020,7 @@ int brcmf_fws_init(struct brcmf_pub *drvr) struct brcmf_fws_info *fws; u32 tlv = BRCMF_FWS_FLAGS_RSSI_SIGNALS; int rc; + u32 mode; drvr->fws = kzalloc(sizeof(*(drvr->fws)), GFP_KERNEL); if (!drvr->fws) { @@ -1966,6 +2079,18 @@ int brcmf_fws_init(struct brcmf_pub *drvr) if (brcmf_fil_iovar_int_set(drvr->iflist[0], "ampdu_hostreorder", 1)) brcmf_dbg(INFO, "enabling AMPDU host-reorder failed\n"); + /* Enable seq number reuse, if supported */ + if (brcmf_fil_iovar_int_get(drvr->iflist[0], "wlfc_mode", &mode) == 0) { + if (BRCMF_FWS_MODE_GET_REUSESEQ(mode)) { + mode = 0; + BRCMF_FWS_MODE_SET_REUSESEQ(mode, 1); + if (brcmf_fil_iovar_int_set(drvr->iflist[0], + "wlfc_mode", mode) == 0) { + BRCMF_FWS_MODE_SET_REUSESEQ(fws->mode, 1); + } + } + } + brcmf_fws_hanger_init(&fws->hanger); brcmf_fws_macdesc_init(&fws->desc.other, NULL, 0); brcmf_fws_macdesc_set_name(fws, &fws->desc.other); @@ -2022,7 +2147,7 @@ void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb) } brcmf_fws_lock(fws); hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT); - brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED, hslot, 0); + brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED, hslot, 0, 0); brcmf_fws_unlock(fws); } -- cgit v1.2.3-70-g09d2 From 8dee77bab2eda24b48bfb8aecf5ac1370e424416 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Fri, 29 Nov 2013 11:48:14 +0100 Subject: brcmfmac: add separate function for passing bus tx overhead The common driver needs the packet overhead for the bus in order to reserve headroom for sk_buffs. For the SDIO driver this depends on firmware features so it is not possible to provide it in the brcmf_attach() call. Reviewed-by: Franky Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h | 3 ++- drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c | 14 ++++++++++++-- drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 4 +++- drivers/net/wireless/brcm80211/brcmfmac/usb.c | 4 ++-- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h index a6eb09e5d46..a129d21498f 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h @@ -139,7 +139,7 @@ bool brcmf_c_prec_enq(struct device *dev, struct pktq *q, struct sk_buff *pkt, void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp); /* Indication from bus module regarding presence/insertion of dongle. */ -int brcmf_attach(uint bus_hdrlen, struct device *dev); +int brcmf_attach(struct device *dev); /* Indication from bus module regarding removal/absence of dongle */ void brcmf_detach(struct device *dev); /* Indication from bus module that dongle should be reset */ @@ -151,6 +151,7 @@ void brcmf_txflowblock(struct device *dev, bool state); void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success); int brcmf_bus_start(struct device *dev); +void brcmf_bus_add_txhdrlen(struct device *dev, uint len); #ifdef CONFIG_BRCMFMAC_SDIO void brcmf_sdio_exit(void); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index 64e9cff241b..0c4c2306647 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -1016,7 +1016,7 @@ void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx) } } -int brcmf_attach(uint bus_hdrlen, struct device *dev) +int brcmf_attach(struct device *dev) { struct brcmf_pub *drvr = NULL; int ret = 0; @@ -1031,7 +1031,7 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev) mutex_init(&drvr->proto_block); /* Link to bus module */ - drvr->hdrlen = bus_hdrlen; + drvr->hdrlen = 0; drvr->bus_if = dev_get_drvdata(dev); drvr->bus_if->drvr = drvr; @@ -1138,6 +1138,16 @@ fail: return 0; } +void brcmf_bus_add_txhdrlen(struct device *dev, uint len) +{ + struct brcmf_bus *bus_if = dev_get_drvdata(dev); + struct brcmf_pub *drvr = bus_if->drvr; + + if (drvr) { + drvr->hdrlen += len; + } +} + static void brcmf_bus_detach(struct brcmf_pub *drvr) { brcmf_dbg(TRACE, "Enter\n"); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index b02953c4ade..928983be800 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -3983,7 +3983,7 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) bus->tx_hdrlen = SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN; /* Attach to the common layer, reserve hdr space */ - ret = brcmf_attach(bus->tx_hdrlen, bus->sdiodev->dev); + ret = brcmf_attach(bus->sdiodev->dev); if (ret != 0) { brcmf_err("brcmf_attach failed\n"); goto fail; @@ -4027,6 +4027,8 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) list_add(&dlst->list, &bus->sdiodev->bus_if->dcmd_list); } + brcmf_bus_add_txhdrlen(bus->sdiodev->dev, bus->tx_hdrlen); + /* if firmware path present try to download and bring up bus */ ret = brcmf_bus_start(bus->sdiodev->dev); if (ret != 0) { diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c index 422f44c6317..51c4de054b1 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c @@ -1255,7 +1255,7 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo) bus->chiprev = bus_pub->chiprev; /* Attach to the common driver interface */ - ret = brcmf_attach(0, dev); + ret = brcmf_attach(dev); if (ret) { brcmf_err("brcmf_attach failed\n"); goto fail; @@ -1454,7 +1454,7 @@ static int brcmf_usb_resume(struct usb_interface *intf) struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev); brcmf_dbg(USB, "Enter\n"); - if (!brcmf_attach(0, devinfo->dev)) + if (!brcmf_attach(devinfo->dev)) return brcmf_bus_start(&usb->dev); return 0; -- cgit v1.2.3-70-g09d2 From cf4582875a77c13adf8fec79b8ab3896d2b38e97 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Fri, 29 Nov 2013 11:48:15 +0100 Subject: brcmfmac: replace dongle command list with .preinit() callback The bus-specific interface allowed a list of dongle commands to be provided to the common driver part. However, upcoming functionality requires a more dynamic behaviour. Hence the list is replaced by a new callback function so the bus-specific driver part can implement this behaviour. Reviewed-by: Franky Lin Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h | 12 ++++- .../net/wireless/brcm80211/brcmfmac/dhd_common.c | 15 +----- .../net/wireless/brcm80211/brcmfmac/dhd_linux.c | 10 +++- drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 58 +++++++++++----------- 4 files changed, 51 insertions(+), 44 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h index a129d21498f..6a54905528b 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h @@ -34,6 +34,7 @@ struct brcmf_bus_dcmd { /** * struct brcmf_bus_ops - bus callback operations. * + * @preinit: execute bus/device specific dongle init commands (optional). * @init: prepare for communication with dongle. * @stop: clear pending frames, disable data flow. * @txdata: send a data frame to the dongle. When the data @@ -51,6 +52,7 @@ struct brcmf_bus_dcmd { * indicated otherwise these callbacks are mandatory. */ struct brcmf_bus_ops { + int (*preinit)(struct device *dev); int (*init)(struct device *dev); void (*stop)(struct device *dev); int (*txdata)(struct device *dev, struct sk_buff *skb); @@ -85,7 +87,6 @@ struct brcmf_bus { unsigned long tx_realloc; u32 chip; u32 chiprev; - struct list_head dcmd_list; struct brcmf_bus_ops *ops; }; @@ -93,6 +94,13 @@ struct brcmf_bus { /* * callback wrappers */ +static inline int brcmf_bus_preinit(struct brcmf_bus *bus) +{ + if (!bus->ops->preinit) + return 0; + return bus->ops->preinit(bus->dev); +} + static inline int brcmf_bus_init(struct brcmf_bus *bus) { return bus->ops->init(bus->dev); @@ -151,6 +159,8 @@ void brcmf_txflowblock(struct device *dev, bool state); void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success); int brcmf_bus_start(struct device *dev); +s32 brcmf_iovar_data_set(struct device *dev, char *name, void *data, + u32 len); void brcmf_bus_add_txhdrlen(struct device *dev, uint len); #ifdef CONFIG_BRCMFMAC_SDIO diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c index 9431af2465f..5c0c9191b79 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c @@ -257,8 +257,6 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) u8 buf[BRCMF_DCMD_SMLEN]; char *ptr; s32 err; - struct brcmf_bus_dcmd *cmdlst; - struct list_head *cur, *q; /* retreive mac address */ err = brcmf_fil_iovar_data_get(ifp, "cur_etheraddr", ifp->mac_addr, @@ -342,17 +340,8 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) brcmf_c_pktfilter_offload_enable(ifp, BRCMF_DEFAULT_PACKET_FILTER, 0, true); - /* set bus specific command if there is any */ - list_for_each_safe(cur, q, &ifp->drvr->bus_if->dcmd_list) { - cmdlst = list_entry(cur, struct brcmf_bus_dcmd, list); - if (cmdlst->name && cmdlst->param && cmdlst->param_len) { - brcmf_fil_iovar_data_set(ifp, cmdlst->name, - cmdlst->param, - cmdlst->param_len); - } - list_del(cur); - kfree(cmdlst); - } + /* do bus specific preinit here */ + err = brcmf_bus_preinit(ifp->drvr->bus_if); done: return err; } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index 0c4c2306647..ab207e22e51 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -1048,8 +1048,6 @@ int brcmf_attach(struct device *dev) /* attach firmware event handler */ brcmf_fweh_attach(drvr); - INIT_LIST_HEAD(&drvr->bus_if->dcmd_list); - return ret; fail: @@ -1206,6 +1204,14 @@ void brcmf_detach(struct device *dev) kfree(drvr); } +s32 brcmf_iovar_data_set(struct device *dev, char *name, void *data, u32 len) +{ + struct brcmf_bus *bus_if = dev_get_drvdata(dev); + struct brcmf_if *ifp = bus_if->drvr->iflist[0]; + + return brcmf_fil_iovar_data_set(ifp, name, data, len); +} + static int brcmf_get_pend_8021x_cnt(struct brcmf_if *ifp) { return atomic_read(&ifp->pend_8021x_cnt); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 928983be800..2597a534e69 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -3425,6 +3425,35 @@ brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus) return ret; } +static int brcmf_sdbrcm_bus_preinit(struct device *dev) +{ + struct brcmf_bus *bus_if = dev_get_drvdata(dev); + struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; + struct brcmf_sdio *bus = sdiodev->bus; + u32 value; + u8 idx; + int err; + + /* sdio bus core specific dcmd */ + idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV); + if (bus->ci->c_inf[idx].rev < 12) { + /* for sdio core rev < 12, disable txgloming */ + value = 0; + err = brcmf_iovar_data_set(dev, "bus:txglom", &value, + sizeof(u32)); + } else { + /* otherwise, set txglomalign */ + value = 4; + if (sdiodev->pdata) + value = sdiodev->pdata->sd_sgentry_align; + /* SDIO ADMA requires at least 32 bit alignment */ + value = max_t(u32, value, 4); + err = brcmf_iovar_data_set(dev, "bus:txglomalign", &value, + sizeof(u32)); + } + return err; +} + static int brcmf_sdbrcm_bus_init(struct device *dev) { struct brcmf_bus *bus_if = dev_get_drvdata(dev); @@ -3905,6 +3934,7 @@ static void brcmf_sdbrcm_release(struct brcmf_sdio *bus) static struct brcmf_bus_ops brcmf_sdio_bus_ops = { .stop = brcmf_sdbrcm_bus_stop, + .preinit = brcmf_sdbrcm_bus_preinit, .init = brcmf_sdbrcm_bus_init, .txdata = brcmf_sdbrcm_bus_txdata, .txctl = brcmf_sdbrcm_bus_txctl, @@ -3916,10 +3946,6 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) { int ret; struct brcmf_sdio *bus; - struct brcmf_bus_dcmd *dlst; - u32 dngl_txglom; - u32 txglomalign = 0; - u8 idx; brcmf_dbg(TRACE, "Enter\n"); @@ -4003,30 +4029,6 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) brcmf_sdio_debugfs_create(bus); brcmf_dbg(INFO, "completed!!\n"); - /* sdio bus core specific dcmd */ - idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV); - dlst = kzalloc(sizeof(struct brcmf_bus_dcmd), GFP_KERNEL); - if (dlst) { - if (bus->ci->c_inf[idx].rev < 12) { - /* for sdio core rev < 12, disable txgloming */ - dngl_txglom = 0; - dlst->name = "bus:txglom"; - dlst->param = (char *)&dngl_txglom; - dlst->param_len = sizeof(u32); - } else { - /* otherwise, set txglomalign */ - if (sdiodev->pdata) - txglomalign = sdiodev->pdata->sd_sgentry_align; - /* SDIO ADMA requires at least 32 bit alignment */ - if (txglomalign < 4) - txglomalign = 4; - dlst->name = "bus:txglomalign"; - dlst->param = (char *)&txglomalign; - dlst->param_len = sizeof(u32); - } - list_add(&dlst->list, &bus->sdiodev->bus_if->dcmd_list); - } - brcmf_bus_add_txhdrlen(bus->sdiodev->dev, bus->tx_hdrlen); /* if firmware path present try to download and bring up bus */ -- cgit v1.2.3-70-g09d2 From dcede4b8767dc4b12ce6324ac772776ae9f28569 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Fri, 29 Nov 2013 11:48:16 +0100 Subject: brcmfmac: start netif queues only when setup is completed successful Moving the call to netif_start_queue() after brcmf_cfg80211_up() is completed successful. If not return -EIO instead of -1 as that results in 'Operation not permitted' which can put user on wrong track. Reviewed-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index ab207e22e51..f4eeaa1b731 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -769,7 +769,6 @@ static int brcmf_netdev_open(struct net_device *ndev) struct brcmf_pub *drvr = ifp->drvr; struct brcmf_bus *bus_if = drvr->bus_if; u32 toe_ol; - s32 ret = 0; brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); @@ -788,14 +787,14 @@ static int brcmf_netdev_open(struct net_device *ndev) else ndev->features &= ~NETIF_F_IP_CSUM; - /* Allow transmit calls */ - netif_start_queue(ndev); if (brcmf_cfg80211_up(ndev)) { brcmf_err("failed to bring up cfg80211\n"); - return -1; + return -EIO; } - return ret; + /* Allow transmit calls */ + netif_start_queue(ndev); + return 0; } static const struct net_device_ops brcmf_netdev_ops_pri = { -- cgit v1.2.3-70-g09d2 From 15265f95c2020940350b2febbc513cbbeae0f77e Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Fri, 29 Nov 2013 11:48:17 +0100 Subject: brcmfmac: remove empty brcmf_proto_stop remove empty brcmf_proto_stop from protocol layer Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Arend Van Spriel Reviewed-by: Hante Meuleman Signed-off-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c | 5 ----- drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c | 3 --- drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h | 3 --- 3 files changed, 11 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c index dd85401063c..42aaf104cc4 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c @@ -385,8 +385,3 @@ void brcmf_proto_detach(struct brcmf_pub *drvr) kfree(drvr->prot); drvr->prot = NULL; } - -void brcmf_proto_stop(struct brcmf_pub *drvr) -{ - /* Nothing to do for CDC */ -} diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index f4eeaa1b731..c34ca703d2a 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -1150,9 +1150,6 @@ static void brcmf_bus_detach(struct brcmf_pub *drvr) brcmf_dbg(TRACE, "Enter\n"); if (drvr) { - /* Stop the protocol module */ - brcmf_proto_stop(drvr); - /* Stop the bus module */ brcmf_bus_stop(drvr->bus_if); } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h index 53c6e710f2c..d633362a52d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h @@ -27,9 +27,6 @@ int brcmf_proto_attach(struct brcmf_pub *drvr); /* Unlink, frees allocated protocol memory (including brcmf_proto) */ void brcmf_proto_detach(struct brcmf_pub *drvr); -/* Stop protocol: sync w/dongle state. */ -void brcmf_proto_stop(struct brcmf_pub *drvr); - /* Add any protocol-specific data header. * Caller must reserve prot_hdrlen prepend space. */ -- cgit v1.2.3-70-g09d2 From b317d1d543fbafd768525db6fbc11ca4af9c921b Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Fri, 29 Nov 2013 11:48:18 +0100 Subject: brcmfmac: reduce logging noise accessing SDIO SleepCSR register The SleepCSR register is accessed to wakeup the device from the host side. Depending on the state of the device this may take multiple attempts. The failed attempt are not real failures so reduce the log level specifically for this register. The calling function will scream when the multiple attempts all failed. Reviewed-by: Hante Meuleman Reviewed-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- .../net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c index 905704e335d..009d2a021b8 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c @@ -156,10 +156,21 @@ int brcmf_sdioh_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw, uint func, } } - if (err_ret) - brcmf_err("Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n", - rw ? "write" : "read", func, regaddr, *byte, err_ret); - + if (err_ret) { + /* + * SleepCSR register access can fail when + * waking up the device so reduce this noise + * in the logs. + */ + if (regaddr != SBSDIO_FUNC1_SLEEPCSR) + brcmf_err("Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n", + rw ? "write" : "read", func, regaddr, *byte, + err_ret); + else + brcmf_dbg(SDIO, "Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n", + rw ? "write" : "read", func, regaddr, *byte, + err_ret); + } return err_ret; } -- cgit v1.2.3-70-g09d2 From 89eda3640cd4dfc00971406fb5ba2d614f61ac29 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Fri, 29 Nov 2013 11:48:19 +0100 Subject: brcmsmac: select CONFIG_BCMA when possible The brcmsmac relies BCMA functionality to access the device. This patch selects CONFIG_BCMA when CONFIG_BCMA_POSSIBLE is set. This way the user does not need to be select BCMA to make the brcmsmac driver show up in his menuconfig. Reported-by: Dan Carpenter Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/brcm80211/Kconfig b/drivers/net/wireless/brcm80211/Kconfig index b00a7e92225..d9d85e93d09 100644 --- a/drivers/net/wireless/brcm80211/Kconfig +++ b/drivers/net/wireless/brcm80211/Kconfig @@ -4,7 +4,8 @@ config BRCMUTIL config BRCMSMAC tristate "Broadcom IEEE802.11n PCIe SoftMAC WLAN driver" depends on MAC80211 - depends on BCMA + depends on BCMA_POSSIBLE + select BCMA select BRCMUTIL select FW_LOADER select CRC_CCITT -- cgit v1.2.3-70-g09d2 From 4b776961a0d2099c684f4c2256896cb64e4fa9e7 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Fri, 29 Nov 2013 12:25:06 +0100 Subject: brcmfmac: support hardware extension header in trace_brcmf_sdpcm_hdr() The SDPCM header can be traced, but it used a fixed header size. With txglom feature the SDPCM header will have additional 8 bytes of hardware extension header so SDIO core can properly handle the txglom packet. Reviewed-by: Franky Lin Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 4 +-- .../net/wireless/brcm80211/brcmfmac/tracepoint.h | 29 +++++++++++++++------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 2597a534e69..510ab184efb 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -1147,7 +1147,7 @@ static int brcmf_sdio_hdparse(struct brcmf_sdio *bus, u8 *header, u8 rx_seq, fc, tx_seq_max; u32 swheader; - trace_brcmf_sdpcm_hdr(false, header); + trace_brcmf_sdpcm_hdr(SDPCM_RX, header); /* hw header */ len = get_unaligned_le16(header); @@ -1271,7 +1271,7 @@ static void brcmf_sdio_hdpack(struct brcmf_sdio *bus, u8 *header, SDPCM_DOFFSET_MASK; *(((__le32 *)header) + 1) = cpu_to_le32(sw_header); *(((__le32 *)header) + 2) = 0; - trace_brcmf_sdpcm_hdr(true, header); + trace_brcmf_sdpcm_hdr(SDPCM_TX, header); } static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/tracepoint.h b/drivers/net/wireless/brcm80211/brcmfmac/tracepoint.h index 3c67529b907..d229cda98aa 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/tracepoint.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/tracepoint.h @@ -110,21 +110,32 @@ TRACE_EVENT(brcmf_bdchdr, TP_printk("bdc: prio=%d siglen=%d", __entry->prio, __entry->siglen) ); +#ifndef SDPCM_RX +#define SDPCM_RX 0 +#endif +#ifndef SDPCM_TX +#define SDPCM_TX 1 +#endif +#ifndef SDPCM_GLOM +#define SDPCM_GLOM 2 +#endif + TRACE_EVENT(brcmf_sdpcm_hdr, - TP_PROTO(bool tx, void *data), - TP_ARGS(tx, data), + TP_PROTO(u8 dir, void *data), + TP_ARGS(dir, data), TP_STRUCT__entry( - __field(u8, tx) + __field(u8, dir) __field(u16, len) - __array(u8, hdr, 12) + __dynamic_array(u8, hdr, dir == SDPCM_GLOM ? 20 : 12) ), TP_fast_assign( - memcpy(__entry->hdr, data, 12); - __entry->len = __entry->hdr[0] | (__entry->hdr[1] << 8); - __entry->tx = tx ? 1 : 0; + memcpy(__get_dynamic_array(hdr), data, dir == SDPCM_GLOM ? 20 : 12); + __entry->len = *(u8 *)data | (*((u8 *)data + 1) << 8); + __entry->dir = dir; ), - TP_printk("sdpcm: %s len %u, seq %d", __entry->tx ? "TX" : "RX", - __entry->len, __entry->hdr[4]) + TP_printk("sdpcm: %s len %u, seq %d", + __entry->dir == SDPCM_RX ? "RX" : "TX", + __entry->len, ((u8 *)__get_dynamic_array(hdr))[4]) ); #ifdef CONFIG_BRCM_TRACING -- cgit v1.2.3-70-g09d2 From 2f5f817f1aceca10b9fb7eaf8a07b2a67f8ad15c Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Fri, 29 Nov 2013 12:25:07 +0100 Subject: brcmfmac: determine sd host controller related variable earlier The commit "eb9c174 brcmfmac: determine host controller related variables during probe" was not implemented correctly as the information is already needed in brcmf_sdbrcm_probe(). This patch moves it to brcmf_sdioh_attach() instead. Reviewed-by: Franky Lin Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- .../net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c | 32 ++++++++++++---------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c index 009d2a021b8..225493aec72 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c @@ -278,6 +278,9 @@ static int brcmf_sdioh_enablefuncs(struct brcmf_sdio_dev *sdiodev) int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev) { int err_ret = 0; + struct mmc_host *host; + struct sdio_func *func; + uint max_blocks; brcmf_dbg(SDIO, "\n"); @@ -299,6 +302,20 @@ int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev) brcmf_sdioh_enablefuncs(sdiodev); + /* + * determine host related variables after brcmf_sdio_probe() + * as func->cur_blksize is properly set and F2 init has been + * completed successfully. + */ + func = sdiodev->func[2]; + host = func->card->host; + sdiodev->sg_support = host->max_segs > 1; + max_blocks = min_t(uint, host->max_blk_count, 511u); + sdiodev->max_request_size = min_t(uint, host->max_req_size, + max_blocks * func->cur_blksize); + sdiodev->max_segment_count = min_t(uint, host->max_segs, + SG_MAX_SINGLE_ALLOC); + sdiodev->max_segment_size = host->max_seg_size; out: sdio_release_host(sdiodev->func[1]); brcmf_dbg(SDIO, "Done\n"); @@ -327,8 +344,6 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func, int err; struct brcmf_sdio_dev *sdiodev; struct brcmf_bus *bus_if; - struct mmc_host *host; - uint max_blocks; brcmf_dbg(SDIO, "Enter\n"); brcmf_dbg(SDIO, "Class=%x\n", func->class); @@ -376,19 +391,6 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func, goto fail; } - /* - * determine host related variables after brcmf_sdio_probe() - * as func->cur_blksize is properly set and F2 init has been - * completed successfully. - */ - host = func->card->host; - sdiodev->sg_support = host->max_segs > 1; - max_blocks = min_t(uint, host->max_blk_count, 511u); - sdiodev->max_request_size = min_t(uint, host->max_req_size, - max_blocks * func->cur_blksize); - sdiodev->max_segment_count = min_t(uint, host->max_segs, - SG_MAX_SINGLE_ALLOC); - sdiodev->max_segment_size = host->max_seg_size; brcmf_dbg(SDIO, "F2 init completed...\n"); return 0; -- cgit v1.2.3-70-g09d2 From 9a9e405f95b8c28a76cc0711a603bac7b71dd6b4 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Fri, 29 Nov 2013 12:25:08 +0100 Subject: brcmfmac: fix driver build issue when CONFIG_BRCMDBG is not set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When CONFIG_BRCMDBG is not set we get the following build issue: CC [M] drivers/net/wireless/brcm80211/brcmfmac/fwsignal.o drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c: In function ‘brcmf_fws_hdrpush’: drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c:852:18: error: ‘BRCMF_FWS_TYPE_SEQ_LEN’ undeclared The define BRCMF_FWS_TYPE_SEQ_LEN was introduced by: commit 6918f38e4ed4e0493a90a4331e0033bdfc806e00 Author: Hante Meuleman Date: Wed Oct 23 14:58:51 2013 +0200 brcmfmac: Update fwsignal to fix out of order tx. Unfortunately, it was put in conditional part of the source file under #ifdef DEBUG. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c index 784cf94072e..296dbf1d142 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c @@ -105,8 +105,6 @@ static struct { }; #undef BRCMF_FWS_TLV_DEF -#define BRCMF_FWS_TYPE_SEQ_LEN 2 - static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id) { @@ -125,6 +123,12 @@ static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id) } #endif /* DEBUG */ +/* + * The PKTTAG tlv has additional bytes when firmware-signalling + * mode has REUSESEQ flag set. + */ +#define BRCMF_FWS_TYPE_SEQ_LEN 2 + /* * flags used to enable tlv signalling from firmware. */ -- cgit v1.2.3-70-g09d2 From bed89b64bcbc73a078028f04f64bc955a87ec8ad Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Fri, 29 Nov 2013 12:25:09 +0100 Subject: brcmfmac: add firmware and nvram file name for bcm4339 Add firmware/nvram file name for bcm4339 so fmac can actually be functional with the chip. Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 510ab184efb..f017c92c731 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -499,6 +499,8 @@ enum brcmf_sdio_frmtype { #define BCM4334_NVRAM_NAME "brcm/brcmfmac4334-sdio.txt" #define BCM4335_FIRMWARE_NAME "brcm/brcmfmac4335-sdio.bin" #define BCM4335_NVRAM_NAME "brcm/brcmfmac4335-sdio.txt" +#define BCM4339_FIRMWARE_NAME "brcm/brcmfmac4339-sdio.bin" +#define BCM4339_NVRAM_NAME "brcm/brcmfmac4339-sdio.txt" MODULE_FIRMWARE(BCM43143_FIRMWARE_NAME); MODULE_FIRMWARE(BCM43143_NVRAM_NAME); @@ -514,6 +516,8 @@ MODULE_FIRMWARE(BCM4334_FIRMWARE_NAME); MODULE_FIRMWARE(BCM4334_NVRAM_NAME); MODULE_FIRMWARE(BCM4335_FIRMWARE_NAME); MODULE_FIRMWARE(BCM4335_NVRAM_NAME); +MODULE_FIRMWARE(BCM4339_FIRMWARE_NAME); +MODULE_FIRMWARE(BCM4339_NVRAM_NAME); struct brcmf_firmware_names { u32 chipid; @@ -537,7 +541,8 @@ static const struct brcmf_firmware_names brcmf_fwname_data[] = { { BCM4329_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4329) }, { BCM4330_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4330) }, { BCM4334_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4334) }, - { BCM4335_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4335) } + { BCM4335_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4335) }, + { BCM4339_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4339) } }; -- cgit v1.2.3-70-g09d2 From 8da9d2c86888257c7874687467e9519405aa87d5 Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Fri, 29 Nov 2013 12:25:10 +0100 Subject: brcmfmac: add host tx glomming support New WiFi full dongle supports receiving chained packets in one command through the SDIO bus. This patch adds the support on the host side to send chained packets. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 327 ++++++++++++++------- 1 file changed, 227 insertions(+), 100 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index f017c92c731..f5d3650659e 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -110,6 +111,8 @@ struct rte_console { #define BRCMF_TXBOUND 20 /* Default for max tx frames in one scheduling */ +#define BRCMF_DEFAULT_TXGLOM_SIZE 32 /* max tx frames in glom chain */ + #define BRCMF_TXMINMAX 1 /* Max tx frames if rx still pending */ #define MEMBLOCK 2048 /* Block size used for downloading @@ -360,6 +363,8 @@ struct brcmf_sdio_hdrinfo { u16 len_left; u16 len_nxtfrm; u8 dat_offset; + bool lastfrm; + u16 tail_pad; }; /* misc chip info needed by some of the routines */ @@ -455,6 +460,8 @@ struct brcmf_sdio { bool sleeping; /* SDIO bus sleeping */ u8 tx_hdrlen; /* sdio bus header length for tx packet */ + bool txglom; /* host tx glomming enable flag */ + struct sk_buff *txglom_sgpad; /* scatter-gather padding buffer */ }; /* clkstate */ @@ -479,6 +486,10 @@ static const uint max_roundup = 512; #define ALIGNMENT 4 +static int brcmf_sdio_txglomsz = BRCMF_DEFAULT_TXGLOM_SIZE; +module_param_named(txglomsz, brcmf_sdio_txglomsz, int, 0); +MODULE_PARM_DESC(txglomsz, "maximum tx packet chain size [SDIO]"); + enum brcmf_sdio_frmtype { BRCMF_SDIO_FT_NORMAL, BRCMF_SDIO_FT_SUPER, @@ -1102,10 +1113,18 @@ static void brcmf_sdbrcm_free_glom(struct brcmf_sdio *bus) * host and WiFi dongle which contains information needed for SDIO core and * firmware * - * It consists of 2 parts: hw header and software header + * It consists of 3 parts: hardware header, hardware extension header and + * software header * hardware header (frame tag) - 4 bytes * Byte 0~1: Frame length * Byte 2~3: Checksum, bit-wise inverse of frame length + * hardware extension header - 8 bytes + * Tx glom mode only, N/A for Rx or normal Tx + * Byte 0~1: Packet length excluding hw frame tag + * Byte 2: Reserved + * Byte 3: Frame flags, bit 0: last frame indication + * Byte 4~5: Reserved + * Byte 6~7: Tail padding length * software header - 8 bytes * Byte 0: Rx/Tx sequence number * Byte 1: 4 MSB Channel number, 4 LSB arbitrary flag @@ -1116,6 +1135,7 @@ static void brcmf_sdbrcm_free_glom(struct brcmf_sdio *bus) * Byte 6~7: Reserved */ #define SDPCM_HWHDR_LEN 4 +#define SDPCM_HWEXT_LEN 8 #define SDPCM_SWHDR_LEN 8 #define SDPCM_HDRLEN (SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN) /* software header */ @@ -1265,18 +1285,28 @@ static inline void brcmf_sdio_update_hwhdr(u8 *header, u16 frm_length) static void brcmf_sdio_hdpack(struct brcmf_sdio *bus, u8 *header, struct brcmf_sdio_hdrinfo *hd_info) { - u32 sw_header; + u32 hdrval; + u8 hdr_offset; brcmf_sdio_update_hwhdr(header, hd_info->len); - - sw_header = bus->tx_seq; - sw_header |= (hd_info->channel << SDPCM_CHANNEL_SHIFT) & - SDPCM_CHANNEL_MASK; - sw_header |= (hd_info->dat_offset << SDPCM_DOFFSET_SHIFT) & - SDPCM_DOFFSET_MASK; - *(((__le32 *)header) + 1) = cpu_to_le32(sw_header); - *(((__le32 *)header) + 2) = 0; - trace_brcmf_sdpcm_hdr(SDPCM_TX, header); + hdr_offset = SDPCM_HWHDR_LEN; + + if (bus->txglom) { + hdrval = (hd_info->len - hdr_offset) | (hd_info->lastfrm << 24); + *((__le32 *)(header + hdr_offset)) = cpu_to_le32(hdrval); + hdrval = (u16)hd_info->tail_pad << 16; + *(((__le32 *)(header + hdr_offset)) + 1) = cpu_to_le32(hdrval); + hdr_offset += SDPCM_HWEXT_LEN; + } + + hdrval = hd_info->seq_num; + hdrval |= (hd_info->channel << SDPCM_CHANNEL_SHIFT) & + SDPCM_CHANNEL_MASK; + hdrval |= (hd_info->dat_offset << SDPCM_DOFFSET_SHIFT) & + SDPCM_DOFFSET_MASK; + *((__le32 *)(header + hdr_offset)) = cpu_to_le32(hdrval); + *(((__le32 *)(header + hdr_offset)) + 1) = 0; + trace_brcmf_sdpcm_hdr(SDPCM_TX + !!(bus->txglom), header); } static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) @@ -1876,6 +1906,34 @@ brcmf_sdbrcm_wait_event_wakeup(struct brcmf_sdio *bus) return; } +static int brcmf_sdio_txpkt_hdalign(struct brcmf_sdio *bus, struct sk_buff *pkt) +{ + u16 head_align, head_pad; + u8 *dat_buf; + + /* SDIO ADMA requires at least 32 bit alignment */ + head_align = 4; + if (bus->sdiodev->pdata && bus->sdiodev->pdata->sd_head_align > 4) + head_align = bus->sdiodev->pdata->sd_head_align; + + dat_buf = (u8 *)(pkt->data); + + /* Check head padding */ + head_pad = ((unsigned long)dat_buf % head_align); + if (head_pad) { + if (skb_headroom(pkt) < head_pad) { + bus->sdiodev->bus_if->tx_realloc++; + head_pad = 0; + if (skb_cow(pkt, head_pad)) + return -ENOMEM; + } + skb_push(pkt, head_pad); + dat_buf = (u8 *)(pkt->data); + memset(dat_buf, 0, head_pad + bus->tx_hdrlen); + } + return head_pad; +} + /** * struct brcmf_skbuff_cb reserves first two bytes in sk_buff::cb for * bus layer usage. @@ -1885,16 +1943,18 @@ brcmf_sdbrcm_wait_event_wakeup(struct brcmf_sdio *bus) /* bit mask of data length chopped from the previous packet */ #define ALIGN_SKB_CHOP_LEN_MASK 0x7fff -static int brcmf_sdio_txpkt_prep_sg(struct brcmf_sdio_dev *sdiodev, +static int brcmf_sdio_txpkt_prep_sg(struct brcmf_sdio *bus, struct sk_buff_head *pktq, - struct sk_buff *pkt, uint chan) + struct sk_buff *pkt, u16 total_len) { + struct brcmf_sdio_dev *sdiodev; struct sk_buff *pkt_pad; - u16 tail_pad, tail_chop, sg_align; + u16 tail_pad, tail_chop, sg_align, chain_pad; unsigned int blksize; - u8 *dat_buf; - int ntail; + bool lastfrm; + int ntail, ret; + sdiodev = bus->sdiodev; blksize = sdiodev->func[SDIO_FUNC_2]->cur_blksize; sg_align = 4; if (sdiodev->pdata && sdiodev->pdata->sd_sgentry_align > 4) @@ -1903,14 +1963,23 @@ static int brcmf_sdio_txpkt_prep_sg(struct brcmf_sdio_dev *sdiodev, WARN_ON(blksize % sg_align); /* Check tail padding */ - pkt_pad = NULL; + lastfrm = skb_queue_is_last(pktq, pkt); + tail_pad = 0; tail_chop = pkt->len % sg_align; - tail_pad = sg_align - tail_chop; - tail_pad += blksize - (pkt->len + tail_pad) % blksize; + if (tail_chop) + tail_pad = sg_align - tail_chop; + chain_pad = (total_len + tail_pad) % blksize; + if (lastfrm && chain_pad) + tail_pad += blksize - chain_pad; if (skb_tailroom(pkt) < tail_pad && pkt->len > blksize) { - pkt_pad = brcmu_pkt_buf_get_skb(tail_pad + tail_chop); + pkt_pad = bus->txglom_sgpad; + if (pkt_pad == NULL) + brcmu_pkt_buf_get_skb(tail_pad + tail_chop); if (pkt_pad == NULL) return -ENOMEM; + ret = brcmf_sdio_txpkt_hdalign(bus, pkt_pad); + if (unlikely(ret < 0)) + return ret; memcpy(pkt_pad->data, pkt->data + pkt->len - tail_chop, tail_chop); @@ -1925,14 +1994,10 @@ static int brcmf_sdio_txpkt_prep_sg(struct brcmf_sdio_dev *sdiodev, return -ENOMEM; if (skb_linearize(pkt)) return -ENOMEM; - dat_buf = (u8 *)(pkt->data); __skb_put(pkt, tail_pad); } - if (pkt_pad) - return pkt->len + tail_chop; - else - return pkt->len - tail_pad; + return tail_pad; } /** @@ -1951,58 +2016,66 @@ static int brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq, uint chan) { - u16 head_pad, head_align; + u16 head_pad, total_len; struct sk_buff *pkt_next; - u8 *dat_buf; - int err; + u8 txseq; + int ret; struct brcmf_sdio_hdrinfo hd_info = {0}; - /* SDIO ADMA requires at least 32 bit alignment */ - head_align = 4; - if (bus->sdiodev->pdata && bus->sdiodev->pdata->sd_head_align > 4) - head_align = bus->sdiodev->pdata->sd_head_align; + txseq = bus->tx_seq; + total_len = 0; + skb_queue_walk(pktq, pkt_next) { + /* alignment packet inserted in previous + * loop cycle can be skipped as it is + * already properly aligned and does not + * need an sdpcm header. + */ + if (*(u32 *)(pkt_next->cb) & ALIGN_SKB_FLAG) + continue; - pkt_next = pktq->next; - dat_buf = (u8 *)(pkt_next->data); + /* align packet data pointer */ + ret = brcmf_sdio_txpkt_hdalign(bus, pkt_next); + if (ret < 0) + return ret; + head_pad = (u16)ret; + if (head_pad) + memset(pkt_next->data, 0, head_pad + bus->tx_hdrlen); - /* Check head padding */ - head_pad = ((unsigned long)dat_buf % head_align); - if (head_pad) { - if (skb_headroom(pkt_next) < head_pad) { - bus->sdiodev->bus_if->tx_realloc++; - head_pad = 0; - if (skb_cow(pkt_next, head_pad)) - return -ENOMEM; - } - skb_push(pkt_next, head_pad); - dat_buf = (u8 *)(pkt_next->data); - memset(dat_buf, 0, head_pad + bus->tx_hdrlen); - } + total_len += pkt_next->len; - if (bus->sdiodev->sg_support && pktq->qlen > 1) { - err = brcmf_sdio_txpkt_prep_sg(bus->sdiodev, pktq, - pkt_next, chan); - if (err < 0) - return err; - hd_info.len = (u16)err; - } else { hd_info.len = pkt_next->len; - } - - hd_info.channel = chan; - hd_info.dat_offset = head_pad + bus->tx_hdrlen; - - /* Now fill the header */ - brcmf_sdio_hdpack(bus, dat_buf, &hd_info); - - if (BRCMF_BYTES_ON() && - ((BRCMF_CTL_ON() && chan == SDPCM_CONTROL_CHANNEL) || - (BRCMF_DATA_ON() && chan != SDPCM_CONTROL_CHANNEL))) - brcmf_dbg_hex_dump(true, pkt_next, hd_info.len, "Tx Frame:\n"); - else if (BRCMF_HDRS_ON()) - brcmf_dbg_hex_dump(true, pkt_next, head_pad + bus->tx_hdrlen, - "Tx Header:\n"); + hd_info.lastfrm = skb_queue_is_last(pktq, pkt_next); + if (bus->txglom && pktq->qlen > 1) { + ret = brcmf_sdio_txpkt_prep_sg(bus, pktq, + pkt_next, total_len); + if (ret < 0) + return ret; + hd_info.tail_pad = (u16)ret; + total_len += (u16)ret; + } + hd_info.channel = chan; + hd_info.dat_offset = head_pad + bus->tx_hdrlen; + hd_info.seq_num = txseq++; + + /* Now fill the header */ + brcmf_sdio_hdpack(bus, pkt_next->data, &hd_info); + + if (BRCMF_BYTES_ON() && + ((BRCMF_CTL_ON() && chan == SDPCM_CONTROL_CHANNEL) || + (BRCMF_DATA_ON() && chan != SDPCM_CONTROL_CHANNEL))) + brcmf_dbg_hex_dump(true, pkt_next, hd_info.len, + "Tx Frame:\n"); + else if (BRCMF_HDRS_ON()) + brcmf_dbg_hex_dump(true, pkt_next, + head_pad + bus->tx_hdrlen, + "Tx Header:\n"); + } + /* Hardware length tag of the first packet should be total + * length of the chain (including padding) + */ + if (bus->txglom) + brcmf_sdio_update_hwhdr(pktq->next->data, total_len); return 0; } @@ -2020,6 +2093,7 @@ brcmf_sdio_txpkt_postp(struct brcmf_sdio *bus, struct sk_buff_head *pktq) { u8 *hdr; u32 dat_offset; + u16 tail_pad; u32 dummy_flags, chop_len; struct sk_buff *pkt_next, *tmp, *pkt_prev; @@ -2029,42 +2103,42 @@ brcmf_sdio_txpkt_postp(struct brcmf_sdio *bus, struct sk_buff_head *pktq) chop_len = dummy_flags & ALIGN_SKB_CHOP_LEN_MASK; if (chop_len) { pkt_prev = pkt_next->prev; - memcpy(pkt_prev->data + pkt_prev->len, - pkt_next->data, chop_len); skb_put(pkt_prev, chop_len); } __skb_unlink(pkt_next, pktq); brcmu_pkt_buf_free_skb(pkt_next); } else { - hdr = pkt_next->data + SDPCM_HWHDR_LEN; + hdr = pkt_next->data + bus->tx_hdrlen - SDPCM_SWHDR_LEN; dat_offset = le32_to_cpu(*(__le32 *)hdr); dat_offset = (dat_offset & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT; skb_pull(pkt_next, dat_offset); + if (bus->txglom) { + tail_pad = le16_to_cpu(*(__le16 *)(hdr - 2)); + skb_trim(pkt_next, pkt_next->len - tail_pad); + } } } } /* Writes a HW/SW header into the packet and sends it. */ /* Assumes: (a) header space already there, (b) caller holds lock */ -static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt, +static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff_head *pktq, uint chan) { int ret; int i; - struct sk_buff_head localq; + struct sk_buff *pkt_next, *tmp; brcmf_dbg(TRACE, "Enter\n"); - __skb_queue_head_init(&localq); - __skb_queue_tail(&localq, pkt); - ret = brcmf_sdio_txpkt_prep(bus, &localq, chan); + ret = brcmf_sdio_txpkt_prep(bus, pktq, chan); if (ret) goto done; sdio_claim_host(bus->sdiodev->func[1]); ret = brcmf_sdcard_send_pkt(bus->sdiodev, bus->sdiodev->sbwad, - SDIO_FUNC_2, F2SYNC, &localq); + SDIO_FUNC_2, F2SYNC, pktq); bus->sdcnt.f2txdata++; if (ret < 0) { @@ -2088,42 +2162,56 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt, if ((hi == 0) && (lo == 0)) break; } - } sdio_release_host(bus->sdiodev->func[1]); - if (ret == 0) - bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP; done: - brcmf_sdio_txpkt_postp(bus, &localq); - __skb_dequeue_tail(&localq); - brcmf_txcomplete(bus->sdiodev->dev, pkt, ret == 0); + brcmf_sdio_txpkt_postp(bus, pktq); + if (ret == 0) + bus->tx_seq = (bus->tx_seq + pktq->qlen) % SDPCM_SEQ_WRAP; + skb_queue_walk_safe(pktq, pkt_next, tmp) { + __skb_unlink(pkt_next, pktq); + brcmf_txcomplete(bus->sdiodev->dev, pkt_next, ret == 0); + } return ret; } static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes) { struct sk_buff *pkt; + struct sk_buff_head pktq; u32 intstatus = 0; - int ret = 0, prec_out; + int ret = 0, prec_out, i; uint cnt = 0; - u8 tx_prec_map; + u8 tx_prec_map, pkt_num; brcmf_dbg(TRACE, "Enter\n"); tx_prec_map = ~bus->flowcontrol; /* Send frames until the limit or some other event */ - for (cnt = 0; (cnt < maxframes) && data_ok(bus); cnt++) { + for (cnt = 0; (cnt < maxframes) && data_ok(bus);) { + pkt_num = 1; + __skb_queue_head_init(&pktq); + if (bus->txglom) + pkt_num = min_t(u8, bus->tx_max - bus->tx_seq, + brcmf_sdio_txglomsz); + pkt_num = min_t(u32, pkt_num, + brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol)); spin_lock_bh(&bus->txqlock); - pkt = brcmu_pktq_mdeq(&bus->txq, tx_prec_map, &prec_out); - if (pkt == NULL) { - spin_unlock_bh(&bus->txqlock); - break; + for (i = 0; i < pkt_num; i++) { + pkt = brcmu_pktq_mdeq(&bus->txq, tx_prec_map, + &prec_out); + if (pkt == NULL) + break; + __skb_queue_tail(&pktq, pkt); } spin_unlock_bh(&bus->txqlock); + if (i == 0) + break; - ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL); + ret = brcmf_sdbrcm_txpkt(bus, &pktq, SDPCM_DATA_CHANNEL); + cnt += i; /* In poll mode, need to check for other events */ if (!bus->intr && cnt) { @@ -2670,7 +2758,7 @@ static int brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) { u8 *frame; - u16 len; + u16 len, pad; uint retries = 0; u8 doff = 0; int ret = -1; @@ -2697,13 +2785,15 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) doff += bus->tx_hdrlen; /* Round send length to next SDIO block */ + pad = 0; if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { - u16 pad = bus->blocksize - (len % bus->blocksize); - if ((pad <= bus->roundup) && (pad < bus->blocksize)) - len += pad; + pad = bus->blocksize - (len % bus->blocksize); + if ((pad > bus->roundup) || (pad >= bus->blocksize)) + pad = 0; } else if (len % BRCMF_SDALIGN) { - len += BRCMF_SDALIGN - (len % BRCMF_SDALIGN); + pad = BRCMF_SDALIGN - (len % BRCMF_SDALIGN); } + len += pad; /* Satisfy length-alignment requirements */ if (len & (ALIGNMENT - 1)) @@ -2719,8 +2809,16 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) hd_info.len = (u16)msglen; hd_info.channel = SDPCM_CONTROL_CHANNEL; hd_info.dat_offset = doff; + hd_info.seq_num = bus->tx_seq; + if (bus->txglom) { + hd_info.lastfrm = true; + hd_info.tail_pad = pad; + } brcmf_sdio_hdpack(bus, frame, &hd_info); + if (bus->txglom) + brcmf_sdio_update_hwhdr(frame, len); + if (!data_ok(bus)) { brcmf_dbg(INFO, "No bus credit bus->tx_max %d, bus->tx_seq %d\n", bus->tx_max, bus->tx_seq); @@ -3435,11 +3533,15 @@ static int brcmf_sdbrcm_bus_preinit(struct device *dev) struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; struct brcmf_sdio *bus = sdiodev->bus; + uint pad_size; u32 value; u8 idx; int err; - /* sdio bus core specific dcmd */ + /* the commands below use the terms tx and rx from + * a device perspective, ie. bus:txglom affects the + * bus transfers from device to host. + */ idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV); if (bus->ci->c_inf[idx].rev < 12) { /* for sdio core rev < 12, disable txgloming */ @@ -3456,6 +3558,32 @@ static int brcmf_sdbrcm_bus_preinit(struct device *dev) err = brcmf_iovar_data_set(dev, "bus:txglomalign", &value, sizeof(u32)); } + + if (err < 0) + goto done; + + bus->tx_hdrlen = SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN; + if (sdiodev->sg_support) { + bus->txglom = false; + value = 1; + pad_size = bus->sdiodev->func[2]->cur_blksize << 1; + bus->txglom_sgpad = brcmu_pkt_buf_get_skb(pad_size); + if (!bus->txglom_sgpad) + brcmf_err("allocating txglom padding skb failed, reduced performance\n"); + + err = brcmf_iovar_data_set(bus->sdiodev->dev, "bus:rxglom", + &value, sizeof(u32)); + if (err < 0) { + /* bus:rxglom is allowed to fail */ + err = 0; + } else { + bus->txglom = true; + bus->tx_hdrlen += SDPCM_HWEXT_LEN; + } + } + brcmf_bus_add_txhdrlen(bus->sdiodev->dev, bus->tx_hdrlen); + +done: return err; } @@ -3929,6 +4057,7 @@ static void brcmf_sdbrcm_release(struct brcmf_sdio *bus) brcmf_sdbrcm_release_dongle(bus); } + brcmu_pkt_buf_free_skb(bus->txglom_sgpad); brcmf_sdbrcm_release_malloc(bus); kfree(bus); @@ -4034,8 +4163,6 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) brcmf_sdio_debugfs_create(bus); brcmf_dbg(INFO, "completed!!\n"); - brcmf_bus_add_txhdrlen(bus->sdiodev->dev, bus->tx_hdrlen); - /* if firmware path present try to download and bring up bus */ ret = brcmf_bus_start(bus->sdiodev->dev); if (ret != 0) { -- cgit v1.2.3-70-g09d2 From 5d406f8e03921b742fb549def43939254572dee9 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Fri, 29 Nov 2013 12:46:29 +0100 Subject: brcmfmac: rename dhd_cdc to bcdc dhd_cdc is renamed to bcdc. This is a step in cleaning and restructuring protocol layer. This is done so new protocols can be added in the future. This step only renames the source files. Reviewed-by: Arend Van Spriel Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman [arend@broadcom.com: use 'git mv' to do the rename] Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/Makefile | 2 +- drivers/net/wireless/brcm80211/brcmfmac/bcdc.c | 387 ++++++++++++++++++++++ drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c | 387 ---------------------- 3 files changed, 388 insertions(+), 388 deletions(-) create mode 100644 drivers/net/wireless/brcm80211/brcmfmac/bcdc.c delete mode 100644 drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c diff --git a/drivers/net/wireless/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/brcm80211/brcmfmac/Makefile index 8e9b1221b32..e15b61c2614 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/Makefile +++ b/drivers/net/wireless/brcm80211/brcmfmac/Makefile @@ -28,7 +28,7 @@ brcmfmac-objs += \ fweh.o \ fwsignal.o \ p2p.o \ - dhd_cdc.o \ + bcdc.o \ dhd_common.o \ dhd_linux.o \ btcoex.o diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c new file mode 100644 index 00000000000..42aaf104cc4 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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. + */ + +/******************************************************************************* + * Communicates with the dongle by using dcmd codes. + * For certain dcmd codes, the dongle interprets string data from the host. + ******************************************************************************/ + +#include +#include + +#include +#include + +#include "dhd.h" +#include "dhd_proto.h" +#include "dhd_bus.h" +#include "fwsignal.h" +#include "dhd_dbg.h" +#include "tracepoint.h" + +struct brcmf_proto_cdc_dcmd { + __le32 cmd; /* dongle command value */ + __le32 len; /* lower 16: output buflen; + * upper 16: input buflen (excludes header) */ + __le32 flags; /* flag defns given below */ + __le32 status; /* status code returned from the device */ +}; + +/* Max valid buffer size that can be sent to the dongle */ +#define CDC_MAX_MSG_SIZE (ETH_FRAME_LEN+ETH_FCS_LEN) + +/* CDC flag definitions */ +#define CDC_DCMD_ERROR 0x01 /* 1=cmd failed */ +#define CDC_DCMD_SET 0x02 /* 0=get, 1=set cmd */ +#define CDC_DCMD_IF_MASK 0xF000 /* I/F index */ +#define CDC_DCMD_IF_SHIFT 12 +#define CDC_DCMD_ID_MASK 0xFFFF0000 /* id an cmd pairing */ +#define CDC_DCMD_ID_SHIFT 16 /* ID Mask shift bits */ +#define CDC_DCMD_ID(flags) \ + (((flags) & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT) + +/* + * BDC header - Broadcom specific extension of CDC. + * Used on data packets to convey priority across USB. + */ +#define BDC_HEADER_LEN 4 +#define BDC_PROTO_VER 2 /* Protocol version */ +#define BDC_FLAG_VER_MASK 0xf0 /* Protocol version mask */ +#define BDC_FLAG_VER_SHIFT 4 /* Protocol version shift */ +#define BDC_FLAG_SUM_GOOD 0x04 /* Good RX checksums */ +#define BDC_FLAG_SUM_NEEDED 0x08 /* Dongle needs to do TX checksums */ +#define BDC_PRIORITY_MASK 0x7 +#define BDC_FLAG2_IF_MASK 0x0f /* packet rx interface in APSTA */ +#define BDC_FLAG2_IF_SHIFT 0 + +#define BDC_GET_IF_IDX(hdr) \ + ((int)((((hdr)->flags2) & BDC_FLAG2_IF_MASK) >> BDC_FLAG2_IF_SHIFT)) +#define BDC_SET_IF_IDX(hdr, idx) \ + ((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_IF_MASK) | \ + ((idx) << BDC_FLAG2_IF_SHIFT))) + +/** + * struct brcmf_proto_bdc_header - BDC header format + * + * @flags: flags contain protocol and checksum info. + * @priority: 802.1d priority and USB flow control info (bit 4:7). + * @flags2: additional flags containing dongle interface index. + * @data_offset: start of packet data. header is following by firmware signals. + */ +struct brcmf_proto_bdc_header { + u8 flags; + u8 priority; + u8 flags2; + u8 data_offset; +}; + +/* + * maximum length of firmware signal data between + * the BDC header and packet data in the tx path. + */ +#define BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES 12 + +#define RETRIES 2 /* # of retries to retrieve matching dcmd response */ +#define BUS_HEADER_LEN (16+64) /* Must be atleast SDPCM_RESERVE + * (amount of header tha might be added) + * plus any space that might be needed + * for bus alignment padding. + */ +#define ROUND_UP_MARGIN 2048 /* Biggest bus block size possible for + * round off at the end of buffer + * Currently is SDIO + */ + +struct brcmf_proto { + u16 reqid; + u8 bus_header[BUS_HEADER_LEN]; + struct brcmf_proto_cdc_dcmd msg; + unsigned char buf[BRCMF_DCMD_MAXLEN + ROUND_UP_MARGIN]; +}; + +static int brcmf_proto_cdc_msg(struct brcmf_pub *drvr) +{ + struct brcmf_proto *prot = drvr->prot; + int len = le32_to_cpu(prot->msg.len) + + sizeof(struct brcmf_proto_cdc_dcmd); + + brcmf_dbg(CDC, "Enter\n"); + + /* NOTE : cdc->msg.len holds the desired length of the buffer to be + * returned. Only up to CDC_MAX_MSG_SIZE of this buffer area + * is actually sent to the dongle + */ + if (len > CDC_MAX_MSG_SIZE) + len = CDC_MAX_MSG_SIZE; + + /* Send request */ + return brcmf_bus_txctl(drvr->bus_if, (unsigned char *)&prot->msg, len); +} + +static int brcmf_proto_cdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len) +{ + int ret; + struct brcmf_proto *prot = drvr->prot; + + brcmf_dbg(CDC, "Enter\n"); + len += sizeof(struct brcmf_proto_cdc_dcmd); + do { + ret = brcmf_bus_rxctl(drvr->bus_if, (unsigned char *)&prot->msg, + len); + if (ret < 0) + break; + } while (CDC_DCMD_ID(le32_to_cpu(prot->msg.flags)) != id); + + return ret; +} + +int +brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, + void *buf, uint len) +{ + struct brcmf_proto *prot = drvr->prot; + struct brcmf_proto_cdc_dcmd *msg = &prot->msg; + void *info; + int ret = 0, retries = 0; + u32 id, flags; + + brcmf_dbg(CDC, "Enter, cmd %d len %d\n", cmd, len); + + memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd)); + + msg->cmd = cpu_to_le32(cmd); + msg->len = cpu_to_le32(len); + flags = (++prot->reqid << CDC_DCMD_ID_SHIFT); + flags = (flags & ~CDC_DCMD_IF_MASK) | + (ifidx << CDC_DCMD_IF_SHIFT); + msg->flags = cpu_to_le32(flags); + + if (buf) + memcpy(prot->buf, buf, len); + + ret = brcmf_proto_cdc_msg(drvr); + if (ret < 0) { + brcmf_err("brcmf_proto_cdc_msg failed w/status %d\n", + ret); + goto done; + } + +retry: + /* wait for interrupt and get first fragment */ + ret = brcmf_proto_cdc_cmplt(drvr, prot->reqid, len); + if (ret < 0) + goto done; + + flags = le32_to_cpu(msg->flags); + id = (flags & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT; + + if ((id < prot->reqid) && (++retries < RETRIES)) + goto retry; + if (id != prot->reqid) { + brcmf_err("%s: unexpected request id %d (expected %d)\n", + brcmf_ifname(drvr, ifidx), id, prot->reqid); + ret = -EINVAL; + goto done; + } + + /* Check info buffer */ + info = (void *)&msg[1]; + + /* Copy info buffer */ + if (buf) { + if (ret < (int)len) + len = ret; + memcpy(buf, info, len); + } + + /* Check the ERROR flag */ + if (flags & CDC_DCMD_ERROR) + ret = le32_to_cpu(msg->status); + +done: + return ret; +} + +int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, + void *buf, uint len) +{ + struct brcmf_proto *prot = drvr->prot; + struct brcmf_proto_cdc_dcmd *msg = &prot->msg; + int ret = 0; + u32 flags, id; + + brcmf_dbg(CDC, "Enter, cmd %d len %d\n", cmd, len); + + memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd)); + + msg->cmd = cpu_to_le32(cmd); + msg->len = cpu_to_le32(len); + flags = (++prot->reqid << CDC_DCMD_ID_SHIFT) | CDC_DCMD_SET; + flags = (flags & ~CDC_DCMD_IF_MASK) | + (ifidx << CDC_DCMD_IF_SHIFT); + msg->flags = cpu_to_le32(flags); + + if (buf) + memcpy(prot->buf, buf, len); + + ret = brcmf_proto_cdc_msg(drvr); + if (ret < 0) + goto done; + + ret = brcmf_proto_cdc_cmplt(drvr, prot->reqid, len); + if (ret < 0) + goto done; + + flags = le32_to_cpu(msg->flags); + id = (flags & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT; + + if (id != prot->reqid) { + brcmf_err("%s: unexpected request id %d (expected %d)\n", + brcmf_ifname(drvr, ifidx), id, prot->reqid); + ret = -EINVAL; + goto done; + } + + /* Check the ERROR flag */ + if (flags & CDC_DCMD_ERROR) + ret = le32_to_cpu(msg->status); + +done: + return ret; +} + +static bool pkt_sum_needed(struct sk_buff *skb) +{ + return skb->ip_summed == CHECKSUM_PARTIAL; +} + +static void pkt_set_sum_good(struct sk_buff *skb, bool x) +{ + skb->ip_summed = (x ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE); +} + +void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx, u8 offset, + struct sk_buff *pktbuf) +{ + struct brcmf_proto_bdc_header *h; + + brcmf_dbg(CDC, "Enter\n"); + + /* Push BDC header used to convey priority for buses that don't */ + skb_push(pktbuf, BDC_HEADER_LEN); + + h = (struct brcmf_proto_bdc_header *)(pktbuf->data); + + h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); + if (pkt_sum_needed(pktbuf)) + h->flags |= BDC_FLAG_SUM_NEEDED; + + h->priority = (pktbuf->priority & BDC_PRIORITY_MASK); + h->flags2 = 0; + h->data_offset = offset; + BDC_SET_IF_IDX(h, ifidx); + trace_brcmf_bdchdr(pktbuf->data); +} + +int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx, + struct sk_buff *pktbuf) +{ + struct brcmf_proto_bdc_header *h; + + brcmf_dbg(CDC, "Enter\n"); + + /* Pop BDC header used to convey priority for buses that don't */ + + if (pktbuf->len <= BDC_HEADER_LEN) { + brcmf_dbg(INFO, "rx data too short (%d <= %d)\n", + pktbuf->len, BDC_HEADER_LEN); + return -EBADE; + } + + trace_brcmf_bdchdr(pktbuf->data); + h = (struct brcmf_proto_bdc_header *)(pktbuf->data); + + *ifidx = BDC_GET_IF_IDX(h); + if (*ifidx >= BRCMF_MAX_IFS) { + brcmf_err("rx data ifnum out of range (%d)\n", *ifidx); + return -EBADE; + } + /* The ifidx is the idx to map to matching netdev/ifp. When receiving + * events this is easy because it contains the bssidx which maps + * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd. + * bssidx 1 is used for p2p0 and no data can be received or + * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0 + */ + if (*ifidx) + (*ifidx)++; + + if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) != + BDC_PROTO_VER) { + brcmf_err("%s: non-BDC packet received, flags 0x%x\n", + brcmf_ifname(drvr, *ifidx), h->flags); + return -EBADE; + } + + if (h->flags & BDC_FLAG_SUM_GOOD) { + brcmf_dbg(CDC, "%s: BDC rcv, good checksum, flags 0x%x\n", + brcmf_ifname(drvr, *ifidx), h->flags); + pkt_set_sum_good(pktbuf, true); + } + + pktbuf->priority = h->priority & BDC_PRIORITY_MASK; + + skb_pull(pktbuf, BDC_HEADER_LEN); + if (do_fws) + brcmf_fws_hdrpull(drvr, *ifidx, h->data_offset << 2, pktbuf); + else + skb_pull(pktbuf, h->data_offset << 2); + + if (pktbuf->len == 0) + return -ENODATA; + return 0; +} + +int brcmf_proto_attach(struct brcmf_pub *drvr) +{ + struct brcmf_proto *cdc; + + cdc = kzalloc(sizeof(struct brcmf_proto), GFP_ATOMIC); + if (!cdc) + goto fail; + + /* ensure that the msg buf directly follows the cdc msg struct */ + if ((unsigned long)(&cdc->msg + 1) != (unsigned long)cdc->buf) { + brcmf_err("struct brcmf_proto is not correctly defined\n"); + goto fail; + } + + drvr->prot = cdc; + drvr->hdrlen += BDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES; + drvr->bus_if->maxctl = BRCMF_DCMD_MAXLEN + + sizeof(struct brcmf_proto_cdc_dcmd) + ROUND_UP_MARGIN; + return 0; + +fail: + kfree(cdc); + return -ENOMEM; +} + +/* ~NOTE~ What if another thread is waiting on the semaphore? Holding it? */ +void brcmf_proto_detach(struct brcmf_pub *drvr) +{ + kfree(drvr->prot); + drvr->prot = NULL; +} diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c deleted file mode 100644 index 42aaf104cc4..00000000000 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c +++ /dev/null @@ -1,387 +0,0 @@ -/* - * Copyright (c) 2010 Broadcom Corporation - * - * 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. - */ - -/******************************************************************************* - * Communicates with the dongle by using dcmd codes. - * For certain dcmd codes, the dongle interprets string data from the host. - ******************************************************************************/ - -#include -#include - -#include -#include - -#include "dhd.h" -#include "dhd_proto.h" -#include "dhd_bus.h" -#include "fwsignal.h" -#include "dhd_dbg.h" -#include "tracepoint.h" - -struct brcmf_proto_cdc_dcmd { - __le32 cmd; /* dongle command value */ - __le32 len; /* lower 16: output buflen; - * upper 16: input buflen (excludes header) */ - __le32 flags; /* flag defns given below */ - __le32 status; /* status code returned from the device */ -}; - -/* Max valid buffer size that can be sent to the dongle */ -#define CDC_MAX_MSG_SIZE (ETH_FRAME_LEN+ETH_FCS_LEN) - -/* CDC flag definitions */ -#define CDC_DCMD_ERROR 0x01 /* 1=cmd failed */ -#define CDC_DCMD_SET 0x02 /* 0=get, 1=set cmd */ -#define CDC_DCMD_IF_MASK 0xF000 /* I/F index */ -#define CDC_DCMD_IF_SHIFT 12 -#define CDC_DCMD_ID_MASK 0xFFFF0000 /* id an cmd pairing */ -#define CDC_DCMD_ID_SHIFT 16 /* ID Mask shift bits */ -#define CDC_DCMD_ID(flags) \ - (((flags) & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT) - -/* - * BDC header - Broadcom specific extension of CDC. - * Used on data packets to convey priority across USB. - */ -#define BDC_HEADER_LEN 4 -#define BDC_PROTO_VER 2 /* Protocol version */ -#define BDC_FLAG_VER_MASK 0xf0 /* Protocol version mask */ -#define BDC_FLAG_VER_SHIFT 4 /* Protocol version shift */ -#define BDC_FLAG_SUM_GOOD 0x04 /* Good RX checksums */ -#define BDC_FLAG_SUM_NEEDED 0x08 /* Dongle needs to do TX checksums */ -#define BDC_PRIORITY_MASK 0x7 -#define BDC_FLAG2_IF_MASK 0x0f /* packet rx interface in APSTA */ -#define BDC_FLAG2_IF_SHIFT 0 - -#define BDC_GET_IF_IDX(hdr) \ - ((int)((((hdr)->flags2) & BDC_FLAG2_IF_MASK) >> BDC_FLAG2_IF_SHIFT)) -#define BDC_SET_IF_IDX(hdr, idx) \ - ((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_IF_MASK) | \ - ((idx) << BDC_FLAG2_IF_SHIFT))) - -/** - * struct brcmf_proto_bdc_header - BDC header format - * - * @flags: flags contain protocol and checksum info. - * @priority: 802.1d priority and USB flow control info (bit 4:7). - * @flags2: additional flags containing dongle interface index. - * @data_offset: start of packet data. header is following by firmware signals. - */ -struct brcmf_proto_bdc_header { - u8 flags; - u8 priority; - u8 flags2; - u8 data_offset; -}; - -/* - * maximum length of firmware signal data between - * the BDC header and packet data in the tx path. - */ -#define BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES 12 - -#define RETRIES 2 /* # of retries to retrieve matching dcmd response */ -#define BUS_HEADER_LEN (16+64) /* Must be atleast SDPCM_RESERVE - * (amount of header tha might be added) - * plus any space that might be needed - * for bus alignment padding. - */ -#define ROUND_UP_MARGIN 2048 /* Biggest bus block size possible for - * round off at the end of buffer - * Currently is SDIO - */ - -struct brcmf_proto { - u16 reqid; - u8 bus_header[BUS_HEADER_LEN]; - struct brcmf_proto_cdc_dcmd msg; - unsigned char buf[BRCMF_DCMD_MAXLEN + ROUND_UP_MARGIN]; -}; - -static int brcmf_proto_cdc_msg(struct brcmf_pub *drvr) -{ - struct brcmf_proto *prot = drvr->prot; - int len = le32_to_cpu(prot->msg.len) + - sizeof(struct brcmf_proto_cdc_dcmd); - - brcmf_dbg(CDC, "Enter\n"); - - /* NOTE : cdc->msg.len holds the desired length of the buffer to be - * returned. Only up to CDC_MAX_MSG_SIZE of this buffer area - * is actually sent to the dongle - */ - if (len > CDC_MAX_MSG_SIZE) - len = CDC_MAX_MSG_SIZE; - - /* Send request */ - return brcmf_bus_txctl(drvr->bus_if, (unsigned char *)&prot->msg, len); -} - -static int brcmf_proto_cdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len) -{ - int ret; - struct brcmf_proto *prot = drvr->prot; - - brcmf_dbg(CDC, "Enter\n"); - len += sizeof(struct brcmf_proto_cdc_dcmd); - do { - ret = brcmf_bus_rxctl(drvr->bus_if, (unsigned char *)&prot->msg, - len); - if (ret < 0) - break; - } while (CDC_DCMD_ID(le32_to_cpu(prot->msg.flags)) != id); - - return ret; -} - -int -brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, - void *buf, uint len) -{ - struct brcmf_proto *prot = drvr->prot; - struct brcmf_proto_cdc_dcmd *msg = &prot->msg; - void *info; - int ret = 0, retries = 0; - u32 id, flags; - - brcmf_dbg(CDC, "Enter, cmd %d len %d\n", cmd, len); - - memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd)); - - msg->cmd = cpu_to_le32(cmd); - msg->len = cpu_to_le32(len); - flags = (++prot->reqid << CDC_DCMD_ID_SHIFT); - flags = (flags & ~CDC_DCMD_IF_MASK) | - (ifidx << CDC_DCMD_IF_SHIFT); - msg->flags = cpu_to_le32(flags); - - if (buf) - memcpy(prot->buf, buf, len); - - ret = brcmf_proto_cdc_msg(drvr); - if (ret < 0) { - brcmf_err("brcmf_proto_cdc_msg failed w/status %d\n", - ret); - goto done; - } - -retry: - /* wait for interrupt and get first fragment */ - ret = brcmf_proto_cdc_cmplt(drvr, prot->reqid, len); - if (ret < 0) - goto done; - - flags = le32_to_cpu(msg->flags); - id = (flags & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT; - - if ((id < prot->reqid) && (++retries < RETRIES)) - goto retry; - if (id != prot->reqid) { - brcmf_err("%s: unexpected request id %d (expected %d)\n", - brcmf_ifname(drvr, ifidx), id, prot->reqid); - ret = -EINVAL; - goto done; - } - - /* Check info buffer */ - info = (void *)&msg[1]; - - /* Copy info buffer */ - if (buf) { - if (ret < (int)len) - len = ret; - memcpy(buf, info, len); - } - - /* Check the ERROR flag */ - if (flags & CDC_DCMD_ERROR) - ret = le32_to_cpu(msg->status); - -done: - return ret; -} - -int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, - void *buf, uint len) -{ - struct brcmf_proto *prot = drvr->prot; - struct brcmf_proto_cdc_dcmd *msg = &prot->msg; - int ret = 0; - u32 flags, id; - - brcmf_dbg(CDC, "Enter, cmd %d len %d\n", cmd, len); - - memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd)); - - msg->cmd = cpu_to_le32(cmd); - msg->len = cpu_to_le32(len); - flags = (++prot->reqid << CDC_DCMD_ID_SHIFT) | CDC_DCMD_SET; - flags = (flags & ~CDC_DCMD_IF_MASK) | - (ifidx << CDC_DCMD_IF_SHIFT); - msg->flags = cpu_to_le32(flags); - - if (buf) - memcpy(prot->buf, buf, len); - - ret = brcmf_proto_cdc_msg(drvr); - if (ret < 0) - goto done; - - ret = brcmf_proto_cdc_cmplt(drvr, prot->reqid, len); - if (ret < 0) - goto done; - - flags = le32_to_cpu(msg->flags); - id = (flags & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT; - - if (id != prot->reqid) { - brcmf_err("%s: unexpected request id %d (expected %d)\n", - brcmf_ifname(drvr, ifidx), id, prot->reqid); - ret = -EINVAL; - goto done; - } - - /* Check the ERROR flag */ - if (flags & CDC_DCMD_ERROR) - ret = le32_to_cpu(msg->status); - -done: - return ret; -} - -static bool pkt_sum_needed(struct sk_buff *skb) -{ - return skb->ip_summed == CHECKSUM_PARTIAL; -} - -static void pkt_set_sum_good(struct sk_buff *skb, bool x) -{ - skb->ip_summed = (x ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE); -} - -void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx, u8 offset, - struct sk_buff *pktbuf) -{ - struct brcmf_proto_bdc_header *h; - - brcmf_dbg(CDC, "Enter\n"); - - /* Push BDC header used to convey priority for buses that don't */ - skb_push(pktbuf, BDC_HEADER_LEN); - - h = (struct brcmf_proto_bdc_header *)(pktbuf->data); - - h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); - if (pkt_sum_needed(pktbuf)) - h->flags |= BDC_FLAG_SUM_NEEDED; - - h->priority = (pktbuf->priority & BDC_PRIORITY_MASK); - h->flags2 = 0; - h->data_offset = offset; - BDC_SET_IF_IDX(h, ifidx); - trace_brcmf_bdchdr(pktbuf->data); -} - -int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx, - struct sk_buff *pktbuf) -{ - struct brcmf_proto_bdc_header *h; - - brcmf_dbg(CDC, "Enter\n"); - - /* Pop BDC header used to convey priority for buses that don't */ - - if (pktbuf->len <= BDC_HEADER_LEN) { - brcmf_dbg(INFO, "rx data too short (%d <= %d)\n", - pktbuf->len, BDC_HEADER_LEN); - return -EBADE; - } - - trace_brcmf_bdchdr(pktbuf->data); - h = (struct brcmf_proto_bdc_header *)(pktbuf->data); - - *ifidx = BDC_GET_IF_IDX(h); - if (*ifidx >= BRCMF_MAX_IFS) { - brcmf_err("rx data ifnum out of range (%d)\n", *ifidx); - return -EBADE; - } - /* The ifidx is the idx to map to matching netdev/ifp. When receiving - * events this is easy because it contains the bssidx which maps - * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd. - * bssidx 1 is used for p2p0 and no data can be received or - * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0 - */ - if (*ifidx) - (*ifidx)++; - - if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) != - BDC_PROTO_VER) { - brcmf_err("%s: non-BDC packet received, flags 0x%x\n", - brcmf_ifname(drvr, *ifidx), h->flags); - return -EBADE; - } - - if (h->flags & BDC_FLAG_SUM_GOOD) { - brcmf_dbg(CDC, "%s: BDC rcv, good checksum, flags 0x%x\n", - brcmf_ifname(drvr, *ifidx), h->flags); - pkt_set_sum_good(pktbuf, true); - } - - pktbuf->priority = h->priority & BDC_PRIORITY_MASK; - - skb_pull(pktbuf, BDC_HEADER_LEN); - if (do_fws) - brcmf_fws_hdrpull(drvr, *ifidx, h->data_offset << 2, pktbuf); - else - skb_pull(pktbuf, h->data_offset << 2); - - if (pktbuf->len == 0) - return -ENODATA; - return 0; -} - -int brcmf_proto_attach(struct brcmf_pub *drvr) -{ - struct brcmf_proto *cdc; - - cdc = kzalloc(sizeof(struct brcmf_proto), GFP_ATOMIC); - if (!cdc) - goto fail; - - /* ensure that the msg buf directly follows the cdc msg struct */ - if ((unsigned long)(&cdc->msg + 1) != (unsigned long)cdc->buf) { - brcmf_err("struct brcmf_proto is not correctly defined\n"); - goto fail; - } - - drvr->prot = cdc; - drvr->hdrlen += BDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES; - drvr->bus_if->maxctl = BRCMF_DCMD_MAXLEN + - sizeof(struct brcmf_proto_cdc_dcmd) + ROUND_UP_MARGIN; - return 0; - -fail: - kfree(cdc); - return -ENOMEM; -} - -/* ~NOTE~ What if another thread is waiting on the semaphore? Holding it? */ -void brcmf_proto_detach(struct brcmf_pub *drvr) -{ - kfree(drvr->prot); - drvr->prot = NULL; -} -- cgit v1.2.3-70-g09d2 From f931868d498ec4e7a1b8730e7173b5a17d36dd1a Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Fri, 29 Nov 2013 12:25:12 +0100 Subject: brcmfmac: removed dhd_proto.h. dhd_proto.h was cleaned up and prototypes were moved to dhd.h. dhd_proto.h was removed. This is a step in cleaning and restucturing protocol layer. Reviewed-by: Arend Van Spriel Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/bcdc.c | 1 - drivers/net/wireless/brcm80211/brcmfmac/dhd.h | 15 +++++++++ .../net/wireless/brcm80211/brcmfmac/dhd_common.c | 1 - .../net/wireless/brcm80211/brcmfmac/dhd_linux.c | 1 - .../net/wireless/brcm80211/brcmfmac/dhd_proto.h | 39 ---------------------- drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c | 1 - 6 files changed, 15 insertions(+), 43 deletions(-) delete mode 100644 drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c index 42aaf104cc4..59c6c054b11 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c @@ -26,7 +26,6 @@ #include #include "dhd.h" -#include "dhd_proto.h" #include "dhd_bus.h" #include "fwsignal.h" #include "dhd_dbg.h" diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h index 899a2ada5b8..dc2ebefa4ca 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h @@ -635,6 +635,18 @@ int brcmf_netdev_wait_pend8021x(struct net_device *ndev); /* Return pointer to interface name */ char *brcmf_ifname(struct brcmf_pub *drvr, int idx); +/* Linkage, sets prot link and updates hdrlen in pub */ +int brcmf_proto_attach(struct brcmf_pub *drvr); + +/* Unlink, frees allocated protocol memory (including brcmf_proto) */ +void brcmf_proto_detach(struct brcmf_pub *drvr); + +/* Add any protocol-specific data header. + * Caller must reserve prot_hdrlen prepend space. + */ +void brcmf_proto_hdrpush(struct brcmf_pub *, int ifidx, u8 offset, + struct sk_buff *txp); + /* Query dongle */ int brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf, uint len); @@ -655,4 +667,7 @@ u32 brcmf_get_chip_info(struct brcmf_if *ifp); void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, bool success); +/* Sets dongle media info (drv_version, mac address). */ +int brcmf_c_preinit_dcmds(struct brcmf_if *ifp); + #endif /* _BRCMF_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c index 5c0c9191b79..60176339318 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c @@ -21,7 +21,6 @@ #include #include "dhd.h" #include "dhd_bus.h" -#include "dhd_proto.h" #include "dhd_dbg.h" #include "fwil.h" #include "tracepoint.h" diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index c34ca703d2a..c626938665a 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -24,7 +24,6 @@ #include "dhd.h" #include "dhd_bus.h" -#include "dhd_proto.h" #include "dhd_dbg.h" #include "fwil_types.h" #include "p2p.h" diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h deleted file mode 100644 index d633362a52d..00000000000 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2010 Broadcom Corporation - * - * 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. - */ - -#ifndef _BRCMF_PROTO_H_ -#define _BRCMF_PROTO_H_ - -/* - * Exported from the brcmf protocol module (brcmf_cdc) - */ - -/* Linkage, sets prot link and updates hdrlen in pub */ -int brcmf_proto_attach(struct brcmf_pub *drvr); - -/* Unlink, frees allocated protocol memory (including brcmf_proto) */ -void brcmf_proto_detach(struct brcmf_pub *drvr); - -/* Add any protocol-specific data header. - * Caller must reserve prot_hdrlen prepend space. - */ -void brcmf_proto_hdrpush(struct brcmf_pub *, int ifidx, u8 offset, - struct sk_buff *txp); - -/* Sets dongle media info (drv_version, mac address). */ -int brcmf_c_preinit_dcmds(struct brcmf_if *ifp); - -#endif /* _BRCMF_PROTO_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c index 296dbf1d142..b96ee3a93a6 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c @@ -27,7 +27,6 @@ #include #include #include "dhd.h" -#include "dhd_proto.h" #include "dhd_dbg.h" #include "dhd_bus.h" #include "fwil.h" -- cgit v1.2.3-70-g09d2 From e217d1c8bfbd97316f5a1d3845587284cc137291 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Fri, 29 Nov 2013 12:25:13 +0100 Subject: brcmfmac: determine alignment values during probe The alignment values were being determined for each transmit and receive depending on platform data. Instead determine these once during the probe. Reviewed-by: Franky Lin Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 48 +++++++++++----------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index f5d3650659e..584ffb8ff4f 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -462,6 +462,8 @@ struct brcmf_sdio { u8 tx_hdrlen; /* sdio bus header length for tx packet */ bool txglom; /* host tx glomming enable flag */ struct sk_buff *txglom_sgpad; /* scatter-gather padding buffer */ + u16 head_align; /* buffer pointer alignment */ + u16 sgentry_align; /* scatter-gather buffer alignment */ }; /* clkstate */ @@ -1313,7 +1315,6 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) { u16 dlen, totlen; u8 *dptr, num = 0; - u32 align = 0; u16 sublen; struct sk_buff *pfirst, *pnext; @@ -1328,11 +1329,6 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) brcmf_dbg(SDIO, "start: glomd %p glom %p\n", bus->glomd, skb_peek(&bus->glom)); - if (bus->sdiodev->pdata) - align = bus->sdiodev->pdata->sd_sgentry_align; - if (align < 4) - align = 4; - /* If there's a descriptor, generate the packet chain */ if (bus->glomd) { pfirst = pnext = NULL; @@ -1356,9 +1352,9 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) pnext = NULL; break; } - if (sublen % align) { + if (sublen % bus->sgentry_align) { brcmf_err("sublen %d not multiple of %d\n", - sublen, align); + sublen, bus->sgentry_align); } totlen += sublen; @@ -1371,7 +1367,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) } /* Allocate/chain packet for next subframe */ - pnext = brcmu_pkt_buf_get_skb(sublen + align); + pnext = brcmu_pkt_buf_get_skb(sublen + bus->sgentry_align); if (pnext == NULL) { brcmf_err("bcm_pkt_buf_get_skb failed, num %d len %d\n", num, sublen); @@ -1380,7 +1376,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) skb_queue_tail(&bus->glom, pnext); /* Adhere to start alignment requirements */ - pkt_align(pnext, sublen, align); + pkt_align(pnext, sublen, bus->sgentry_align); } /* If all allocations succeeded, save packet chain @@ -1908,18 +1904,13 @@ brcmf_sdbrcm_wait_event_wakeup(struct brcmf_sdio *bus) static int brcmf_sdio_txpkt_hdalign(struct brcmf_sdio *bus, struct sk_buff *pkt) { - u16 head_align, head_pad; + u16 head_pad; u8 *dat_buf; - /* SDIO ADMA requires at least 32 bit alignment */ - head_align = 4; - if (bus->sdiodev->pdata && bus->sdiodev->pdata->sd_head_align > 4) - head_align = bus->sdiodev->pdata->sd_head_align; - dat_buf = (u8 *)(pkt->data); /* Check head padding */ - head_pad = ((unsigned long)dat_buf % head_align); + head_pad = ((unsigned long)dat_buf % bus->head_align); if (head_pad) { if (skb_headroom(pkt) < head_pad) { bus->sdiodev->bus_if->tx_realloc++; @@ -1949,25 +1940,22 @@ static int brcmf_sdio_txpkt_prep_sg(struct brcmf_sdio *bus, { struct brcmf_sdio_dev *sdiodev; struct sk_buff *pkt_pad; - u16 tail_pad, tail_chop, sg_align, chain_pad; + u16 tail_pad, tail_chop, chain_pad; unsigned int blksize; bool lastfrm; int ntail, ret; sdiodev = bus->sdiodev; blksize = sdiodev->func[SDIO_FUNC_2]->cur_blksize; - sg_align = 4; - if (sdiodev->pdata && sdiodev->pdata->sd_sgentry_align > 4) - sg_align = sdiodev->pdata->sd_sgentry_align; /* sg entry alignment should be a divisor of block size */ - WARN_ON(blksize % sg_align); + WARN_ON(blksize % bus->sgentry_align); /* Check tail padding */ lastfrm = skb_queue_is_last(pktq, pkt); tail_pad = 0; - tail_chop = pkt->len % sg_align; + tail_chop = pkt->len % bus->sgentry_align; if (tail_chop) - tail_pad = sg_align - tail_chop; + tail_pad = bus->sgentry_align - tail_chop; chain_pad = (total_len + tail_pad) % blksize; if (lastfrm && chain_pad) tail_pad += blksize - chain_pad; @@ -4099,6 +4087,18 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) bus->txminmax = BRCMF_TXMINMAX; bus->tx_seq = SDPCM_SEQ_WRAP - 1; + /* platform specific configuration: + * alignments must be at least 4 bytes for ADMA + */ + bus->head_align = ALIGNMENT; + bus->sgentry_align = ALIGNMENT; + if (sdiodev->pdata) { + if (sdiodev->pdata->sd_head_align > ALIGNMENT) + bus->head_align = sdiodev->pdata->sd_head_align; + if (sdiodev->pdata->sd_sgentry_align > ALIGNMENT) + bus->sgentry_align = sdiodev->pdata->sd_sgentry_align; + } + INIT_WORK(&bus->datawork, brcmf_sdio_dataworker); bus->brcmf_wq = create_singlethread_workqueue("brcmf_wq"); if (bus->brcmf_wq == NULL) { -- cgit v1.2.3-70-g09d2 From 9b2d2f2a890847277371d953e2751c4224efa273 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Fri, 29 Nov 2013 12:25:14 +0100 Subject: brcmfmac: use platform specific alignment in SDIO The SDIO part of the brcmfmac driver uses a static define BRCMF_SDALIGN to align buffers used for SDIO transfers. This patch replaces it by using alignment derived from the platform specific data. Reviewed-by: Franky Lin Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 50 ++++++++++------------ 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 584ffb8ff4f..0f95f3e79c1 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -389,7 +389,7 @@ struct brcmf_sdio { u8 tx_seq; /* Transmit sequence number (next) */ u8 tx_max; /* Maximum transmit sequence allowed */ - u8 hdrbuf[MAX_HDR_READ + BRCMF_SDALIGN]; + u8 *hdrbuf; /* buffer for handling rx frame */ u8 *rxhdr; /* Header of current rx frame (in hdrbuf) */ u8 rx_seq; /* Receive sequence number (expected) */ struct brcmf_sdio_hdrinfo cur_read; @@ -1580,9 +1580,9 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff) goto done; rbuf = bus->rxbuf; - pad = ((unsigned long)rbuf % BRCMF_SDALIGN); + pad = ((unsigned long)rbuf % bus->head_align); if (pad) - rbuf += (BRCMF_SDALIGN - pad); + rbuf += (bus->head_align - pad); /* Copy the already-read portion over */ memcpy(buf, hdr, BRCMF_FIRSTREAD); @@ -1596,14 +1596,10 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff) if ((pad <= bus->roundup) && (pad < bus->blocksize) && ((len + pad) < bus->sdiodev->bus_if->maxctl)) rdlen += pad; - } else if (rdlen % BRCMF_SDALIGN) { - rdlen += BRCMF_SDALIGN - (rdlen % BRCMF_SDALIGN); + } else if (rdlen % bus->head_align) { + rdlen += bus->head_align - (rdlen % bus->head_align); } - /* Satisfy length-alignment requirements */ - if (rdlen & (ALIGNMENT - 1)) - rdlen = roundup(rdlen, ALIGNMENT); - /* Drop if the read is too big or it exceeds our maximum */ if ((rdlen + BRCMF_FIRSTREAD) > bus->sdiodev->bus_if->maxctl) { brcmf_err("%d-byte control read exceeds %d-byte buffer\n", @@ -1668,8 +1664,8 @@ static void brcmf_pad(struct brcmf_sdio *bus, u16 *pad, u16 *rdlen) if (*pad <= bus->roundup && *pad < bus->blocksize && *rdlen + *pad + BRCMF_FIRSTREAD < MAX_RX_DATASZ) *rdlen += *pad; - } else if (*rdlen % BRCMF_SDALIGN) { - *rdlen += BRCMF_SDALIGN - (*rdlen % BRCMF_SDALIGN); + } else if (*rdlen % bus->head_align) { + *rdlen += bus->head_align - (*rdlen % bus->head_align); } } @@ -1757,7 +1753,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) brcmf_pad(bus, &pad, &rd->len_left); pkt = brcmu_pkt_buf_get_skb(rd->len_left + head_read + - BRCMF_SDALIGN); + bus->head_align); if (!pkt) { /* Give up on data, request rtx of events */ brcmf_err("brcmu_pkt_buf_get_skb failed\n"); @@ -1767,7 +1763,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) continue; } skb_pull(pkt, head_read); - pkt_align(pkt, rd->len_left, BRCMF_SDALIGN); + pkt_align(pkt, rd->len_left, bus->head_align); ret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad, SDIO_FUNC_2, F2SYNC, pkt); @@ -2762,14 +2758,14 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) len = (msglen += bus->tx_hdrlen); /* Add alignment padding (optional for ctl frames) */ - doff = ((unsigned long)frame % BRCMF_SDALIGN); + doff = ((unsigned long)frame % bus->head_align); if (doff) { frame -= doff; len += doff; msglen += doff; memset(frame, 0, doff + bus->tx_hdrlen); } - /* precondition: doff < BRCMF_SDALIGN */ + /* precondition: doff < bus->head_align */ doff += bus->tx_hdrlen; /* Round send length to next SDIO block */ @@ -2778,15 +2774,11 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) pad = bus->blocksize - (len % bus->blocksize); if ((pad > bus->roundup) || (pad >= bus->blocksize)) pad = 0; - } else if (len % BRCMF_SDALIGN) { - pad = BRCMF_SDALIGN - (len % BRCMF_SDALIGN); + } else if (len % bus->head_align) { + pad = bus->head_align - (len % bus->head_align); } len += pad; - /* Satisfy length-alignment requirements */ - if (len & (ALIGNMENT - 1)) - len = roundup(len, ALIGNMENT); - /* precondition: IS_ALIGNED((unsigned long)frame, 2) */ /* Make sure backplane clock is on */ @@ -2798,10 +2790,8 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) hd_info.channel = SDPCM_CONTROL_CHANNEL; hd_info.dat_offset = doff; hd_info.seq_num = bus->tx_seq; - if (bus->txglom) { - hd_info.lastfrm = true; - hd_info.tail_pad = pad; - } + hd_info.lastfrm = true; + hd_info.tail_pad = pad; brcmf_sdio_hdpack(bus, frame, &hd_info); if (bus->txglom) @@ -3823,7 +3813,7 @@ static bool brcmf_sdbrcm_probe_malloc(struct brcmf_sdio *bus) if (bus->sdiodev->bus_if->maxctl) { bus->rxblen = roundup((bus->sdiodev->bus_if->maxctl + SDPCM_HDRLEN), - ALIGNMENT) + BRCMF_SDALIGN; + ALIGNMENT) + bus->head_align; bus->rxbuf = kmalloc(bus->rxblen, GFP_ATOMIC); if (!(bus->rxbuf)) return false; @@ -3924,9 +3914,13 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva) brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN); + /* allocate header buffer */ + bus->hdrbuf = kzalloc(MAX_HDR_READ + bus->head_align, GFP_KERNEL); + if (!bus->hdrbuf) + return false; /* Locate an appropriately-aligned portion of hdrbuf */ bus->rxhdr = (u8 *) roundup((unsigned long)&bus->hdrbuf[0], - BRCMF_SDALIGN); + bus->head_align); /* Set the poll and/or interrupt flags */ bus->intr = true; @@ -4047,7 +4041,7 @@ static void brcmf_sdbrcm_release(struct brcmf_sdio *bus) brcmu_pkt_buf_free_skb(bus->txglom_sgpad); brcmf_sdbrcm_release_malloc(bus); - + kfree(bus->hdrbuf); kfree(bus); } -- cgit v1.2.3-70-g09d2 From e601fb37405af384781284f90125fd4da665a7b3 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Fri, 29 Nov 2013 12:25:15 +0100 Subject: brcmfmac: remove redundant ioctl handlers The ioctl() entry points were empty except for handling SIOC_ETHTOOL but that has been obsoleted in favor of struct ethtool_ops. Cleaning up removing the ioctl() handlers. Reviewed-by: Hante Meuleman Reviewed-by: Franky Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- .../net/wireless/brcm80211/brcmfmac/dhd_linux.c | 149 --------------------- 1 file changed, 149 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index c626938665a..9336f6dd3f8 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -591,28 +591,6 @@ static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev) return &ifp->stats; } -/* - * Set current toe component enables in toe_ol iovar, - * and set toe global enable iovar - */ -static int brcmf_toe_set(struct brcmf_if *ifp, u32 toe_ol) -{ - s32 err; - - err = brcmf_fil_iovar_int_set(ifp, "toe_ol", toe_ol); - if (err < 0) { - brcmf_err("Setting toe_ol failed, %d\n", err); - return err; - } - - err = brcmf_fil_iovar_int_set(ifp, "toe", (toe_ol != 0)); - if (err < 0) - brcmf_err("Setting toe failed, %d\n", err); - - return err; - -} - static void brcmf_ethtool_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info) { @@ -630,124 +608,6 @@ static const struct ethtool_ops brcmf_ethtool_ops = { .get_drvinfo = brcmf_ethtool_get_drvinfo, }; -static int brcmf_ethtool(struct brcmf_if *ifp, void __user *uaddr) -{ - struct brcmf_pub *drvr = ifp->drvr; - struct ethtool_drvinfo info; - char drvname[sizeof(info.driver)]; - u32 cmd; - struct ethtool_value edata; - u32 toe_cmpnt, csum_dir; - int ret; - - brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); - - /* all ethtool calls start with a cmd word */ - if (copy_from_user(&cmd, uaddr, sizeof(u32))) - return -EFAULT; - - switch (cmd) { - case ETHTOOL_GDRVINFO: - /* Copy out any request driver name */ - if (copy_from_user(&info, uaddr, sizeof(info))) - return -EFAULT; - strncpy(drvname, info.driver, sizeof(info.driver)); - drvname[sizeof(info.driver) - 1] = '\0'; - - /* clear struct for return */ - memset(&info, 0, sizeof(info)); - info.cmd = cmd; - - /* if requested, identify ourselves */ - if (strcmp(drvname, "?dhd") == 0) { - sprintf(info.driver, "dhd"); - strcpy(info.version, BRCMF_VERSION_STR); - } - /* report dongle driver type */ - else - sprintf(info.driver, "wl"); - - sprintf(info.version, "%lu", drvr->drv_version); - if (copy_to_user(uaddr, &info, sizeof(info))) - return -EFAULT; - brcmf_dbg(TRACE, "given %*s, returning %s\n", - (int)sizeof(drvname), drvname, info.driver); - break; - - /* Get toe offload components from dongle */ - case ETHTOOL_GRXCSUM: - case ETHTOOL_GTXCSUM: - ret = brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_cmpnt); - if (ret < 0) - return ret; - - csum_dir = - (cmd == ETHTOOL_GTXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL; - - edata.cmd = cmd; - edata.data = (toe_cmpnt & csum_dir) ? 1 : 0; - - if (copy_to_user(uaddr, &edata, sizeof(edata))) - return -EFAULT; - break; - - /* Set toe offload components in dongle */ - case ETHTOOL_SRXCSUM: - case ETHTOOL_STXCSUM: - if (copy_from_user(&edata, uaddr, sizeof(edata))) - return -EFAULT; - - /* Read the current settings, update and write back */ - ret = brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_cmpnt); - if (ret < 0) - return ret; - - csum_dir = - (cmd == ETHTOOL_STXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL; - - if (edata.data != 0) - toe_cmpnt |= csum_dir; - else - toe_cmpnt &= ~csum_dir; - - ret = brcmf_toe_set(ifp, toe_cmpnt); - if (ret < 0) - return ret; - - /* If setting TX checksum mode, tell Linux the new mode */ - if (cmd == ETHTOOL_STXCSUM) { - if (edata.data) - ifp->ndev->features |= NETIF_F_IP_CSUM; - else - ifp->ndev->features &= ~NETIF_F_IP_CSUM; - } - - break; - - default: - return -EOPNOTSUPP; - } - - return 0; -} - -static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr, - int cmd) -{ - struct brcmf_if *ifp = netdev_priv(ndev); - struct brcmf_pub *drvr = ifp->drvr; - - brcmf_dbg(TRACE, "Enter, idx=%d, cmd=0x%04x\n", ifp->bssidx, cmd); - - if (!drvr->iflist[ifp->bssidx]) - return -1; - - if (cmd == SIOCETHTOOL) - return brcmf_ethtool(ifp, ifr->ifr_data); - - return -EOPNOTSUPP; -} - static int brcmf_netdev_stop(struct net_device *ndev) { struct brcmf_if *ifp = netdev_priv(ndev); @@ -800,7 +660,6 @@ static const struct net_device_ops brcmf_netdev_ops_pri = { .ndo_open = brcmf_netdev_open, .ndo_stop = brcmf_netdev_stop, .ndo_get_stats = brcmf_netdev_get_stats, - .ndo_do_ioctl = brcmf_netdev_ioctl_entry, .ndo_start_xmit = brcmf_netdev_start_xmit, .ndo_set_mac_address = brcmf_netdev_set_mac_address, .ndo_set_rx_mode = brcmf_netdev_set_multicast_list @@ -866,13 +725,6 @@ static int brcmf_net_p2p_stop(struct net_device *ndev) return brcmf_cfg80211_down(ndev); } -static int brcmf_net_p2p_do_ioctl(struct net_device *ndev, - struct ifreq *ifr, int cmd) -{ - brcmf_dbg(TRACE, "Enter\n"); - return 0; -} - static netdev_tx_t brcmf_net_p2p_start_xmit(struct sk_buff *skb, struct net_device *ndev) { @@ -885,7 +737,6 @@ static netdev_tx_t brcmf_net_p2p_start_xmit(struct sk_buff *skb, static const struct net_device_ops brcmf_netdev_ops_p2p = { .ndo_open = brcmf_net_p2p_open, .ndo_stop = brcmf_net_p2p_stop, - .ndo_do_ioctl = brcmf_net_p2p_do_ioctl, .ndo_start_xmit = brcmf_net_p2p_start_xmit }; -- cgit v1.2.3-70-g09d2 From 85b8413371225e9bcbbb30cf3caa5889fed5f6a4 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Fri, 29 Nov 2013 12:25:16 +0100 Subject: brcmfmac: Dynamically register a protocol layer. BCDC is the default protocol layer and being called directly. This patch installs the functions for this layer dynamically. This allows new protocols to be added and selected dynamically depending on the hw capabilties. As currently only BCDC is supported this is always the installed protocol. Reviewed-by: Arend Van Spriel Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/Makefile | 1 + drivers/net/wireless/brcm80211/brcmfmac/bcdc.c | 93 ++++++++++++---------- drivers/net/wireless/brcm80211/brcmfmac/bcdc.h | 24 ++++++ drivers/net/wireless/brcm80211/brcmfmac/dhd.h | 24 +----- .../net/wireless/brcm80211/brcmfmac/dhd_linux.c | 4 +- drivers/net/wireless/brcm80211/brcmfmac/fwil.c | 7 +- drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c | 1 + drivers/net/wireless/brcm80211/brcmfmac/proto.c | 62 +++++++++++++++ drivers/net/wireless/brcm80211/brcmfmac/proto.h | 57 +++++++++++++ 9 files changed, 202 insertions(+), 71 deletions(-) create mode 100644 drivers/net/wireless/brcm80211/brcmfmac/bcdc.h create mode 100644 drivers/net/wireless/brcm80211/brcmfmac/proto.c create mode 100644 drivers/net/wireless/brcm80211/brcmfmac/proto.h diff --git a/drivers/net/wireless/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/brcm80211/brcmfmac/Makefile index e15b61c2614..2082402d4b6 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/Makefile +++ b/drivers/net/wireless/brcm80211/brcmfmac/Makefile @@ -28,6 +28,7 @@ brcmfmac-objs += \ fweh.o \ fwsignal.o \ p2p.o \ + proto.o \ bcdc.o \ dhd_common.o \ dhd_linux.o \ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c index 59c6c054b11..b5a25290877 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c @@ -30,6 +30,8 @@ #include "fwsignal.h" #include "dhd_dbg.h" #include "tracepoint.h" +#include "proto.h" +#include "bcdc.h" struct brcmf_proto_cdc_dcmd { __le32 cmd; /* dongle command value */ @@ -104,7 +106,7 @@ struct brcmf_proto_bdc_header { * Currently is SDIO */ -struct brcmf_proto { +struct brcmf_bcdc { u16 reqid; u8 bus_header[BUS_HEADER_LEN]; struct brcmf_proto_cdc_dcmd msg; @@ -113,8 +115,8 @@ struct brcmf_proto { static int brcmf_proto_cdc_msg(struct brcmf_pub *drvr) { - struct brcmf_proto *prot = drvr->prot; - int len = le32_to_cpu(prot->msg.len) + + struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd; + int len = le32_to_cpu(bcdc->msg.len) + sizeof(struct brcmf_proto_cdc_dcmd); brcmf_dbg(CDC, "Enter\n"); @@ -127,32 +129,32 @@ static int brcmf_proto_cdc_msg(struct brcmf_pub *drvr) len = CDC_MAX_MSG_SIZE; /* Send request */ - return brcmf_bus_txctl(drvr->bus_if, (unsigned char *)&prot->msg, len); + return brcmf_bus_txctl(drvr->bus_if, (unsigned char *)&bcdc->msg, len); } static int brcmf_proto_cdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len) { int ret; - struct brcmf_proto *prot = drvr->prot; + struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd; brcmf_dbg(CDC, "Enter\n"); len += sizeof(struct brcmf_proto_cdc_dcmd); do { - ret = brcmf_bus_rxctl(drvr->bus_if, (unsigned char *)&prot->msg, + ret = brcmf_bus_rxctl(drvr->bus_if, (unsigned char *)&bcdc->msg, len); if (ret < 0) break; - } while (CDC_DCMD_ID(le32_to_cpu(prot->msg.flags)) != id); + } while (CDC_DCMD_ID(le32_to_cpu(bcdc->msg.flags)) != id); return ret; } -int -brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, - void *buf, uint len) +static int +brcmf_proto_bcdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, + void *buf, uint len) { - struct brcmf_proto *prot = drvr->prot; - struct brcmf_proto_cdc_dcmd *msg = &prot->msg; + struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd; + struct brcmf_proto_cdc_dcmd *msg = &bcdc->msg; void *info; int ret = 0, retries = 0; u32 id, flags; @@ -163,13 +165,13 @@ brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, msg->cmd = cpu_to_le32(cmd); msg->len = cpu_to_le32(len); - flags = (++prot->reqid << CDC_DCMD_ID_SHIFT); + flags = (++bcdc->reqid << CDC_DCMD_ID_SHIFT); flags = (flags & ~CDC_DCMD_IF_MASK) | (ifidx << CDC_DCMD_IF_SHIFT); msg->flags = cpu_to_le32(flags); if (buf) - memcpy(prot->buf, buf, len); + memcpy(bcdc->buf, buf, len); ret = brcmf_proto_cdc_msg(drvr); if (ret < 0) { @@ -180,18 +182,18 @@ brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, retry: /* wait for interrupt and get first fragment */ - ret = brcmf_proto_cdc_cmplt(drvr, prot->reqid, len); + ret = brcmf_proto_cdc_cmplt(drvr, bcdc->reqid, len); if (ret < 0) goto done; flags = le32_to_cpu(msg->flags); id = (flags & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT; - if ((id < prot->reqid) && (++retries < RETRIES)) + if ((id < bcdc->reqid) && (++retries < RETRIES)) goto retry; - if (id != prot->reqid) { + if (id != bcdc->reqid) { brcmf_err("%s: unexpected request id %d (expected %d)\n", - brcmf_ifname(drvr, ifidx), id, prot->reqid); + brcmf_ifname(drvr, ifidx), id, bcdc->reqid); ret = -EINVAL; goto done; } @@ -214,11 +216,12 @@ done: return ret; } -int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, - void *buf, uint len) +static int +brcmf_proto_bcdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, + void *buf, uint len) { - struct brcmf_proto *prot = drvr->prot; - struct brcmf_proto_cdc_dcmd *msg = &prot->msg; + struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd; + struct brcmf_proto_cdc_dcmd *msg = &bcdc->msg; int ret = 0; u32 flags, id; @@ -228,28 +231,28 @@ int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, msg->cmd = cpu_to_le32(cmd); msg->len = cpu_to_le32(len); - flags = (++prot->reqid << CDC_DCMD_ID_SHIFT) | CDC_DCMD_SET; + flags = (++bcdc->reqid << CDC_DCMD_ID_SHIFT) | CDC_DCMD_SET; flags = (flags & ~CDC_DCMD_IF_MASK) | (ifidx << CDC_DCMD_IF_SHIFT); msg->flags = cpu_to_le32(flags); if (buf) - memcpy(prot->buf, buf, len); + memcpy(bcdc->buf, buf, len); ret = brcmf_proto_cdc_msg(drvr); if (ret < 0) goto done; - ret = brcmf_proto_cdc_cmplt(drvr, prot->reqid, len); + ret = brcmf_proto_cdc_cmplt(drvr, bcdc->reqid, len); if (ret < 0) goto done; flags = le32_to_cpu(msg->flags); id = (flags & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT; - if (id != prot->reqid) { + if (id != bcdc->reqid) { brcmf_err("%s: unexpected request id %d (expected %d)\n", - brcmf_ifname(drvr, ifidx), id, prot->reqid); + brcmf_ifname(drvr, ifidx), id, bcdc->reqid); ret = -EINVAL; goto done; } @@ -272,7 +275,8 @@ static void pkt_set_sum_good(struct sk_buff *skb, bool x) skb->ip_summed = (x ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE); } -void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx, u8 offset, +static void +brcmf_proto_bcdc_hdrpush(struct brcmf_pub *drvr, int ifidx, u8 offset, struct sk_buff *pktbuf) { struct brcmf_proto_bdc_header *h; @@ -295,8 +299,9 @@ void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx, u8 offset, trace_brcmf_bdchdr(pktbuf->data); } -int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx, - struct sk_buff *pktbuf) +static int +brcmf_proto_bcdc_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx, + struct sk_buff *pktbuf) { struct brcmf_proto_bdc_header *h; @@ -353,34 +358,38 @@ int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx, return 0; } -int brcmf_proto_attach(struct brcmf_pub *drvr) +int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr) { - struct brcmf_proto *cdc; + struct brcmf_bcdc *bcdc; - cdc = kzalloc(sizeof(struct brcmf_proto), GFP_ATOMIC); - if (!cdc) + bcdc = kzalloc(sizeof(*bcdc), GFP_ATOMIC); + if (!bcdc) goto fail; /* ensure that the msg buf directly follows the cdc msg struct */ - if ((unsigned long)(&cdc->msg + 1) != (unsigned long)cdc->buf) { - brcmf_err("struct brcmf_proto is not correctly defined\n"); + if ((unsigned long)(&bcdc->msg + 1) != (unsigned long)bcdc->buf) { + brcmf_err("struct brcmf_proto_bcdc is not correctly defined\n"); goto fail; } - drvr->prot = cdc; + drvr->proto->hdrpush = brcmf_proto_bcdc_hdrpush; + drvr->proto->hdrpull = brcmf_proto_bcdc_hdrpull; + drvr->proto->query_dcmd = brcmf_proto_bcdc_query_dcmd; + drvr->proto->set_dcmd = brcmf_proto_bcdc_set_dcmd; + drvr->proto->pd = bcdc; + drvr->hdrlen += BDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES; drvr->bus_if->maxctl = BRCMF_DCMD_MAXLEN + sizeof(struct brcmf_proto_cdc_dcmd) + ROUND_UP_MARGIN; return 0; fail: - kfree(cdc); + kfree(bcdc); return -ENOMEM; } -/* ~NOTE~ What if another thread is waiting on the semaphore? Holding it? */ -void brcmf_proto_detach(struct brcmf_pub *drvr) +void brcmf_proto_bcdc_detach(struct brcmf_pub *drvr) { - kfree(drvr->prot); - drvr->prot = NULL; + kfree(drvr->proto->pd); + drvr->proto->pd = NULL; } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcdc.h b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.h new file mode 100644 index 00000000000..17e8c039ff3 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2013 Broadcom Corporation + * + * 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. + */ +#ifndef BRCMFMAC_BCDC_H +#define BRCMFMAC_BCDC_H + + +int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr); +void brcmf_proto_bcdc_detach(struct brcmf_pub *drvr); + + +#endif /* BRCMFMAC_BCDC_H */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h index dc2ebefa4ca..4ed7a97bd19 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h @@ -535,7 +535,7 @@ struct brcmf_fws_info; /* firmware signalling info */ struct brcmf_pub { /* Linkage ponters */ struct brcmf_bus *bus_if; - struct brcmf_proto *prot; + struct brcmf_proto *proto; struct brcmf_cfg80211_info *config; /* Internal brcmf items */ @@ -635,28 +635,6 @@ int brcmf_netdev_wait_pend8021x(struct net_device *ndev); /* Return pointer to interface name */ char *brcmf_ifname(struct brcmf_pub *drvr, int idx); -/* Linkage, sets prot link and updates hdrlen in pub */ -int brcmf_proto_attach(struct brcmf_pub *drvr); - -/* Unlink, frees allocated protocol memory (including brcmf_proto) */ -void brcmf_proto_detach(struct brcmf_pub *drvr); - -/* Add any protocol-specific data header. - * Caller must reserve prot_hdrlen prepend space. - */ -void brcmf_proto_hdrpush(struct brcmf_pub *, int ifidx, u8 offset, - struct sk_buff *txp); - -/* Query dongle */ -int brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, - void *buf, uint len); -int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, - void *buf, uint len); - -/* Remove any protocol-specific data header. */ -int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx, - struct sk_buff *rxp); - int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked); struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx, char *name, u8 *mac_addr); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index 9336f6dd3f8..644e62e1963 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -30,6 +30,7 @@ #include "wl_cfg80211.h" #include "fwil.h" #include "fwsignal.h" +#include "proto.h" MODULE_AUTHOR("Broadcom Corporation"); MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver."); @@ -1040,8 +1041,7 @@ void brcmf_detach(struct device *dev) brcmf_bus_detach(drvr); - if (drvr->prot) - brcmf_proto_detach(drvr); + brcmf_proto_detach(drvr); brcmf_fws_deinit(drvr); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c index 04f395930d8..b72d3395499 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c @@ -27,6 +27,7 @@ #include "dhd_dbg.h" #include "tracepoint.h" #include "fwil.h" +#include "proto.h" #define MAX_HEX_DUMP_LEN 64 @@ -46,11 +47,9 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set) if (data != NULL) len = min_t(uint, len, BRCMF_DCMD_MAXLEN); if (set) - err = brcmf_proto_cdc_set_dcmd(drvr, ifp->ifidx, cmd, data, - len); + err = brcmf_proto_set_dcmd(drvr, ifp->ifidx, cmd, data, len); else - err = brcmf_proto_cdc_query_dcmd(drvr, ifp->ifidx, cmd, data, - len); + err = brcmf_proto_query_dcmd(drvr, ifp->ifidx, cmd, data, len); if (err >= 0) err = 0; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c index b96ee3a93a6..e9bdfdb95d8 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c @@ -35,6 +35,7 @@ #include "fwsignal.h" #include "p2p.h" #include "wl_cfg80211.h" +#include "proto.h" /** * DOC: Firmware Signalling diff --git a/drivers/net/wireless/brcm80211/brcmfmac/proto.c b/drivers/net/wireless/brcm80211/brcmfmac/proto.c new file mode 100644 index 00000000000..87eb2bd4c07 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/proto.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2013 Broadcom Corporation + * + * 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 + +#include +#include "dhd.h" +#include "dhd_dbg.h" +#include "proto.h" +#include "bcdc.h" + + +int brcmf_proto_attach(struct brcmf_pub *drvr) +{ + struct brcmf_proto *proto; + + proto = kzalloc(sizeof(*proto), GFP_ATOMIC); + if (!proto) + goto fail; + + drvr->proto = proto; + /* BCDC protocol is only protocol supported for the moment */ + if (brcmf_proto_bcdc_attach(drvr)) + goto fail; + + if ((proto->hdrpush == NULL) || (proto->hdrpull == NULL) || + (proto->query_dcmd == NULL) || (proto->set_dcmd == NULL)) { + brcmf_err("Not all proto handlers have been installed\n"); + goto fail; + } + return 0; + +fail: + kfree(proto); + drvr->proto = NULL; + return -ENOMEM; +} + +void brcmf_proto_detach(struct brcmf_pub *drvr) +{ + if (drvr->proto) { + brcmf_proto_bcdc_detach(drvr); + kfree(drvr->proto); + drvr->proto = NULL; + } +} diff --git a/drivers/net/wireless/brcm80211/brcmfmac/proto.h b/drivers/net/wireless/brcm80211/brcmfmac/proto.h new file mode 100644 index 00000000000..8de1b3bce22 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/proto.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2013 Broadcom Corporation + * + * 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. + */ +#ifndef BRCMFMAC_PROTO_H +#define BRCMFMAC_PROTO_H + +struct brcmf_proto { + void (*hdrpush)(struct brcmf_pub *drvr, int ifidx, u8 offset, + struct sk_buff *skb); + int (*hdrpull)(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx, + struct sk_buff *skb); + int (*query_dcmd)(struct brcmf_pub *drvr, int ifidx, uint cmd, + void *buf, uint len); + int (*set_dcmd)(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf, + uint len); + void *pd; +}; + + +int brcmf_proto_attach(struct brcmf_pub *drvr); +void brcmf_proto_detach(struct brcmf_pub *drvr); + +static inline void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx, + u8 offset, struct sk_buff *skb) +{ + drvr->proto->hdrpush(drvr, ifidx, offset, skb); +} +static inline int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws, + u8 *ifidx, struct sk_buff *skb) +{ + return drvr->proto->hdrpull(drvr, do_fws, ifidx, skb); +} +static inline int brcmf_proto_query_dcmd(struct brcmf_pub *drvr, int ifidx, + uint cmd, void *buf, uint len) +{ + return drvr->proto->query_dcmd(drvr, ifidx, cmd, buf, len); +} +static inline int brcmf_proto_set_dcmd(struct brcmf_pub *drvr, int ifidx, + uint cmd, void *buf, uint len) +{ + return drvr->proto->set_dcmd(drvr, ifidx, cmd, buf, len); +} + + +#endif /* BRCMFMAC_PROTO_H */ -- cgit v1.2.3-70-g09d2 From 55685b8f2f9f419b1b1c5abf78a5c82f01ef0fe3 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Fri, 29 Nov 2013 12:25:17 +0100 Subject: brcmfmac: provide firmware version in ethtool driver info Knowing the firmware version is pretty useful information when looking at issues. It is retrieved during initialization so store it in driver data structure to fill the ethtool driver info when requested. Reviewed-by: Hante Meuleman Reviewed-by: Franky Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd.h | 7 ++++++- drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c | 5 +++++ drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c | 4 ++-- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h index 4ed7a97bd19..714194c16a9 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h @@ -211,6 +211,11 @@ #define BRCMF_AMPDU_RX_REORDER_MAXFLOWS 256 +/* Length of firmware version string stored for + * ethtool driver info which uses 32 bytes as well. + */ +#define BRCMF_DRIVER_FIRMWARE_VERSION_LEN 32 + /* Pattern matching filter. Specifies an offset within received packets to * start matching, the pattern to match, the size of the pattern, and a bitmask * that indicates which bits within the pattern should be matched. @@ -544,7 +549,7 @@ struct brcmf_pub { u8 wme_dp; /* wme discard priority */ /* Dongle media info */ - unsigned long drv_version; /* Version of dongle-resident driver */ + char fwver[BRCMF_DRIVER_FIRMWARE_VERSION_LEN]; u8 mac[ETH_ALEN]; /* MAC address obtained from dongle */ /* Multicast data packets sent to dongle */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c index 60176339318..d5811a46a33 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c @@ -278,9 +278,14 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) } ptr = (char *)buf; strsep(&ptr, "\n"); + /* Print fw version info */ brcmf_err("Firmware version = %s\n", buf); + /* locate firmware version number for ethtool */ + ptr = strrchr(buf, ' ') + 1; + strlcpy(ifp->drvr->fwver, ptr, sizeof(ifp->drvr->fwver)); + /* * Setup timeout if Beacons are lost and roam is off to report * link down diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index 644e62e1963..bce0b8e511f 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -599,8 +599,8 @@ static void brcmf_ethtool_get_drvinfo(struct net_device *ndev, struct brcmf_pub *drvr = ifp->drvr; strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); - snprintf(info->version, sizeof(info->version), "%lu", - drvr->drv_version); + snprintf(info->version, sizeof(info->version), "n/a"); + strlcpy(info->fw_version, drvr->fwver, sizeof(info->fw_version)); strlcpy(info->bus_info, dev_name(drvr->bus_if->dev), sizeof(info->bus_info)); } -- cgit v1.2.3-70-g09d2 From 84c69fb164cb0713c3e95bd190611f196d24c5b5 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Fri, 29 Nov 2013 12:25:18 +0100 Subject: brcmfmac: remove unnecessary EXPORT_SYMBOL() usage In bcmsdh.c the functions brcmf_sdio_probe() and brcmf_sdio_remove() were exported, but that is not needed. The functions are linked into the driver module, which is the only one needing to call these. Reviewed-by: Franky Lin Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Daniel (Deognyoun) Kim Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index 3e10b801eee..91651ec7f13 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -17,7 +17,6 @@ #include #include -#include #include #include #include @@ -774,7 +773,6 @@ out: return ret; } -EXPORT_SYMBOL(brcmf_sdio_probe); int brcmf_sdio_remove(struct brcmf_sdio_dev *sdiodev) { @@ -791,7 +789,6 @@ int brcmf_sdio_remove(struct brcmf_sdio_dev *sdiodev) return 0; } -EXPORT_SYMBOL(brcmf_sdio_remove); void brcmf_sdio_wdtmr_enable(struct brcmf_sdio_dev *sdiodev, bool enable) { -- cgit v1.2.3-70-g09d2 From 6f5838a48aad77defef5e2ed91608e862309e351 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Fri, 29 Nov 2013 12:25:19 +0100 Subject: brcmfmac: move firmware related structures to fwil_types.h The firmware control interface is provided by fwil source file, but a number of structures used to communicate with the firmware still resided in dhd.h. The patch moves them to fwil_types.h. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd.h | 306 --------------------- .../net/wireless/brcm80211/brcmfmac/dhd_common.c | 1 + .../net/wireless/brcm80211/brcmfmac/fwil_types.h | 304 ++++++++++++++++++++ .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 10 +- 4 files changed, 310 insertions(+), 311 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h index 714194c16a9..780615577fa 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h @@ -100,31 +100,11 @@ #define TOE_TX_CSUM_OL 0x00000001 #define TOE_RX_CSUM_OL 0x00000002 -#define BRCMF_BSS_INFO_VERSION 109 /* curr ver of brcmf_bss_info_le struct */ - -/* size of brcmf_scan_params not including variable length array */ -#define BRCMF_SCAN_PARAMS_FIXED_SIZE 64 - -/* masks for channel and ssid count */ -#define BRCMF_SCAN_PARAMS_COUNT_MASK 0x0000ffff -#define BRCMF_SCAN_PARAMS_NSSID_SHIFT 16 - -/* primary (ie tx) key */ -#define BRCMF_PRIMARY_KEY (1 << 1) - /* For supporting multiple interfaces */ #define BRCMF_MAX_IFS 16 -#define DOT11_BSSTYPE_ANY 2 #define DOT11_MAX_DEFAULT_KEYS 4 -#define BRCMF_ESCAN_REQ_VERSION 1 - -#define WLC_BSS_RSSI_ON_CHANNEL 0x0002 - -#define BRCMF_MAXRATES_IN_SET 16 /* max # of rates in rateset */ -#define BRCMF_STA_ASSOC 0x10 /* Associated */ - #define BRCMF_E_STATUS_SUCCESS 0 #define BRCMF_E_STATUS_FAIL 1 #define BRCMF_E_STATUS_TIMEOUT 2 @@ -216,292 +196,6 @@ */ #define BRCMF_DRIVER_FIRMWARE_VERSION_LEN 32 -/* Pattern matching filter. Specifies an offset within received packets to - * start matching, the pattern to match, the size of the pattern, and a bitmask - * that indicates which bits within the pattern should be matched. - */ -struct brcmf_pkt_filter_pattern_le { - /* - * Offset within received packet to start pattern matching. - * Offset '0' is the first byte of the ethernet header. - */ - __le32 offset; - /* Size of the pattern. Bitmask must be the same size.*/ - __le32 size_bytes; - /* - * Variable length mask and pattern data. mask starts at offset 0. - * Pattern immediately follows mask. - */ - u8 mask_and_pattern[1]; -}; - -/* IOVAR "pkt_filter_add" parameter. Used to install packet filters. */ -struct brcmf_pkt_filter_le { - __le32 id; /* Unique filter id, specified by app. */ - __le32 type; /* Filter type (WL_PKT_FILTER_TYPE_xxx). */ - __le32 negate_match; /* Negate the result of filter matches */ - union { /* Filter definitions */ - struct brcmf_pkt_filter_pattern_le pattern; /* Filter pattern */ - } u; -}; - -/* IOVAR "pkt_filter_enable" parameter. */ -struct brcmf_pkt_filter_enable_le { - __le32 id; /* Unique filter id */ - __le32 enable; /* Enable/disable bool */ -}; - -/* BSS info structure - * Applications MUST CHECK ie_offset field and length field to access IEs and - * next bss_info structure in a vector (in struct brcmf_scan_results) - */ -struct brcmf_bss_info_le { - __le32 version; /* version field */ - __le32 length; /* byte length of data in this record, - * starting at version and including IEs - */ - u8 BSSID[ETH_ALEN]; - __le16 beacon_period; /* units are Kusec */ - __le16 capability; /* Capability information */ - u8 SSID_len; - u8 SSID[32]; - struct { - __le32 count; /* # rates in this set */ - u8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */ - } rateset; /* supported rates */ - __le16 chanspec; /* chanspec for bss */ - __le16 atim_window; /* units are Kusec */ - u8 dtim_period; /* DTIM period */ - __le16 RSSI; /* receive signal strength (in dBm) */ - s8 phy_noise; /* noise (in dBm) */ - - u8 n_cap; /* BSS is 802.11N Capable */ - /* 802.11N BSS Capabilities (based on HT_CAP_*): */ - __le32 nbss_cap; - u8 ctl_ch; /* 802.11N BSS control channel number */ - __le32 reserved32[1]; /* Reserved for expansion of BSS properties */ - u8 flags; /* flags */ - u8 reserved[3]; /* Reserved for expansion of BSS properties */ - u8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */ - - __le16 ie_offset; /* offset at which IEs start, from beginning */ - __le32 ie_length; /* byte length of Information Elements */ - __le16 SNR; /* average SNR of during frame reception */ - /* Add new fields here */ - /* variable length Information Elements */ -}; - -struct brcm_rateset_le { - /* # rates in this set */ - __le32 count; - /* rates in 500kbps units w/hi bit set if basic */ - u8 rates[BRCMF_MAXRATES_IN_SET]; -}; - -struct brcmf_ssid { - u32 SSID_len; - unsigned char SSID[32]; -}; - -struct brcmf_ssid_le { - __le32 SSID_len; - unsigned char SSID[32]; -}; - -struct brcmf_scan_params_le { - struct brcmf_ssid_le ssid_le; /* default: {0, ""} */ - u8 bssid[ETH_ALEN]; /* default: bcast */ - s8 bss_type; /* default: any, - * DOT11_BSSTYPE_ANY/INFRASTRUCTURE/INDEPENDENT - */ - u8 scan_type; /* flags, 0 use default */ - __le32 nprobes; /* -1 use default, number of probes per channel */ - __le32 active_time; /* -1 use default, dwell time per channel for - * active scanning - */ - __le32 passive_time; /* -1 use default, dwell time per channel - * for passive scanning - */ - __le32 home_time; /* -1 use default, dwell time for the - * home channel between channel scans - */ - __le32 channel_num; /* count of channels and ssids that follow - * - * low half is count of channels in - * channel_list, 0 means default (use all - * available channels) - * - * high half is entries in struct brcmf_ssid - * array that follows channel_list, aligned for - * s32 (4 bytes) meaning an odd channel count - * implies a 2-byte pad between end of - * channel_list and first ssid - * - * if ssid count is zero, single ssid in the - * fixed parameter portion is assumed, otherwise - * ssid in the fixed portion is ignored - */ - __le16 channel_list[1]; /* list of chanspecs */ -}; - -struct brcmf_scan_results { - u32 buflen; - u32 version; - u32 count; - struct brcmf_bss_info_le bss_info_le[]; -}; - -struct brcmf_escan_params_le { - __le32 version; - __le16 action; - __le16 sync_id; - struct brcmf_scan_params_le params_le; -}; - -struct brcmf_escan_result_le { - __le32 buflen; - __le32 version; - __le16 sync_id; - __le16 bss_count; - struct brcmf_bss_info_le bss_info_le; -}; - -#define WL_ESCAN_RESULTS_FIXED_SIZE (sizeof(struct brcmf_escan_result_le) - \ - sizeof(struct brcmf_bss_info_le)) - -/* used for association with a specific BSSID and chanspec list */ -struct brcmf_assoc_params_le { - /* 00:00:00:00:00:00: broadcast scan */ - u8 bssid[ETH_ALEN]; - /* 0: all available channels, otherwise count of chanspecs in - * chanspec_list */ - __le32 chanspec_num; - /* list of chanspecs */ - __le16 chanspec_list[1]; -}; - -/* used for join with or without a specific bssid and channel list */ -struct brcmf_join_params { - struct brcmf_ssid_le ssid_le; - struct brcmf_assoc_params_le params_le; -}; - -/* scan params for extended join */ -struct brcmf_join_scan_params_le { - u8 scan_type; /* 0 use default, active or passive scan */ - __le32 nprobes; /* -1 use default, nr of probes per channel */ - __le32 active_time; /* -1 use default, dwell time per channel for - * active scanning - */ - __le32 passive_time; /* -1 use default, dwell time per channel - * for passive scanning - */ - __le32 home_time; /* -1 use default, dwell time for the home - * channel between channel scans - */ -}; - -/* extended join params */ -struct brcmf_ext_join_params_le { - struct brcmf_ssid_le ssid_le; /* {0, ""}: wildcard scan */ - struct brcmf_join_scan_params_le scan_le; - struct brcmf_assoc_params_le assoc_le; -}; - -struct brcmf_wsec_key { - u32 index; /* key index */ - u32 len; /* key length */ - u8 data[WLAN_MAX_KEY_LEN]; /* key data */ - u32 pad_1[18]; - u32 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */ - u32 flags; /* misc flags */ - u32 pad_2[3]; - u32 iv_initialized; /* has IV been initialized already? */ - u32 pad_3; - /* Rx IV */ - struct { - u32 hi; /* upper 32 bits of IV */ - u16 lo; /* lower 16 bits of IV */ - } rxiv; - u32 pad_4[2]; - u8 ea[ETH_ALEN]; /* per station */ -}; - -/* - * dongle requires same struct as above but with fields in little endian order - */ -struct brcmf_wsec_key_le { - __le32 index; /* key index */ - __le32 len; /* key length */ - u8 data[WLAN_MAX_KEY_LEN]; /* key data */ - __le32 pad_1[18]; - __le32 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */ - __le32 flags; /* misc flags */ - __le32 pad_2[3]; - __le32 iv_initialized; /* has IV been initialized already? */ - __le32 pad_3; - /* Rx IV */ - struct { - __le32 hi; /* upper 32 bits of IV */ - __le16 lo; /* lower 16 bits of IV */ - } rxiv; - __le32 pad_4[2]; - u8 ea[ETH_ALEN]; /* per station */ -}; - -/* Used to get specific STA parameters */ -struct brcmf_scb_val_le { - __le32 val; - u8 ea[ETH_ALEN]; -}; - -/* channel encoding */ -struct brcmf_channel_info_le { - __le32 hw_channel; - __le32 target_channel; - __le32 scan_channel; -}; - -struct brcmf_sta_info_le { - __le16 ver; /* version of this struct */ - __le16 len; /* length in bytes of this structure */ - __le16 cap; /* sta's advertised capabilities */ - __le32 flags; /* flags defined below */ - __le32 idle; /* time since data pkt rx'd from sta */ - u8 ea[ETH_ALEN]; /* Station address */ - __le32 count; /* # rates in this set */ - u8 rates[BRCMF_MAXRATES_IN_SET]; /* rates in 500kbps units */ - /* w/hi bit set if basic */ - __le32 in; /* seconds elapsed since associated */ - __le32 listen_interval_inms; /* Min Listen interval in ms for STA */ - __le32 tx_pkts; /* # of packets transmitted */ - __le32 tx_failures; /* # of packets failed */ - __le32 rx_ucast_pkts; /* # of unicast packets received */ - __le32 rx_mcast_pkts; /* # of multicast packets received */ - __le32 tx_rate; /* Rate of last successful tx frame */ - __le32 rx_rate; /* Rate of last successful rx frame */ - __le32 rx_decrypt_succeeds; /* # of packet decrypted successfully */ - __le32 rx_decrypt_failures; /* # of packet decrypted failed */ -}; - -struct brcmf_chanspec_list { - __le32 count; /* # of entries */ - __le32 element[1]; /* variable length uint32 list */ -}; - -/* - * WLC_E_PROBRESP_MSG - * WLC_E_P2P_PROBREQ_MSG - * WLC_E_ACTION_FRAME_RX - */ -struct brcmf_rx_mgmt_data { - __be16 version; - __be16 chanspec; - __be32 rssi; - __be32 mactime; - __be32 rate; -}; - /* Bus independent dongle command */ struct brcmf_dcmd { uint cmd; /* common dongle cmd definition */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c index d5811a46a33..548dbb5542c 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c @@ -23,6 +23,7 @@ #include "dhd_bus.h" #include "dhd_dbg.h" #include "fwil.h" +#include "fwil_types.h" #include "tracepoint.h" #define PKTFILTER_BUF_SIZE 128 diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h index ecabb04f33c..af17a5bc8b8 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h @@ -29,6 +29,24 @@ #define BRCMF_ARP_OL_HOST_AUTO_REPLY 0x00000004 #define BRCMF_ARP_OL_PEER_AUTO_REPLY 0x00000008 +#define BRCMF_BSS_INFO_VERSION 109 /* curr ver of brcmf_bss_info_le struct */ +#define BRCMF_BSS_RSSI_ON_CHANNEL 0x0002 + +#define BRCMF_STA_ASSOC 0x10 /* Associated */ + +/* size of brcmf_scan_params not including variable length array */ +#define BRCMF_SCAN_PARAMS_FIXED_SIZE 64 + +/* masks for channel and ssid count */ +#define BRCMF_SCAN_PARAMS_COUNT_MASK 0x0000ffff +#define BRCMF_SCAN_PARAMS_NSSID_SHIFT 16 + +/* primary (ie tx) key */ +#define BRCMF_PRIMARY_KEY (1 << 1) +#define DOT11_BSSTYPE_ANY 2 +#define BRCMF_ESCAN_REQ_VERSION 1 + +#define BRCMF_MAXRATES_IN_SET 16 /* max # of rates in rateset */ enum brcmf_fil_p2p_if_types { BRCMF_FIL_P2P_IF_CLIENT, @@ -90,4 +108,290 @@ enum brcmf_tdls_manual_ep_ops { BRCMF_TDLS_MANUAL_EP_DISCOVERY = 6 }; +/* Pattern matching filter. Specifies an offset within received packets to + * start matching, the pattern to match, the size of the pattern, and a bitmask + * that indicates which bits within the pattern should be matched. + */ +struct brcmf_pkt_filter_pattern_le { + /* + * Offset within received packet to start pattern matching. + * Offset '0' is the first byte of the ethernet header. + */ + __le32 offset; + /* Size of the pattern. Bitmask must be the same size.*/ + __le32 size_bytes; + /* + * Variable length mask and pattern data. mask starts at offset 0. + * Pattern immediately follows mask. + */ + u8 mask_and_pattern[1]; +}; + +/* IOVAR "pkt_filter_add" parameter. Used to install packet filters. */ +struct brcmf_pkt_filter_le { + __le32 id; /* Unique filter id, specified by app. */ + __le32 type; /* Filter type (WL_PKT_FILTER_TYPE_xxx). */ + __le32 negate_match; /* Negate the result of filter matches */ + union { /* Filter definitions */ + struct brcmf_pkt_filter_pattern_le pattern; /* Filter pattern */ + } u; +}; + +/* IOVAR "pkt_filter_enable" parameter. */ +struct brcmf_pkt_filter_enable_le { + __le32 id; /* Unique filter id */ + __le32 enable; /* Enable/disable bool */ +}; + +/* BSS info structure + * Applications MUST CHECK ie_offset field and length field to access IEs and + * next bss_info structure in a vector (in struct brcmf_scan_results) + */ +struct brcmf_bss_info_le { + __le32 version; /* version field */ + __le32 length; /* byte length of data in this record, + * starting at version and including IEs + */ + u8 BSSID[ETH_ALEN]; + __le16 beacon_period; /* units are Kusec */ + __le16 capability; /* Capability information */ + u8 SSID_len; + u8 SSID[32]; + struct { + __le32 count; /* # rates in this set */ + u8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */ + } rateset; /* supported rates */ + __le16 chanspec; /* chanspec for bss */ + __le16 atim_window; /* units are Kusec */ + u8 dtim_period; /* DTIM period */ + __le16 RSSI; /* receive signal strength (in dBm) */ + s8 phy_noise; /* noise (in dBm) */ + + u8 n_cap; /* BSS is 802.11N Capable */ + /* 802.11N BSS Capabilities (based on HT_CAP_*): */ + __le32 nbss_cap; + u8 ctl_ch; /* 802.11N BSS control channel number */ + __le32 reserved32[1]; /* Reserved for expansion of BSS properties */ + u8 flags; /* flags */ + u8 reserved[3]; /* Reserved for expansion of BSS properties */ + u8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */ + + __le16 ie_offset; /* offset at which IEs start, from beginning */ + __le32 ie_length; /* byte length of Information Elements */ + __le16 SNR; /* average SNR of during frame reception */ + /* Add new fields here */ + /* variable length Information Elements */ +}; + +struct brcm_rateset_le { + /* # rates in this set */ + __le32 count; + /* rates in 500kbps units w/hi bit set if basic */ + u8 rates[BRCMF_MAXRATES_IN_SET]; +}; + +struct brcmf_ssid { + u32 SSID_len; + unsigned char SSID[32]; +}; + +struct brcmf_ssid_le { + __le32 SSID_len; + unsigned char SSID[32]; +}; + +struct brcmf_scan_params_le { + struct brcmf_ssid_le ssid_le; /* default: {0, ""} */ + u8 bssid[ETH_ALEN]; /* default: bcast */ + s8 bss_type; /* default: any, + * DOT11_BSSTYPE_ANY/INFRASTRUCTURE/INDEPENDENT + */ + u8 scan_type; /* flags, 0 use default */ + __le32 nprobes; /* -1 use default, number of probes per channel */ + __le32 active_time; /* -1 use default, dwell time per channel for + * active scanning + */ + __le32 passive_time; /* -1 use default, dwell time per channel + * for passive scanning + */ + __le32 home_time; /* -1 use default, dwell time for the + * home channel between channel scans + */ + __le32 channel_num; /* count of channels and ssids that follow + * + * low half is count of channels in + * channel_list, 0 means default (use all + * available channels) + * + * high half is entries in struct brcmf_ssid + * array that follows channel_list, aligned for + * s32 (4 bytes) meaning an odd channel count + * implies a 2-byte pad between end of + * channel_list and first ssid + * + * if ssid count is zero, single ssid in the + * fixed parameter portion is assumed, otherwise + * ssid in the fixed portion is ignored + */ + __le16 channel_list[1]; /* list of chanspecs */ +}; + +struct brcmf_scan_results { + u32 buflen; + u32 version; + u32 count; + struct brcmf_bss_info_le bss_info_le[]; +}; + +struct brcmf_escan_params_le { + __le32 version; + __le16 action; + __le16 sync_id; + struct brcmf_scan_params_le params_le; +}; + +struct brcmf_escan_result_le { + __le32 buflen; + __le32 version; + __le16 sync_id; + __le16 bss_count; + struct brcmf_bss_info_le bss_info_le; +}; + +#define WL_ESCAN_RESULTS_FIXED_SIZE (sizeof(struct brcmf_escan_result_le) - \ + sizeof(struct brcmf_bss_info_le)) + +/* used for association with a specific BSSID and chanspec list */ +struct brcmf_assoc_params_le { + /* 00:00:00:00:00:00: broadcast scan */ + u8 bssid[ETH_ALEN]; + /* 0: all available channels, otherwise count of chanspecs in + * chanspec_list */ + __le32 chanspec_num; + /* list of chanspecs */ + __le16 chanspec_list[1]; +}; + +/* used for join with or without a specific bssid and channel list */ +struct brcmf_join_params { + struct brcmf_ssid_le ssid_le; + struct brcmf_assoc_params_le params_le; +}; + +/* scan params for extended join */ +struct brcmf_join_scan_params_le { + u8 scan_type; /* 0 use default, active or passive scan */ + __le32 nprobes; /* -1 use default, nr of probes per channel */ + __le32 active_time; /* -1 use default, dwell time per channel for + * active scanning + */ + __le32 passive_time; /* -1 use default, dwell time per channel + * for passive scanning + */ + __le32 home_time; /* -1 use default, dwell time for the home + * channel between channel scans + */ +}; + +/* extended join params */ +struct brcmf_ext_join_params_le { + struct brcmf_ssid_le ssid_le; /* {0, ""}: wildcard scan */ + struct brcmf_join_scan_params_le scan_le; + struct brcmf_assoc_params_le assoc_le; +}; + +struct brcmf_wsec_key { + u32 index; /* key index */ + u32 len; /* key length */ + u8 data[WLAN_MAX_KEY_LEN]; /* key data */ + u32 pad_1[18]; + u32 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */ + u32 flags; /* misc flags */ + u32 pad_2[3]; + u32 iv_initialized; /* has IV been initialized already? */ + u32 pad_3; + /* Rx IV */ + struct { + u32 hi; /* upper 32 bits of IV */ + u16 lo; /* lower 16 bits of IV */ + } rxiv; + u32 pad_4[2]; + u8 ea[ETH_ALEN]; /* per station */ +}; + +/* + * dongle requires same struct as above but with fields in little endian order + */ +struct brcmf_wsec_key_le { + __le32 index; /* key index */ + __le32 len; /* key length */ + u8 data[WLAN_MAX_KEY_LEN]; /* key data */ + __le32 pad_1[18]; + __le32 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */ + __le32 flags; /* misc flags */ + __le32 pad_2[3]; + __le32 iv_initialized; /* has IV been initialized already? */ + __le32 pad_3; + /* Rx IV */ + struct { + __le32 hi; /* upper 32 bits of IV */ + __le16 lo; /* lower 16 bits of IV */ + } rxiv; + __le32 pad_4[2]; + u8 ea[ETH_ALEN]; /* per station */ +}; + +/* Used to get specific STA parameters */ +struct brcmf_scb_val_le { + __le32 val; + u8 ea[ETH_ALEN]; +}; + +/* channel encoding */ +struct brcmf_channel_info_le { + __le32 hw_channel; + __le32 target_channel; + __le32 scan_channel; +}; + +struct brcmf_sta_info_le { + __le16 ver; /* version of this struct */ + __le16 len; /* length in bytes of this structure */ + __le16 cap; /* sta's advertised capabilities */ + __le32 flags; /* flags defined below */ + __le32 idle; /* time since data pkt rx'd from sta */ + u8 ea[ETH_ALEN]; /* Station address */ + __le32 count; /* # rates in this set */ + u8 rates[BRCMF_MAXRATES_IN_SET]; /* rates in 500kbps units */ + /* w/hi bit set if basic */ + __le32 in; /* seconds elapsed since associated */ + __le32 listen_interval_inms; /* Min Listen interval in ms for STA */ + __le32 tx_pkts; /* # of packets transmitted */ + __le32 tx_failures; /* # of packets failed */ + __le32 rx_ucast_pkts; /* # of unicast packets received */ + __le32 rx_mcast_pkts; /* # of multicast packets received */ + __le32 tx_rate; /* Rate of last successful tx frame */ + __le32 rx_rate; /* Rate of last successful rx frame */ + __le32 rx_decrypt_succeeds; /* # of packet decrypted successfully */ + __le32 rx_decrypt_failures; /* # of packet decrypted failed */ +}; + +struct brcmf_chanspec_list { + __le32 count; /* # of entries */ + __le32 element[1]; /* variable length uint32 list */ +}; + +/* + * WLC_E_PROBRESP_MSG + * WLC_E_P2P_PROBREQ_MSG + * WLC_E_ACTION_FRAME_RX + */ +struct brcmf_rx_mgmt_data { + __be16 version; + __be16 chanspec; + __be32 rssi; + __be32 mactime; + __be32 rate; +}; + #endif /* FWIL_TYPES_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 571f013cebb..470a47f2b38 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -2556,8 +2556,8 @@ brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg, ch_bss.band == ch_bss_info_le.band && bss_info_le->SSID_len == bss->SSID_len && !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) { - if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) == - (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL)) { + if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) == + (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL)) { s16 bss_rssi = le16_to_cpu(bss->RSSI); s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI); @@ -2566,13 +2566,13 @@ brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg, */ if (bss_info_rssi > bss_rssi) bss->RSSI = bss_info_le->RSSI; - } else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) && - (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) { + } else if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) && + (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL) == 0) { /* preserve the on-channel rssi measurement * if the new measurement is off channel */ bss->RSSI = bss_info_le->RSSI; - bss->flags |= WLC_BSS_RSSI_ON_CHANNEL; + bss->flags |= BRCMF_BSS_RSSI_ON_CHANNEL; } return 1; } -- cgit v1.2.3-70-g09d2 From 5ca85216b173ebac0aa523e4dd826d82d530a465 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Fri, 29 Nov 2013 12:25:20 +0100 Subject: brcmfmac: move firmware command code definitions Move the command codes to the firmware interface module as that makes a bit more sense. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd.h | 61 -------------------------- drivers/net/wireless/brcm80211/brcmfmac/fwil.h | 61 ++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 61 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h index 780615577fa..a85f9db3628 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h @@ -25,67 +25,6 @@ #include "fweh.h" -/******************************************************************************* - * IO codes that are interpreted by dongle firmware - ******************************************************************************/ -#define BRCMF_C_GET_VERSION 1 -#define BRCMF_C_UP 2 -#define BRCMF_C_DOWN 3 -#define BRCMF_C_SET_PROMISC 10 -#define BRCMF_C_GET_RATE 12 -#define BRCMF_C_GET_INFRA 19 -#define BRCMF_C_SET_INFRA 20 -#define BRCMF_C_GET_AUTH 21 -#define BRCMF_C_SET_AUTH 22 -#define BRCMF_C_GET_BSSID 23 -#define BRCMF_C_GET_SSID 25 -#define BRCMF_C_SET_SSID 26 -#define BRCMF_C_TERMINATED 28 -#define BRCMF_C_GET_CHANNEL 29 -#define BRCMF_C_SET_CHANNEL 30 -#define BRCMF_C_GET_SRL 31 -#define BRCMF_C_SET_SRL 32 -#define BRCMF_C_GET_LRL 33 -#define BRCMF_C_SET_LRL 34 -#define BRCMF_C_GET_RADIO 37 -#define BRCMF_C_SET_RADIO 38 -#define BRCMF_C_GET_PHYTYPE 39 -#define BRCMF_C_SET_KEY 45 -#define BRCMF_C_SET_PASSIVE_SCAN 49 -#define BRCMF_C_SCAN 50 -#define BRCMF_C_SCAN_RESULTS 51 -#define BRCMF_C_DISASSOC 52 -#define BRCMF_C_REASSOC 53 -#define BRCMF_C_SET_ROAM_TRIGGER 55 -#define BRCMF_C_SET_ROAM_DELTA 57 -#define BRCMF_C_GET_BCNPRD 75 -#define BRCMF_C_SET_BCNPRD 76 -#define BRCMF_C_GET_DTIMPRD 77 -#define BRCMF_C_SET_DTIMPRD 78 -#define BRCMF_C_SET_COUNTRY 84 -#define BRCMF_C_GET_PM 85 -#define BRCMF_C_SET_PM 86 -#define BRCMF_C_GET_CURR_RATESET 114 -#define BRCMF_C_GET_AP 117 -#define BRCMF_C_SET_AP 118 -#define BRCMF_C_GET_RSSI 127 -#define BRCMF_C_GET_WSEC 133 -#define BRCMF_C_SET_WSEC 134 -#define BRCMF_C_GET_PHY_NOISE 135 -#define BRCMF_C_GET_BSS_INFO 136 -#define BRCMF_C_GET_BANDLIST 140 -#define BRCMF_C_SET_SCB_TIMEOUT 158 -#define BRCMF_C_GET_PHYLIST 180 -#define BRCMF_C_SET_SCAN_CHANNEL_TIME 185 -#define BRCMF_C_SET_SCAN_UNASSOC_TIME 187 -#define BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON 201 -#define BRCMF_C_GET_VALID_CHANNELS 217 -#define BRCMF_C_GET_KEY_PRIMARY 235 -#define BRCMF_C_SET_KEY_PRIMARY 236 -#define BRCMF_C_SET_SCAN_PASSIVE_TIME 258 -#define BRCMF_C_GET_VAR 262 -#define BRCMF_C_SET_VAR 263 - /* phy types (returned by WLC_GET_PHYTPE) */ #define WLC_PHY_TYPE_A 0 #define WLC_PHY_TYPE_B 1 diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil.h index 16eb8202fb1..77eae86e55c 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.h @@ -17,6 +17,67 @@ #ifndef _fwil_h_ #define _fwil_h_ +/******************************************************************************* + * Dongle command codes that are interpreted by firmware + ******************************************************************************/ +#define BRCMF_C_GET_VERSION 1 +#define BRCMF_C_UP 2 +#define BRCMF_C_DOWN 3 +#define BRCMF_C_SET_PROMISC 10 +#define BRCMF_C_GET_RATE 12 +#define BRCMF_C_GET_INFRA 19 +#define BRCMF_C_SET_INFRA 20 +#define BRCMF_C_GET_AUTH 21 +#define BRCMF_C_SET_AUTH 22 +#define BRCMF_C_GET_BSSID 23 +#define BRCMF_C_GET_SSID 25 +#define BRCMF_C_SET_SSID 26 +#define BRCMF_C_TERMINATED 28 +#define BRCMF_C_GET_CHANNEL 29 +#define BRCMF_C_SET_CHANNEL 30 +#define BRCMF_C_GET_SRL 31 +#define BRCMF_C_SET_SRL 32 +#define BRCMF_C_GET_LRL 33 +#define BRCMF_C_SET_LRL 34 +#define BRCMF_C_GET_RADIO 37 +#define BRCMF_C_SET_RADIO 38 +#define BRCMF_C_GET_PHYTYPE 39 +#define BRCMF_C_SET_KEY 45 +#define BRCMF_C_SET_PASSIVE_SCAN 49 +#define BRCMF_C_SCAN 50 +#define BRCMF_C_SCAN_RESULTS 51 +#define BRCMF_C_DISASSOC 52 +#define BRCMF_C_REASSOC 53 +#define BRCMF_C_SET_ROAM_TRIGGER 55 +#define BRCMF_C_SET_ROAM_DELTA 57 +#define BRCMF_C_GET_BCNPRD 75 +#define BRCMF_C_SET_BCNPRD 76 +#define BRCMF_C_GET_DTIMPRD 77 +#define BRCMF_C_SET_DTIMPRD 78 +#define BRCMF_C_SET_COUNTRY 84 +#define BRCMF_C_GET_PM 85 +#define BRCMF_C_SET_PM 86 +#define BRCMF_C_GET_CURR_RATESET 114 +#define BRCMF_C_GET_AP 117 +#define BRCMF_C_SET_AP 118 +#define BRCMF_C_GET_RSSI 127 +#define BRCMF_C_GET_WSEC 133 +#define BRCMF_C_SET_WSEC 134 +#define BRCMF_C_GET_PHY_NOISE 135 +#define BRCMF_C_GET_BSS_INFO 136 +#define BRCMF_C_GET_BANDLIST 140 +#define BRCMF_C_SET_SCB_TIMEOUT 158 +#define BRCMF_C_GET_PHYLIST 180 +#define BRCMF_C_SET_SCAN_CHANNEL_TIME 185 +#define BRCMF_C_SET_SCAN_UNASSOC_TIME 187 +#define BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON 201 +#define BRCMF_C_GET_VALID_CHANNELS 217 +#define BRCMF_C_GET_KEY_PRIMARY 235 +#define BRCMF_C_SET_KEY_PRIMARY 236 +#define BRCMF_C_SET_SCAN_PASSIVE_TIME 258 +#define BRCMF_C_GET_VAR 262 +#define BRCMF_C_SET_VAR 263 + s32 brcmf_fil_cmd_data_set(struct brcmf_if *ifp, u32 cmd, void *data, u32 len); s32 brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len); s32 brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data); -- cgit v1.2.3-70-g09d2 From aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0c Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Fri, 29 Nov 2013 12:25:21 +0100 Subject: brcmfmac: Use consistent naming for BCDC. The BCDC protocol layer is using a mix of naming of CDC, BDC and BCDC. Use the name BCDC consistenly over all functions, defines and variables. This patch does not change code functionality. Reviewed-by: Arend Van Spriel Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/bcdc.c | 195 ++++++++++----------- drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h | 2 +- .../net/wireless/brcm80211/brcmfmac/tracepoint.h | 4 +- 3 files changed, 95 insertions(+), 106 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c index b5a25290877..06848e426f9 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c @@ -33,7 +33,7 @@ #include "proto.h" #include "bcdc.h" -struct brcmf_proto_cdc_dcmd { +struct brcmf_proto_bcdc_dcmd { __le32 cmd; /* dongle command value */ __le32 len; /* lower 16: output buflen; * upper 16: input buflen (excludes header) */ @@ -42,47 +42,47 @@ struct brcmf_proto_cdc_dcmd { }; /* Max valid buffer size that can be sent to the dongle */ -#define CDC_MAX_MSG_SIZE (ETH_FRAME_LEN+ETH_FCS_LEN) - -/* CDC flag definitions */ -#define CDC_DCMD_ERROR 0x01 /* 1=cmd failed */ -#define CDC_DCMD_SET 0x02 /* 0=get, 1=set cmd */ -#define CDC_DCMD_IF_MASK 0xF000 /* I/F index */ -#define CDC_DCMD_IF_SHIFT 12 -#define CDC_DCMD_ID_MASK 0xFFFF0000 /* id an cmd pairing */ -#define CDC_DCMD_ID_SHIFT 16 /* ID Mask shift bits */ -#define CDC_DCMD_ID(flags) \ - (((flags) & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT) +#define BCDC_MAX_MSG_SIZE (ETH_FRAME_LEN+ETH_FCS_LEN) + +/* BCDC flag definitions */ +#define BCDC_DCMD_ERROR 0x01 /* 1=cmd failed */ +#define BCDC_DCMD_SET 0x02 /* 0=get, 1=set cmd */ +#define BCDC_DCMD_IF_MASK 0xF000 /* I/F index */ +#define BCDC_DCMD_IF_SHIFT 12 +#define BCDC_DCMD_ID_MASK 0xFFFF0000 /* id an cmd pairing */ +#define BCDC_DCMD_ID_SHIFT 16 /* ID Mask shift bits */ +#define BCDC_DCMD_ID(flags) \ + (((flags) & BCDC_DCMD_ID_MASK) >> BCDC_DCMD_ID_SHIFT) /* - * BDC header - Broadcom specific extension of CDC. + * BCDC header - Broadcom specific extension of CDC. * Used on data packets to convey priority across USB. */ -#define BDC_HEADER_LEN 4 -#define BDC_PROTO_VER 2 /* Protocol version */ -#define BDC_FLAG_VER_MASK 0xf0 /* Protocol version mask */ -#define BDC_FLAG_VER_SHIFT 4 /* Protocol version shift */ -#define BDC_FLAG_SUM_GOOD 0x04 /* Good RX checksums */ -#define BDC_FLAG_SUM_NEEDED 0x08 /* Dongle needs to do TX checksums */ -#define BDC_PRIORITY_MASK 0x7 -#define BDC_FLAG2_IF_MASK 0x0f /* packet rx interface in APSTA */ -#define BDC_FLAG2_IF_SHIFT 0 - -#define BDC_GET_IF_IDX(hdr) \ - ((int)((((hdr)->flags2) & BDC_FLAG2_IF_MASK) >> BDC_FLAG2_IF_SHIFT)) -#define BDC_SET_IF_IDX(hdr, idx) \ - ((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_IF_MASK) | \ - ((idx) << BDC_FLAG2_IF_SHIFT))) +#define BCDC_HEADER_LEN 4 +#define BCDC_PROTO_VER 2 /* Protocol version */ +#define BCDC_FLAG_VER_MASK 0xf0 /* Protocol version mask */ +#define BCDC_FLAG_VER_SHIFT 4 /* Protocol version shift */ +#define BCDC_FLAG_SUM_GOOD 0x04 /* Good RX checksums */ +#define BCDC_FLAG_SUM_NEEDED 0x08 /* Dongle needs to do TX checksums */ +#define BCDC_PRIORITY_MASK 0x7 +#define BCDC_FLAG2_IF_MASK 0x0f /* packet rx interface in APSTA */ +#define BCDC_FLAG2_IF_SHIFT 0 + +#define BCDC_GET_IF_IDX(hdr) \ + ((int)((((hdr)->flags2) & BCDC_FLAG2_IF_MASK) >> BCDC_FLAG2_IF_SHIFT)) +#define BCDC_SET_IF_IDX(hdr, idx) \ + ((hdr)->flags2 = (((hdr)->flags2 & ~BCDC_FLAG2_IF_MASK) | \ + ((idx) << BCDC_FLAG2_IF_SHIFT))) /** - * struct brcmf_proto_bdc_header - BDC header format + * struct brcmf_proto_bcdc_header - BCDC header format * * @flags: flags contain protocol and checksum info. * @priority: 802.1d priority and USB flow control info (bit 4:7). * @flags2: additional flags containing dongle interface index. * @data_offset: start of packet data. header is following by firmware signals. */ -struct brcmf_proto_bdc_header { +struct brcmf_proto_bcdc_header { u8 flags; u8 priority; u8 flags2; @@ -91,7 +91,7 @@ struct brcmf_proto_bdc_header { /* * maximum length of firmware signal data between - * the BDC header and packet data in the tx path. + * the BCDC header and packet data in the tx path. */ #define BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES 12 @@ -109,42 +109,42 @@ struct brcmf_proto_bdc_header { struct brcmf_bcdc { u16 reqid; u8 bus_header[BUS_HEADER_LEN]; - struct brcmf_proto_cdc_dcmd msg; + struct brcmf_proto_bcdc_dcmd msg; unsigned char buf[BRCMF_DCMD_MAXLEN + ROUND_UP_MARGIN]; }; -static int brcmf_proto_cdc_msg(struct brcmf_pub *drvr) +static int brcmf_proto_bcdc_msg(struct brcmf_pub *drvr) { struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd; int len = le32_to_cpu(bcdc->msg.len) + - sizeof(struct brcmf_proto_cdc_dcmd); + sizeof(struct brcmf_proto_bcdc_dcmd); - brcmf_dbg(CDC, "Enter\n"); + brcmf_dbg(BCDC, "Enter\n"); - /* NOTE : cdc->msg.len holds the desired length of the buffer to be - * returned. Only up to CDC_MAX_MSG_SIZE of this buffer area + /* NOTE : bcdc->msg.len holds the desired length of the buffer to be + * returned. Only up to BCDC_MAX_MSG_SIZE of this buffer area * is actually sent to the dongle */ - if (len > CDC_MAX_MSG_SIZE) - len = CDC_MAX_MSG_SIZE; + if (len > BCDC_MAX_MSG_SIZE) + len = BCDC_MAX_MSG_SIZE; /* Send request */ return brcmf_bus_txctl(drvr->bus_if, (unsigned char *)&bcdc->msg, len); } -static int brcmf_proto_cdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len) +static int brcmf_proto_bcdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len) { int ret; struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd; - brcmf_dbg(CDC, "Enter\n"); - len += sizeof(struct brcmf_proto_cdc_dcmd); + brcmf_dbg(BCDC, "Enter\n"); + len += sizeof(struct brcmf_proto_bcdc_dcmd); do { ret = brcmf_bus_rxctl(drvr->bus_if, (unsigned char *)&bcdc->msg, len); if (ret < 0) break; - } while (CDC_DCMD_ID(le32_to_cpu(bcdc->msg.flags)) != id); + } while (BCDC_DCMD_ID(le32_to_cpu(bcdc->msg.flags)) != id); return ret; } @@ -154,40 +154,40 @@ brcmf_proto_bcdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf, uint len) { struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd; - struct brcmf_proto_cdc_dcmd *msg = &bcdc->msg; + struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg; void *info; int ret = 0, retries = 0; u32 id, flags; - brcmf_dbg(CDC, "Enter, cmd %d len %d\n", cmd, len); + brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len); - memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd)); + memset(msg, 0, sizeof(struct brcmf_proto_bcdc_dcmd)); msg->cmd = cpu_to_le32(cmd); msg->len = cpu_to_le32(len); - flags = (++bcdc->reqid << CDC_DCMD_ID_SHIFT); - flags = (flags & ~CDC_DCMD_IF_MASK) | - (ifidx << CDC_DCMD_IF_SHIFT); + flags = (++bcdc->reqid << BCDC_DCMD_ID_SHIFT); + flags = (flags & ~BCDC_DCMD_IF_MASK) | + (ifidx << BCDC_DCMD_IF_SHIFT); msg->flags = cpu_to_le32(flags); if (buf) memcpy(bcdc->buf, buf, len); - ret = brcmf_proto_cdc_msg(drvr); + ret = brcmf_proto_bcdc_msg(drvr); if (ret < 0) { - brcmf_err("brcmf_proto_cdc_msg failed w/status %d\n", + brcmf_err("brcmf_proto_bcdc_msg failed w/status %d\n", ret); goto done; } retry: /* wait for interrupt and get first fragment */ - ret = brcmf_proto_cdc_cmplt(drvr, bcdc->reqid, len); + ret = brcmf_proto_bcdc_cmplt(drvr, bcdc->reqid, len); if (ret < 0) goto done; flags = le32_to_cpu(msg->flags); - id = (flags & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT; + id = (flags & BCDC_DCMD_ID_MASK) >> BCDC_DCMD_ID_SHIFT; if ((id < bcdc->reqid) && (++retries < RETRIES)) goto retry; @@ -209,7 +209,7 @@ retry: } /* Check the ERROR flag */ - if (flags & CDC_DCMD_ERROR) + if (flags & BCDC_DCMD_ERROR) ret = le32_to_cpu(msg->status); done: @@ -221,34 +221,34 @@ brcmf_proto_bcdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf, uint len) { struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd; - struct brcmf_proto_cdc_dcmd *msg = &bcdc->msg; + struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg; int ret = 0; u32 flags, id; - brcmf_dbg(CDC, "Enter, cmd %d len %d\n", cmd, len); + brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len); - memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd)); + memset(msg, 0, sizeof(struct brcmf_proto_bcdc_dcmd)); msg->cmd = cpu_to_le32(cmd); msg->len = cpu_to_le32(len); - flags = (++bcdc->reqid << CDC_DCMD_ID_SHIFT) | CDC_DCMD_SET; - flags = (flags & ~CDC_DCMD_IF_MASK) | - (ifidx << CDC_DCMD_IF_SHIFT); + flags = (++bcdc->reqid << BCDC_DCMD_ID_SHIFT) | BCDC_DCMD_SET; + flags = (flags & ~BCDC_DCMD_IF_MASK) | + (ifidx << BCDC_DCMD_IF_SHIFT); msg->flags = cpu_to_le32(flags); if (buf) memcpy(bcdc->buf, buf, len); - ret = brcmf_proto_cdc_msg(drvr); + ret = brcmf_proto_bcdc_msg(drvr); if (ret < 0) goto done; - ret = brcmf_proto_cdc_cmplt(drvr, bcdc->reqid, len); + ret = brcmf_proto_bcdc_cmplt(drvr, bcdc->reqid, len); if (ret < 0) goto done; flags = le32_to_cpu(msg->flags); - id = (flags & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT; + id = (flags & BCDC_DCMD_ID_MASK) >> BCDC_DCMD_ID_SHIFT; if (id != bcdc->reqid) { brcmf_err("%s: unexpected request id %d (expected %d)\n", @@ -258,67 +258,56 @@ brcmf_proto_bcdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, } /* Check the ERROR flag */ - if (flags & CDC_DCMD_ERROR) + if (flags & BCDC_DCMD_ERROR) ret = le32_to_cpu(msg->status); done: return ret; } -static bool pkt_sum_needed(struct sk_buff *skb) -{ - return skb->ip_summed == CHECKSUM_PARTIAL; -} - -static void pkt_set_sum_good(struct sk_buff *skb, bool x) -{ - skb->ip_summed = (x ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE); -} - static void brcmf_proto_bcdc_hdrpush(struct brcmf_pub *drvr, int ifidx, u8 offset, struct sk_buff *pktbuf) { - struct brcmf_proto_bdc_header *h; + struct brcmf_proto_bcdc_header *h; - brcmf_dbg(CDC, "Enter\n"); + brcmf_dbg(BCDC, "Enter\n"); /* Push BDC header used to convey priority for buses that don't */ - skb_push(pktbuf, BDC_HEADER_LEN); + skb_push(pktbuf, BCDC_HEADER_LEN); - h = (struct brcmf_proto_bdc_header *)(pktbuf->data); + h = (struct brcmf_proto_bcdc_header *)(pktbuf->data); - h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); - if (pkt_sum_needed(pktbuf)) - h->flags |= BDC_FLAG_SUM_NEEDED; + h->flags = (BCDC_PROTO_VER << BCDC_FLAG_VER_SHIFT); + if (pktbuf->ip_summed == CHECKSUM_PARTIAL) + h->flags |= BCDC_FLAG_SUM_NEEDED; - h->priority = (pktbuf->priority & BDC_PRIORITY_MASK); + h->priority = (pktbuf->priority & BCDC_PRIORITY_MASK); h->flags2 = 0; h->data_offset = offset; - BDC_SET_IF_IDX(h, ifidx); - trace_brcmf_bdchdr(pktbuf->data); + BCDC_SET_IF_IDX(h, ifidx); + trace_brcmf_bcdchdr(pktbuf->data); } static int brcmf_proto_bcdc_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx, struct sk_buff *pktbuf) { - struct brcmf_proto_bdc_header *h; - - brcmf_dbg(CDC, "Enter\n"); + struct brcmf_proto_bcdc_header *h; - /* Pop BDC header used to convey priority for buses that don't */ + brcmf_dbg(BCDC, "Enter\n"); - if (pktbuf->len <= BDC_HEADER_LEN) { + /* Pop BCDC header used to convey priority for buses that don't */ + if (pktbuf->len <= BCDC_HEADER_LEN) { brcmf_dbg(INFO, "rx data too short (%d <= %d)\n", - pktbuf->len, BDC_HEADER_LEN); + pktbuf->len, BCDC_HEADER_LEN); return -EBADE; } - trace_brcmf_bdchdr(pktbuf->data); - h = (struct brcmf_proto_bdc_header *)(pktbuf->data); + trace_brcmf_bcdchdr(pktbuf->data); + h = (struct brcmf_proto_bcdc_header *)(pktbuf->data); - *ifidx = BDC_GET_IF_IDX(h); + *ifidx = BCDC_GET_IF_IDX(h); if (*ifidx >= BRCMF_MAX_IFS) { brcmf_err("rx data ifnum out of range (%d)\n", *ifidx); return -EBADE; @@ -332,22 +321,22 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx, if (*ifidx) (*ifidx)++; - if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) != - BDC_PROTO_VER) { - brcmf_err("%s: non-BDC packet received, flags 0x%x\n", + if (((h->flags & BCDC_FLAG_VER_MASK) >> BCDC_FLAG_VER_SHIFT) != + BCDC_PROTO_VER) { + brcmf_err("%s: non-BCDC packet received, flags 0x%x\n", brcmf_ifname(drvr, *ifidx), h->flags); return -EBADE; } - if (h->flags & BDC_FLAG_SUM_GOOD) { - brcmf_dbg(CDC, "%s: BDC rcv, good checksum, flags 0x%x\n", + if (h->flags & BCDC_FLAG_SUM_GOOD) { + brcmf_dbg(BCDC, "%s: BDC rcv, good checksum, flags 0x%x\n", brcmf_ifname(drvr, *ifidx), h->flags); - pkt_set_sum_good(pktbuf, true); + pktbuf->ip_summed = CHECKSUM_UNNECESSARY; } - pktbuf->priority = h->priority & BDC_PRIORITY_MASK; + pktbuf->priority = h->priority & BCDC_PRIORITY_MASK; - skb_pull(pktbuf, BDC_HEADER_LEN); + skb_pull(pktbuf, BCDC_HEADER_LEN); if (do_fws) brcmf_fws_hdrpull(drvr, *ifidx, h->data_offset << 2, pktbuf); else @@ -378,9 +367,9 @@ int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr) drvr->proto->set_dcmd = brcmf_proto_bcdc_set_dcmd; drvr->proto->pd = bcdc; - drvr->hdrlen += BDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES; + drvr->hdrlen += BCDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES; drvr->bus_if->maxctl = BRCMF_DCMD_MAXLEN + - sizeof(struct brcmf_proto_cdc_dcmd) + ROUND_UP_MARGIN; + sizeof(struct brcmf_proto_bcdc_dcmd) + ROUND_UP_MARGIN; return 0; fail: diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h index 0af1f5dc583..ef52ed7abc6 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h @@ -33,7 +33,7 @@ #define BRCMF_USB_VAL 0x00002000 #define BRCMF_SCAN_VAL 0x00004000 #define BRCMF_CONN_VAL 0x00008000 -#define BRCMF_CDC_VAL 0x00010000 +#define BRCMF_BCDC_VAL 0x00010000 #define BRCMF_SDIO_VAL 0x00020000 /* set default print format */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/tracepoint.h b/drivers/net/wireless/brcm80211/brcmfmac/tracepoint.h index d229cda98aa..4d7d51f9571 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/tracepoint.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/tracepoint.h @@ -89,7 +89,7 @@ TRACE_EVENT(brcmf_hexdump, TP_printk("hexdump [addr=%lx, length=%lu]", __entry->addr, __entry->len) ); -TRACE_EVENT(brcmf_bdchdr, +TRACE_EVENT(brcmf_bcdchdr, TP_PROTO(void *data), TP_ARGS(data), TP_STRUCT__entry( @@ -107,7 +107,7 @@ TRACE_EVENT(brcmf_bdchdr, memcpy(__get_dynamic_array(signal), (u8 *)data + 4, __entry->siglen); ), - TP_printk("bdc: prio=%d siglen=%d", __entry->prio, __entry->siglen) + TP_printk("bcdc: prio=%d siglen=%d", __entry->prio, __entry->siglen) ); #ifndef SDPCM_RX -- cgit v1.2.3-70-g09d2 From b881879dea8d4bbfc71534d9dc5c9cf8298127a9 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Fri, 29 Nov 2013 12:25:22 +0100 Subject: brcmfmac: remove some unused definitions Removing WLC_PHY_TYPE and some BRCMF_E_.* definitions as these are not used in the driver sources. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd.h | 48 --------------------------- 1 file changed, 48 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h index a85f9db3628..da5cf00ac09 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h @@ -25,17 +25,6 @@ #include "fweh.h" -/* phy types (returned by WLC_GET_PHYTPE) */ -#define WLC_PHY_TYPE_A 0 -#define WLC_PHY_TYPE_B 1 -#define WLC_PHY_TYPE_G 2 -#define WLC_PHY_TYPE_N 4 -#define WLC_PHY_TYPE_LP 5 -#define WLC_PHY_TYPE_SSN 6 -#define WLC_PHY_TYPE_HT 7 -#define WLC_PHY_TYPE_LCN 8 -#define WLC_PHY_TYPE_NULL 0xf - #define TOE_TX_CSUM_OL 0x00000001 #define TOE_RX_CSUM_OL 0x00000002 @@ -75,38 +64,6 @@ #define BRCMF_E_REASON_TSPEC_REJECTED 7 #define BRCMF_E_REASON_BETTER_AP 8 -#define BRCMF_E_PRUNE_ENCR_MISMATCH 1 -#define BRCMF_E_PRUNE_BCAST_BSSID 2 -#define BRCMF_E_PRUNE_MAC_DENY 3 -#define BRCMF_E_PRUNE_MAC_NA 4 -#define BRCMF_E_PRUNE_REG_PASSV 5 -#define BRCMF_E_PRUNE_SPCT_MGMT 6 -#define BRCMF_E_PRUNE_RADAR 7 -#define BRCMF_E_RSN_MISMATCH 8 -#define BRCMF_E_PRUNE_NO_COMMON_RATES 9 -#define BRCMF_E_PRUNE_BASIC_RATES 10 -#define BRCMF_E_PRUNE_CIPHER_NA 12 -#define BRCMF_E_PRUNE_KNOWN_STA 13 -#define BRCMF_E_PRUNE_WDS_PEER 15 -#define BRCMF_E_PRUNE_QBSS_LOAD 16 -#define BRCMF_E_PRUNE_HOME_AP 17 - -#define BRCMF_E_SUP_OTHER 0 -#define BRCMF_E_SUP_DECRYPT_KEY_DATA 1 -#define BRCMF_E_SUP_BAD_UCAST_WEP128 2 -#define BRCMF_E_SUP_BAD_UCAST_WEP40 3 -#define BRCMF_E_SUP_UNSUP_KEY_LEN 4 -#define BRCMF_E_SUP_PW_KEY_CIPHER 5 -#define BRCMF_E_SUP_MSG3_TOO_MANY_IE 6 -#define BRCMF_E_SUP_MSG3_IE_MISMATCH 7 -#define BRCMF_E_SUP_NO_INSTALL_FLAG 8 -#define BRCMF_E_SUP_MSG3_NO_GTK 9 -#define BRCMF_E_SUP_GRP_KEY_CIPHER 10 -#define BRCMF_E_SUP_GRP_MSG1_NO_GTK 11 -#define BRCMF_E_SUP_GTK_DECRYPT_FAIL 12 -#define BRCMF_E_SUP_SEND_FAIL 13 -#define BRCMF_E_SUP_DEAUTH 14 - #define BRCMF_E_IF_ADD 1 #define BRCMF_E_IF_DEL 2 #define BRCMF_E_IF_CHANGE 3 @@ -117,11 +74,6 @@ #define BRCMF_E_IF_ROLE_AP 1 #define BRCMF_E_IF_ROLE_WDS 2 -#define BRCMF_E_LINK_BCN_LOSS 1 -#define BRCMF_E_LINK_DISASSOC 2 -#define BRCMF_E_LINK_ASSOC_REC 3 -#define BRCMF_E_LINK_BSSCFG_DIS 4 - /* Small, medium and maximum buffer size for dcmd */ #define BRCMF_DCMD_SMLEN 256 -- cgit v1.2.3-70-g09d2 From 01376a07bcf72fdad1ed5ed906025ca786d333dc Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Fri, 29 Nov 2013 12:25:23 +0100 Subject: brcmfmac: move firmware event related defines to fweh.h The dhd.h file contained a number of definitions that are related to events received from the firmware. Those are processed and dispatched in the driver by fweh. Hence the definitions are moved to its include file. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd.h | 49 ----------------------- drivers/net/wireless/brcm80211/brcmfmac/fweh.h | 54 ++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 49 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h index da5cf00ac09..252024bcbc3 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h @@ -33,47 +33,6 @@ #define DOT11_MAX_DEFAULT_KEYS 4 -#define BRCMF_E_STATUS_SUCCESS 0 -#define BRCMF_E_STATUS_FAIL 1 -#define BRCMF_E_STATUS_TIMEOUT 2 -#define BRCMF_E_STATUS_NO_NETWORKS 3 -#define BRCMF_E_STATUS_ABORT 4 -#define BRCMF_E_STATUS_NO_ACK 5 -#define BRCMF_E_STATUS_UNSOLICITED 6 -#define BRCMF_E_STATUS_ATTEMPT 7 -#define BRCMF_E_STATUS_PARTIAL 8 -#define BRCMF_E_STATUS_NEWSCAN 9 -#define BRCMF_E_STATUS_NEWASSOC 10 -#define BRCMF_E_STATUS_11HQUIET 11 -#define BRCMF_E_STATUS_SUPPRESS 12 -#define BRCMF_E_STATUS_NOCHANS 13 -#define BRCMF_E_STATUS_CS_ABORT 15 -#define BRCMF_E_STATUS_ERROR 16 - -#define BRCMF_E_REASON_INITIAL_ASSOC 0 -#define BRCMF_E_REASON_LOW_RSSI 1 -#define BRCMF_E_REASON_DEAUTH 2 -#define BRCMF_E_REASON_DISASSOC 3 -#define BRCMF_E_REASON_BCNS_LOST 4 -#define BRCMF_E_REASON_MINTXRATE 9 -#define BRCMF_E_REASON_TXFAIL 10 - -#define BRCMF_E_REASON_LINK_BSSCFG_DIS 4 -#define BRCMF_E_REASON_FAST_ROAM_FAILED 5 -#define BRCMF_E_REASON_DIRECTED_ROAM 6 -#define BRCMF_E_REASON_TSPEC_REJECTED 7 -#define BRCMF_E_REASON_BETTER_AP 8 - -#define BRCMF_E_IF_ADD 1 -#define BRCMF_E_IF_DEL 2 -#define BRCMF_E_IF_CHANGE 3 - -#define BRCMF_E_IF_FLAG_NOIF 1 - -#define BRCMF_E_IF_ROLE_STA 0 -#define BRCMF_E_IF_ROLE_AP 1 -#define BRCMF_E_IF_ROLE_WDS 2 - /* Small, medium and maximum buffer size for dcmd */ #define BRCMF_DCMD_SMLEN 256 @@ -156,14 +115,6 @@ struct brcmf_pub { #endif }; -struct brcmf_if_event { - u8 ifidx; - u8 action; - u8 flags; - u8 bssidx; - u8 role; -}; - /* forward declarations */ struct brcmf_cfg80211_vif; struct brcmf_fws_mac_descriptor; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h index 14bc24dc5ba..51b53a73d07 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h @@ -122,6 +122,52 @@ enum brcmf_fweh_event_code { #define BRCMF_EVENT_MSG_FLUSHTXQ 0x02 #define BRCMF_EVENT_MSG_GROUP 0x04 +/* status field values in struct brcmf_event_msg */ +#define BRCMF_E_STATUS_SUCCESS 0 +#define BRCMF_E_STATUS_FAIL 1 +#define BRCMF_E_STATUS_TIMEOUT 2 +#define BRCMF_E_STATUS_NO_NETWORKS 3 +#define BRCMF_E_STATUS_ABORT 4 +#define BRCMF_E_STATUS_NO_ACK 5 +#define BRCMF_E_STATUS_UNSOLICITED 6 +#define BRCMF_E_STATUS_ATTEMPT 7 +#define BRCMF_E_STATUS_PARTIAL 8 +#define BRCMF_E_STATUS_NEWSCAN 9 +#define BRCMF_E_STATUS_NEWASSOC 10 +#define BRCMF_E_STATUS_11HQUIET 11 +#define BRCMF_E_STATUS_SUPPRESS 12 +#define BRCMF_E_STATUS_NOCHANS 13 +#define BRCMF_E_STATUS_CS_ABORT 15 +#define BRCMF_E_STATUS_ERROR 16 + +/* reason field values in struct brcmf_event_msg */ +#define BRCMF_E_REASON_INITIAL_ASSOC 0 +#define BRCMF_E_REASON_LOW_RSSI 1 +#define BRCMF_E_REASON_DEAUTH 2 +#define BRCMF_E_REASON_DISASSOC 3 +#define BRCMF_E_REASON_BCNS_LOST 4 +#define BRCMF_E_REASON_MINTXRATE 9 +#define BRCMF_E_REASON_TXFAIL 10 + +#define BRCMF_E_REASON_LINK_BSSCFG_DIS 4 +#define BRCMF_E_REASON_FAST_ROAM_FAILED 5 +#define BRCMF_E_REASON_DIRECTED_ROAM 6 +#define BRCMF_E_REASON_TSPEC_REJECTED 7 +#define BRCMF_E_REASON_BETTER_AP 8 + +/* action field values for brcmf_ifevent */ +#define BRCMF_E_IF_ADD 1 +#define BRCMF_E_IF_DEL 2 +#define BRCMF_E_IF_CHANGE 3 + +/* flag field values for brcmf_ifevent */ +#define BRCMF_E_IF_FLAG_NOIF 1 + +/* role field values for brcmf_ifevent */ +#define BRCMF_E_IF_ROLE_STA 0 +#define BRCMF_E_IF_ROLE_AP 1 +#define BRCMF_E_IF_ROLE_WDS 2 + /** * definitions for event packet validation. */ @@ -160,6 +206,14 @@ struct brcmf_event_msg { u8 bsscfgidx; }; +struct brcmf_if_event { + u8 ifidx; + u8 action; + u8 flags; + u8 bssidx; + u8 role; +}; + typedef int (*brcmf_fweh_handler_t)(struct brcmf_if *ifp, const struct brcmf_event_msg *evtmsg, void *data); -- cgit v1.2.3-70-g09d2 From 7d68849f40cd9169088249cc889d95c8998c3fb8 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Fri, 29 Nov 2013 12:25:24 +0100 Subject: brcmfmac: expose chip information through debugfs Adding the debugfs file /brcmfmac//chipinfo which contains the chip number and revision. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c | 36 ++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c index 0f9e9057e7d..03fe8aca4d3 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c @@ -22,7 +22,6 @@ #include "dhd.h" #include "dhd_bus.h" #include "dhd_dbg.h" -#include "tracepoint.h" static struct dentry *root_folder; @@ -42,6 +41,40 @@ void brcmf_debugfs_exit(void) root_folder = NULL; } +static +ssize_t brcmf_debugfs_chipinfo_read(struct file *f, char __user *data, + size_t count, loff_t *ppos) +{ + struct brcmf_pub *drvr = f->private_data; + struct brcmf_bus *bus = drvr->bus_if; + char buf[40]; + int res; + + /* only allow read from start */ + if (*ppos > 0) + return 0; + + res = scnprintf(buf, sizeof(buf), "chip: %x(%u) rev %u\n", + bus->chip, bus->chip, bus->chiprev); + return simple_read_from_buffer(data, count, ppos, buf, res); +} + +static const struct file_operations brcmf_debugfs_chipinfo_ops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = brcmf_debugfs_chipinfo_read +}; + +static int brcmf_debugfs_create_chipinfo(struct brcmf_pub *drvr) +{ + struct dentry *dentry = drvr->dbgfs_dir; + + if (!IS_ERR_OR_NULL(dentry)) + debugfs_create_file("chipinfo", S_IRUGO, dentry, drvr, + &brcmf_debugfs_chipinfo_ops); + return 0; +} + int brcmf_debugfs_attach(struct brcmf_pub *drvr) { struct device *dev = drvr->bus_if->dev; @@ -50,6 +83,7 @@ int brcmf_debugfs_attach(struct brcmf_pub *drvr) return -ENODEV; drvr->dbgfs_dir = debugfs_create_dir(dev_name(dev), root_folder); + brcmf_debugfs_create_chipinfo(drvr); return PTR_ERR_OR_ZERO(drvr->dbgfs_dir); } -- cgit v1.2.3-70-g09d2 From 18cfd3bfc904e2360af3a1c059c84b3f1944afb4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 3 Dec 2013 13:21:36 +0100 Subject: Revert "mac80211: add driver callback for per-interface multicast filter" This reverts commit 488b366a452934141959384c7a1b52b22d6154ef. The code isn't used by anyone, and the Intel driver isn't planning to use it either right now. Signed-off-by: Johannes Berg --- include/net/mac80211.h | 7 ------- net/mac80211/driver-ops.h | 16 ---------------- net/mac80211/iface.c | 11 ----------- net/mac80211/trace.h | 24 ------------------------ 4 files changed, 58 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 3cd408b326d..73d99bc3e63 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2398,9 +2398,6 @@ enum ieee80211_roc_type { * See the section "Frame filtering" for more information. * This callback must be implemented and can sleep. * - * @set_multicast_list: Configure the device's interface specific RX multicast - * filter. This callback is optional. This callback must be atomic. - * * @set_tim: Set TIM bit. mac80211 calls this function when a TIM bit * must be set or cleared for a given STA. Must be atomic. * @@ -2764,10 +2761,6 @@ struct ieee80211_ops { unsigned int changed_flags, unsigned int *total_flags, u64 multicast); - void (*set_multicast_list)(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, bool allmulti, - struct netdev_hw_addr_list *mc_list); - int (*set_tim)(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set); int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd, diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 5d03c47c0a4..f98059a45aa 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -242,22 +242,6 @@ static inline u64 drv_prepare_multicast(struct ieee80211_local *local, return ret; } -static inline void drv_set_multicast_list(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, - struct netdev_hw_addr_list *mc_list) -{ - bool allmulti = sdata->flags & IEEE80211_SDATA_ALLMULTI; - - trace_drv_set_multicast_list(local, sdata, mc_list->count); - - check_sdata_in_driver(sdata); - - if (local->ops->set_multicast_list) - local->ops->set_multicast_list(&local->hw, &sdata->vif, - allmulti, mc_list); - trace_drv_return_void(local); -} - static inline void drv_configure_filter(struct ieee80211_local *local, unsigned int changed_flags, unsigned int *total_flags, diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index d226751ba63..3e5c89a295b 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1018,17 +1018,6 @@ static void ieee80211_set_multicast_list(struct net_device *dev) atomic_dec(&local->iff_promiscs); sdata->flags ^= IEEE80211_SDATA_PROMISC; } - - /* - * TODO: If somebody needs this on AP interfaces, - * it can be enabled easily but multicast - * addresses from VLANs need to be synced. - */ - if (sdata->vif.type != NL80211_IFTYPE_MONITOR && - sdata->vif.type != NL80211_IFTYPE_AP_VLAN && - sdata->vif.type != NL80211_IFTYPE_AP) - drv_set_multicast_list(local, sdata, &dev->mc); - spin_lock_bh(&local->filter_lock); __hw_addr_sync(&local->mc_list, &dev->mc, dev->addr_len); spin_unlock_bh(&local->filter_lock); diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 8db560190ca..9d213e82326 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -443,30 +443,6 @@ TRACE_EVENT(drv_prepare_multicast, ) ); -TRACE_EVENT(drv_set_multicast_list, - TP_PROTO(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, int mc_count), - - TP_ARGS(local, sdata, mc_count), - - TP_STRUCT__entry( - LOCAL_ENTRY - __field(bool, allmulti) - __field(int, mc_count) - ), - - TP_fast_assign( - LOCAL_ASSIGN; - __entry->allmulti = sdata->flags & IEEE80211_SDATA_ALLMULTI; - __entry->mc_count = mc_count; - ), - - TP_printk( - LOCAL_PR_FMT " configure mc filter, count=%d, allmulti=%d", - LOCAL_PR_ARG, __entry->mc_count, __entry->allmulti - ) -); - TRACE_EVENT(drv_configure_filter, TP_PROTO(struct ieee80211_local *local, unsigned int changed_flags, -- cgit v1.2.3-70-g09d2 From e01362265487f05b69233aab4426ab6166f7b1ec Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 2 Dec 2013 19:22:17 +0100 Subject: mac80211: move align variable to remove __maybe_unused There's no reason for the variable to not be inside the #ifdef, move it. Signed-off-by: Johannes Berg --- net/mac80211/rx.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 30ac6099da0..5cf7285f6df 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1963,8 +1963,6 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) } if (skb) { - int align __maybe_unused; - #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS /* * 'align' will only take the values 0 or 2 here @@ -1975,7 +1973,8 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) * access fields as 2-byte aligned (e.g. for * compare_ether_addr) */ - align = ((unsigned long)(skb->data + sizeof(struct ethhdr))) & 3; + int align = ((unsigned long)(skb->data + + sizeof(struct ethhdr))) & 3; if (align) { if (WARN_ON(skb_headroom(skb) < 3)) { dev_kfree_skb(skb); -- cgit v1.2.3-70-g09d2 From 60f4a7b1676c9028edb90e22f6994ebb698c9088 Mon Sep 17 00:00:00 2001 From: Marek Kwaczynski Date: Tue, 3 Dec 2013 10:04:59 +0100 Subject: nl80211/cfg80211: Set Operating Mode Notification This attribute is needed for setting Operating Mode Notification in AP mode from User Space. This functionality is required when User Space received Assoc Request contains Operation Mode Notification element. Signed-off-by: Marek Kwaczynski [fix typos, nl80211 documentation] Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 4 ++++ include/uapi/linux/nl80211.h | 6 ++++++ net/wireless/nl80211.c | 7 +++++++ 3 files changed, 17 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index e9abc7b536c..47290a4059a 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -747,6 +747,8 @@ enum station_parameters_apply_mask { * @supported_channels_len: number of supported channels * @supported_oper_classes: supported oper classes in IEEE 802.11 format * @supported_oper_classes_len: number of supported operating classes + * @opmode_notif: operating mode field from Operating Mode Notification + * @opmode_notif_used: information if operating mode field is used */ struct station_parameters { const u8 *supported_rates; @@ -770,6 +772,8 @@ struct station_parameters { u8 supported_channels_len; const u8 *supported_oper_classes; u8 supported_oper_classes_len; + u8 opmode_notif; + bool opmode_notif_used; }; /** diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 129b7b08714..9a4d0e18251 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1520,6 +1520,10 @@ enum nl80211_commands { * @NL80211_ATTR_SUPPORT_10_MHZ: A flag indicating that the device supports * 10 MHz channel bandwidth. * + * @NL80211_ATTR_OPMODE_NOTIF: Operating mode field from Operating Mode + * Notification Element based on association request when used with + * %NL80211_CMD_NEW_STATION; u8 attribute. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1839,6 +1843,8 @@ enum nl80211_attrs { NL80211_ATTR_SUPPORT_5_MHZ, NL80211_ATTR_SUPPORT_10_MHZ, + NL80211_ATTR_OPMODE_NOTIF, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 95882a788b5..93e3356091f 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -357,6 +357,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_STA_SUPPORTED_CHANNELS] = { .type = NLA_BINARY }, [NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES] = { .type = NLA_BINARY }, [NL80211_ATTR_HANDLE_DFS] = { .type = NLA_FLAG }, + [NL80211_ATTR_OPMODE_NOTIF] = { .type = NLA_U8 }, }; /* policy for the key attributes */ @@ -4132,6 +4133,12 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) params.vht_capa = nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]); + if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) { + params.opmode_notif_used = true; + params.opmode_notif = + nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]); + } + if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) { params.plink_action = nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); -- cgit v1.2.3-70-g09d2 From 6c474799dccc91c9cf03cd18ec32f97929549e9f Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 25 Nov 2013 20:56:09 +0100 Subject: cfg80211: add reg_get_dfs_region() This can be used outside of the regulatory context for any checks on the DFS region. The central cfg80211 dfs_region is always used and if it does not match with the wiphy a debug print is issued. Signed-off-by: Luis R. Rodriguez Signed-off-by: Johannes Berg --- net/wireless/reg.c | 27 +++++++++++++++++++++++++++ net/wireless/reg.h | 1 + 2 files changed, 28 insertions(+) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index ec54e1aac8e..7d20d844ca6 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -135,6 +135,33 @@ static const char *reg_dfs_region_str(enum nl80211_dfs_regions dfs_region) return "Unknown"; } +enum nl80211_dfs_regions reg_get_dfs_region(struct wiphy *wiphy) +{ + const struct ieee80211_regdomain *regd = NULL; + const struct ieee80211_regdomain *wiphy_regd = NULL; + + regd = get_cfg80211_regdom(); + if (!wiphy) + goto out; + + wiphy_regd = get_wiphy_regdom(wiphy); + if (!wiphy_regd) + goto out; + + if (wiphy_regd->dfs_region == regd->dfs_region) + goto out; + + REG_DBG_PRINT("%s: device specific dfs_region " + "(%s) disagrees with cfg80211's " + "central dfs_region (%s)\n", + dev_name(&wiphy->dev), + reg_dfs_region_str(wiphy_regd->dfs_region), + reg_dfs_region_str(regd->dfs_region)); + +out: + return regd->dfs_region; +} + static void rcu_free_regdom(const struct ieee80211_regdomain *r) { if (!r) diff --git a/net/wireless/reg.h b/net/wireless/reg.h index cc4c2c0a672..02bd8f4b092 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h @@ -21,6 +21,7 @@ extern const struct ieee80211_regdomain __rcu *cfg80211_regdomain; bool reg_is_valid_request(const char *alpha2); bool is_world_regdom(const char *alpha2); bool reg_supported_dfs_region(enum nl80211_dfs_regions dfs_region); +enum nl80211_dfs_regions reg_get_dfs_region(struct wiphy *wiphy); int regulatory_hint_user(const char *alpha2, enum nl80211_user_reg_hint_type user_reg_hint_type); -- cgit v1.2.3-70-g09d2 From 55f7435c189498ccbfe6a5fba606933587948d85 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 25 Nov 2013 20:56:10 +0100 Subject: cfg80211: DFS check dfs_region before usage Check the DFS region before channel availability check. Signed-off-by: Luis R. Rodriguez Signed-off-by: Janusz Dziedzic Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 93e3356091f..9cd8c6113e9 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -5651,8 +5651,13 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, struct net_device *dev = info->user_ptr[1]; struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_chan_def chandef; + enum nl80211_dfs_regions dfs_region; int err; + dfs_region = reg_get_dfs_region(wdev->wiphy); + if (dfs_region == NL80211_DFS_UNSET) + return -EINVAL; + err = nl80211_parse_chandef(rdev, info, &chandef); if (err) return err; -- cgit v1.2.3-70-g09d2 From de61b610def5249a1295b1eac92f3ce2bfa76b9d Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Tue, 3 Dec 2013 15:02:15 +0200 Subject: mac80211: remove duplicate code The same code appears just a few lines below. Signed-off-by: Eliad Peller Signed-off-by: Johannes Berg --- net/mac80211/scan.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index c22cbb57b49..b12bb72a5f3 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -785,14 +785,6 @@ void ieee80211_scan_work(struct work_struct *work) goto out; } - /* - * Avoid re-scheduling when the sdata is going away. - */ - if (!ieee80211_sdata_running(sdata)) { - aborted = true; - goto out_complete; - } - /* * as long as no delay is required advance immediately * without scheduling a new work -- cgit v1.2.3-70-g09d2 From 7869303b17a3cc78c9e9f26544be98b5734ac97c Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Tue, 3 Dec 2013 09:50:44 +0100 Subject: nl80211: don't clear bitrate_mask twice Don't clear cfg80211_bitrate_mask twice in nl80211_set_tx_bitrate_mask() function. Signed-off-by: Janusz Dziedzic Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 9cd8c6113e9..bdcf256e362 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -7349,15 +7349,14 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, /* Default to all rates enabled */ for (i = 0; i < IEEE80211_NUM_BANDS; i++) { sband = rdev->wiphy.bands[i]; - mask.control[i].legacy = - sband ? (1 << sband->n_bitrates) - 1 : 0; - if (sband) - memcpy(mask.control[i].mcs, - sband->ht_cap.mcs.rx_mask, - sizeof(mask.control[i].mcs)); - else - memset(mask.control[i].mcs, 0, - sizeof(mask.control[i].mcs)); + + if (!sband) + continue; + + mask.control[i].legacy = (1 << sband->n_bitrates) - 1; + memcpy(mask.control[i].mcs, + sband->ht_cap.mcs.rx_mask, + sizeof(mask.control[i].mcs)); } /* -- cgit v1.2.3-70-g09d2 From ad7e718c9b4f717823fd920a0103f7b0fb06183f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 13 Nov 2013 13:37:47 +0100 Subject: nl80211: vendor command support Add support for vendor-specific commands to nl80211. This is intended to be used for really vendor-specific functionality that can't be implemented in a generic fashion for any reason. It's *NOT* intended to be used for any normal/generic feature or any optimisations that could be implemented across drivers. Currently, only vendor commands (with replies) are supported, no dump operations or vendor-specific notifications. Also add a function wdev_to_ieee80211_vif() to mac80211 which is needed for mac80211-based drivers wanting to implement any vendor commands. Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 116 ++++++++++++++++++++- include/net/mac80211.h | 13 +++ include/uapi/linux/nl80211.h | 41 ++++++++ net/mac80211/util.c | 11 ++ net/wireless/core.h | 4 +- net/wireless/nl80211.c | 237 ++++++++++++++++++++++++++++++------------- 6 files changed, 348 insertions(+), 74 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 47290a4059a..884ac69b5e5 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2679,6 +2679,34 @@ struct wiphy_coalesce_support { int max_pkt_offset; }; +/** + * enum wiphy_vendor_command_flags - validation flags for vendor commands + * @WIPHY_VENDOR_CMD_NEED_WDEV: vendor command requires wdev + * @WIPHY_VENDOR_CMD_NEED_NETDEV: vendor command requires netdev + * @WIPHY_VENDOR_CMD_NEED_RUNNING: interface/wdev must be up & running + * (must be combined with %_WDEV or %_NETDEV) + */ +enum wiphy_vendor_command_flags { + WIPHY_VENDOR_CMD_NEED_WDEV = BIT(0), + WIPHY_VENDOR_CMD_NEED_NETDEV = BIT(1), + WIPHY_VENDOR_CMD_NEED_RUNNING = BIT(2), +}; + +/** + * struct wiphy_vendor_command - vendor command definition + * @info: vendor command identifying information, as used in nl80211 + * @flags: flags, see &enum wiphy_vendor_command_flags + * @doit: callback for the operation, note that wdev is %NULL if the + * flags didn't ask for a wdev and non-%NULL otherwise; the data + * pointer may be %NULL if userspace provided no data at all + */ +struct wiphy_vendor_command { + struct nl80211_vendor_cmd_info info; + u32 flags; + int (*doit)(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int data_len); +}; + /** * struct wiphy - wireless hardware description * @reg_notifier: the driver's regulatory notification callback, @@ -2792,6 +2820,9 @@ struct wiphy_coalesce_support { * @extended_capabilities_mask: mask of the valid values * @extended_capabilities_len: length of the extended capabilities * @coalesce: packet coalescing support information + * + * @vendor_commands: array of vendor commands supported by the hardware + * @n_vendor_commands: number of vendor commands */ struct wiphy { /* assign these fields before you register the wiphy */ @@ -2903,6 +2934,9 @@ struct wiphy { const struct wiphy_coalesce_support *coalesce; + const struct wiphy_vendor_command *vendor_commands; + int n_vendor_commands; + char priv[0] __aligned(NETDEV_ALIGN); }; @@ -3847,6 +3881,75 @@ void wiphy_rfkill_start_polling(struct wiphy *wiphy); */ void wiphy_rfkill_stop_polling(struct wiphy *wiphy); +/** + * DOC: Vendor commands + * + * Occasionally, there are special protocol or firmware features that + * can't be implemented very openly. For this and similar cases, the + * vendor command functionality allows implementing the features with + * (typically closed-source) userspace and firmware, using nl80211 as + * the configuration mechanism. + * + * A driver supporting vendor commands must register them as an array + * in struct wiphy, with handlers for each one, each command has an + * OUI and sub command ID to identify it. + * + * Note that this feature should not be (ab)used to implement protocol + * features that could openly be shared across drivers. In particular, + * it must never be required to use vendor commands to implement any + * "normal" functionality that higher-level userspace like connection + * managers etc. need. + */ + +struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy, + enum nl80211_commands cmd, + enum nl80211_attrs attr, + int approxlen); + +/** + * cfg80211_vendor_cmd_alloc_reply_skb - allocate vendor command reply + * @wiphy: the wiphy + * @approxlen: an upper bound of the length of the data that will + * be put into the skb + * + * This function allocates and pre-fills an skb for a reply to + * a vendor command. Since it is intended for a reply, calling + * it outside of a vendor command's doit() operation is invalid. + * + * The returned skb is pre-filled with some identifying data in + * a way that any data that is put into the skb (with skb_put(), + * nla_put() or similar) will end up being within the + * %NL80211_ATTR_VENDOR_DATA attribute, so all that needs to be done + * with the skb is adding data for the corresponding userspace tool + * which can then read that data out of the vendor data attribute. + * You must not modify the skb in any other way. + * + * When done, call cfg80211_vendor_cmd_reply() with the skb and return + * its error code as the result of the doit() operation. + * + * Return: An allocated and pre-filled skb. %NULL if any errors happen. + */ +static inline struct sk_buff * +cfg80211_vendor_cmd_alloc_reply_skb(struct wiphy *wiphy, int approxlen) +{ + return __cfg80211_alloc_reply_skb(wiphy, NL80211_CMD_VENDOR, + NL80211_ATTR_VENDOR_DATA, approxlen); +} + +/** + * cfg80211_vendor_cmd_reply - send the reply skb + * @skb: The skb, must have been allocated with + * cfg80211_vendor_cmd_alloc_reply_skb() + * + * Since calling this function will usually be the last thing + * before returning from the vendor command doit() you should + * return the error code. Note that this function consumes the + * skb regardless of the return value. + * + * Return: An error code or 0 on success. + */ +int cfg80211_vendor_cmd_reply(struct sk_buff *skb); + #ifdef CONFIG_NL80211_TESTMODE /** * DOC: Test mode @@ -3882,8 +3985,12 @@ void wiphy_rfkill_stop_polling(struct wiphy *wiphy); * * Return: An allocated and pre-filled skb. %NULL if any errors happen. */ -struct sk_buff *cfg80211_testmode_alloc_reply_skb(struct wiphy *wiphy, - int approxlen); +static inline struct sk_buff * +cfg80211_testmode_alloc_reply_skb(struct wiphy *wiphy, int approxlen) +{ + return __cfg80211_alloc_reply_skb(wiphy, NL80211_CMD_TESTMODE, + NL80211_ATTR_TESTDATA, approxlen); +} /** * cfg80211_testmode_reply - send the reply skb @@ -3897,7 +4004,10 @@ struct sk_buff *cfg80211_testmode_alloc_reply_skb(struct wiphy *wiphy, * * Return: An error code or 0 on success. */ -int cfg80211_testmode_reply(struct sk_buff *skb); +static inline int cfg80211_testmode_reply(struct sk_buff *skb) +{ + return cfg80211_vendor_cmd_reply(skb); +} /** * cfg80211_testmode_alloc_event_skb - allocate testmode event diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 73d99bc3e63..c014acc09eb 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1162,6 +1162,19 @@ static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif) return false; } +/** + * wdev_to_ieee80211_vif - return a vif struct from a wdev + * @wdev: the wdev to get the vif for + * + * This can be used by mac80211 drivers with direct cfg80211 APIs + * (like the vendor commands) that get a wdev. + * + * Note that this function may return %NULL if the given wdev isn't + * associated with a vif that the driver knows about (e.g. monitor + * or AP_VLAN interfaces.) + */ +struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev); + /** * enum ieee80211_key_flags - key flags * diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 9a4d0e18251..72ba3584c90 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -693,6 +693,15 @@ * other station that transmission must be blocked until the channel * switch is complete. * + * @NL80211_CMD_VENDOR: Vendor-specified command/event. The command is specified + * by the %NL80211_ATTR_VENDOR_ID attribute and a sub-command in + * %NL80211_ATTR_VENDOR_SUBCMD. Parameter(s) can be transported in + * %NL80211_ATTR_VENDOR_DATA. + * For feature advertisement, the %NL80211_ATTR_VENDOR_DATA attribute is + * used in the wiphy data as a nested attribute containing descriptions + * (&struct nl80211_vendor_cmd_info) of the supported vendor commands. + * This may also be sent as an event with the same attributes. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -860,6 +869,8 @@ enum nl80211_commands { NL80211_CMD_CHANNEL_SWITCH, + NL80211_CMD_VENDOR, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -1524,6 +1535,12 @@ enum nl80211_commands { * Notification Element based on association request when used with * %NL80211_CMD_NEW_STATION; u8 attribute. * + * @NL80211_ATTR_VENDOR_ID: The vendor ID, either a 24-bit OUI or, if + * %NL80211_VENDOR_ID_IS_LINUX is set, a special Linux ID (not used yet) + * @NL80211_ATTR_VENDOR_SUBCMD: vendor sub-command + * @NL80211_ATTR_VENDOR_DATA: data for the vendor command, if any; this + * attribute is also used for vendor command feature advertisement + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1845,6 +1862,10 @@ enum nl80211_attrs { NL80211_ATTR_OPMODE_NOTIF, + NL80211_ATTR_VENDOR_ID, + NL80211_ATTR_VENDOR_SUBCMD, + NL80211_ATTR_VENDOR_DATA, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -3965,4 +3986,24 @@ enum nl80211_rxmgmt_flags { NL80211_RXMGMT_FLAG_ANSWERED = 1 << 0, }; +/* + * If this flag is unset, the lower 24 bits are an OUI, if set + * a Linux nl80211 vendor ID is used (no such IDs are allocated + * yet, so that's not valid so far) + */ +#define NL80211_VENDOR_ID_IS_LINUX 0x80000000 + +/** + * struct nl80211_vendor_cmd_info - vendor command data + * @vendor_id: If the %NL80211_VENDOR_ID_IS_LINUX flag is clear, then the + * value is a 24-bit OUI; if it is set then a separately allocated ID + * may be used, but no such IDs are allocated yet. New IDs should be + * added to this file when needed. + * @subcmd: sub-command ID for the command + */ +struct nl80211_vendor_cmd_info { + __u32 vendor_id; + __u32 subcmd; +}; + #endif /* __LINUX_NL80211_H */ diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 06265d7f8cc..4a376a72415 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -642,6 +642,17 @@ void ieee80211_iterate_active_interfaces_rtnl( } EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_rtnl); +struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); + + if (!ieee80211_sdata_running(sdata) || + !(sdata->flags & IEEE80211_SDATA_IN_DRIVER)) + return NULL; + return &sdata->vif; +} +EXPORT_SYMBOL_GPL(wdev_to_ieee80211_vif); + /* * Nothing should have been stuffed into the workqueue during * the suspend->resume cycle. If this WARN is seen then there diff --git a/net/wireless/core.h b/net/wireless/core.h index 6716c5c3f74..ac77644cf89 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -67,9 +67,7 @@ struct cfg80211_registered_device { struct work_struct scan_done_wk; struct work_struct sched_scan_results_wk; -#ifdef CONFIG_NL80211_TESTMODE - struct genl_info *testmode_info; -#endif + struct genl_info *cur_cmd_info; struct work_struct conn_work; struct work_struct event_work; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index bdcf256e362..6989989de09 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -358,6 +358,9 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES] = { .type = NLA_BINARY }, [NL80211_ATTR_HANDLE_DFS] = { .type = NLA_FLAG }, [NL80211_ATTR_OPMODE_NOTIF] = { .type = NLA_U8 }, + [NL80211_ATTR_VENDOR_ID] = { .type = NLA_U32 }, + [NL80211_ATTR_VENDOR_SUBCMD] = { .type = NLA_U32 }, + [NL80211_ATTR_VENDOR_DATA] = { .type = NLA_BINARY }, }; /* policy for the key attributes */ @@ -1166,6 +1169,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, struct nlattr *nl_bands, *nl_band; struct nlattr *nl_freqs, *nl_freq; struct nlattr *nl_cmds; + struct nlattr *nl_vendor_cmds; enum ieee80211_band band; struct ieee80211_channel *chan; int i; @@ -1561,6 +1565,19 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, (nla_put_flag(msg, NL80211_ATTR_SUPPORT_5_MHZ) || nla_put_flag(msg, NL80211_ATTR_SUPPORT_10_MHZ))) goto nla_put_failure; + state->split_start++; + break; + case 11: + nl_vendor_cmds = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA); + if (!nl_vendor_cmds) + goto nla_put_failure; + + for (i = 0; i < dev->wiphy.n_vendor_commands; i++) + if (nla_put(msg, i + 1, + sizeof(struct nl80211_vendor_cmd_info), + &dev->wiphy.vendor_commands[i].info)) + goto nla_put_failure; + nla_nest_end(msg, nl_vendor_cmds); /* done */ state->split_start = 0; @@ -6682,6 +6699,40 @@ static int nl80211_set_mcast_rate(struct sk_buff *skb, struct genl_info *info) return err; } +static struct sk_buff * +__cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev, + int approxlen, u32 portid, u32 seq, + enum nl80211_commands cmd, + enum nl80211_attrs attr, gfp_t gfp) +{ + struct sk_buff *skb; + void *hdr; + struct nlattr *data; + + skb = nlmsg_new(approxlen + 100, gfp); + if (!skb) + return NULL; + + hdr = nl80211hdr_put(skb, portid, seq, 0, cmd); + if (!hdr) { + kfree_skb(skb); + return NULL; + } + + if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx)) + goto nla_put_failure; + data = nla_nest_start(skb, attr); + + ((void **)skb->cb)[0] = rdev; + ((void **)skb->cb)[1] = hdr; + ((void **)skb->cb)[2] = data; + + return skb; + + nla_put_failure: + kfree_skb(skb); + return NULL; +} #ifdef CONFIG_NL80211_TESTMODE static struct genl_multicast_group nl80211_testmode_mcgrp = { @@ -6710,11 +6761,11 @@ static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) if (!info->attrs[NL80211_ATTR_TESTDATA]) return -EINVAL; - rdev->testmode_info = info; + rdev->cur_cmd_info = info; err = rdev_testmode_cmd(rdev, wdev, nla_data(info->attrs[NL80211_ATTR_TESTDATA]), nla_len(info->attrs[NL80211_ATTR_TESTDATA])); - rdev->testmode_info = NULL; + rdev->cur_cmd_info = NULL; return err; } @@ -6814,77 +6865,14 @@ static int nl80211_testmode_dump(struct sk_buff *skb, return err; } -static struct sk_buff * -__cfg80211_testmode_alloc_skb(struct cfg80211_registered_device *rdev, - int approxlen, u32 portid, u32 seq, gfp_t gfp) -{ - struct sk_buff *skb; - void *hdr; - struct nlattr *data; - - skb = nlmsg_new(approxlen + 100, gfp); - if (!skb) - return NULL; - - hdr = nl80211hdr_put(skb, portid, seq, 0, NL80211_CMD_TESTMODE); - if (!hdr) { - kfree_skb(skb); - return NULL; - } - - if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx)) - goto nla_put_failure; - data = nla_nest_start(skb, NL80211_ATTR_TESTDATA); - - ((void **)skb->cb)[0] = rdev; - ((void **)skb->cb)[1] = hdr; - ((void **)skb->cb)[2] = data; - - return skb; - - nla_put_failure: - kfree_skb(skb); - return NULL; -} - -struct sk_buff *cfg80211_testmode_alloc_reply_skb(struct wiphy *wiphy, - int approxlen) -{ - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - - if (WARN_ON(!rdev->testmode_info)) - return NULL; - - return __cfg80211_testmode_alloc_skb(rdev, approxlen, - rdev->testmode_info->snd_portid, - rdev->testmode_info->snd_seq, - GFP_KERNEL); -} -EXPORT_SYMBOL(cfg80211_testmode_alloc_reply_skb); - -int cfg80211_testmode_reply(struct sk_buff *skb) -{ - struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0]; - void *hdr = ((void **)skb->cb)[1]; - struct nlattr *data = ((void **)skb->cb)[2]; - - if (WARN_ON(!rdev->testmode_info)) { - kfree_skb(skb); - return -EINVAL; - } - - nla_nest_end(skb, data); - genlmsg_end(skb, hdr); - return genlmsg_reply(skb, rdev->testmode_info); -} -EXPORT_SYMBOL(cfg80211_testmode_reply); - struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy, int approxlen, gfp_t gfp) { struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - return __cfg80211_testmode_alloc_skb(rdev, approxlen, 0, 0, gfp); + return __cfg80211_alloc_vendor_skb(rdev, approxlen, 0, 0, + NL80211_CMD_TESTMODE, + NL80211_ATTR_TESTDATA, gfp); } EXPORT_SYMBOL(cfg80211_testmode_alloc_event_skb); @@ -8867,6 +8855,111 @@ static int nl80211_crit_protocol_stop(struct sk_buff *skb, return 0; } +static int nl80211_vendor_cmd(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct wireless_dev *wdev = + __cfg80211_wdev_from_attrs(genl_info_net(info), info->attrs); + int i, err; + u32 vid, subcmd; + + if (!rdev->wiphy.vendor_commands) + return -EOPNOTSUPP; + + if (IS_ERR(wdev)) { + err = PTR_ERR(wdev); + if (err != -EINVAL) + return err; + wdev = NULL; + } else if (wdev->wiphy != &rdev->wiphy) { + return -EINVAL; + } + + if (!info->attrs[NL80211_ATTR_VENDOR_ID] || + !info->attrs[NL80211_ATTR_VENDOR_SUBCMD]) + return -EINVAL; + + vid = nla_get_u32(info->attrs[NL80211_ATTR_VENDOR_ID]); + subcmd = nla_get_u32(info->attrs[NL80211_ATTR_VENDOR_SUBCMD]); + for (i = 0; i < rdev->wiphy.n_vendor_commands; i++) { + const struct wiphy_vendor_command *vcmd; + void *data = NULL; + int len = 0; + + vcmd = &rdev->wiphy.vendor_commands[i]; + + if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd) + continue; + + if (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV)) { + if (!wdev) + return -EINVAL; + if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_NETDEV && + !wdev->netdev) + return -EINVAL; + + if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) { + if (wdev->netdev && + !netif_running(wdev->netdev)) + return -ENETDOWN; + if (!wdev->netdev && !wdev->p2p_started) + return -ENETDOWN; + } + } else { + wdev = NULL; + } + + if (info->attrs[NL80211_ATTR_VENDOR_DATA]) { + data = nla_data(info->attrs[NL80211_ATTR_VENDOR_DATA]); + len = nla_len(info->attrs[NL80211_ATTR_VENDOR_DATA]); + } + + rdev->cur_cmd_info = info; + err = rdev->wiphy.vendor_commands[i].doit(&rdev->wiphy, wdev, + data, len); + rdev->cur_cmd_info = NULL; + return err; + } + + return -EOPNOTSUPP; +} + +struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy, + enum nl80211_commands cmd, + enum nl80211_attrs attr, + int approxlen) +{ + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + if (WARN_ON(!rdev->cur_cmd_info)) + return NULL; + + return __cfg80211_alloc_vendor_skb(rdev, approxlen, + rdev->cur_cmd_info->snd_portid, + rdev->cur_cmd_info->snd_seq, + cmd, attr, GFP_KERNEL); +} +EXPORT_SYMBOL(__cfg80211_alloc_reply_skb); + +int cfg80211_vendor_cmd_reply(struct sk_buff *skb) +{ + struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0]; + void *hdr = ((void **)skb->cb)[1]; + struct nlattr *data = ((void **)skb->cb)[2]; + + if (WARN_ON(!rdev->cur_cmd_info)) { + kfree_skb(skb); + return -EINVAL; + } + + nla_nest_end(skb, data); + genlmsg_end(skb, hdr); + return genlmsg_reply(skb, rdev->cur_cmd_info); +} +EXPORT_SYMBOL_GPL(cfg80211_vendor_cmd_reply); + + #define NL80211_FLAG_NEED_WIPHY 0x01 #define NL80211_FLAG_NEED_NETDEV 0x02 #define NL80211_FLAG_NEED_RTNL 0x04 @@ -9591,6 +9684,14 @@ static struct genl_ops nl80211_ops[] = { .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, + { + .cmd = NL80211_CMD_VENDOR, + .doit = nl80211_vendor_cmd, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_WIPHY | + NL80211_FLAG_NEED_RTNL, + }, }; static struct genl_multicast_group nl80211_mlme_mcgrp = { -- cgit v1.2.3-70-g09d2 From 33dde2bfe8ca97bdd8253bc0496482b048fa0b32 Mon Sep 17 00:00:00 2001 From: Chun-Yeow Yeoh Date: Mon, 2 Dec 2013 16:05:49 +0800 Subject: nl80211: allow the use of DFS channel in mesh This permits the use of DFS channel once the CAC is conducted and no radar is detected. Signed-off-by: Chun-Yeow Yeoh Signed-off-by: Johannes Berg --- net/wireless/mesh.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index b0e1869de7d..9c7a11ae793 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c @@ -99,6 +99,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, const struct mesh_config *conf) { struct wireless_dev *wdev = dev->ieee80211_ptr; + u8 radar_detect_width = 0; int err; BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != IEEE80211_MAX_MESH_ID_LEN); @@ -177,8 +178,16 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef)) return -EINVAL; - err = cfg80211_can_use_chan(rdev, wdev, setup->chandef.chan, - CHAN_MODE_SHARED); + err = cfg80211_chandef_dfs_required(wdev->wiphy, &setup->chandef); + if (err < 0) + return err; + if (err) + radar_detect_width = BIT(setup->chandef.width); + + err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, + setup->chandef.chan, + CHAN_MODE_SHARED, + radar_detect_width); if (err) return err; -- cgit v1.2.3-70-g09d2 From 9e890a1f21c626cec3a8955814d36ea1879bdde6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 4 Dec 2013 09:16:31 +0100 Subject: mac80211: neaten ieee80211_deliver_skb Remove the unnecessary duplicate test of "if (skb) {" when !CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS. Remove now unnecessary __maybe_unused, neaten comment Remove unnecessary parenthesis around align cast. Substitute reference to deprecated compare_ether_addr with ether_addr_equal (in the comment.) Signed-off-by: Joe Perches [edit commit log slightly] Signed-off-by: Johannes Berg --- net/mac80211/rx.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 5cf7285f6df..1892f883bd7 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1962,19 +1962,17 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) } } - if (skb) { #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS - /* - * 'align' will only take the values 0 or 2 here - * since all frames are required to be aligned - * to 2-byte boundaries when being passed to - * mac80211; the code here works just as well if - * that isn't true, but mac80211 assumes it can - * access fields as 2-byte aligned (e.g. for - * compare_ether_addr) + if (skb) { + /* 'align' will only take the values 0 or 2 here since all + * frames are required to be aligned to 2-byte boundaries + * when being passed to mac80211; the code here works just + * as well if that isn't true, but mac80211 assumes it can + * access fields as 2-byte aligned (e.g. for ether_addr_equal) */ - int align = ((unsigned long)(skb->data + - sizeof(struct ethhdr))) & 3; + int align; + + align = (unsigned long)(skb->data + sizeof(struct ethhdr)) & 3; if (align) { if (WARN_ON(skb_headroom(skb) < 3)) { dev_kfree_skb(skb); @@ -1987,14 +1985,14 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) skb_set_tail_pointer(skb, len); } } + } #endif - if (skb) { - /* deliver to local stack */ - skb->protocol = eth_type_trans(skb, dev); - memset(skb->cb, 0, sizeof(skb->cb)); - netif_receive_skb(skb); - } + if (skb) { + /* deliver to local stack */ + skb->protocol = eth_type_trans(skb, dev); + memset(skb->cb, 0, sizeof(skb->cb)); + netif_receive_skb(skb); } if (xmit_skb) { -- cgit v1.2.3-70-g09d2 From 33337dcb891e54d63433101af21fbff0b3f87bfa Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 23 Oct 2013 08:28:01 -0700 Subject: Bluetooth: Fix limited discoverable mode for Zeevo modules There is an old Panasonic module with a Zeevo chip in there that is not really operating according to Bluetooth core specification when it comes to setting the IAC LAP for limited discoverable mode. For reference, this is the vendor information about this module: < HCI Command: Read Local Version Information (0x04|0x0001) plen 0 > HCI Event: Command Complete (0x0e) plen 12 Read Local Version Information (0x04|0x0001) ncmd 1 Status: Success (0x00) HCI version: Bluetooth 1.2 (0x02) - Revision 196 (0x00c4) LMP version: Bluetooth 1.2 (0x02) - Subversion 61 (0x003d) Manufacturer: Zeevo, Inc. (18) The module reports only the support for one IAC at a time. And that is totally acceptable according to the Bluetooth core specification since the minimum supported IAC is only one. < HCI Command: Read Number of Supported IAC (0x03|0x0038) plen 0 > HCI Event: Command Complete (0x0e) plen 5 Read Number of Supported IAC (0x03|0x0038) ncmd 1 Status: Success (0x00) Number of IAC: 1 The problem arises when trying to program two IAC into the module on a controller that only supports one. < HCI Command: Write Current IAC LAP (0x03|0x003a) plen 7 Number of IAC: 2 Access code: 0x9e8b00 (Limited Inquiry) Access code: 0x9e8b33 (General Inquiry) > HCI Event: Command Status (0x0f) plen 4 Write Current IAC LAP (0x03|0x003a) ncmd 1 Status: Unknown HCI Command (0x01) While this looks strange, but according to the Bluetooth core specification it is a legal operation. The controller has to ignore the other values and only program as many as it supports. This command shall clear any existing IACs and stores Num_Current_IAC and the IAC_LAPs in to the controller. If Num_Current_IAC is greater than Num_Support_IAC then only the first Num_Support_IAC shall be stored in the controller, and a Command Complete event with error code Success (0x00) shall be generated. This specific controller has a bug here and just returns an error. So in case the number of supported IAC is less than two and the limited discoverable mode is requested, now only the LIAC is written to the controller. < HCI Command: Write Current IAC LAP (0x03|0x003a) plen 4 Number of IAC: 1 Access code: 0x9e8b00 (Limited Inquiry) > HCI Event: Command Complete (0x0e) plen 4 Write Current IAC LAP (0x03|0x003a) ncmd 1 Status: Success (0x00) All other controllers that only support one IAC seem to handle this perfectly fine, but this fix will only write the LIAC for these controllers as well. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 074d83690a4..22cf5471074 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1264,7 +1264,7 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data, if (cp->val == 0x02) { /* Limited discoverable mode */ - hci_cp.num_iac = 2; + hci_cp.num_iac = min_t(u8, hdev->num_iac, 2); hci_cp.iac_lap[0] = 0x00; /* LIAC */ hci_cp.iac_lap[1] = 0x8b; hci_cp.iac_lap[2] = 0x9e; -- cgit v1.2.3-70-g09d2 From bef34c0aa1bdd5bc106697bd7340eb212dcf3c85 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 29 Oct 2013 12:26:51 -0700 Subject: Bluetooth: Set default own address type only during controller setup The default own address type is currently set at every power on of a controller. This overwrites the value set via debugfs. To avoid this issue, set the default own address type only during controller setup. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 6ccc4eb9e55..03e83558a41 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1275,15 +1275,17 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt) hci_setup_link_policy(req); if (lmp_le_capable(hdev)) { - /* If the controller has a public BD_ADDR, then by - * default use that one. If this is a LE only - * controller without one, default to the random - * address. - */ - if (bacmp(&hdev->bdaddr, BDADDR_ANY)) - hdev->own_addr_type = ADDR_LE_DEV_PUBLIC; - else - hdev->own_addr_type = ADDR_LE_DEV_RANDOM; + if (test_bit(HCI_SETUP, &hdev->dev_flags)) { + /* If the controller has a public BD_ADDR, then + * by default use that one. If this is a LE only + * controller without a public address, default + * to the random address. + */ + if (bacmp(&hdev->bdaddr, BDADDR_ANY)) + hdev->own_addr_type = ADDR_LE_DEV_PUBLIC; + else + hdev->own_addr_type = ADDR_LE_DEV_RANDOM; + } hci_set_le_support(req); } -- cgit v1.2.3-70-g09d2 From d3d5dd3eb45c37141096c65a3742f4cf38f785ea Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 31 Oct 2013 04:54:32 -0700 Subject: Bluetooth: Remove debug statement for features complete event The complete list of local features are available through debugfs and so there is no need to add a debug print here. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 5935f748c0f..d75d51ff4fd 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -538,12 +538,6 @@ static void hci_cc_read_local_features(struct hci_dev *hdev, if (hdev->features[0][5] & LMP_EDR_3S_ESCO) hdev->esco_type |= (ESCO_2EV5 | ESCO_3EV5); - - BT_DBG("%s features 0x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", hdev->name, - hdev->features[0][0], hdev->features[0][1], - hdev->features[0][2], hdev->features[0][3], - hdev->features[0][4], hdev->features[0][5], - hdev->features[0][6], hdev->features[0][7]); } static void hci_cc_read_local_ext_features(struct hci_dev *hdev, -- cgit v1.2.3-70-g09d2 From 6a070e6e81adfaed060c5696ef3388126d2165b1 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 31 Oct 2013 04:54:33 -0700 Subject: Bluetooth: Store supported commands only during setup procedure The list of supported commands of a controller can not change during its lifetime. So store the list just once during the setup procedure and not every time the HCI command is executed. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index d75d51ff4fd..4d0f4018df1 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -486,7 +486,10 @@ static void hci_cc_read_local_commands(struct hci_dev *hdev, BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); - if (!rp->status) + if (rp->status) + return; + + if (test_bit(HCI_SETUP, &hdev->dev_flags)) memcpy(hdev->commands, rp->commands, sizeof(hdev->commands)); } -- cgit v1.2.3-70-g09d2 From 3e4543abf9deea8733341d235719e7e02b4068ed Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Thu, 31 Oct 2013 15:08:31 -0700 Subject: Bluetooth: btmrvl: operate on 16-bit opcodes instead of ogf/ocf Replace ogf/ocf and its packing with 16-bit opcodes. Signed-off-by: Bing Zhao Signed-off-by: Amitkumar Karwar Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmrvl_drv.h | 19 +++++++++++-------- drivers/bluetooth/btmrvl_main.c | 21 +++++++++------------ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h index f9d183387f4..e3b49c68ea7 100644 --- a/drivers/bluetooth/btmrvl_drv.h +++ b/drivers/bluetooth/btmrvl_drv.h @@ -90,12 +90,12 @@ struct btmrvl_private { #define MRVL_VENDOR_PKT 0xFE -/* Bluetooth commands */ -#define BT_CMD_AUTO_SLEEP_MODE 0x23 -#define BT_CMD_HOST_SLEEP_CONFIG 0x59 -#define BT_CMD_HOST_SLEEP_ENABLE 0x5A -#define BT_CMD_MODULE_CFG_REQ 0x5B -#define BT_CMD_LOAD_CONFIG_DATA 0x61 +/* Vendor specific Bluetooth commands */ +#define BT_CMD_AUTO_SLEEP_MODE 0xFC23 +#define BT_CMD_HOST_SLEEP_CONFIG 0xFC59 +#define BT_CMD_HOST_SLEEP_ENABLE 0xFC5A +#define BT_CMD_MODULE_CFG_REQ 0xFC5B +#define BT_CMD_LOAD_CONFIG_DATA 0xFC61 /* Sub-commands: Module Bringup/Shutdown Request/Response */ #define MODULE_BRINGUP_REQ 0xF1 @@ -104,6 +104,11 @@ struct btmrvl_private { #define MODULE_SHUTDOWN_REQ 0xF2 +/* Vendor specific Bluetooth events */ +#define BT_EVENT_AUTO_SLEEP_MODE 0x23 +#define BT_EVENT_HOST_SLEEP_CONFIG 0x59 +#define BT_EVENT_HOST_SLEEP_ENABLE 0x5A +#define BT_EVENT_MODULE_CFG_REQ 0x5B #define BT_EVENT_POWER_STATE 0x20 /* Bluetooth Power States */ @@ -111,8 +116,6 @@ struct btmrvl_private { #define BT_PS_DISABLE 0x03 #define BT_PS_SLEEP 0x01 -#define OGF 0x3F - /* Host Sleep states */ #define HS_ACTIVATED 0x01 #define HS_DEACTIVATED 0x00 diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index 5cf31c4fe6d..477b658316b 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -50,12 +50,10 @@ bool btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb) if (hdr->evt == HCI_EV_CMD_COMPLETE) { struct hci_ev_cmd_complete *ec; - u16 opcode, ocf, ogf; + u16 opcode; ec = (void *) (skb->data + HCI_EVENT_HDR_SIZE); opcode = __le16_to_cpu(ec->opcode); - ocf = hci_opcode_ocf(opcode); - ogf = hci_opcode_ogf(opcode); if (priv->btmrvl_dev.sendcmdflag) { priv->btmrvl_dev.sendcmdflag = false; @@ -63,9 +61,8 @@ bool btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb) wake_up_interruptible(&priv->adapter->cmd_wait_q); } - if (ogf == OGF) { - BT_DBG("vendor event skipped: ogf 0x%4.4x ocf 0x%4.4x", - ogf, ocf); + if (hci_opcode_ogf(opcode) == 0x3F) { + BT_DBG("vendor event skipped: opcode=%#4.4x", opcode); kfree_skb(skb); return false; } @@ -89,7 +86,7 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb) } switch (event->data[0]) { - case BT_CMD_AUTO_SLEEP_MODE: + case BT_EVENT_AUTO_SLEEP_MODE: if (!event->data[2]) { if (event->data[1] == BT_PS_ENABLE) adapter->psmode = 1; @@ -102,7 +99,7 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb) } break; - case BT_CMD_HOST_SLEEP_CONFIG: + case BT_EVENT_HOST_SLEEP_CONFIG: if (!event->data[3]) BT_DBG("gpio=%x, gap=%x", event->data[1], event->data[2]); @@ -110,7 +107,7 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb) BT_DBG("HSCFG command failed"); break; - case BT_CMD_HOST_SLEEP_ENABLE: + case BT_EVENT_HOST_SLEEP_ENABLE: if (!event->data[1]) { adapter->hs_state = HS_ACTIVATED; if (adapter->psmode) @@ -121,7 +118,7 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb) } break; - case BT_CMD_MODULE_CFG_REQ: + case BT_EVENT_MODULE_CFG_REQ: if (priv->btmrvl_dev.sendcmdflag && event->data[1] == MODULE_BRINGUP_REQ) { BT_DBG("EVENT:%s", @@ -166,7 +163,7 @@ exit: } EXPORT_SYMBOL_GPL(btmrvl_process_event); -static int btmrvl_send_sync_cmd(struct btmrvl_private *priv, u16 cmd_no, +static int btmrvl_send_sync_cmd(struct btmrvl_private *priv, u16 opcode, const void *param, u8 len) { struct sk_buff *skb; @@ -179,7 +176,7 @@ static int btmrvl_send_sync_cmd(struct btmrvl_private *priv, u16 cmd_no, } hdr = (struct hci_command_hdr *)skb_put(skb, HCI_COMMAND_HDR_SIZE); - hdr->opcode = cpu_to_le16(hci_opcode_pack(OGF, cmd_no)); + hdr->opcode = cpu_to_le16(opcode); hdr->plen = len; if (len) -- cgit v1.2.3-70-g09d2 From 433a9389a11778f1bc342789abccac9ce46eee82 Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Fri, 1 Nov 2013 15:28:24 -0700 Subject: Bluetooth: btmrvl: use cal-data from device-tree instead of conf file Some ARM versions of Chromebook need to download a new calibration data from host driver to firmware. They do have EEPROM but still need a piece of new calibration data in test mode. The cal-data is platform dependent. It's simpler and more feasible to use device tree based cal-data instead of configuration file based cal-data. This patch remove configuration file based cal-data downloading and replace it using cal-data from device tree. When CONFIG_OF is not selected, or the specific property is not present in the device tree, the calibration downloading will not happen. Cc: Mike Frysinger Cc: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: Hyuckjoo Lee Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmrvl_drv.h | 4 -- drivers/bluetooth/btmrvl_main.c | 92 ++++++++--------------------------------- drivers/bluetooth/btmrvl_sdio.c | 9 +--- drivers/bluetooth/btmrvl_sdio.h | 2 - 4 files changed, 18 insertions(+), 89 deletions(-) diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h index e3b49c68ea7..98187f09393 100644 --- a/drivers/bluetooth/btmrvl_drv.h +++ b/drivers/bluetooth/btmrvl_drv.h @@ -23,8 +23,6 @@ #include #include #include -#include -#include #define BTM_HEADER_LEN 4 #define BTM_UPLD_SIZE 2312 @@ -43,8 +41,6 @@ struct btmrvl_thread { struct btmrvl_device { void *card; struct hci_dev *hcidev; - struct device *dev; - const char *cal_data; u8 dev_type; diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index 477b658316b..6441f724aeb 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -19,7 +19,7 @@ **/ #include - +#include #include #include @@ -414,52 +414,8 @@ static int btmrvl_open(struct hci_dev *hdev) return 0; } -/* - * This function parses provided calibration data input. It should contain - * hex bytes separated by space or new line character. Here is an example. - * 00 1C 01 37 FF FF FF FF 02 04 7F 01 - * CE BA 00 00 00 2D C6 C0 00 00 00 00 - * 00 F0 00 00 - */ -static int btmrvl_parse_cal_cfg(const u8 *src, u32 len, u8 *dst, u32 dst_size) -{ - const u8 *s = src; - u8 *d = dst; - int ret; - u8 tmp[3]; - - tmp[2] = '\0'; - while ((s - src) <= len - 2) { - if (isspace(*s)) { - s++; - continue; - } - - if (isxdigit(*s)) { - if ((d - dst) >= dst_size) { - BT_ERR("calibration data file too big!!!"); - return -EINVAL; - } - - memcpy(tmp, s, 2); - - ret = kstrtou8(tmp, 16, d++); - if (ret < 0) - return ret; - - s += 2; - } else { - return -EINVAL; - } - } - if (d == dst) - return -EINVAL; - - return 0; -} - -static int btmrvl_load_cal_data(struct btmrvl_private *priv, - u8 *config_data) +static int btmrvl_download_cal_data(struct btmrvl_private *priv, + u8 *config_data) { int i, ret; u8 data[BT_CMD_DATA_SIZE]; @@ -487,54 +443,40 @@ static int btmrvl_load_cal_data(struct btmrvl_private *priv, return 0; } -static int -btmrvl_process_cal_cfg(struct btmrvl_private *priv, u8 *data, u32 size) +static int btmrvl_cal_data_dt(struct btmrvl_private *priv) { + struct device_node *dt_node; u8 cal_data[BT_CAL_DATA_SIZE]; + const char name[] = "btmrvl_caldata"; + const char property[] = "btmrvl,caldata"; int ret; - ret = btmrvl_parse_cal_cfg(data, size, cal_data, sizeof(cal_data)); + dt_node = of_find_node_by_name(NULL, name); + if (!dt_node) + return -ENODEV; + + ret = of_property_read_u8_array(dt_node, property, cal_data, + sizeof(cal_data)); if (ret) return ret; - ret = btmrvl_load_cal_data(priv, cal_data); + BT_DBG("Use cal data from device tree"); + ret = btmrvl_download_cal_data(priv, cal_data); if (ret) { - BT_ERR("Fail to load calibrate data"); + BT_ERR("Fail to download calibrate data"); return ret; } return 0; } -static int btmrvl_cal_data_config(struct btmrvl_private *priv) -{ - const struct firmware *cfg; - int ret; - const char *cal_data = priv->btmrvl_dev.cal_data; - - if (!cal_data) - return 0; - - ret = request_firmware(&cfg, cal_data, priv->btmrvl_dev.dev); - if (ret < 0) { - BT_DBG("Failed to get %s file, skipping cal data download", - cal_data); - return 0; - } - - ret = btmrvl_process_cal_cfg(priv, (u8 *)cfg->data, cfg->size); - release_firmware(cfg); - return ret; -} - static int btmrvl_setup(struct hci_dev *hdev) { struct btmrvl_private *priv = hci_get_drvdata(hdev); btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ); - if (btmrvl_cal_data_config(priv)) - BT_ERR("Set cal data failed"); + btmrvl_cal_data_dt(priv); priv->btmrvl_dev.psmode = 1; btmrvl_enable_ps(priv); diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index fabcf5bb48a..1b52c9f5230 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -18,6 +18,7 @@ * this warranty disclaimer. **/ +#include #include #include @@ -101,7 +102,6 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_88xx = { static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = { .helper = "mrvl/sd8688_helper.bin", .firmware = "mrvl/sd8688.bin", - .cal_data = NULL, .reg = &btmrvl_reg_8688, .sd_blksz_fw_dl = 64, }; @@ -109,7 +109,6 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = { static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = { .helper = NULL, .firmware = "mrvl/sd8787_uapsta.bin", - .cal_data = NULL, .reg = &btmrvl_reg_87xx, .sd_blksz_fw_dl = 256, }; @@ -117,7 +116,6 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = { static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = { .helper = NULL, .firmware = "mrvl/sd8797_uapsta.bin", - .cal_data = "mrvl/sd8797_caldata.conf", .reg = &btmrvl_reg_87xx, .sd_blksz_fw_dl = 256, }; @@ -125,7 +123,6 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = { static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = { .helper = NULL, .firmware = "mrvl/sd8897_uapsta.bin", - .cal_data = NULL, .reg = &btmrvl_reg_88xx, .sd_blksz_fw_dl = 256, }; @@ -1007,7 +1004,6 @@ static int btmrvl_sdio_probe(struct sdio_func *func, struct btmrvl_sdio_device *data = (void *) id->driver_data; card->helper = data->helper; card->firmware = data->firmware; - card->cal_data = data->cal_data; card->reg = data->reg; card->sd_blksz_fw_dl = data->sd_blksz_fw_dl; } @@ -1036,8 +1032,6 @@ static int btmrvl_sdio_probe(struct sdio_func *func, } card->priv = priv; - priv->btmrvl_dev.dev = &card->func->dev; - priv->btmrvl_dev.cal_data = card->cal_data; /* Initialize the interface specific function pointers */ priv->hw_host_to_card = btmrvl_sdio_host_to_card; @@ -1220,5 +1214,4 @@ MODULE_FIRMWARE("mrvl/sd8688_helper.bin"); MODULE_FIRMWARE("mrvl/sd8688.bin"); MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin"); MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin"); -MODULE_FIRMWARE("mrvl/sd8797_caldata.conf"); MODULE_FIRMWARE("mrvl/sd8897_uapsta.bin"); diff --git a/drivers/bluetooth/btmrvl_sdio.h b/drivers/bluetooth/btmrvl_sdio.h index 6872d9ecac0..43d35a609ca 100644 --- a/drivers/bluetooth/btmrvl_sdio.h +++ b/drivers/bluetooth/btmrvl_sdio.h @@ -85,7 +85,6 @@ struct btmrvl_sdio_card { u32 ioport; const char *helper; const char *firmware; - const char *cal_data; const struct btmrvl_sdio_card_reg *reg; u16 sd_blksz_fw_dl; u8 rx_unit; @@ -95,7 +94,6 @@ struct btmrvl_sdio_card { struct btmrvl_sdio_device { const char *helper; const char *firmware; - const char *cal_data; const struct btmrvl_sdio_card_reg *reg; u16 sd_blksz_fw_dl; }; -- cgit v1.2.3-70-g09d2 From 8a4934f1d62b8be7a00cdb4e65124f4d02d412f3 Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Fri, 1 Nov 2013 15:28:25 -0700 Subject: Bluetooth: btmrvl: remove cal-data byte swapping and redundant mem copy The device tree property can define the cal-data in proper order. There is no need to swap the bytes in driver. Also remove the redundant cal-data memory copy after removing the byte swapping. Cc: Mike Frysinger Cc: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: Hyuckjoo Lee Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmrvl_drv.h | 2 +- drivers/bluetooth/btmrvl_main.c | 27 ++++++++++----------------- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h index 98187f09393..7399303d7d9 100644 --- a/drivers/bluetooth/btmrvl_drv.h +++ b/drivers/bluetooth/btmrvl_drv.h @@ -120,7 +120,7 @@ struct btmrvl_private { #define PS_SLEEP 0x01 #define PS_AWAKE 0x00 -#define BT_CMD_DATA_SIZE 32 +#define BT_CAL_HDR_LEN 4 #define BT_CAL_DATA_SIZE 28 struct btmrvl_event { diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index 6441f724aeb..1e0320af00c 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -415,28 +415,20 @@ static int btmrvl_open(struct hci_dev *hdev) } static int btmrvl_download_cal_data(struct btmrvl_private *priv, - u8 *config_data) + u8 *data, int len) { - int i, ret; - u8 data[BT_CMD_DATA_SIZE]; + int ret; data[0] = 0x00; data[1] = 0x00; data[2] = 0x00; - data[3] = BT_CMD_DATA_SIZE - 4; - - /* Swap cal-data bytes. Each four bytes are swapped. Considering 4 - * byte SDIO header offset, mapping of input and output bytes will be - * {3, 2, 1, 0} -> {0+4, 1+4, 2+4, 3+4}, - * {7, 6, 5, 4} -> {4+4, 5+4, 6+4, 7+4} */ - for (i = 4; i < BT_CMD_DATA_SIZE; i++) - data[i] = config_data[(i / 4) * 8 - 1 - i]; + data[3] = len; print_hex_dump_bytes("Calibration data: ", - DUMP_PREFIX_OFFSET, data, BT_CMD_DATA_SIZE); + DUMP_PREFIX_OFFSET, data, BT_CAL_HDR_LEN + len); ret = btmrvl_send_sync_cmd(priv, BT_CMD_LOAD_CONFIG_DATA, data, - BT_CMD_DATA_SIZE); + BT_CAL_HDR_LEN + len); if (ret) BT_ERR("Failed to download caibration data\n"); @@ -446,7 +438,7 @@ static int btmrvl_download_cal_data(struct btmrvl_private *priv, static int btmrvl_cal_data_dt(struct btmrvl_private *priv) { struct device_node *dt_node; - u8 cal_data[BT_CAL_DATA_SIZE]; + u8 cal_data[BT_CAL_HDR_LEN + BT_CAL_DATA_SIZE]; const char name[] = "btmrvl_caldata"; const char property[] = "btmrvl,caldata"; int ret; @@ -455,13 +447,14 @@ static int btmrvl_cal_data_dt(struct btmrvl_private *priv) if (!dt_node) return -ENODEV; - ret = of_property_read_u8_array(dt_node, property, cal_data, - sizeof(cal_data)); + ret = of_property_read_u8_array(dt_node, property, + cal_data + BT_CAL_HDR_LEN, + BT_CAL_DATA_SIZE); if (ret) return ret; BT_DBG("Use cal data from device tree"); - ret = btmrvl_download_cal_data(priv, cal_data); + ret = btmrvl_download_cal_data(priv, cal_data, BT_CAL_DATA_SIZE); if (ret) { BT_ERR("Fail to download calibrate data"); return ret; -- cgit v1.2.3-70-g09d2 From 3655bba8fe693e31c44c43cd30a9aaeee8bd45df Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 30 Oct 2013 19:01:40 -0300 Subject: Bluetooth: Check address in mgmt_disconnect_failed() Check the address and address type in mgmt_disconnect_failed() otherwise we may wrongly fail the MGMT_OP_DISCONNECT command. Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 22cf5471074..6a74aa77654 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4613,6 +4613,8 @@ void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 status) { + u8 bdaddr_type = link_to_bdaddr(link_type, addr_type); + struct mgmt_cp_disconnect *cp; struct mgmt_rp_disconnect rp; struct pending_cmd *cmd; @@ -4623,8 +4625,16 @@ void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, if (!cmd) return; + cp = cmd->param; + + if (bacmp(bdaddr, &cp->addr.bdaddr)) + return; + + if (cp->addr.type != bdaddr_type) + return; + bacpy(&rp.addr.bdaddr, bdaddr); - rp.addr.type = link_to_bdaddr(link_type, addr_type); + rp.addr.type = bdaddr_type; cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, mgmt_status(status), &rp, sizeof(rp)); -- cgit v1.2.3-70-g09d2 From 57eb776feac497c8e5b561c0a24156245f0c08db Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 30 Oct 2013 19:01:41 -0300 Subject: Bluetooth: Add an extra check in mgmt_device_disconnected() This patch adds an extra check in mgmt_device_disconnected() so we only send the "Device Disconnected" event if it is ACL_LINK or LE_LINK link type. Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 6a74aa77654..a03ca3ca91b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4595,6 +4595,9 @@ void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, struct mgmt_ev_device_disconnected ev; struct sock *sk = NULL; + if (link_type != ACL_LINK && link_type != LE_LINK) + return; + mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk); bacpy(&ev.addr.bdaddr, bdaddr); -- cgit v1.2.3-70-g09d2 From 4ebbd5357531694b9243b176674ae27edf5bd8e1 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 30 Oct 2013 19:01:42 -0300 Subject: Bluetooth: Remove link type check in hci_disconn_complete_evt() We can safely remove the link type check from hci_disconn_complete_ evt() since this check in not required for mgmt_disconnect_failed() and mgmt_device_disconnected() does it internally. Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 4d0f4018df1..142aa61f9c3 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1792,8 +1792,7 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) if (ev->status == 0) conn->state = BT_CLOSED; - if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags) && - (conn->type == ACL_LINK || conn->type == LE_LINK)) { + if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) { if (ev->status) { mgmt_disconnect_failed(hdev, &conn->dst, conn->type, conn->dst_type, ev->status); -- cgit v1.2.3-70-g09d2 From 84794e119a22f67f2cac3f0ae958f2d69c46fa1e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 6 Nov 2013 11:24:57 +0200 Subject: Bluetooth: Remove unnecessary 'send' parameter from smp_failure() The send parameter has only been used for determining whether to send a Pairing Failed PDU or not. However, the function can equally well use the already existing reason parameter to make this choice and send the PDU whenever a non-zero value was passed. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 4b07acb8293..f99352d1aa4 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -257,11 +257,11 @@ static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size) return 0; } -static void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send) +static void smp_failure(struct l2cap_conn *conn, u8 reason) { struct hci_conn *hcon = conn->hcon; - if (send) + if (reason) smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), &reason); @@ -406,7 +406,7 @@ static void confirm_work(struct work_struct *work) return; error: - smp_failure(conn, reason, 1); + smp_failure(conn, reason); } static void random_work(struct work_struct *work) @@ -490,7 +490,7 @@ static void random_work(struct work_struct *work) return; error: - smp_failure(conn, reason, 1); + smp_failure(conn, reason); } static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) @@ -555,10 +555,10 @@ int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey) break; case MGMT_OP_USER_PASSKEY_NEG_REPLY: case MGMT_OP_USER_CONFIRM_NEG_REPLY: - smp_failure(conn, SMP_PASSKEY_ENTRY_FAILED, 1); + smp_failure(conn, SMP_PASSKEY_ENTRY_FAILED); return 0; default: - smp_failure(conn, SMP_PASSKEY_ENTRY_FAILED, 1); + smp_failure(conn, SMP_PASSKEY_ENTRY_FAILED); return -EOPNOTSUPP; } @@ -895,7 +895,7 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) break; case SMP_CMD_PAIRING_FAIL: - smp_failure(conn, skb->data[0], 0); + smp_failure(conn, 0); reason = 0; err = -EPERM; break; @@ -941,7 +941,7 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) done: if (reason) - smp_failure(conn, reason, 1); + smp_failure(conn, reason); kfree_skb(skb); return err; -- cgit v1.2.3-70-g09d2 From bd0fca1b2be8c96dfc391a2bc2ee4ce6970ae6af Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 6 Nov 2013 10:56:00 +0530 Subject: Bluetooth: ath3k: Add support for another AR3012 card T: Bus=03 Lev=01 Prnt=01 Port=02 Cnt=01 Dev#= 2 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=04ca ProdID=300b Rev= 0.01 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA A: FirstIf#= 0 IfCount= 2 Cls=e0(wlcon) Sub=01 Prot=01 I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb Reported-by: Face Signed-off-by: Sujith Manoharan Signed-off-by: Marcel Holtmann --- drivers/bluetooth/ath3k.c | 2 ++ drivers/bluetooth/btusb.c | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 6bfc1bb318f..cb5ef5ba965 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -83,6 +83,7 @@ static const struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x04CA, 0x3005) }, { USB_DEVICE(0x04CA, 0x3006) }, { USB_DEVICE(0x04CA, 0x3008) }, + { USB_DEVICE(0x04CA, 0x300b) }, { USB_DEVICE(0x13d3, 0x3362) }, { USB_DEVICE(0x0CF3, 0xE004) }, { USB_DEVICE(0x0CF3, 0xE005) }, @@ -125,6 +126,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = { { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 }, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index c0ff34f2d2d..67790b78a97 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -150,6 +150,7 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 }, -- cgit v1.2.3-70-g09d2 From 35580d223b6b04d9a570e4fe377c46a102413fe8 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 4 Nov 2013 21:38:23 +0530 Subject: Bluetooth: ath3k: Add support for a new AR3012 device T: Bus=02 Lev=01 Prnt=01 Port=04 Cnt=01 Dev#= 9 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0489 ProdID=e05f Rev= 0.02 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA A: FirstIf#= 0 IfCount= 2 Cls=e0(wlcon) Sub=01 Prot=01 I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb Reported-by: Joshua Richenhagen Signed-off-by: Sujith Manoharan Signed-off-by: Johan Hedberg --- drivers/bluetooth/ath3k.c | 2 ++ drivers/bluetooth/btusb.c | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index cb5ef5ba965..d3fdc32b579 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -97,6 +97,7 @@ static const struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x13d3, 0x3402) }, { USB_DEVICE(0x0cf3, 0x3121) }, { USB_DEVICE(0x0cf3, 0xe003) }, + { USB_DEVICE(0x0489, 0xe05f) }, /* Atheros AR5BBU12 with sflash firmware */ { USB_DEVICE(0x0489, 0xE02C) }, @@ -140,6 +141,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = { { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 }, /* Atheros AR5BBU22 with sflash firmware */ { USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 }, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 67790b78a97..3d04bce0d12 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -164,6 +164,7 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 }, /* Atheros AR5BBU12 with sflash firmware */ { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE }, -- cgit v1.2.3-70-g09d2 From abf54a506d06e0b3ba2c408040e647791af37937 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Thu, 7 Nov 2013 17:36:09 -0300 Subject: Bluetooth: Remove unneeded check in hci_disconn_complete_evt() According to b644ba336 (patch that introduced HCI_CONN_MGMT_CONNECTED flag), the HCI_CONN_MGMT_CONNECTED flag tracks when mgmt has been notified about the connection. That being said, there is no point in calling mgmt_disconnect_failed() conditionally based on this flag. mgmt_disconnect_failed() removes pending MGMT_OP_DISCONNECT commands, it doesn't matter if that connection was notified or not. Moreover, if the Disconnection Complete event has status then we have nothing else to do but call mgmt_disconnect_failed() and return. Signed-off-by: Andre Guedes Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 142aa61f9c3..eb99a12948c 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1779,6 +1779,7 @@ static u8 hci_to_mgmt_reason(u8 err) static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_disconn_complete *ev = (void *) skb->data; + u8 reason = hci_to_mgmt_reason(ev->reason); struct hci_conn *conn; BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); @@ -1792,18 +1793,16 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) if (ev->status == 0) conn->state = BT_CLOSED; - if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) { - if (ev->status) { - mgmt_disconnect_failed(hdev, &conn->dst, conn->type, - conn->dst_type, ev->status); - } else { - u8 reason = hci_to_mgmt_reason(ev->reason); - - mgmt_device_disconnected(hdev, &conn->dst, conn->type, - conn->dst_type, reason); - } + if (ev->status) { + mgmt_disconnect_failed(hdev, &conn->dst, conn->type, + conn->dst_type, ev->status); + goto unlock; } + if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) + mgmt_device_disconnected(hdev, &conn->dst, conn->type, + conn->dst_type, reason); + if (ev->status == 0) { u8 type = conn->type; -- cgit v1.2.3-70-g09d2 From 3846220b0df414816d00365cec559ff3c8b7c4bf Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Thu, 7 Nov 2013 17:36:10 -0300 Subject: Bluetooth: Refactor hci_disconn_complete_evt hci_disconn_complete_evt() logic is more complicated than what it should be, making it hard to follow and add new features. So this patch does some code refactoring by handling the error cases in the beginning of the function and by moving the main flow into the first level of function scope. No change is done in the event handling logic itself. Besides organizing this messy code, this patch makes easier to add code for handling LE auto connection (which will be added in a further patch). Signed-off-by: Andre Guedes Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 43 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index eb99a12948c..5fb3df66c2c 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1781,6 +1781,7 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) struct hci_ev_disconn_complete *ev = (void *) skb->data; u8 reason = hci_to_mgmt_reason(ev->reason); struct hci_conn *conn; + u8 type; BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); @@ -1790,40 +1791,38 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) if (!conn) goto unlock; - if (ev->status == 0) - conn->state = BT_CLOSED; - if (ev->status) { mgmt_disconnect_failed(hdev, &conn->dst, conn->type, conn->dst_type, ev->status); goto unlock; } + conn->state = BT_CLOSED; + if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) mgmt_device_disconnected(hdev, &conn->dst, conn->type, conn->dst_type, reason); - if (ev->status == 0) { - u8 type = conn->type; + if (conn->type == ACL_LINK && conn->flush_key) + hci_remove_link_key(hdev, &conn->dst); - if (type == ACL_LINK && conn->flush_key) - hci_remove_link_key(hdev, &conn->dst); - hci_proto_disconn_cfm(conn, ev->reason); - hci_conn_del(conn); + type = conn->type; - /* Re-enable advertising if necessary, since it might - * have been disabled by the connection. From the - * HCI_LE_Set_Advertise_Enable command description in - * the core specification (v4.0): - * "The Controller shall continue advertising until the Host - * issues an LE_Set_Advertise_Enable command with - * Advertising_Enable set to 0x00 (Advertising is disabled) - * or until a connection is created or until the Advertising - * is timed out due to Directed Advertising." - */ - if (type == LE_LINK) - mgmt_reenable_advertising(hdev); - } + hci_proto_disconn_cfm(conn, ev->reason); + hci_conn_del(conn); + + /* Re-enable advertising if necessary, since it might + * have been disabled by the connection. From the + * HCI_LE_Set_Advertise_Enable command description in + * the core specification (v4.0): + * "The Controller shall continue advertising until the Host + * issues an LE_Set_Advertise_Enable command with + * Advertising_Enable set to 0x00 (Advertising is disabled) + * or until a connection is created or until the Advertising + * is timed out due to Directed Advertising." + */ + if (type == LE_LINK) + mgmt_reenable_advertising(hdev); unlock: hci_dev_unlock(hdev); -- cgit v1.2.3-70-g09d2 From ef4e5e4a756ff077dbdbdb8481d0e3788a07c005 Mon Sep 17 00:00:00 2001 From: Tedd Ho-Jeong An Date: Tue, 12 Nov 2013 13:10:58 -0800 Subject: Bluetooth: Add support for Intel Bluetooth device [8087:0a2a] This patch adds support for new Intel Bluetooth device. T: Bus=02 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 4 Spd=12 MxCh= 0 D: Ver= 2.01 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=8087 ProdID=0a2a Rev= 0.01 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 64 Ivl=1ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms Signed-off-by: Tedd Ho-Jeong An Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btusb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 3d04bce0d12..b73ae34cdbe 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -225,6 +225,7 @@ static const struct usb_device_id blacklist_table[] = { /* Intel Bluetooth device */ { USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL }, + { USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL }, { } /* Terminating entry */ }; -- cgit v1.2.3-70-g09d2 From d2bee8fb6e18f6116aada39851918473761f7ab1 Mon Sep 17 00:00:00 2001 From: Tedd Ho-Jeong An Date: Tue, 12 Nov 2013 13:16:41 -0800 Subject: Bluetooth: Enable autosuspend for Intel Bluetooth device This patch enables autosuspend for Intel Bluetooth device. After btusb is loaded for Intel Bluetooth device, the power/control attribute contains "on" value by default which disables the autosuspend. Based on the USB PM document(Documentation/usb/power-management.txt), kernel disabled the autosuspend for all devices other than hub by default. "The USB specification states that all USB devices must support power management. Nevertheless, the sad fact is that many devices do not support it very well. You can suspend them all right, but when you try to resume them they disconnect themselves from the USB bus or they stop working entirely. This seems to be especially prevalent among printers and scanners, but plenty of other types of device have the same deficiency. For this reason, by default the kernel disables autosuspend (the power/control attribute is initialized to "on") for all devices other than hubs. Hubs, at least, appear to be reasonably well-behaved in this regard." This document also described how the driver can enables the autosuspend by using an USB api. "Drivers can enable autosuspend for their devices by calling usb_enable_autosuspend(struct usb_device *udev); in their probe() routine, if they know that the device is capable of suspending and resuming correctly. This is exactly equivalent to writing "auto" to the device's power/control attribute." For Intel Bluetooth device, the autosuspend needs to be enabled so the device can transit to LPM(Low Power Mode) and ULPM(Ultra LPM) states after receiving suspend message from the host. Signed-off-by: Tedd Ho-Jeong An Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btusb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index b73ae34cdbe..bfbcc5a772a 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -1438,8 +1438,10 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_BCM92035) hdev->setup = btusb_setup_bcm92035; - if (id->driver_info & BTUSB_INTEL) + if (id->driver_info & BTUSB_INTEL) { + usb_enable_autosuspend(data->udev); hdev->setup = btusb_setup_intel; + } /* Interface numbers are hardcoded in the specification */ data->isoc = usb_ifnum_to_if(data->udev, 1); -- cgit v1.2.3-70-g09d2 From e84a6b139bdd3af2914f194ff840b1a36fa55598 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 2 Dec 2013 10:49:03 +0200 Subject: Bluetooth: Remove useless smp_rand function This function was always just making a single get_random_bytes() call and always returning the value 0. It's simpler to just call get_random_bytes() directly where needed. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index f99352d1aa4..3bcb765b6a9 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -143,13 +143,6 @@ static int smp_s1(struct crypto_blkcipher *tfm, u8 k[16], u8 r1[16], return err; } -static int smp_rand(u8 *buf) -{ - get_random_bytes(buf, 16); - - return 0; -} - static struct sk_buff *smp_build_cmd(struct l2cap_conn *conn, u8 code, u16 dlen, void *data) { @@ -606,9 +599,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) if (check_enc_key_size(conn, key_size)) return SMP_ENC_KEY_SIZE; - ret = smp_rand(smp->prnd); - if (ret) - return SMP_UNSPECIFIED; + get_random_bytes(smp->prnd, sizeof(smp->prnd)); smp->prsp[0] = SMP_CMD_PAIRING_RSP; memcpy(&smp->prsp[1], &rsp, sizeof(rsp)); @@ -644,9 +635,7 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) if (check_enc_key_size(conn, key_size)) return SMP_ENC_KEY_SIZE; - ret = smp_rand(smp->prnd); - if (ret) - return SMP_UNSPECIFIED; + get_random_bytes(smp->prnd, sizeof(smp->prnd)); smp->prsp[0] = SMP_CMD_PAIRING_RSP; memcpy(&smp->prsp[1], rsp, sizeof(*rsp)); -- cgit v1.2.3-70-g09d2 From 201a5929c8c788f9ef53b010065c9ce70c9c06f0 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 2 Dec 2013 10:49:04 +0200 Subject: Bluetooth: Remove dead code from SMP encryption function The AES cipher is used in ECB mode by SMP and therefore doesn't use an IV (crypto_blkcipher_ivsize returns 0) so the code trying to set the IV was never getting called. Simply remove this code to avoid anyone from thinking it actually makes some difference. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 3bcb765b6a9..e61e74a1aab 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -53,8 +53,7 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r) { struct blkcipher_desc desc; struct scatterlist sg; - int err, iv_len; - unsigned char iv[128]; + int err; if (tfm == NULL) { BT_ERR("tfm %p", tfm); @@ -72,12 +71,6 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r) sg_init_one(&sg, r, 16); - iv_len = crypto_blkcipher_ivsize(tfm); - if (iv_len) { - memset(&iv, 0xff, iv_len); - crypto_blkcipher_set_iv(tfm, iv, iv_len); - } - err = crypto_blkcipher_encrypt(&desc, &sg, &sg, 16); if (err) BT_ERR("Encrypt data error %d", err); -- cgit v1.2.3-70-g09d2 From b01711be4bff93d16ac921350d2ada1a60ecc160 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 4 Dec 2013 20:25:27 +0100 Subject: mac80211: warn if unhashing station fails This shouldn't be happening, so warn if it does, since we'd then leak a station entry. Signed-off-by: Johannes Berg --- net/mac80211/sta_info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 8ed97f76c3c..8ae37f60d60 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -868,7 +868,7 @@ int __must_check __sta_info_destroy(struct sta_info *sta) ieee80211_sta_tear_down_BA_sessions(sta, AGG_STOP_DESTROY_STA); ret = sta_info_hash_del(local, sta); - if (ret) + if (WARN_ON(ret)) return ret; list_del_rcu(&sta->list); -- cgit v1.2.3-70-g09d2 From 6d3c15da1ddbffff2d0f50132a239209b2fa138e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 2 Dec 2013 22:13:24 +0200 Subject: Bluetooth: Remove unnecessary braces from one-line if-statement This patch is just a trivial coding style fix to remove unnecessary braces from a one-line if-statement. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 4af3821df88..70be2eb8ed0 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -6612,11 +6612,10 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) } if (chan->state == BT_CONNECT) { - if (!status) { + if (!status) l2cap_start_connection(chan); - } else { + else __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); - } } else if (chan->state == BT_CONNECT2) { struct l2cap_conn_rsp rsp; __u16 res, stat; -- cgit v1.2.3-70-g09d2 From 9149761ad74f618371b58fd37141d4c3706d88fc Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 2 Dec 2013 11:20:20 +0200 Subject: Bluetooth: Add module parameter to enable LE CoC support Along with the L2CAP Connection Oriented Channels features it is now allowed to use both custom fixed CIDs as well as PSM based (connection oriented connections). Since the support for this (with the subsequent patches) is still on an experimental stage, add a module parameter to enable it. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 1 + net/bluetooth/l2cap_sock.c | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index c853b16de4e..94645d56fea 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -809,6 +809,7 @@ static inline long l2cap_chan_no_get_sndtimeo(struct l2cap_chan *chan) } extern bool disable_ertm; +extern bool enable_lecoc; int l2cap_init_sockets(void); void l2cap_cleanup_sockets(void); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 7cc24d263ca..5a1d0cb0b8d 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -27,6 +27,7 @@ /* Bluetooth L2CAP sockets. */ +#include #include #include @@ -35,6 +36,8 @@ #include "smp.h" +bool enable_lecoc; + static struct bt_sock_list l2cap_sk_list = { .lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock) }; @@ -73,11 +76,11 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) return -EINVAL; if (bdaddr_type_is_le(la.l2_bdaddr_type)) { - /* Connection oriented channels are not supported on LE */ - if (la.l2_psm) + if (!enable_lecoc && la.l2_psm) return -EINVAL; /* We only allow ATT user space socket */ - if (la.l2_cid != __constant_cpu_to_le16(L2CAP_CID_ATT)) + if (la.l2_cid && + la.l2_cid != __constant_cpu_to_le16(L2CAP_CID_ATT)) return -EINVAL; } @@ -189,11 +192,11 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, return -EINVAL; if (bdaddr_type_is_le(la.l2_bdaddr_type)) { - /* Connection oriented channels are not supported on LE */ - if (la.l2_psm) + if (!enable_lecoc && la.l2_psm) return -EINVAL; /* We only allow ATT user space socket */ - if (la.l2_cid != __constant_cpu_to_le16(L2CAP_CID_ATT)) + if (la.l2_cid && + la.l2_cid != __constant_cpu_to_le16(L2CAP_CID_ATT)) return -EINVAL; } @@ -1469,3 +1472,6 @@ void l2cap_cleanup_sockets(void) bt_sock_unregister(BTPROTO_L2CAP); proto_unregister(&l2cap_proto); } + +module_param(enable_lecoc, bool, 0644); +MODULE_PARM_DESC(enable_lecoc, "Enable support for LE CoC"); -- cgit v1.2.3-70-g09d2 From bf20fd4ec1d39df78e31fd7c7a4066f69b8bcd8a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 14 May 2013 13:23:13 +0300 Subject: Bluetooth: Update l2cap_global_chan_by_psm() to take a link type Once connection oriented L2CAP channels become possible for LE we need to be able to specify the link type we're interested in when looking up L2CAP channels. Therefore, add a link_type parameter to the l2cap_global_chan_by_psm() function which gets compared to the address type associated with each l2cap_chan. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 70be2eb8ed0..03b641c2f39 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1703,7 +1703,8 @@ EXPORT_SYMBOL(l2cap_conn_put); */ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src, - bdaddr_t *dst) + bdaddr_t *dst, + u8 link_type) { struct l2cap_chan *c, *c1 = NULL; @@ -1713,6 +1714,12 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, if (state && c->state != state) continue; + if (link_type == ACL_LINK && c->src_type != BDADDR_BREDR) + continue; + + if (link_type == LE_LINK && c->src_type == BDADDR_BREDR) + continue; + if (c->psm == psm) { int src_match, dst_match; int src_any, dst_any; @@ -3713,7 +3720,7 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn, /* Check if we have socket listening on psm */ pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, &conn->hcon->src, - &conn->hcon->dst); + &conn->hcon->dst, ACL_LINK); if (!pchan) { result = L2CAP_CR_BAD_PSM; goto sendresp; @@ -6380,7 +6387,8 @@ static void l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, if (hcon->type != ACL_LINK) goto drop; - chan = l2cap_global_chan_by_psm(0, psm, &hcon->src, &hcon->dst); + chan = l2cap_global_chan_by_psm(0, psm, &hcon->src, &hcon->dst, + ACL_LINK); if (!chan) goto drop; -- cgit v1.2.3-70-g09d2 From a17de2fe02b1853f115a841bf707f6a75bc6da22 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 14 May 2013 13:25:37 +0300 Subject: Bluetooth: Allow l2cap_chan_check_security() to be used for LE links. With connection oriented L2CAP channels some code paths will be shared with BR/EDR links. It is therefore necessary to allow the l2cap_chan_check_security function to be usable also for LE links in addition to BR/EDR ones. This means that smp_conn_security() needs to be called instead of hci_conn_security() in the case of an LE link. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 03b641c2f39..510a17cefd2 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -726,6 +726,9 @@ int l2cap_chan_check_security(struct l2cap_chan *chan) struct l2cap_conn *conn = chan->conn; __u8 auth_type; + if (conn->hcon->type == LE_LINK) + return smp_conn_security(conn->hcon, chan->sec_level); + auth_type = l2cap_get_auth_type(chan); return hci_conn_security(conn->hcon, chan->sec_level, auth_type); -- cgit v1.2.3-70-g09d2 From 203e639ecbcc66c7c4d55f1f59bc61a1c1ca495d Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 15 May 2013 10:07:15 +0300 Subject: Bluetooth: Pass command length to LE signaling channel handlers The LE signaling PDU length is already calculated in the l2cap_le_sig_channel function so we can just pass the value to the various handler functions to avoid unnecessary recalculations (byte order conversions). Right now the only user is the connection parameter update procedure, but as new LE signaling operations become available (for connection oriented channels) they will also be able to make use of the value. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 510a17cefd2..eafcdf65718 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -5165,18 +5165,17 @@ static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency, static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, - u8 *data) + u16 cmd_len, u8 *data) { struct hci_conn *hcon = conn->hcon; struct l2cap_conn_param_update_req *req; struct l2cap_conn_param_update_rsp rsp; - u16 min, max, latency, to_multiplier, cmd_len; + u16 min, max, latency, to_multiplier; int err; if (!(hcon->link_mode & HCI_LM_MASTER)) return -EINVAL; - cmd_len = __le16_to_cpu(cmd->len); if (cmd_len != sizeof(struct l2cap_conn_param_update_req)) return -EPROTO; @@ -5287,14 +5286,15 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn, } static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn, - struct l2cap_cmd_hdr *cmd, u8 *data) + struct l2cap_cmd_hdr *cmd, u16 cmd_len, + u8 *data) { switch (cmd->code) { case L2CAP_COMMAND_REJ: return 0; case L2CAP_CONN_PARAM_UPDATE_REQ: - return l2cap_conn_param_update_req(conn, cmd, data); + return l2cap_conn_param_update_req(conn, cmd, cmd_len, data); case L2CAP_CONN_PARAM_UPDATE_RSP: return 0; @@ -5331,7 +5331,7 @@ static inline void l2cap_le_sig_channel(struct l2cap_conn *conn, goto drop; } - err = l2cap_le_sig_cmd(conn, cmd, skb->data); + err = l2cap_le_sig_cmd(conn, cmd, len, skb->data); if (err) { struct l2cap_cmd_rej_unk rej; -- cgit v1.2.3-70-g09d2 From 96ac34fb4050e358eed55ac93572f58191a304aa Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 13 May 2013 11:15:07 +0300 Subject: Bluetooth: Move LE L2CAP initiator procedure to its own function Once connection oriented L2CAP channels over LE are supported they will need a completely separate handling from BR/EDR channels. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index eafcdf65718..d250d8af7fd 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1170,12 +1170,17 @@ static void l2cap_start_connection(struct l2cap_chan *chan) } } +static void l2cap_le_start(struct l2cap_chan *chan) +{ + l2cap_chan_ready(chan); +} + static void l2cap_do_start(struct l2cap_chan *chan) { struct l2cap_conn *conn = chan->conn; if (conn->hcon->type == LE_LINK) { - l2cap_chan_ready(chan); + l2cap_le_start(chan); return; } -- cgit v1.2.3-70-g09d2 From ee5ec5cf00760b8810f7e3350b82434092a960e3 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 13 May 2013 12:15:39 +0300 Subject: Bluetooth: Add definitions for LE connection oriented channels This patch adds the necessary defines and structs for LE connection oriented channels. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 94645d56fea..84c0754b87d 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -112,6 +112,9 @@ struct l2cap_conninfo { #define L2CAP_MOVE_CHAN_CFM_RSP 0x11 #define L2CAP_CONN_PARAM_UPDATE_REQ 0x12 #define L2CAP_CONN_PARAM_UPDATE_RSP 0x13 +#define L2CAP_LE_CONN_REQ 0x14 +#define L2CAP_LE_CONN_RSP 0x15 +#define L2CAP_LE_CREDITS 0x16 /* L2CAP extended feature mask */ #define L2CAP_FEAT_FLOWCTL 0x00000001 @@ -257,6 +260,10 @@ struct l2cap_conn_rsp { #define L2CAP_CR_SEC_BLOCK 0x0003 #define L2CAP_CR_NO_MEM 0x0004 #define L2CAP_CR_BAD_AMP 0x0005 +#define L2CAP_CR_AUTHENTICATION 0x0005 +#define L2CAP_CR_AUTHORIZATION 0x0006 +#define L2CAP_CR_BAD_KEY_SIZE 0x0007 +#define L2CAP_CR_ENCRYPTION 0x0008 /* connect/create channel status */ #define L2CAP_CS_NO_INFO 0x0000 @@ -423,6 +430,30 @@ struct l2cap_conn_param_update_rsp { #define L2CAP_CONN_PARAM_ACCEPTED 0x0000 #define L2CAP_CONN_PARAM_REJECTED 0x0001 +#define L2CAP_LE_MAX_CREDITS 10 +#define L2CAP_LE_DEFAULT_MPS 230 + +struct l2cap_le_conn_req { + __le16 psm; + __le16 scid; + __le16 mtu; + __le16 mps; + __le16 credits; +} __packed; + +struct l2cap_le_conn_rsp { + __le16 dcid; + __le16 mtu; + __le16 mps; + __le16 credits; + __le16 result; +} __packed; + +struct l2cap_le_credits { + __le16 cid; + __le16 credits; +} __packed; + /* ----- L2CAP channels and connections ----- */ struct l2cap_seq_list { __u16 head; -- cgit v1.2.3-70-g09d2 From f1496dee9cbde2a62821f4441dadb0d3360f60c3 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 13 May 2013 14:15:56 +0300 Subject: Bluetooth: Add initial code for LE L2CAP Connect Request This patch adds the necessary code to send an LE L2CAP Connect Request and handle its response when user space has provided us with an LE socket with a PSM instead of a fixed CID. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 106 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 98 insertions(+), 8 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index d250d8af7fd..256662578f8 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1160,21 +1160,51 @@ static void l2cap_chan_ready(struct l2cap_chan *chan) chan->ops->ready(chan); } +static void l2cap_le_connect(struct l2cap_chan *chan) +{ + struct l2cap_conn *conn = chan->conn; + struct l2cap_le_conn_req req; + + req.psm = chan->psm; + req.scid = cpu_to_le16(chan->scid); + req.mtu = cpu_to_le16(chan->imtu); + req.mps = __constant_cpu_to_le16(L2CAP_LE_DEFAULT_MPS); + req.credits = __constant_cpu_to_le16(L2CAP_LE_MAX_CREDITS); + + chan->ident = l2cap_get_ident(conn); + + l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CONN_REQ, + sizeof(req), &req); +} + +static void l2cap_le_start(struct l2cap_chan *chan) +{ + struct l2cap_conn *conn = chan->conn; + + if (!smp_conn_security(conn->hcon, chan->sec_level)) + return; + + if (!chan->psm) { + l2cap_chan_ready(chan); + return; + } + + if (chan->state == BT_CONNECT) + l2cap_le_connect(chan); +} + static void l2cap_start_connection(struct l2cap_chan *chan) { if (__amp_capable(chan)) { BT_DBG("chan %p AMP capable: discover AMPs", chan); a2mp_discover_amp(chan); + } else if (chan->conn->hcon->type == LE_LINK) { + l2cap_le_start(chan); } else { l2cap_send_conn_req(chan); } } -static void l2cap_le_start(struct l2cap_chan *chan) -{ - l2cap_chan_ready(chan); -} - static void l2cap_do_start(struct l2cap_chan *chan) { struct l2cap_conn *conn = chan->conn; @@ -1438,9 +1468,7 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) } if (hcon->type == LE_LINK) { - if (smp_conn_security(hcon, chan->sec_level)) - l2cap_chan_ready(chan); - + l2cap_le_start(chan); } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { l2cap_chan_ready(chan); @@ -5210,6 +5238,64 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn, return 0; } +static int l2cap_le_connect_rsp(struct l2cap_conn *conn, + struct l2cap_cmd_hdr *cmd, u16 cmd_len, + u8 *data) +{ + struct l2cap_le_conn_rsp *rsp = (struct l2cap_le_conn_rsp *) data; + u16 dcid, mtu, mps, credits, result; + struct l2cap_chan *chan; + int err; + + if (cmd_len < sizeof(*rsp)) + return -EPROTO; + + dcid = __le16_to_cpu(rsp->dcid); + mtu = __le16_to_cpu(rsp->mtu); + mps = __le16_to_cpu(rsp->mps); + credits = __le16_to_cpu(rsp->credits); + result = __le16_to_cpu(rsp->result); + + if (result == L2CAP_CR_SUCCESS && (mtu < 23 || mps < 23)) + return -EPROTO; + + BT_DBG("dcid 0x%4.4x mtu %u mps %u credits %u result 0x%2.2x", + dcid, mtu, mps, credits, result); + + mutex_lock(&conn->chan_lock); + + chan = __l2cap_get_chan_by_ident(conn, cmd->ident); + if (!chan) { + err = -EBADSLT; + goto unlock; + } + + err = 0; + + l2cap_chan_lock(chan); + + switch (result) { + case L2CAP_CR_SUCCESS: + chan->ident = 0; + chan->dcid = dcid; + chan->omtu = mtu; + chan->remote_mps = mps; + l2cap_chan_ready(chan); + break; + + default: + l2cap_chan_del(chan, ECONNREFUSED); + break; + } + + l2cap_chan_unlock(chan); + +unlock: + mutex_unlock(&conn->chan_lock); + + return err; +} + static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) @@ -5304,6 +5390,10 @@ static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn, case L2CAP_CONN_PARAM_UPDATE_RSP: return 0; + case L2CAP_LE_CONN_RSP: + l2cap_le_connect_rsp(conn, cmd, cmd_len, data); + return 0; + default: BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code); return -EINVAL; -- cgit v1.2.3-70-g09d2 From ad32a2f5ced269f5516950fc8f52b6673462d208 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 14 May 2013 18:05:12 +0300 Subject: Bluetooth: Add smp_sufficient_security helper function This function is needed both by the smp_conn_security function as well as upcoming code to check for the security requirements when receiving an L2CAP connect request over LE. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 16 ++++++++++++---- net/bluetooth/smp.h | 1 + 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index e61e74a1aab..45007362683 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -750,6 +750,17 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) return 0; } +bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level) +{ + if (sec_level == BT_SECURITY_LOW) + return true; + + if (hcon->sec_level >= sec_level) + return true; + + return false; +} + int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) { struct l2cap_conn *conn = hcon->l2cap_data; @@ -761,10 +772,7 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) if (!test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags)) return 1; - if (sec_level == BT_SECURITY_LOW) - return 1; - - if (hcon->sec_level >= sec_level) + if (smp_sufficient_security(hcon, sec_level)) return 1; if (hcon->link_mode & HCI_LM_MASTER) diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index f8ba07f3e5f..a700bcb490d 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -136,6 +136,7 @@ struct smp_chan { }; /* SMP Commands */ +bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level); int smp_conn_security(struct hci_conn *hcon, __u8 sec_level); int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb); int smp_distribute_keys(struct l2cap_conn *conn, __u8 force); -- cgit v1.2.3-70-g09d2 From 791d60f71a8d743df17a5029bb080a24afc4fff6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 14 May 2013 22:24:44 +0300 Subject: Bluetooth: Refactor L2CAP connect rejection to its own function We'll need to have a separate code path for LE based connection rejection so it's cleaner to move out the response construction code into its own function (and later a second one for LE). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 256662578f8..5f9287fd86d 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -617,6 +617,27 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) return; } +static void l2cap_chan_connect_reject(struct l2cap_chan *chan) +{ + struct l2cap_conn *conn = chan->conn; + struct l2cap_conn_rsp rsp; + u16 result; + + if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) + result = L2CAP_CR_SEC_BLOCK; + else + result = L2CAP_CR_BAD_PSM; + + l2cap_state_change(chan, BT_DISCONN); + + rsp.scid = cpu_to_le16(chan->dcid); + rsp.dcid = cpu_to_le16(chan->scid); + rsp.result = cpu_to_le16(result); + rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO); + + l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); +} + void l2cap_chan_close(struct l2cap_chan *chan, int reason) { struct l2cap_conn *conn = chan->conn; @@ -639,24 +660,9 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason) break; case BT_CONNECT2: - if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && - conn->hcon->type == ACL_LINK) { - struct l2cap_conn_rsp rsp; - __u16 result; - - if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) - result = L2CAP_CR_SEC_BLOCK; - else - result = L2CAP_CR_BAD_PSM; - - l2cap_state_change(chan, BT_DISCONN); - - rsp.scid = cpu_to_le16(chan->dcid); - rsp.dcid = cpu_to_le16(chan->scid); - rsp.result = cpu_to_le16(result); - rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO); - l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, - sizeof(rsp), &rsp); + if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED) { + if (conn->hcon->type == ACL_LINK) + l2cap_chan_connect_reject(chan); } l2cap_chan_del(chan, reason); -- cgit v1.2.3-70-g09d2 From 27e2d4c8d28be1d1b4ecfbffab572d7dbd35254d Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 14 May 2013 13:27:21 +0300 Subject: Bluetooth: Add basic LE L2CAP connect request receiving support This patch adds the necessary boiler plate code to handle receiving L2CAP connect requests over LE and respond to them with a proper connect response. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 1 + net/bluetooth/l2cap_core.c | 152 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 84c0754b87d..84b25202596 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -846,6 +846,7 @@ int l2cap_init_sockets(void); void l2cap_cleanup_sockets(void); bool l2cap_is_socket(struct socket *sock); +void __l2cap_le_connect_rsp_defer(struct l2cap_chan *chan); void __l2cap_connect_rsp_defer(struct l2cap_chan *chan); int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 5f9287fd86d..d6f518d7e61 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -617,6 +617,29 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) return; } +static void l2cap_chan_le_connect_reject(struct l2cap_chan *chan) +{ + struct l2cap_conn *conn = chan->conn; + struct l2cap_le_conn_rsp rsp; + u16 result; + + if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) + result = L2CAP_CR_AUTHORIZATION; + else + result = L2CAP_CR_BAD_PSM; + + l2cap_state_change(chan, BT_DISCONN); + + rsp.dcid = cpu_to_le16(chan->scid); + rsp.mtu = cpu_to_le16(chan->imtu); + rsp.mps = __constant_cpu_to_le16(L2CAP_LE_DEFAULT_MPS); + rsp.credits = __constant_cpu_to_le16(L2CAP_LE_MAX_CREDITS); + rsp.result = cpu_to_le16(result); + + l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CONN_RSP, sizeof(rsp), + &rsp); +} + static void l2cap_chan_connect_reject(struct l2cap_chan *chan) { struct l2cap_conn *conn = chan->conn; @@ -663,6 +686,8 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason) if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED) { if (conn->hcon->type == ACL_LINK) l2cap_chan_connect_reject(chan); + else if (conn->hcon->type == LE_LINK) + l2cap_chan_le_connect_reject(chan); } l2cap_chan_del(chan, reason); @@ -3641,6 +3666,23 @@ static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, return ptr - data; } +void __l2cap_le_connect_rsp_defer(struct l2cap_chan *chan) +{ + struct l2cap_le_conn_rsp rsp; + struct l2cap_conn *conn = chan->conn; + + BT_DBG("chan %p", chan); + + rsp.dcid = cpu_to_le16(chan->scid); + rsp.mtu = cpu_to_le16(chan->imtu); + rsp.mps = __constant_cpu_to_le16(L2CAP_LE_DEFAULT_MPS); + rsp.credits = __constant_cpu_to_le16(L2CAP_LE_MAX_CREDITS); + rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS); + + l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CONN_RSP, sizeof(rsp), + &rsp); +} + void __l2cap_connect_rsp_defer(struct l2cap_chan *chan) { struct l2cap_conn_rsp rsp; @@ -5382,6 +5424,113 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn, return err; } +static int l2cap_le_connect_req(struct l2cap_conn *conn, + struct l2cap_cmd_hdr *cmd, u16 cmd_len, + u8 *data) +{ + struct l2cap_le_conn_req *req = (struct l2cap_le_conn_req *) data; + struct l2cap_le_conn_rsp rsp; + struct l2cap_chan *chan, *pchan; + u16 dcid, scid, mtu, mps; + __le16 psm; + u8 result; + + if (cmd_len != sizeof(*req)) + return -EPROTO; + + scid = __le16_to_cpu(req->scid); + mtu = __le16_to_cpu(req->mtu); + mps = __le16_to_cpu(req->mps); + psm = req->psm; + dcid = 0; + + if (mtu < 23 || mps < 23) + return -EPROTO; + + BT_DBG("psm 0x%2.2x scid 0x%4.4x mtu %u mps %u", __le16_to_cpu(psm), + scid, mtu, mps); + + /* Check if we have socket listening on psm */ + pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, &conn->hcon->src, + &conn->hcon->dst, LE_LINK); + if (!pchan) { + result = L2CAP_CR_BAD_PSM; + chan = NULL; + goto response; + } + + mutex_lock(&conn->chan_lock); + l2cap_chan_lock(pchan); + + if (!smp_sufficient_security(conn->hcon, pchan->sec_level)) { + result = L2CAP_CR_AUTHENTICATION; + chan = NULL; + goto response_unlock; + } + + /* Check if we already have channel with that dcid */ + if (__l2cap_get_chan_by_dcid(conn, scid)) { + result = L2CAP_CR_NO_MEM; + chan = NULL; + goto response_unlock; + } + + chan = pchan->ops->new_connection(pchan); + if (!chan) { + result = L2CAP_CR_NO_MEM; + goto response_unlock; + } + + bacpy(&chan->src, &conn->hcon->src); + bacpy(&chan->dst, &conn->hcon->dst); + chan->src_type = bdaddr_type(conn->hcon, conn->hcon->src_type); + chan->dst_type = bdaddr_type(conn->hcon, conn->hcon->dst_type); + chan->psm = psm; + chan->dcid = scid; + chan->omtu = mtu; + chan->remote_mps = mps; + + __l2cap_chan_add(conn, chan); + dcid = chan->scid; + + __set_chan_timer(chan, chan->ops->get_sndtimeo(chan)); + + chan->ident = cmd->ident; + + if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) { + l2cap_state_change(chan, BT_CONNECT2); + result = L2CAP_CR_PEND; + chan->ops->defer(chan); + } else { + l2cap_chan_ready(chan); + result = L2CAP_CR_SUCCESS; + } + +response_unlock: + l2cap_chan_unlock(pchan); + mutex_unlock(&conn->chan_lock); + + if (result == L2CAP_CR_PEND) + return 0; + +response: + if (chan) { + rsp.mtu = cpu_to_le16(chan->imtu); + rsp.mps = __constant_cpu_to_le16(L2CAP_LE_DEFAULT_MPS); + } else { + rsp.mtu = 0; + rsp.mps = 0; + } + + rsp.dcid = cpu_to_le16(dcid); + rsp.credits = __constant_cpu_to_le16(L2CAP_LE_MAX_CREDITS); + rsp.result = cpu_to_le16(result); + + l2cap_send_cmd(conn, cmd->ident, L2CAP_LE_CONN_RSP, sizeof(rsp), &rsp); + + return 0; +} + static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) @@ -5400,6 +5549,9 @@ static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn, l2cap_le_connect_rsp(conn, cmd, cmd_len, data); return 0; + case L2CAP_LE_CONN_REQ: + return l2cap_le_connect_req(conn, cmd, cmd_len, data); + default: BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code); return -EINVAL; -- cgit v1.2.3-70-g09d2 From cea04ce35eb3e2e53e7c7bb8ebe9c10312f79b84 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 14 May 2013 22:46:01 +0300 Subject: Bluetooth: Fix L2CAP channel closing for LE connections Sending of the L2CAP Disconnect request should also be performed for LE based channels. The proper thing to do is therefore to look at whether there's a PSM specified for the channel instead of looking at the link type. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index d6f518d7e61..744afae6193 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -674,8 +674,10 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason) case BT_CONNECTED: case BT_CONFIG: - if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && - conn->hcon->type == ACL_LINK) { + /* ATT uses L2CAP_CHAN_CONN_ORIENTED so we must also + * check for chan->psm. + */ + if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && chan->psm) { __set_chan_timer(chan, chan->ops->get_sndtimeo(chan)); l2cap_send_disconn_req(chan, reason); } else -- cgit v1.2.3-70-g09d2 From 3defe01a4839978f0822b63f21bb6ed676e866e3 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 15 May 2013 10:16:06 +0300 Subject: Bluetooth: Add L2CAP Disconnect suppport for LE The normal L2CAP Disconnect request and response are also used for LE connection oriented channels. Therefore, we can simply use the existing handler functions for terminating LE based L2CAP channels. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 744afae6193..8775d43bf05 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -5554,6 +5554,13 @@ static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn, case L2CAP_LE_CONN_REQ: return l2cap_le_connect_req(conn, cmd, cmd_len, data); + case L2CAP_DISCONN_REQ: + return l2cap_disconnect_req(conn, cmd, cmd_len, data); + + case L2CAP_DISCONN_RSP: + l2cap_disconnect_rsp(conn, cmd, cmd_len, data); + return 0; + default: BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code); return -EINVAL; -- cgit v1.2.3-70-g09d2 From b5ecba642290a0f28a2dca15e4fdf2a9779bc116 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 2 Dec 2013 12:21:29 +0200 Subject: Bluetooth: Make l2cap_le_sig_cmd logic consistent This patch makes the error handling and return logic of l2cap_le_sig_cmd consistent with its BR/EDR counterpart. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 8775d43bf05..907fc174532 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -5537,34 +5537,42 @@ static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) { + int err = 0; + switch (cmd->code) { case L2CAP_COMMAND_REJ: - return 0; + break; case L2CAP_CONN_PARAM_UPDATE_REQ: - return l2cap_conn_param_update_req(conn, cmd, cmd_len, data); + err = l2cap_conn_param_update_req(conn, cmd, cmd_len, data); + break; case L2CAP_CONN_PARAM_UPDATE_RSP: - return 0; + break; case L2CAP_LE_CONN_RSP: l2cap_le_connect_rsp(conn, cmd, cmd_len, data); - return 0; + break; case L2CAP_LE_CONN_REQ: - return l2cap_le_connect_req(conn, cmd, cmd_len, data); + err = l2cap_le_connect_req(conn, cmd, cmd_len, data); + break; case L2CAP_DISCONN_REQ: - return l2cap_disconnect_req(conn, cmd, cmd_len, data); + err = l2cap_disconnect_req(conn, cmd, cmd_len, data); + break; case L2CAP_DISCONN_RSP: l2cap_disconnect_rsp(conn, cmd, cmd_len, data); - return 0; + break; default: BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code); - return -EINVAL; + err = -EINVAL; + break; } + + return err; } static inline void l2cap_le_sig_channel(struct l2cap_conn *conn, -- cgit v1.2.3-70-g09d2 From 3831971355d901ccfb76533a422b4395072849a3 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 17 May 2013 12:49:23 +0300 Subject: Bluetooth: Add LE L2CAP flow control mode The LE connection oriented channels have their own mode with its own data transfer rules. In order to implement this properly we need to distinguish L2CAP channels operating in this mode from other modes. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 7 +++++++ net/bluetooth/l2cap_core.c | 13 +++++++++++++ net/bluetooth/l2cap_sock.c | 21 ++++++++++++++++++--- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 84b25202596..063d786b099 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -328,6 +328,12 @@ struct l2cap_conf_rfc { #define L2CAP_MODE_ERTM 0x03 #define L2CAP_MODE_STREAMING 0x04 +/* Unlike the above this one doesn't actually map to anything that would + * ever be sent over the air. Therefore, use a value that's unlikely to + * ever be used in the BR/EDR configuration phase. + */ +#define L2CAP_MODE_LE_FLOWCTL 0x80 + struct l2cap_conf_efs { __u8 id; __u8 stype; @@ -861,6 +867,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, void l2cap_chan_busy(struct l2cap_chan *chan, int busy); int l2cap_chan_check_security(struct l2cap_chan *chan); void l2cap_chan_set_defaults(struct l2cap_chan *chan); +void l2cap_le_flowctl_init(struct l2cap_chan *chan); int l2cap_ertm_init(struct l2cap_chan *chan); void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan); void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 907fc174532..e260753184b 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -490,6 +490,13 @@ void l2cap_chan_set_defaults(struct l2cap_chan *chan) set_bit(FLAG_FORCE_ACTIVE, &chan->flags); } +void l2cap_le_flowctl_init(struct l2cap_chan *chan) +{ + chan->imtu = L2CAP_DEFAULT_MTU; + chan->omtu = L2CAP_LE_MIN_MTU; + chan->mode = L2CAP_MODE_LE_FLOWCTL; +} + void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) { BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, @@ -597,6 +604,9 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) case L2CAP_MODE_BASIC: break; + case L2CAP_MODE_LE_FLOWCTL: + break; + case L2CAP_MODE_ERTM: __clear_retrans_timer(chan); __clear_monitor_timer(chan); @@ -1849,6 +1859,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, switch (chan->mode) { case L2CAP_MODE_BASIC: + case L2CAP_MODE_LE_FLOWCTL: break; case L2CAP_MODE_ERTM: case L2CAP_MODE_STREAMING: @@ -2530,6 +2541,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, switch (chan->mode) { case L2CAP_MODE_BASIC: + case L2CAP_MODE_LE_FLOWCTL: /* Check outgoing MTU */ if (len > chan->omtu) return -EMSGSIZE; @@ -6621,6 +6633,7 @@ static void l2cap_data_channel(struct l2cap_conn *conn, u16 cid, goto drop; switch (chan->mode) { + case L2CAP_MODE_LE_FLOWCTL: case L2CAP_MODE_BASIC: /* If socket recv buffers overflows we drop data here * which is *bad* because L2CAP has to be reliable. diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 5a1d0cb0b8d..485ca349fed 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -130,6 +130,9 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) bacpy(&chan->src, &la.l2_bdaddr); chan->src_type = la.l2_bdaddr_type; + if (chan->psm && bdaddr_type_is_le(chan->src_type)) + l2cap_le_flowctl_init(chan); + chan->state = BT_BOUND; sk->sk_state = BT_BOUND; @@ -200,6 +203,9 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, return -EINVAL; } + if (chan->psm && bdaddr_type_is_le(chan->src_type)) + l2cap_le_flowctl_init(chan); + err = l2cap_chan_connect(chan, la.l2_psm, __le16_to_cpu(la.l2_cid), &la.l2_bdaddr, la.l2_bdaddr_type); if (err) @@ -237,6 +243,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog) switch (chan->mode) { case L2CAP_MODE_BASIC: + case L2CAP_MODE_LE_FLOWCTL: break; case L2CAP_MODE_ERTM: case L2CAP_MODE_STREAMING: @@ -588,6 +595,8 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, chan->mode = opts.mode; switch (chan->mode) { + case L2CAP_MODE_LE_FLOWCTL: + break; case L2CAP_MODE_BASIC: clear_bit(CONF_STATE2_DEVICE, &chan->conf_state); break; @@ -862,10 +871,16 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, if (sk->sk_state == BT_CONNECT2 && test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) { - sk->sk_state = BT_CONFIG; - pi->chan->state = BT_CONFIG; + if (bdaddr_type_is_le(pi->chan->src_type)) { + sk->sk_state = BT_CONNECTED; + pi->chan->state = BT_CONNECTED; + __l2cap_le_connect_rsp_defer(pi->chan); + } else { + sk->sk_state = BT_CONFIG; + pi->chan->state = BT_CONFIG; + __l2cap_connect_rsp_defer(pi->chan); + } - __l2cap_connect_rsp_defer(pi->chan); err = 0; goto done; } -- cgit v1.2.3-70-g09d2 From 0cd75f7ed740a8c605fe55ac71a9b5162c612422 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 17 May 2013 13:09:05 +0300 Subject: Bluetooth: Track LE L2CAP credits in l2cap_chan This patch adds tracking of L2CAP connection oriented channel local and remote credits to struct l2cap_chan and ensures that connect requests and responses contain the right values. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 3 +++ net/bluetooth/l2cap_core.c | 16 +++++++++++----- net/bluetooth/l2cap_sock.c | 2 ++ 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 063d786b099..d7cd1ddfe57 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -514,6 +514,9 @@ struct l2cap_chan { __u16 monitor_timeout; __u16 mps; + __u16 tx_credits; + __u16 rx_credits; + __u8 tx_state; __u8 rx_state; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index e260753184b..fe55162947f 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -495,6 +495,8 @@ void l2cap_le_flowctl_init(struct l2cap_chan *chan) chan->imtu = L2CAP_DEFAULT_MTU; chan->omtu = L2CAP_LE_MIN_MTU; chan->mode = L2CAP_MODE_LE_FLOWCTL; + chan->tx_credits = 0; + chan->rx_credits = L2CAP_LE_MAX_CREDITS; } void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) @@ -643,7 +645,7 @@ static void l2cap_chan_le_connect_reject(struct l2cap_chan *chan) rsp.dcid = cpu_to_le16(chan->scid); rsp.mtu = cpu_to_le16(chan->imtu); rsp.mps = __constant_cpu_to_le16(L2CAP_LE_DEFAULT_MPS); - rsp.credits = __constant_cpu_to_le16(L2CAP_LE_MAX_CREDITS); + rsp.credits = cpu_to_le16(chan->rx_credits); rsp.result = cpu_to_le16(result); l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CONN_RSP, sizeof(rsp), @@ -1212,7 +1214,7 @@ static void l2cap_le_connect(struct l2cap_chan *chan) req.scid = cpu_to_le16(chan->scid); req.mtu = cpu_to_le16(chan->imtu); req.mps = __constant_cpu_to_le16(L2CAP_LE_DEFAULT_MPS); - req.credits = __constant_cpu_to_le16(L2CAP_LE_MAX_CREDITS); + req.credits = cpu_to_le16(chan->rx_credits); chan->ident = l2cap_get_ident(conn); @@ -3690,7 +3692,7 @@ void __l2cap_le_connect_rsp_defer(struct l2cap_chan *chan) rsp.dcid = cpu_to_le16(chan->scid); rsp.mtu = cpu_to_le16(chan->imtu); rsp.mps = __constant_cpu_to_le16(L2CAP_LE_DEFAULT_MPS); - rsp.credits = __constant_cpu_to_le16(L2CAP_LE_MAX_CREDITS); + rsp.credits = cpu_to_le16(chan->rx_credits); rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS); l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CONN_RSP, sizeof(rsp), @@ -5342,6 +5344,7 @@ static int l2cap_le_connect_rsp(struct l2cap_conn *conn, chan->dcid = dcid; chan->omtu = mtu; chan->remote_mps = mps; + chan->tx_credits = credits; l2cap_chan_ready(chan); break; @@ -5445,7 +5448,7 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn, struct l2cap_le_conn_req *req = (struct l2cap_le_conn_req *) data; struct l2cap_le_conn_rsp rsp; struct l2cap_chan *chan, *pchan; - u16 dcid, scid, mtu, mps; + u16 dcid, scid, credits, mtu, mps; __le16 psm; u8 result; @@ -5457,6 +5460,7 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn, mps = __le16_to_cpu(req->mps); psm = req->psm; dcid = 0; + credits = 0; if (mtu < 23 || mps < 23) return -EPROTO; @@ -5503,9 +5507,11 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn, chan->dcid = scid; chan->omtu = mtu; chan->remote_mps = mps; + chan->tx_credits = __le16_to_cpu(req->credits); __l2cap_chan_add(conn, chan); dcid = chan->scid; + credits = chan->rx_credits; __set_chan_timer(chan, chan->ops->get_sndtimeo(chan)); @@ -5537,7 +5543,7 @@ response: } rsp.dcid = cpu_to_le16(dcid); - rsp.credits = __constant_cpu_to_le16(L2CAP_LE_MAX_CREDITS); + rsp.credits = cpu_to_le16(credits); rsp.result = cpu_to_le16(result); l2cap_send_cmd(conn, cmd->ident, L2CAP_LE_CONN_RSP, sizeof(rsp), &rsp); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 485ca349fed..61e25bafdf4 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1321,6 +1321,8 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) chan->tx_win_max = pchan->tx_win_max; chan->sec_level = pchan->sec_level; chan->flags = pchan->flags; + chan->tx_credits = pchan->tx_credits; + chan->rx_credits = pchan->rx_credits; security_sk_clone(parent, sk); } else { -- cgit v1.2.3-70-g09d2 From 64b4f8dc763d5c26dea0f483d6e475540eaf9759 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 2 Dec 2013 16:02:03 +0200 Subject: Bluetooth: Limit L2CAP_OPTIONS socket option usage with LE Most of the values in L2CAP_OPTIONS are not applicable for LE and those that are have different semantics. It makes therefore sense to completely block this socket option for LE and add (in a separate patch) a new socket option for tweaking the values that do make sense (mainly the send and receive MTU). Legacy user space ATT code still depends on getsockopt for L2CAP_OPTIONS though so we need to plug a hole for that for backwards compatibility. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_sock.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 61e25bafdf4..a20fcc3ddcd 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -370,6 +370,16 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, switch (optname) { case L2CAP_OPTIONS: + /* LE sockets should use BT_SNDMTU/BT_RCVMTU, but since + * legacy ATT code depends on getsockopt for + * L2CAP_OPTIONS we need to let this pass. + */ + if (bdaddr_type_is_le(chan->src_type) && + chan->scid != L2CAP_CID_ATT) { + err = -EINVAL; + break; + } + memset(&opts, 0, sizeof(opts)); opts.imtu = chan->imtu; opts.omtu = chan->omtu; @@ -564,6 +574,11 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, switch (optname) { case L2CAP_OPTIONS: + if (bdaddr_type_is_le(chan->src_type)) { + err = -EINVAL; + break; + } + if (sk->sk_state == BT_CONNECTED) { err = -EINVAL; break; -- cgit v1.2.3-70-g09d2 From 1f435424ce2c93c31c3887ec67e3afb6056f18f6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 2 Dec 2013 16:34:18 +0200 Subject: Bluetooth: Add new BT_SNDMTU and BT_RCVMTU socket options This patch adds new socket options for LE sockets since the existing L2CAP_OPTIONS socket option is not usable for LE. For now, the new socket options also require LE CoC support to be explicitly enabled to leave some playroom in case something needs to be changed in a backwards incompatible way. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/bluetooth.h | 3 ++ net/bluetooth/l2cap_sock.c | 76 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 2a628b28249..f4f9ee46679 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -115,6 +115,9 @@ struct bt_voice { #define BT_VOICE_TRANSPARENT 0x0003 #define BT_VOICE_CVSD_16BIT 0x0060 +#define BT_SNDMTU 12 +#define BT_RCVMTU 13 + __printf(1, 2) int bt_info(const char *fmt, ...); __printf(1, 2) diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index a20fcc3ddcd..01d65bc99b0 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -534,6 +534,41 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, err = -EFAULT; break; + case BT_SNDMTU: + if (!enable_lecoc) { + err = -EPROTONOSUPPORT; + break; + } + + if (!bdaddr_type_is_le(chan->src_type)) { + err = -EINVAL; + break; + } + + if (sk->sk_state != BT_CONNECTED) { + err = -ENOTCONN; + break; + } + + if (put_user(chan->omtu, (u16 __user *) optval)) + err = -EFAULT; + break; + + case BT_RCVMTU: + if (!enable_lecoc) { + err = -EPROTONOSUPPORT; + break; + } + + if (!bdaddr_type_is_le(chan->src_type)) { + err = -EINVAL; + break; + } + + if (put_user(chan->imtu, (u16 __user *) optval)) + err = -EFAULT; + break; + default: err = -ENOPROTOOPT; break; @@ -834,6 +869,47 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, break; + case BT_SNDMTU: + if (!enable_lecoc) { + err = -EPROTONOSUPPORT; + break; + } + + if (!bdaddr_type_is_le(chan->src_type)) { + err = -EINVAL; + break; + } + + /* Setting is not supported as it's the remote side that + * decides this. + */ + err = -EPERM; + break; + + case BT_RCVMTU: + if (!enable_lecoc) { + err = -EPROTONOSUPPORT; + break; + } + + if (!bdaddr_type_is_le(chan->src_type)) { + err = -EINVAL; + break; + } + + if (sk->sk_state == BT_CONNECTED) { + err = -EISCONN; + break; + } + + if (get_user(opt, (u32 __user *) optval)) { + err = -EFAULT; + break; + } + + chan->imtu = opt; + break; + default: err = -ENOPROTOOPT; break; -- cgit v1.2.3-70-g09d2 From b1c325c23d75c5e27607fdcc89bc9bf80af0ba9b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 5 Dec 2013 09:43:34 +0200 Subject: Bluetooth: Implement returning of LE L2CAP credits We should return credits to the remote side whenever they fall below a certain level (in our case under half of the initially given amount). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index fe55162947f..4e0e2bedd45 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -6610,6 +6610,32 @@ drop: return 0; } +static void l2cap_chan_le_send_credits(struct l2cap_chan *chan) +{ + struct l2cap_conn *conn = chan->conn; + struct l2cap_le_credits pkt; + u16 return_credits; + + /* We return more credits to the sender only after the amount of + * credits falls below half of the initial amount. + */ + if (chan->rx_credits >= (L2CAP_LE_MAX_CREDITS + 1) / 2) + return; + + return_credits = L2CAP_LE_MAX_CREDITS - chan->rx_credits; + + BT_DBG("chan %p returning %u credits to sender", chan, return_credits); + + chan->rx_credits += return_credits; + + pkt.cid = cpu_to_le16(chan->scid); + pkt.credits = cpu_to_le16(return_credits); + + chan->ident = l2cap_get_ident(conn); + + l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CREDITS, sizeof(pkt), &pkt); +} + static void l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb) { -- cgit v1.2.3-70-g09d2 From fad5fc89594de31388572a26f33caa7c30a23782 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 5 Dec 2013 09:45:01 +0200 Subject: Bluetooth: Add LE flow control discipline This patch adds the necessary discipline for reacting to LE L2CAP Credits packets, sending those packets, and modifying the known credits accordingly. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 67 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 4e0e2bedd45..8a0d235215c 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -2542,8 +2542,12 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, } switch (chan->mode) { - case L2CAP_MODE_BASIC: case L2CAP_MODE_LE_FLOWCTL: + if (!chan->tx_credits) + return -EAGAIN; + + /* fall through */ + case L2CAP_MODE_BASIC: /* Check outgoing MTU */ if (len > chan->omtu) return -EMSGSIZE; @@ -5551,6 +5555,42 @@ response: return 0; } +static inline int l2cap_le_credits(struct l2cap_conn *conn, + struct l2cap_cmd_hdr *cmd, u16 cmd_len, + u8 *data) +{ + struct l2cap_le_credits *pkt; + struct l2cap_chan *chan; + u16 cid, credits; + + if (cmd_len != sizeof(*pkt)) + return -EPROTO; + + pkt = (struct l2cap_le_credits *) data; + cid = __le16_to_cpu(pkt->cid); + credits = __le16_to_cpu(pkt->credits); + + BT_DBG("cid 0x%4.4x credits 0x%4.4x", cid, credits); + + chan = l2cap_get_chan_by_dcid(conn, cid); + if (!chan) + return -EBADSLT; + + chan->tx_credits += credits; + + while (chan->tx_credits && !skb_queue_empty(&chan->tx_q)) { + l2cap_do_send(chan, skb_dequeue(&chan->tx_q)); + chan->tx_credits--; + } + + if (chan->tx_credits) + chan->ops->resume(chan); + + l2cap_chan_unlock(chan); + + return 0; +} + static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) @@ -5576,6 +5616,10 @@ static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn, err = l2cap_le_connect_req(conn, cmd, cmd_len, data); break; + case L2CAP_LE_CREDITS: + err = l2cap_le_credits(conn, cmd, cmd_len, data); + break; + case L2CAP_DISCONN_REQ: err = l2cap_disconnect_req(conn, cmd, cmd_len, data); break; @@ -6636,6 +6680,22 @@ static void l2cap_chan_le_send_credits(struct l2cap_chan *chan) l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CREDITS, sizeof(pkt), &pkt); } +static int l2cap_le_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) +{ + if (!chan->rx_credits) + return -ENOBUFS; + + if (chan->imtu < skb->len) + return -ENOBUFS; + + chan->rx_credits--; + BT_DBG("rx_credits %u -> %u", chan->rx_credits + 1, chan->rx_credits); + + l2cap_chan_le_send_credits(chan); + + return chan->ops->recv(chan, skb); +} + static void l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb) { @@ -6666,6 +6726,11 @@ static void l2cap_data_channel(struct l2cap_conn *conn, u16 cid, switch (chan->mode) { case L2CAP_MODE_LE_FLOWCTL: + if (l2cap_le_data_rcv(chan, skb) < 0) + goto drop; + + goto done; + case L2CAP_MODE_BASIC: /* If socket recv buffers overflows we drop data here * which is *bad* because L2CAP has to be reliable. -- cgit v1.2.3-70-g09d2 From 3af8ace653c83c663d4b97c6ea7f01463d366bf9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 3 Dec 2013 09:51:51 +0200 Subject: Bluetooth: Reject LE CoC commands when the feature is not enabled Since LE CoC support needs to be enabled through a module option for now we need to reject any related signaling PDUs in addition to rejecting the creation of LE CoC sockets (which we already do). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 8a0d235215c..aaa98a2318c 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -5597,6 +5597,17 @@ static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn, { int err = 0; + if (!enable_lecoc) { + switch (cmd->code) { + case L2CAP_LE_CONN_REQ: + case L2CAP_LE_CONN_RSP: + case L2CAP_LE_CREDITS: + case L2CAP_DISCONN_REQ: + case L2CAP_DISCONN_RSP: + return -EINVAL; + } + } + switch (cmd->code) { case L2CAP_COMMAND_REJ: break; -- cgit v1.2.3-70-g09d2 From 837776f7904024df451422f32b09c67e88ae2aa2 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 15 Oct 2013 11:03:18 +0300 Subject: Bluetooth: Introduce L2CAP channel callback for suspending Setting the BT_SK_SUSPEND socket flag from the L2CAP core is causing a dependency on the socket. So instead of doing that, use a channel callback into the socket handling to suspend. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 1 + net/bluetooth/l2cap_sock.c | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index d7cd1ddfe57..b0d7e4adb16 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -593,6 +593,7 @@ struct l2cap_ops { void (*ready) (struct l2cap_chan *chan); void (*defer) (struct l2cap_chan *chan); void (*resume) (struct l2cap_chan *chan); + void (*suspend) (struct l2cap_chan *chan); void (*set_shutdown) (struct l2cap_chan *chan); long (*get_sndtimeo) (struct l2cap_chan *chan); struct sk_buff *(*alloc_skb) (struct l2cap_chan *chan, diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 01d65bc99b0..a51844a8c5e 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1345,6 +1345,14 @@ static long l2cap_sock_get_sndtimeo_cb(struct l2cap_chan *chan) return sk->sk_sndtimeo; } +static void l2cap_sock_suspend_cb(struct l2cap_chan *chan) +{ + struct sock *sk = chan->data; + + set_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags); + sk->sk_state_change(sk); +} + static struct l2cap_ops l2cap_chan_ops = { .name = "L2CAP Socket Interface", .new_connection = l2cap_sock_new_connection_cb, @@ -1355,6 +1363,7 @@ static struct l2cap_ops l2cap_chan_ops = { .ready = l2cap_sock_ready_cb, .defer = l2cap_sock_defer_cb, .resume = l2cap_sock_resume_cb, + .suspend = l2cap_sock_suspend_cb, .set_shutdown = l2cap_sock_set_shutdown_cb, .get_sndtimeo = l2cap_sock_get_sndtimeo_cb, .alloc_skb = l2cap_sock_alloc_skb_cb, -- cgit v1.2.3-70-g09d2 From 177f8f2b1259a1292a09a1b7563ebb90675f88ff Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 31 May 2013 17:54:51 +0300 Subject: Bluetooth: Add LE L2CAP segmentation support for outgoing data This patch adds segmentation support for outgoing data packets. Packets are segmented based on the MTU and MPS values. The l2cap_chan struct already contains many helpful variables from BR/EDR Enhanced L2CAP which can be used for this. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 127 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 126 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index aaa98a2318c..bdc1c40ba1b 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -607,6 +607,7 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) break; case L2CAP_MODE_LE_FLOWCTL: + skb_queue_purge(&chan->tx_q); break; case L2CAP_MODE_ERTM: @@ -1194,12 +1195,24 @@ static void l2cap_move_done(struct l2cap_chan *chan) } } +static void l2cap_le_flowctl_start(struct l2cap_chan *chan) +{ + chan->sdu = NULL; + chan->sdu_last_frag = NULL; + chan->sdu_len = 0; + + skb_queue_head_init(&chan->tx_q); +} + static void l2cap_chan_ready(struct l2cap_chan *chan) { /* This clears all conf flags, including CONF_NOT_COMPLETE */ chan->conf_state = 0; __clear_chan_timer(chan); + if (chan->mode == L2CAP_MODE_LE_FLOWCTL) + l2cap_le_flowctl_start(chan); + chan->state = BT_CONNECTED; chan->ops->ready(chan); @@ -2521,6 +2534,89 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan, return 0; } +static struct sk_buff *l2cap_create_le_flowctl_pdu(struct l2cap_chan *chan, + struct msghdr *msg, + size_t len, u16 sdulen) +{ + struct l2cap_conn *conn = chan->conn; + struct sk_buff *skb; + int err, count, hlen; + struct l2cap_hdr *lh; + + BT_DBG("chan %p len %zu", chan, len); + + if (!conn) + return ERR_PTR(-ENOTCONN); + + hlen = L2CAP_HDR_SIZE; + + if (sdulen) + hlen += L2CAP_SDULEN_SIZE; + + count = min_t(unsigned int, (conn->mtu - hlen), len); + + skb = chan->ops->alloc_skb(chan, count + hlen, + msg->msg_flags & MSG_DONTWAIT); + if (IS_ERR(skb)) + return skb; + + /* Create L2CAP header */ + lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); + lh->cid = cpu_to_le16(chan->dcid); + lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); + + if (sdulen) + put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE)); + + err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb); + if (unlikely(err < 0)) { + kfree_skb(skb); + return ERR_PTR(err); + } + + return skb; +} + +static int l2cap_segment_le_sdu(struct l2cap_chan *chan, + struct sk_buff_head *seg_queue, + struct msghdr *msg, size_t len) +{ + struct sk_buff *skb; + size_t pdu_len; + u16 sdu_len; + + BT_DBG("chan %p, msg %p, len %zu", chan, msg, len); + + pdu_len = chan->conn->mtu - L2CAP_HDR_SIZE; + + pdu_len = min_t(size_t, pdu_len, chan->remote_mps); + + sdu_len = len; + pdu_len -= L2CAP_SDULEN_SIZE; + + while (len > 0) { + if (len <= pdu_len) + pdu_len = len; + + skb = l2cap_create_le_flowctl_pdu(chan, msg, pdu_len, sdu_len); + if (IS_ERR(skb)) { + __skb_queue_purge(seg_queue); + return PTR_ERR(skb); + } + + __skb_queue_tail(seg_queue, skb); + + len -= pdu_len; + + if (sdu_len) { + sdu_len = 0; + pdu_len += L2CAP_SDULEN_SIZE; + } + } + + return 0; +} + int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u32 priority) { @@ -2543,10 +2639,39 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, switch (chan->mode) { case L2CAP_MODE_LE_FLOWCTL: + /* Check outgoing MTU */ + if (len > chan->omtu) + return -EMSGSIZE; + if (!chan->tx_credits) return -EAGAIN; - /* fall through */ + __skb_queue_head_init(&seg_queue); + + err = l2cap_segment_le_sdu(chan, &seg_queue, msg, len); + + if (chan->state != BT_CONNECTED) { + __skb_queue_purge(&seg_queue); + err = -ENOTCONN; + } + + if (err) + return err; + + skb_queue_splice_tail_init(&seg_queue, &chan->tx_q); + + while (chan->tx_credits && !skb_queue_empty(&chan->tx_q)) { + l2cap_do_send(chan, skb_dequeue(&chan->tx_q)); + chan->tx_credits--; + } + + if (!chan->tx_credits) + chan->ops->suspend(chan); + + err = len; + + break; + case L2CAP_MODE_BASIC: /* Check outgoing MTU */ if (len > chan->omtu) -- cgit v1.2.3-70-g09d2 From aac23bf636593cc2d67144aed373a46a1a5f76b1 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 1 Jun 2013 10:14:57 +0300 Subject: Bluetooth: Implement LE L2CAP reassembly When receiving fragments over an LE Connection oriented Channel they need to be collected up and eventually merged into a single SDU. This patch adds the necessary code for collecting up the fragment skbs to the channel context and passing them to the recv() callback when the entire SDU has been received. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 79 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index bdc1c40ba1b..1c94e51a28f 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -6818,18 +6818,91 @@ static void l2cap_chan_le_send_credits(struct l2cap_chan *chan) static int l2cap_le_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) { - if (!chan->rx_credits) + int err; + + if (!chan->rx_credits) { + BT_ERR("No credits to receive LE L2CAP data"); return -ENOBUFS; + } - if (chan->imtu < skb->len) + if (chan->imtu < skb->len) { + BT_ERR("Too big LE L2CAP PDU"); return -ENOBUFS; + } chan->rx_credits--; BT_DBG("rx_credits %u -> %u", chan->rx_credits + 1, chan->rx_credits); l2cap_chan_le_send_credits(chan); - return chan->ops->recv(chan, skb); + err = 0; + + if (!chan->sdu) { + u16 sdu_len; + + sdu_len = get_unaligned_le16(skb->data); + skb_pull(skb, L2CAP_SDULEN_SIZE); + + BT_DBG("Start of new SDU. sdu_len %u skb->len %u imtu %u", + sdu_len, skb->len, chan->imtu); + + if (sdu_len > chan->imtu) { + BT_ERR("Too big LE L2CAP SDU length received"); + err = -EMSGSIZE; + goto failed; + } + + if (skb->len > sdu_len) { + BT_ERR("Too much LE L2CAP data received"); + err = -EINVAL; + goto failed; + } + + if (skb->len == sdu_len) + return chan->ops->recv(chan, skb); + + chan->sdu = skb; + chan->sdu_len = sdu_len; + chan->sdu_last_frag = skb; + + return 0; + } + + BT_DBG("SDU fragment. chan->sdu->len %u skb->len %u chan->sdu_len %u", + chan->sdu->len, skb->len, chan->sdu_len); + + if (chan->sdu->len + skb->len > chan->sdu_len) { + BT_ERR("Too much LE L2CAP data received"); + err = -EINVAL; + goto failed; + } + + append_skb_frag(chan->sdu, skb, &chan->sdu_last_frag); + skb = NULL; + + if (chan->sdu->len == chan->sdu_len) { + err = chan->ops->recv(chan, chan->sdu); + if (!err) { + chan->sdu = NULL; + chan->sdu_last_frag = NULL; + chan->sdu_len = 0; + } + } + +failed: + if (err) { + kfree_skb(skb); + kfree_skb(chan->sdu); + chan->sdu = NULL; + chan->sdu_last_frag = NULL; + chan->sdu_len = 0; + } + + /* We can't return an error here since we took care of the skb + * freeing internally. An error return would cause the caller to + * do a double-free of the skb. + */ + return 0; } static void l2cap_data_channel(struct l2cap_conn *conn, u16 cid, -- cgit v1.2.3-70-g09d2 From 595177f311f5d42804f729e927f7eac87bbcc21b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 2 Dec 2013 22:12:22 +0200 Subject: Bluetooth: Fix LE L2CAP Connect Request handling together with SMP Unlike BR/EDR, for LE when we're in the BT_CONNECT state we may or may not have already have sent the Connect Request. This means that we need some extra tracking of the request. This patch adds an extra channel flag to prevent the request from being sent a second time. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 1 + net/bluetooth/l2cap_core.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index b0d7e4adb16..292749c0f4b 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -695,6 +695,7 @@ enum { FLAG_EXT_CTRL, FLAG_EFS_ENABLE, FLAG_DEFER_SETUP, + FLAG_LE_CONN_REQ_SENT, }; enum { diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 1c94e51a28f..407e9d61d06 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1223,6 +1223,9 @@ static void l2cap_le_connect(struct l2cap_chan *chan) struct l2cap_conn *conn = chan->conn; struct l2cap_le_conn_req req; + if (test_and_set_bit(FLAG_LE_CONN_REQ_SENT, &chan->flags)) + return; + req.psm = chan->psm; req.scid = cpu_to_le16(chan->scid); req.mtu = cpu_to_le16(chan->imtu); -- cgit v1.2.3-70-g09d2 From 029727a39a4316c081347749d5c25f76d5eb891c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 7 Oct 2013 14:44:48 +0200 Subject: Bluetooth: Fix suspending the L2CAP socket if we start with 0 credits If the peer gives us zero credits in its connection request or response we must call the suspend channel callback so the BT_SK_SUSPEND flag gets set and user space is blocked from sending data to the socket. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 407e9d61d06..82aa6f352b2 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1202,6 +1202,9 @@ static void l2cap_le_flowctl_start(struct l2cap_chan *chan) chan->sdu_len = 0; skb_queue_head_init(&chan->tx_q); + + if (!chan->tx_credits) + chan->ops->suspend(chan); } static void l2cap_chan_ready(struct l2cap_chan *chan) -- cgit v1.2.3-70-g09d2 From 3916aed81f1fd07f71a597080690d36f02e88850 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 7 Oct 2013 15:35:26 +0200 Subject: Bluetooth: Limit LE MPS to the MTU value It doesn't make sense to have an MPS value greater than the configured MTU value since we will then not be able to fill up the packets to their full possible size. We need to set the MPS both in flowctl_init() as well as flowctl_start() since the imtu may change after init() but start() is only called after we've sent the LE Connection Request PDU which depends on having a valid MPS value. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 82aa6f352b2..4c8bac9e8d3 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -497,6 +497,11 @@ void l2cap_le_flowctl_init(struct l2cap_chan *chan) chan->mode = L2CAP_MODE_LE_FLOWCTL; chan->tx_credits = 0; chan->rx_credits = L2CAP_LE_MAX_CREDITS; + + if (chan->imtu < L2CAP_LE_DEFAULT_MPS) + chan->mps = chan->imtu; + else + chan->mps = L2CAP_LE_DEFAULT_MPS; } void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) @@ -645,7 +650,7 @@ static void l2cap_chan_le_connect_reject(struct l2cap_chan *chan) rsp.dcid = cpu_to_le16(chan->scid); rsp.mtu = cpu_to_le16(chan->imtu); - rsp.mps = __constant_cpu_to_le16(L2CAP_LE_DEFAULT_MPS); + rsp.mps = cpu_to_le16(chan->mps); rsp.credits = cpu_to_le16(chan->rx_credits); rsp.result = cpu_to_le16(result); @@ -1201,6 +1206,11 @@ static void l2cap_le_flowctl_start(struct l2cap_chan *chan) chan->sdu_last_frag = NULL; chan->sdu_len = 0; + if (chan->imtu < L2CAP_LE_DEFAULT_MPS) + chan->mps = chan->imtu; + else + chan->mps = L2CAP_LE_DEFAULT_MPS; + skb_queue_head_init(&chan->tx_q); if (!chan->tx_credits) @@ -1232,7 +1242,7 @@ static void l2cap_le_connect(struct l2cap_chan *chan) req.psm = chan->psm; req.scid = cpu_to_le16(chan->scid); req.mtu = cpu_to_le16(chan->imtu); - req.mps = __constant_cpu_to_le16(L2CAP_LE_DEFAULT_MPS); + req.mps = cpu_to_le16(chan->mps); req.credits = cpu_to_le16(chan->rx_credits); chan->ident = l2cap_get_ident(conn); @@ -3826,7 +3836,7 @@ void __l2cap_le_connect_rsp_defer(struct l2cap_chan *chan) rsp.dcid = cpu_to_le16(chan->scid); rsp.mtu = cpu_to_le16(chan->imtu); - rsp.mps = __constant_cpu_to_le16(L2CAP_LE_DEFAULT_MPS); + rsp.mps = cpu_to_le16(chan->mps); rsp.credits = cpu_to_le16(chan->rx_credits); rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS); @@ -5671,7 +5681,7 @@ response_unlock: response: if (chan) { rsp.mtu = cpu_to_le16(chan->imtu); - rsp.mps = __constant_cpu_to_le16(L2CAP_LE_DEFAULT_MPS); + rsp.mps = cpu_to_le16(chan->mps); } else { rsp.mtu = 0; rsp.mps = 0; -- cgit v1.2.3-70-g09d2 From aeddd075d5483cc9a34cd98b0df967f28d651f93 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 7 Oct 2013 16:15:25 +0200 Subject: Bluetooth: Fix clearing of chan->omtu for LE CoC channels The outgoing MTU should only be set upon channel creation to the initial minimum value (23) or from a remote connect req/rsp PDU. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 4c8bac9e8d3..eb5604e0610 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -516,12 +516,12 @@ void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) switch (chan->chan_type) { case L2CAP_CHAN_CONN_ORIENTED: if (conn->hcon->type == LE_LINK) { - /* LE connection */ - chan->omtu = L2CAP_DEFAULT_MTU; - if (chan->dcid == L2CAP_CID_ATT) + if (chan->dcid == L2CAP_CID_ATT) { + chan->omtu = L2CAP_DEFAULT_MTU; chan->scid = L2CAP_CID_ATT; - else + } else { chan->scid = l2cap_alloc_cid(conn); + } } else { /* Alloc CID for connection-oriented socket */ chan->scid = l2cap_alloc_cid(conn); -- cgit v1.2.3-70-g09d2 From e77af7559238895ec5fd1706762e1c9f890dcc7e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 8 Oct 2013 10:31:00 +0200 Subject: Bluetooth: Fix CID ranges for LE CoC CID allocations LE CoC used differend CIC ranges than BR/EDR L2CAP. The start of the range is the same (0x0040) but the range ends at 0x007f (unlike BR/EDR where it goes all the way to 0xffff). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 1 + net/bluetooth/l2cap_core.c | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 292749c0f4b..abba765c174 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -252,6 +252,7 @@ struct l2cap_conn_rsp { #define L2CAP_CID_SMP 0x0006 #define L2CAP_CID_DYN_START 0x0040 #define L2CAP_CID_DYN_END 0xffff +#define L2CAP_CID_LE_DYN_END 0x007f /* connect/create channel results */ #define L2CAP_CR_SUCCESS 0x0000 diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index eb5604e0610..76ebd18ff96 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -213,9 +213,14 @@ int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid) static u16 l2cap_alloc_cid(struct l2cap_conn *conn) { - u16 cid = L2CAP_CID_DYN_START; + u16 cid, dyn_end; - for (; cid < L2CAP_CID_DYN_END; cid++) { + if (conn->hcon->type == LE_LINK) + dyn_end = L2CAP_CID_LE_DYN_END; + else + dyn_end = L2CAP_CID_DYN_END; + + for (cid = L2CAP_CID_DYN_START; cid < dyn_end; cid++) { if (!__l2cap_get_chan_by_scid(conn, cid)) return cid; } -- cgit v1.2.3-70-g09d2 From 4946096d43d1d02fb07cc80f82e1747b01571c41 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 8 Oct 2013 13:55:46 +0200 Subject: Bluetooth: Fix validating LE PSM values LE PSM values have different ranges than those for BR/EDR. The valid ranges for fixed, SIG assigned values is 0x0001-0x007f and for dynamic PSM values 0x0080-0x00ff. We need to ensure that bind() and connect() calls conform to these ranges when operating on LE CoC sockets. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 15 +++++++++++++-- net/bluetooth/l2cap_sock.c | 40 +++++++++++++++++++++++++++++++--------- 2 files changed, 44 insertions(+), 11 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 76ebd18ff96..5941c65728b 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1861,6 +1861,18 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, return c1; } +static bool is_valid_psm(u16 psm, u8 dst_type) +{ + if (!psm) + return false; + + if (bdaddr_type_is_le(dst_type)) + return (psm < 0x00ff); + + /* PSM must be odd and lsb of upper byte must be 0 */ + return ((psm & 0x0101) == 0x0001); +} + int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst, u8 dst_type) { @@ -1881,8 +1893,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, l2cap_chan_lock(chan); - /* PSM must be odd and lsb of upper byte must be 0 */ - if ((__le16_to_cpu(psm) & 0x0101) != 0x0001 && !cid && + if (!is_valid_psm(__le16_to_cpu(psm), dst_type) && !cid && chan->chan_type != L2CAP_CHAN_RAW) { err = -EINVAL; goto done; diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index a51844a8c5e..88fa9c07c50 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -53,6 +53,32 @@ bool l2cap_is_socket(struct socket *sock) } EXPORT_SYMBOL(l2cap_is_socket); +static int l2cap_validate_bredr_psm(u16 psm) +{ + /* PSM must be odd and lsb of upper byte must be 0 */ + if ((psm & 0x0101) != 0x0001) + return -EINVAL; + + /* Restrict usage of well-known PSMs */ + if (psm < 0x1001 && !capable(CAP_NET_BIND_SERVICE)) + return -EACCES; + + return 0; +} + +static int l2cap_validate_le_psm(u16 psm) +{ + /* Valid LE_PSM ranges are defined only until 0x00ff */ + if (psm > 0x00ff) + return -EINVAL; + + /* Restrict fixed, SIG assigned PSM values to CAP_NET_BIND_SERVICE */ + if (psm <= 0x007f && !capable(CAP_NET_BIND_SERVICE)) + return -EACCES; + + return 0; +} + static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) { struct sock *sk = sock->sk; @@ -94,17 +120,13 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) if (la.l2_psm) { __u16 psm = __le16_to_cpu(la.l2_psm); - /* PSM must be odd and lsb of upper byte must be 0 */ - if ((psm & 0x0101) != 0x0001) { - err = -EINVAL; - goto done; - } + if (la.l2_bdaddr_type == BDADDR_BREDR) + err = l2cap_validate_bredr_psm(psm); + else + err = l2cap_validate_le_psm(psm); - /* Restrict usage of well-known PSMs */ - if (psm < 0x1001 && !capable(CAP_NET_BIND_SERVICE)) { - err = -EACCES; + if (err) goto done; - } } if (la.l2_cid) -- cgit v1.2.3-70-g09d2 From f15b8ecf9895941ef50134ff604be8bd2c6b1b78 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 3 Dec 2013 15:08:25 +0200 Subject: Bluetooth: Add debugfs controls for LE CoC MPS and Credits This patch adds entries to debugfs to control the values used for the MPS and Credits for LE Flow Control Mode. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 5941c65728b..8e9e883874c 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -49,6 +49,9 @@ static u8 l2cap_fixed_chan[8] = { L2CAP_FC_L2CAP | L2CAP_FC_CONNLESS, }; static LIST_HEAD(chan_list); static DEFINE_RWLOCK(chan_list_lock); +static u16 le_max_credits = L2CAP_LE_MAX_CREDITS; +static u16 le_default_mps = L2CAP_LE_DEFAULT_MPS; + static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, u8 code, u8 ident, u16 dlen, void *data); static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, @@ -501,7 +504,7 @@ void l2cap_le_flowctl_init(struct l2cap_chan *chan) chan->omtu = L2CAP_LE_MIN_MTU; chan->mode = L2CAP_MODE_LE_FLOWCTL; chan->tx_credits = 0; - chan->rx_credits = L2CAP_LE_MAX_CREDITS; + chan->rx_credits = le_max_credits; if (chan->imtu < L2CAP_LE_DEFAULT_MPS) chan->mps = chan->imtu; @@ -1214,7 +1217,7 @@ static void l2cap_le_flowctl_start(struct l2cap_chan *chan) if (chan->imtu < L2CAP_LE_DEFAULT_MPS) chan->mps = chan->imtu; else - chan->mps = L2CAP_LE_DEFAULT_MPS; + chan->mps = le_default_mps; skb_queue_head_init(&chan->tx_q); @@ -6831,10 +6834,10 @@ static void l2cap_chan_le_send_credits(struct l2cap_chan *chan) /* We return more credits to the sender only after the amount of * credits falls below half of the initial amount. */ - if (chan->rx_credits >= (L2CAP_LE_MAX_CREDITS + 1) / 2) + if (chan->rx_credits >= (le_max_credits + 1) / 2) return; - return_credits = L2CAP_LE_MAX_CREDITS - chan->rx_credits; + return_credits = le_max_credits - chan->rx_credits; BT_DBG("chan %p returning %u credits to sender", chan, return_credits); @@ -7448,6 +7451,11 @@ int __init l2cap_init(void) l2cap_debugfs = debugfs_create_file("l2cap", 0444, bt_debugfs, NULL, &l2cap_debugfs_fops); + debugfs_create_u16("l2cap_le_max_credits", 0466, bt_debugfs, + &le_max_credits); + debugfs_create_u16("l2cap_le_default_mps", 0466, bt_debugfs, + &le_default_mps); + return 0; } -- cgit v1.2.3-70-g09d2 From 0ce43ce60d5e0c079d33be1fe33ba92828c7e5da Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 5 Dec 2013 14:55:33 +0200 Subject: Bluetooth: Simplify l2cap_chan initialization for LE CoC The values in l2cap_chan that are used for actually transmitting data only need to be initialized right after we've received an L2CAP Connect Request or just before we send one. The only thing that we need to initialize though bind() and connect() is the chan->mode value. This way all other initializations can be done in the l2cap_le_flowctl_init function (which now becomes private to l2cap_core.c) and the l2cap_le_flowctl_start function can be completely removed. Also, since the l2cap_sock_init function initializes the imtu and omtu to adequate values these do not need to be part of l2cap_le_flowctl_init. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 1 - net/bluetooth/l2cap_core.c | 35 ++++++++++++----------------------- net/bluetooth/l2cap_sock.c | 4 ++-- 3 files changed, 14 insertions(+), 26 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index abba765c174..e149e992fda 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -873,7 +873,6 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, void l2cap_chan_busy(struct l2cap_chan *chan, int busy); int l2cap_chan_check_security(struct l2cap_chan *chan); void l2cap_chan_set_defaults(struct l2cap_chan *chan); -void l2cap_le_flowctl_init(struct l2cap_chan *chan); int l2cap_ertm_init(struct l2cap_chan *chan); void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan); void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 8e9e883874c..6e6f308af03 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -498,11 +498,11 @@ void l2cap_chan_set_defaults(struct l2cap_chan *chan) set_bit(FLAG_FORCE_ACTIVE, &chan->flags); } -void l2cap_le_flowctl_init(struct l2cap_chan *chan) +static void l2cap_le_flowctl_init(struct l2cap_chan *chan) { - chan->imtu = L2CAP_DEFAULT_MTU; - chan->omtu = L2CAP_LE_MIN_MTU; - chan->mode = L2CAP_MODE_LE_FLOWCTL; + chan->sdu = NULL; + chan->sdu_last_frag = NULL; + chan->sdu_len = 0; chan->tx_credits = 0; chan->rx_credits = le_max_credits; @@ -510,6 +510,8 @@ void l2cap_le_flowctl_init(struct l2cap_chan *chan) chan->mps = chan->imtu; else chan->mps = L2CAP_LE_DEFAULT_MPS; + + skb_queue_head_init(&chan->tx_q); } void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) @@ -1208,31 +1210,14 @@ static void l2cap_move_done(struct l2cap_chan *chan) } } -static void l2cap_le_flowctl_start(struct l2cap_chan *chan) -{ - chan->sdu = NULL; - chan->sdu_last_frag = NULL; - chan->sdu_len = 0; - - if (chan->imtu < L2CAP_LE_DEFAULT_MPS) - chan->mps = chan->imtu; - else - chan->mps = le_default_mps; - - skb_queue_head_init(&chan->tx_q); - - if (!chan->tx_credits) - chan->ops->suspend(chan); -} - static void l2cap_chan_ready(struct l2cap_chan *chan) { /* This clears all conf flags, including CONF_NOT_COMPLETE */ chan->conf_state = 0; __clear_chan_timer(chan); - if (chan->mode == L2CAP_MODE_LE_FLOWCTL) - l2cap_le_flowctl_start(chan); + if (chan->mode == L2CAP_MODE_LE_FLOWCTL && !chan->tx_credits) + chan->ops->suspend(chan); chan->state = BT_CONNECTED; @@ -1909,7 +1894,9 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, switch (chan->mode) { case L2CAP_MODE_BASIC: + break; case L2CAP_MODE_LE_FLOWCTL: + l2cap_le_flowctl_init(chan); break; case L2CAP_MODE_ERTM: case L2CAP_MODE_STREAMING: @@ -5663,6 +5650,8 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn, goto response_unlock; } + l2cap_le_flowctl_init(chan); + bacpy(&chan->src, &conn->hcon->src); bacpy(&chan->dst, &conn->hcon->dst); chan->src_type = bdaddr_type(conn->hcon, conn->hcon->src_type); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 88fa9c07c50..e7806e6d282 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -153,7 +153,7 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) chan->src_type = la.l2_bdaddr_type; if (chan->psm && bdaddr_type_is_le(chan->src_type)) - l2cap_le_flowctl_init(chan); + chan->mode = L2CAP_MODE_LE_FLOWCTL; chan->state = BT_BOUND; sk->sk_state = BT_BOUND; @@ -226,7 +226,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, } if (chan->psm && bdaddr_type_is_le(chan->src_type)) - l2cap_le_flowctl_init(chan); + chan->mode = L2CAP_MODE_LE_FLOWCTL; err = l2cap_chan_connect(chan, la.l2_psm, __le16_to_cpu(la.l2_cid), &la.l2_bdaddr, la.l2_bdaddr_type); -- cgit v1.2.3-70-g09d2 From b9243ab0c9e3e4dbd54ae8f44cf0cdb5838c8746 Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Thu, 5 Dec 2013 10:02:14 +0100 Subject: nl80211: allow setting bitrate mask back to default Allow setting the bitrate masks back to default by omitting the NL80211_ATTR_TX_RATES attribute. Signed-off-by: Janusz Dziedzic [rephrase commit message] Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 6989989de09..f61b74c40d2 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -7327,9 +7327,6 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, struct nlattr *tx_rates; struct ieee80211_supported_band *sband; - if (info->attrs[NL80211_ATTR_TX_RATES] == NULL) - return -EINVAL; - if (!rdev->ops->set_bitrate_mask) return -EOPNOTSUPP; @@ -7347,6 +7344,10 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, sizeof(mask.control[i].mcs)); } + /* if no rates are given set it back to the defaults */ + if (!info->attrs[NL80211_ATTR_TX_RATES]) + goto out; + /* * The nested attribute uses enum nl80211_band as the index. This maps * directly to the enum ieee80211_band values used in cfg80211. @@ -7396,6 +7397,7 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, } } +out: return rdev_set_bitrate_mask(rdev, dev, NULL, &mask); } -- cgit v1.2.3-70-g09d2 From d1e33e654ef6bb3dee766353ed9dd31e7dcb8a94 Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Thu, 5 Dec 2013 10:02:15 +0100 Subject: cfg80211: in bitrate_mask, rename mcs to ht_mcs Rename NL80211_TXRATE_MCS to NL80211_TXRATE_HT and also rename mcs to ht_mcs in struct cfg80211_bitrate_mask. Signed-off-by: Janusz Dziedzic [reword commit message] Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath6kl/wmi.c | 6 +++--- drivers/net/wireless/mwifiex/cfg80211.c | 6 +++--- include/net/cfg80211.h | 2 +- include/uapi/linux/nl80211.h | 6 ++++-- net/mac80211/cfg.c | 4 ++-- net/wireless/nl80211.c | 18 +++++++++--------- 6 files changed, 22 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 546d5da0b89..4f16d79c9eb 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -2754,9 +2754,9 @@ static int ath6kl_set_bitrate_mask64(struct wmi *wmi, u8 if_idx, mask->control[band].legacy << 4; /* copy mcs rate mask */ - mcsrate = mask->control[band].mcs[1]; + mcsrate = mask->control[band].ht_mcs[1]; mcsrate <<= 8; - mcsrate |= mask->control[band].mcs[0]; + mcsrate |= mask->control[band].ht_mcs[0]; ratemask[band] |= mcsrate << 12; ratemask[band] |= mcsrate << 28; } @@ -2806,7 +2806,7 @@ static int ath6kl_set_bitrate_mask32(struct wmi *wmi, u8 if_idx, mask->control[band].legacy << 4; /* copy mcs rate mask */ - mcsrate = mask->control[band].mcs[0]; + mcsrate = mask->control[band].ht_mcs[0]; ratemask[band] |= mcsrate << 12; ratemask[band] |= mcsrate << 20; } diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 1c8116d4684..6f5e49b32e7 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1170,10 +1170,10 @@ static int mwifiex_cfg80211_set_bitrate_mask(struct wiphy *wiphy, else bitmap_rates[1] = mask->control[band].legacy; - /* Fill MCS rates */ - bitmap_rates[2] = mask->control[band].mcs[0]; + /* Fill HT MCS rates */ + bitmap_rates[2] = mask->control[band].ht_mcs[0]; if (priv->adapter->hw_dev_mcs_support == HT_STREAM_2X2) - bitmap_rates[2] |= mask->control[band].mcs[1] << 8; + bitmap_rates[2] |= mask->control[band].ht_mcs[1] << 8; return mwifiex_send_cmd_sync(priv, HostCmd_CMD_TX_RATE_CFG, HostCmd_ACT_GEN_SET, 0, bitmap_rates); diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 884ac69b5e5..6c3a650f3a8 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1766,7 +1766,7 @@ enum wiphy_params_flags { struct cfg80211_bitrate_mask { struct { u32 legacy; - u8 mcs[IEEE80211_HT_MCS_MASK_LEN]; + u8 ht_mcs[IEEE80211_HT_MCS_MASK_LEN]; } control[IEEE80211_NUM_BANDS]; }; /** diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 72ba3584c90..6e700645cd2 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -3110,7 +3110,7 @@ enum nl80211_key_attributes { * in an array of rates as defined in IEEE 802.11 7.3.2.2 (u8 values with * 1 = 500 kbps) but without the IE length restriction (at most * %NL80211_MAX_SUPP_RATES in a single array). - * @NL80211_TXRATE_MCS: HT (MCS) rates allowed for TX rate selection + * @NL80211_TXRATE_HT: HT (MCS) rates allowed for TX rate selection * in an array of MCS numbers. * @__NL80211_TXRATE_AFTER_LAST: internal * @NL80211_TXRATE_MAX: highest TX rate attribute @@ -3118,13 +3118,15 @@ enum nl80211_key_attributes { enum nl80211_tx_rate_attributes { __NL80211_TXRATE_INVALID, NL80211_TXRATE_LEGACY, - NL80211_TXRATE_MCS, + NL80211_TXRATE_HT, /* keep last */ __NL80211_TXRATE_AFTER_LAST, NL80211_TXRATE_MAX = __NL80211_TXRATE_AFTER_LAST - 1 }; +#define NL80211_TXRATE_MCS NL80211_TXRATE_HT + /** * enum nl80211_band - Frequency band * @NL80211_BAND_2GHZ: 2.4 GHz ISM band diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 754069cbb75..a74d61d520b 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2588,8 +2588,8 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, int j; sdata->rc_rateidx_mask[i] = mask->control[i].legacy; - memcpy(sdata->rc_rateidx_mcs_mask[i], mask->control[i].mcs, - sizeof(mask->control[i].mcs)); + memcpy(sdata->rc_rateidx_mcs_mask[i], mask->control[i].ht_mcs, + sizeof(mask->control[i].ht_mcs)); sdata->rc_has_mcs_mask[i] = false; if (!sband) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index f61b74c40d2..801e57da88b 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -7312,8 +7312,8 @@ static bool ht_rateset_to_mask(struct ieee80211_supported_band *sband, static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = { [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY, .len = NL80211_MAX_SUPP_RATES }, - [NL80211_TXRATE_MCS] = { .type = NLA_BINARY, - .len = NL80211_MAX_SUPP_HT_RATES }, + [NL80211_TXRATE_HT] = { .type = NLA_BINARY, + .len = NL80211_MAX_SUPP_HT_RATES }, }; static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, @@ -7339,9 +7339,9 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, continue; mask.control[i].legacy = (1 << sband->n_bitrates) - 1; - memcpy(mask.control[i].mcs, + memcpy(mask.control[i].ht_mcs, sband->ht_cap.mcs.rx_mask, - sizeof(mask.control[i].mcs)); + sizeof(mask.control[i].ht_mcs)); } /* if no rates are given set it back to the defaults */ @@ -7372,12 +7372,12 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, nla_len(tb[NL80211_TXRATE_LEGACY])) return -EINVAL; } - if (tb[NL80211_TXRATE_MCS]) { + if (tb[NL80211_TXRATE_HT]) { if (!ht_rateset_to_mask( sband, - nla_data(tb[NL80211_TXRATE_MCS]), - nla_len(tb[NL80211_TXRATE_MCS]), - mask.control[band].mcs)) + nla_data(tb[NL80211_TXRATE_HT]), + nla_len(tb[NL80211_TXRATE_HT]), + mask.control[band].ht_mcs)) return -EINVAL; } @@ -7388,7 +7388,7 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, return -EINVAL; for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) - if (mask.control[band].mcs[i]) + if (mask.control[band].ht_mcs[i]) break; /* legacy and mcs rates may not be both empty */ -- cgit v1.2.3-70-g09d2 From 24d584d70e478bf2e815135e8bf60f72685046f7 Mon Sep 17 00:00:00 2001 From: Barak Bercovitz Date: Thu, 5 Dec 2013 11:21:26 +0200 Subject: cfg80211: stop sched scan only when needed cfg80211_leave stops sched scan when any station vif is leaving. Add an explicit check and call it only when the relevant vif (the one we scan on) is leaving. Signed-off-by: Barak Bercovitz [Eliad - changed the commit message a bit] Signed-off-by: Eliad Peller [Johannes - add ASSERT_RTNL since that protects the pointer] Signed-off-by: Johannes Berg --- net/wireless/core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/wireless/core.c b/net/wireless/core.c index fc968c861ee..c0443558b7b 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -756,13 +756,16 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev, { struct net_device *dev = wdev->netdev; + ASSERT_RTNL(); + switch (wdev->iftype) { case NL80211_IFTYPE_ADHOC: cfg80211_leave_ibss(rdev, dev, true); break; case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_STATION: - __cfg80211_stop_sched_scan(rdev, false); + if (rdev->sched_scan_req && dev == rdev->sched_scan_req->dev) + __cfg80211_stop_sched_scan(rdev, false); wdev_lock(wdev); #ifdef CONFIG_CFG80211_WEXT -- cgit v1.2.3-70-g09d2 From 8bd2a2489971d3bcdbae6d9d9e9414f04cb0543b Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 5 Dec 2013 11:21:27 +0200 Subject: mac80211: determine completed scan type by defined ops In some cases, determining the completed scan type was done by testing the SCAN_HW_SCANNING flag. However, this doesn't take care for the case in which the hw scan was requested, but hasn't started yet (e.g. due to active remain_on_channel). Replace this test by checking whether ops->hw_scan is defined. This solves the following warning: WARNING: CPU: 0 PID: 3552 at net/mac80211/offchannel.c:156 __ieee80211_scan_completed+0x1b4/0x2dc [mac80211]() [] (unwind_backtrace+0x0/0xf0) [] (show_stack+0x10/0x14) [] (dump_stack+0x78/0x94) [] (warn_slowpath_common+0x68/0x8c) [] (warn_slowpath_null+0x1c/0x24) [] (__ieee80211_scan_completed+0x1b4/0x2dc [mac80211]) [] (ieee80211_scan_cancel+0xe8/0x190 [mac80211]) [] (ieee80211_do_stop+0x63c/0x79c [mac80211]) [] (ieee80211_stop+0x10/0x18 [mac80211]) [] (__dev_close_many+0x84/0xcc) [] (__dev_close+0x28/0x3c) [] (__dev_change_flags+0x78/0x144) [] (dev_change_flags+0x10/0x48) [] (devinet_ioctl+0x614/0x6d0) [] (sock_ioctl+0x5c/0x2a4) [] (do_vfs_ioctl+0x7c/0x5d8) [] (SyS_ioctl+0x6c/0x7c) Signed-off-by: Eliad Peller Signed-off-by: Johannes Berg --- net/mac80211/scan.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index b12bb72a5f3..78e968a41f0 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -271,10 +271,10 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) return true; } -static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted, - bool was_hw_scan) +static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) { struct ieee80211_local *local = hw_to_local(hw); + bool hw_scan = local->ops->hw_scan; lockdep_assert_held(&local->mtx); @@ -290,7 +290,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted, if (WARN_ON(!local->scan_req)) return; - if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) { + if (hw_scan && !aborted && ieee80211_prep_hw_scan(local)) { int rc; rc = drv_hw_scan(local, @@ -316,7 +316,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted, /* Set power back to normal operating levels. */ ieee80211_hw_config(local, 0); - if (!was_hw_scan) { + if (!hw_scan) { ieee80211_configure_filter(local); drv_sw_scan_complete(local); ieee80211_offchannel_return(local); @@ -747,7 +747,7 @@ void ieee80211_scan_work(struct work_struct *work) container_of(work, struct ieee80211_local, scan_work.work); struct ieee80211_sub_if_data *sdata; unsigned long next_delay = 0; - bool aborted, hw_scan; + bool aborted; mutex_lock(&local->mtx); @@ -826,8 +826,7 @@ void ieee80211_scan_work(struct work_struct *work) goto out; out_complete: - hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning); - __ieee80211_scan_completed(&local->hw, aborted, hw_scan); + __ieee80211_scan_completed(&local->hw, aborted); out: mutex_unlock(&local->mtx); } @@ -965,7 +964,7 @@ void ieee80211_scan_cancel(struct ieee80211_local *local) */ cancel_delayed_work(&local->scan_work); /* and clean up */ - __ieee80211_scan_completed(&local->hw, true, false); + __ieee80211_scan_completed(&local->hw, true); out: mutex_unlock(&local->mtx); } -- cgit v1.2.3-70-g09d2 From a2b70e833e189a4aefb2d3b668e3d7046dcc45c2 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 5 Dec 2013 11:21:28 +0200 Subject: mac80211: start_next_roc only if scan was actually running On scan completion we try start any pending roc. However, if scan was just pending (and not actually started) there is no point in trying to start the roc, as it might have started already. This solves the following warning: WARNING: CPU: 0 PID: 3552 at net/mac80211/offchannel.c:269 ieee80211_start_next_roc+0x164/0x204 [mac80211]() [] (unwind_backtrace+0x0/0xf0) [] (show_stack+0x10/0x14) [] (dump_stack+0x78/0x94) [] (warn_slowpath_common+0x68/0x8c) [] (warn_slowpath_null+0x1c/0x24) [] (ieee80211_start_next_roc+0x164/0x204 [mac80211]) [] (ieee80211_scan_cancel+0xe8/0x190 [mac80211]) [] (ieee80211_do_stop+0x63c/0x79c [mac80211]) [] (ieee80211_stop+0x10/0x18 [mac80211]) [] (__dev_close_many+0x84/0xcc) [] (__dev_close+0x28/0x3c) [] (__dev_change_flags+0x78/0x144) [] (dev_change_flags+0x10/0x48) [] (devinet_ioctl+0x614/0x6d0) [] (sock_ioctl+0x5c/0x2a4) [] (do_vfs_ioctl+0x7c/0x5d8) [] (SyS_ioctl+0x6c/0x7c) Signed-off-by: Eliad Peller Signed-off-by: Johannes Berg --- net/mac80211/scan.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 78e968a41f0..3ccb5841d50 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -275,6 +275,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) { struct ieee80211_local *local = hw_to_local(hw); bool hw_scan = local->ops->hw_scan; + bool was_scanning = local->scanning; lockdep_assert_held(&local->mtx); @@ -327,7 +328,8 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) ieee80211_mlme_notify_scan_completed(local); ieee80211_ibss_notify_scan_completed(local); ieee80211_mesh_notify_scan_completed(local); - ieee80211_start_next_roc(local); + if (was_scanning) + ieee80211_start_next_roc(local); } void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) -- cgit v1.2.3-70-g09d2 From 4a58e7c38443154fce1b47910e1a9184f65c5d72 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 5 Dec 2013 18:30:17 +0200 Subject: cfg80211: don't "leak" uncompleted scans ___cfg80211_scan_done() can be called in some cases (e.g. on NETDEV_DOWN) before the low level driver notified scan completion (which is indicated by passing leak=true). Clearing rdev->scan_req in this case is buggy, as scan_done_wk might have already being queued/running (and can't be flushed as it takes rtnl()). If a new scan will be requested at this stage, the scan_done_wk will try freeing it (instead of the previous scan), and this will later result in a use after free. Simply remove the "leak" option, and replace it with a standard WARN_ON. An example backtrace after such crash: Unable to handle kernel paging request at virtual address fffffee5 pgd = c0004000 [fffffee5] *pgd=9fdf6821, *pte=00000000, *ppte=00000000 Internal error: Oops: 17 [#1] SMP ARM PC is at cfg80211_scan_done+0x28/0xc4 [cfg80211] LR is at __ieee80211_scan_completed+0xe4/0x2dc [mac80211] [] (cfg80211_scan_done+0x28/0xc4 [cfg80211]) [] (__ieee80211_scan_completed+0xe4/0x2dc [mac80211]) [] (ieee80211_scan_work+0x94/0x4f0 [mac80211]) [] (process_one_work+0x1b0/0x4a8) [] (worker_thread+0x138/0x37c) [] (kthread+0xa4/0xb0) Signed-off-by: Eliad Peller Signed-off-by: Johannes Berg --- net/wireless/core.c | 20 ++++---------------- net/wireless/core.h | 2 +- net/wireless/scan.c | 16 +++------------- 3 files changed, 8 insertions(+), 30 deletions(-) diff --git a/net/wireless/core.c b/net/wireless/core.c index c0443558b7b..1a92c6a0731 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -203,17 +203,8 @@ void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev, rdev->opencount--; - if (rdev->scan_req && rdev->scan_req->wdev == wdev) { - /* - * If the scan request wasn't notified as done, set it - * to aborted and leak it after a warning. The driver - * should have notified us that it ended at the latest - * during rdev_stop_p2p_device(). - */ - if (WARN_ON(!rdev->scan_req->notified)) - rdev->scan_req->aborted = true; - ___cfg80211_scan_done(rdev, !rdev->scan_req->notified); - } + WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev && + !rdev->scan_req->notified); } static int cfg80211_rfkill_set_block(void *data, bool blocked) @@ -859,11 +850,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, break; case NETDEV_DOWN: cfg80211_update_iface_num(rdev, wdev->iftype, -1); - if (rdev->scan_req && rdev->scan_req->wdev == wdev) { - if (WARN_ON(!rdev->scan_req->notified)) - rdev->scan_req->aborted = true; - ___cfg80211_scan_done(rdev, true); - } + WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev && + !rdev->scan_req->notified); if (WARN_ON(rdev->sched_scan_req && rdev->sched_scan_req->dev == wdev->netdev)) { diff --git a/net/wireless/core.h b/net/wireless/core.h index ac77644cf89..453c6ed880f 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -361,7 +361,7 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, struct key_params *params, int key_idx, bool pairwise, const u8 *mac_addr); void __cfg80211_scan_done(struct work_struct *wk); -void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak); +void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev); void __cfg80211_sched_scan_results(struct work_struct *wk); int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, bool driver_initiated); diff --git a/net/wireless/scan.c b/net/wireless/scan.c index d4397eba540..a32d52a04c2 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -161,7 +161,7 @@ static void __cfg80211_bss_expire(struct cfg80211_registered_device *dev, dev->bss_generation++; } -void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) +void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev) { struct cfg80211_scan_request *request; struct wireless_dev *wdev; @@ -210,17 +210,7 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) dev_put(wdev->netdev); rdev->scan_req = NULL; - - /* - * OK. If this is invoked with "leak" then we can't - * free this ... but we've cleaned it up anyway. The - * driver failed to call the scan_done callback, so - * all bets are off, it might still be trying to use - * the scan request or not ... if it accesses the dev - * in there (it shouldn't anyway) then it may crash. - */ - if (!leak) - kfree(request); + kfree(request); } void __cfg80211_scan_done(struct work_struct *wk) @@ -231,7 +221,7 @@ void __cfg80211_scan_done(struct work_struct *wk) scan_done_wk); rtnl_lock(); - ___cfg80211_scan_done(rdev, false); + ___cfg80211_scan_done(rdev); rtnl_unlock(); } -- cgit v1.2.3-70-g09d2 From bafdc614a1f4f8be8cde41b8ab10ac17e67c1837 Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Thu, 5 Dec 2013 19:54:43 +0100 Subject: mac80211: fix nested sdata lock for IBSS/CSA This fixes a regression introduced by my patch "mac80211: don't cancel csa finalize work within stop_ap", which added sdata locks to ieee80211_csa_finalize_work() without removing the locking for ieee80211_ibss_finish_csa(), which is called by the former, resulting in a deadlock due to nested locking. Signed-off-by: Simon Wunderlich Signed-off-by: Johannes Berg --- net/mac80211/ibss.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 0f1fb5db4bd..df21e4f79df 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -534,7 +534,8 @@ int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata) int err; u16 capability; - sdata_lock(sdata); + sdata_assert_lock(sdata); + /* update cfg80211 bss information with the new channel */ if (!is_zero_ether_addr(ifibss->bssid)) { capability = WLAN_CAPABILITY_IBSS; @@ -559,7 +560,6 @@ int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata) /* generate the beacon */ err = ieee80211_ibss_csa_beacon(sdata, NULL); - sdata_unlock(sdata); if (err < 0) return err; -- cgit v1.2.3-70-g09d2 From eac40d9631a7db43570df859fa8a9922e9623607 Mon Sep 17 00:00:00 2001 From: Kevin Lo Date: Mon, 21 Oct 2013 15:38:31 +0800 Subject: rt2x00: rt2800lib: Update BBP register initialization for RT53xx Update bbp register initialization for RT53xx chips to match with the latest MediaTek/Ralink driver. Based on: NICInitRT5390BbpRegisters() From: DPO_RT5572_LinuxSTA_2.6.1.3_20121022/chips/rt5390.c Signed-off-by: Kevin Lo Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 776aff3678f..aaf28d59296 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -5462,15 +5462,14 @@ static void rt2800_init_bbp_53xx(struct rt2x00_dev *rt2x00dev) rt2800_bbp_write(rt2x00dev, 68, 0x0b); - rt2800_bbp_write(rt2x00dev, 69, 0x12); + rt2800_bbp_write(rt2x00dev, 69, 0x0d); + rt2800_bbp_write(rt2x00dev, 70, 0x06); rt2800_bbp_write(rt2x00dev, 73, 0x13); rt2800_bbp_write(rt2x00dev, 75, 0x46); rt2800_bbp_write(rt2x00dev, 76, 0x28); rt2800_bbp_write(rt2x00dev, 77, 0x59); - rt2800_bbp_write(rt2x00dev, 70, 0x0a); - rt2800_bbp_write(rt2x00dev, 79, 0x13); rt2800_bbp_write(rt2x00dev, 80, 0x05); rt2800_bbp_write(rt2x00dev, 81, 0x33); @@ -5513,6 +5512,7 @@ static void rt2800_init_bbp_53xx(struct rt2x00_dev *rt2x00dev) if (rt2x00_rt(rt2x00dev, RT5392)) { rt2800_bbp_write(rt2x00dev, 134, 0xd0); rt2800_bbp_write(rt2x00dev, 135, 0xf6); + rt2800_bbp_write(rt2x00dev, 148, 0x84); } rt2800_disable_unused_dac_adc(rt2x00dev); -- cgit v1.2.3-70-g09d2 From d8d13d32c4a7c6653f22c7649cd3d2d86c2eeacd Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Tue, 22 Oct 2013 15:24:47 -0700 Subject: mwifiex: improvements in mwifiex_ret_tx_power_cfg() 1) Move common code out of switch case handling 2) Return from the function if number of bytes left in response buffer are less than tlv size 3) Pass pg_tlv_hdr directly instead of txp_cfg to mwifiex_get_power_level() Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/sta_cmdresp.c | 35 ++++++++++++++---------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 2675ca7f8d1..551194605aa 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -338,8 +338,7 @@ static int mwifiex_get_power_level(struct mwifiex_private *priv, void *data_buf) if (!data_buf) return -1; - pg_tlv_hdr = (struct mwifiex_types_power_group *) - ((u8 *) data_buf + sizeof(struct host_cmd_ds_txpwr_cfg)); + pg_tlv_hdr = (struct mwifiex_types_power_group *)((u8 *)data_buf); pg = (struct mwifiex_power_group *) ((u8 *) pg_tlv_hdr + sizeof(struct mwifiex_types_power_group)); length = le16_to_cpu(pg_tlv_hdr->length); @@ -383,19 +382,25 @@ static int mwifiex_ret_tx_power_cfg(struct mwifiex_private *priv, struct mwifiex_types_power_group *pg_tlv_hdr; struct mwifiex_power_group *pg; u16 action = le16_to_cpu(txp_cfg->action); + u16 tlv_buf_left; - switch (action) { - case HostCmd_ACT_GEN_GET: - pg_tlv_hdr = (struct mwifiex_types_power_group *) - ((u8 *) txp_cfg + - sizeof(struct host_cmd_ds_txpwr_cfg)); + pg_tlv_hdr = (struct mwifiex_types_power_group *) + ((u8 *)txp_cfg + + sizeof(struct host_cmd_ds_txpwr_cfg)); - pg = (struct mwifiex_power_group *) - ((u8 *) pg_tlv_hdr + - sizeof(struct mwifiex_types_power_group)); + pg = (struct mwifiex_power_group *) + ((u8 *)pg_tlv_hdr + + sizeof(struct mwifiex_types_power_group)); + tlv_buf_left = le16_to_cpu(resp->size) - S_DS_GEN - sizeof(*txp_cfg); + if (tlv_buf_left < + le16_to_cpu(pg_tlv_hdr->length) + sizeof(*pg_tlv_hdr)) + return 0; + + switch (action) { + case HostCmd_ACT_GEN_GET: if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) - mwifiex_get_power_level(priv, txp_cfg); + mwifiex_get_power_level(priv, pg_tlv_hdr); priv->tx_power_level = (u16) pg->power_min; break; @@ -404,14 +409,6 @@ static int mwifiex_ret_tx_power_cfg(struct mwifiex_private *priv, if (!le32_to_cpu(txp_cfg->mode)) break; - pg_tlv_hdr = (struct mwifiex_types_power_group *) - ((u8 *) txp_cfg + - sizeof(struct host_cmd_ds_txpwr_cfg)); - - pg = (struct mwifiex_power_group *) - ((u8 *) pg_tlv_hdr + - sizeof(struct mwifiex_types_power_group)); - if (pg->power_max == pg->power_min) priv->tx_power_level = (u16) pg->power_min; break; -- cgit v1.2.3-70-g09d2 From c8520bcb784df69cf5960308846253814ec45db7 Mon Sep 17 00:00:00 2001 From: Kevin Lo Date: Thu, 24 Oct 2013 13:24:08 +0800 Subject: rt2x00: rt2800lib: update RF registers for RT5390 Mirror the latest MediaTek/Ralink driver with respect to RT5390 RF register programming. The PCI and USB devices use different init values. Signed-off-by: Kevin Lo Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index aaf28d59296..7848b39078c 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -6453,7 +6453,7 @@ static void rt2800_init_rfcsr_5390(struct rt2x00_dev *rt2x00dev) rt2800_rfcsr_write(rt2x00dev, 7, 0x00); rt2800_rfcsr_write(rt2x00dev, 10, 0x53); rt2800_rfcsr_write(rt2x00dev, 11, 0x4a); - rt2800_rfcsr_write(rt2x00dev, 12, 0xc6); + rt2800_rfcsr_write(rt2x00dev, 12, 0x46); rt2800_rfcsr_write(rt2x00dev, 13, 0x9f); rt2800_rfcsr_write(rt2x00dev, 14, 0x00); rt2800_rfcsr_write(rt2x00dev, 15, 0x00); @@ -6466,7 +6466,8 @@ static void rt2800_init_rfcsr_5390(struct rt2x00_dev *rt2x00dev) rt2800_rfcsr_write(rt2x00dev, 22, 0x20); rt2800_rfcsr_write(rt2x00dev, 23, 0x00); rt2800_rfcsr_write(rt2x00dev, 24, 0x00); - if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) + if (rt2x00_is_usb(rt2x00dev) && + rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) rt2800_rfcsr_write(rt2x00dev, 25, 0x80); else rt2800_rfcsr_write(rt2x00dev, 25, 0xc0); @@ -6486,10 +6487,7 @@ static void rt2800_init_rfcsr_5390(struct rt2x00_dev *rt2x00dev) rt2800_rfcsr_write(rt2x00dev, 38, 0x85); rt2800_rfcsr_write(rt2x00dev, 39, 0x1b); - if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) - rt2800_rfcsr_write(rt2x00dev, 40, 0x0b); - else - rt2800_rfcsr_write(rt2x00dev, 40, 0x4b); + rt2800_rfcsr_write(rt2x00dev, 40, 0x0b); rt2800_rfcsr_write(rt2x00dev, 41, 0xbb); rt2800_rfcsr_write(rt2x00dev, 42, 0xd2); rt2800_rfcsr_write(rt2x00dev, 43, 0x9a); @@ -6510,16 +6508,26 @@ static void rt2800_init_rfcsr_5390(struct rt2x00_dev *rt2x00dev) rt2800_rfcsr_write(rt2x00dev, 53, 0x84); rt2800_rfcsr_write(rt2x00dev, 54, 0x78); rt2800_rfcsr_write(rt2x00dev, 55, 0x44); - rt2800_rfcsr_write(rt2x00dev, 56, 0x22); + if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) + rt2800_rfcsr_write(rt2x00dev, 56, 0x42); + else + rt2800_rfcsr_write(rt2x00dev, 56, 0x22); rt2800_rfcsr_write(rt2x00dev, 57, 0x80); rt2800_rfcsr_write(rt2x00dev, 58, 0x7f); rt2800_rfcsr_write(rt2x00dev, 59, 0x8f); rt2800_rfcsr_write(rt2x00dev, 60, 0x45); - if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) - rt2800_rfcsr_write(rt2x00dev, 61, 0xd1); - else - rt2800_rfcsr_write(rt2x00dev, 61, 0xdd); + if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) { + if (rt2x00_is_usb(rt2x00dev)) + rt2800_rfcsr_write(rt2x00dev, 61, 0xd1); + else + rt2800_rfcsr_write(rt2x00dev, 61, 0xd5); + } else { + if (rt2x00_is_usb(rt2x00dev)) + rt2800_rfcsr_write(rt2x00dev, 61, 0xdd); + else + rt2800_rfcsr_write(rt2x00dev, 61, 0xb5); + } rt2800_rfcsr_write(rt2x00dev, 62, 0x00); rt2800_rfcsr_write(rt2x00dev, 63, 0x00); -- cgit v1.2.3-70-g09d2 From d94248ac2aef78e39a76321458a78ba7805dba2e Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 24 Oct 2013 18:33:33 +1100 Subject: libertas/sdio: make sure card enters power-off when firmware is loaded. Since firmware loading became async it is possible that if_sdio_finish_power_of is called with only one remaining runtime_pm reference, so it isn't safe to call pm_runtime_put_noidle. We must call pm_runtime_put(). Diagnosed-by: "Dr. H. Nikolaus Schaller" Signed-off-by: NeilBrown Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/if_sdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index 991238afd1b..828e7f4fc63 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -849,7 +849,7 @@ static void if_sdio_finish_power_on(struct if_sdio_card *card) card->started = true; /* Tell PM core that we don't need the card to be * powered now */ - pm_runtime_put_noidle(&func->dev); + pm_runtime_put(&func->dev); } } -- cgit v1.2.3-70-g09d2 From 60ce473e4938a42d355dd6c83e55211a08ebe25d Mon Sep 17 00:00:00 2001 From: Jing Wang Date: Thu, 24 Oct 2013 16:14:11 +0800 Subject: wl1251: return -ENOMEM if kzalloc fails the original code used goto out if kzalloc fails,but the out include kfree, so return -ENOMEM if kzalloc fails. Signed-off-by: Jing Wang Signed-off-by: John W. Linville --- drivers/net/wireless/ti/wl1251/acx.c | 209 ++++++++++++----------------------- 1 file changed, 68 insertions(+), 141 deletions(-) diff --git a/drivers/net/wireless/ti/wl1251/acx.c b/drivers/net/wireless/ti/wl1251/acx.c index db6430c1a08..374268d5ac6 100644 --- a/drivers/net/wireless/ti/wl1251/acx.c +++ b/drivers/net/wireless/ti/wl1251/acx.c @@ -18,10 +18,8 @@ int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod, wl1251_debug(DEBUG_ACX, "acx frame rates"); rates = kzalloc(sizeof(*rates), GFP_KERNEL); - if (!rates) { - ret = -ENOMEM; - goto out; - } + if (!rates) + return -ENOMEM; rates->tx_ctrl_frame_rate = ctrl_rate; rates->tx_ctrl_frame_mod = ctrl_mod; @@ -49,10 +47,8 @@ int wl1251_acx_station_id(struct wl1251 *wl) wl1251_debug(DEBUG_ACX, "acx dot11_station_id"); mac = kzalloc(sizeof(*mac), GFP_KERNEL); - if (!mac) { - ret = -ENOMEM; - goto out; - } + if (!mac) + return -ENOMEM; for (i = 0; i < ETH_ALEN; i++) mac->mac[i] = wl->mac_addr[ETH_ALEN - 1 - i]; @@ -74,10 +70,8 @@ int wl1251_acx_default_key(struct wl1251 *wl, u8 key_id) wl1251_debug(DEBUG_ACX, "acx dot11_default_key (%d)", key_id); default_key = kzalloc(sizeof(*default_key), GFP_KERNEL); - if (!default_key) { - ret = -ENOMEM; - goto out; - } + if (!default_key) + return -ENOMEM; default_key->id = key_id; @@ -104,10 +98,8 @@ int wl1251_acx_wake_up_conditions(struct wl1251 *wl, u8 wake_up_event, wl1251_debug(DEBUG_ACX, "acx wake up conditions"); wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL); - if (!wake_up) { - ret = -ENOMEM; - goto out; - } + if (!wake_up) + return -ENOMEM; wake_up->wake_up_event = wake_up_event; wake_up->listen_interval = listen_interval; @@ -132,16 +124,13 @@ int wl1251_acx_sleep_auth(struct wl1251 *wl, u8 sleep_auth) wl1251_debug(DEBUG_ACX, "acx sleep auth"); auth = kzalloc(sizeof(*auth), GFP_KERNEL); - if (!auth) { - ret = -ENOMEM; - goto out; - } + if (!auth) + return -ENOMEM; auth->sleep_auth = sleep_auth; ret = wl1251_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth)); -out: kfree(auth); return ret; } @@ -154,10 +143,8 @@ int wl1251_acx_fw_version(struct wl1251 *wl, char *buf, size_t len) wl1251_debug(DEBUG_ACX, "acx fw rev"); rev = kzalloc(sizeof(*rev), GFP_KERNEL); - if (!rev) { - ret = -ENOMEM; - goto out; - } + if (!rev) + return -ENOMEM; ret = wl1251_cmd_interrogate(wl, ACX_FW_REV, rev, sizeof(*rev)); if (ret < 0) { @@ -191,10 +178,8 @@ int wl1251_acx_tx_power(struct wl1251 *wl, int power) return -EINVAL; acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } + if (!acx) + return -ENOMEM; acx->current_tx_power = power * 10; @@ -217,10 +202,8 @@ int wl1251_acx_feature_cfg(struct wl1251 *wl) wl1251_debug(DEBUG_ACX, "acx feature cfg"); feature = kzalloc(sizeof(*feature), GFP_KERNEL); - if (!feature) { - ret = -ENOMEM; - goto out; - } + if (!feature) + return -ENOMEM; /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */ feature->data_flow_options = 0; @@ -261,10 +244,8 @@ int wl1251_acx_data_path_params(struct wl1251 *wl, wl1251_debug(DEBUG_ACX, "acx data path params"); params = kzalloc(sizeof(*params), GFP_KERNEL); - if (!params) { - ret = -ENOMEM; - goto out; - } + if (!params) + return -ENOMEM; params->rx_packet_ring_chunk_size = DP_RX_PACKET_RING_CHUNK_SIZE; params->tx_packet_ring_chunk_size = DP_TX_PACKET_RING_CHUNK_SIZE; @@ -309,10 +290,8 @@ int wl1251_acx_rx_msdu_life_time(struct wl1251 *wl, u32 life_time) wl1251_debug(DEBUG_ACX, "acx rx msdu life time"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } + if (!acx) + return -ENOMEM; acx->lifetime = life_time; ret = wl1251_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME, @@ -335,10 +314,8 @@ int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter) wl1251_debug(DEBUG_ACX, "acx rx config"); rx_config = kzalloc(sizeof(*rx_config), GFP_KERNEL); - if (!rx_config) { - ret = -ENOMEM; - goto out; - } + if (!rx_config) + return -ENOMEM; rx_config->config_options = config; rx_config->filter_options = filter; @@ -363,10 +340,8 @@ int wl1251_acx_pd_threshold(struct wl1251 *wl) wl1251_debug(DEBUG_ACX, "acx data pd threshold"); pd = kzalloc(sizeof(*pd), GFP_KERNEL); - if (!pd) { - ret = -ENOMEM; - goto out; - } + if (!pd) + return -ENOMEM; /* FIXME: threshold value not set */ @@ -389,10 +364,8 @@ int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time) wl1251_debug(DEBUG_ACX, "acx slot"); slot = kzalloc(sizeof(*slot), GFP_KERNEL); - if (!slot) { - ret = -ENOMEM; - goto out; - } + if (!slot) + return -ENOMEM; slot->wone_index = STATION_WONE_INDEX; slot->slot_time = slot_time; @@ -416,10 +389,8 @@ int wl1251_acx_group_address_tbl(struct wl1251 *wl) wl1251_debug(DEBUG_ACX, "acx group address tbl"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } + if (!acx) + return -ENOMEM; /* MAC filtering */ acx->enabled = 0; @@ -444,10 +415,8 @@ int wl1251_acx_service_period_timeout(struct wl1251 *wl) int ret; rx_timeout = kzalloc(sizeof(*rx_timeout), GFP_KERNEL); - if (!rx_timeout) { - ret = -ENOMEM; - goto out; - } + if (!rx_timeout) + return -ENOMEM; wl1251_debug(DEBUG_ACX, "acx service period timeout"); @@ -475,10 +444,8 @@ int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold) wl1251_debug(DEBUG_ACX, "acx rts threshold"); rts = kzalloc(sizeof(*rts), GFP_KERNEL); - if (!rts) { - ret = -ENOMEM; - goto out; - } + if (!rts) + return -ENOMEM; rts->threshold = rts_threshold; @@ -501,10 +468,8 @@ int wl1251_acx_beacon_filter_opt(struct wl1251 *wl, bool enable_filter) wl1251_debug(DEBUG_ACX, "acx beacon filter opt"); beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL); - if (!beacon_filter) { - ret = -ENOMEM; - goto out; - } + if (!beacon_filter) + return -ENOMEM; beacon_filter->enable = enable_filter; beacon_filter->max_num_beacons = 0; @@ -530,10 +495,8 @@ int wl1251_acx_beacon_filter_table(struct wl1251 *wl) wl1251_debug(DEBUG_ACX, "acx beacon filter table"); ie_table = kzalloc(sizeof(*ie_table), GFP_KERNEL); - if (!ie_table) { - ret = -ENOMEM; - goto out; - } + if (!ie_table) + return -ENOMEM; /* configure default beacon pass-through rules */ ie_table->num_ie = 1; @@ -560,10 +523,8 @@ int wl1251_acx_conn_monit_params(struct wl1251 *wl) wl1251_debug(DEBUG_ACX, "acx connection monitor parameters"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } + if (!acx) + return -ENOMEM; acx->synch_fail_thold = SYNCH_FAIL_DEFAULT_THRESHOLD; acx->bss_lose_timeout = NO_BEACON_DEFAULT_TIMEOUT; @@ -589,10 +550,8 @@ int wl1251_acx_sg_enable(struct wl1251 *wl) wl1251_debug(DEBUG_ACX, "acx sg enable"); pta = kzalloc(sizeof(*pta), GFP_KERNEL); - if (!pta) { - ret = -ENOMEM; - goto out; - } + if (!pta) + return -ENOMEM; pta->enable = SG_ENABLE; @@ -615,10 +574,8 @@ int wl1251_acx_sg_cfg(struct wl1251 *wl) wl1251_debug(DEBUG_ACX, "acx sg cfg"); param = kzalloc(sizeof(*param), GFP_KERNEL); - if (!param) { - ret = -ENOMEM; - goto out; - } + if (!param) + return -ENOMEM; /* BT-WLAN coext parameters */ param->min_rate = RATE_INDEX_24MBPS; @@ -669,10 +626,8 @@ int wl1251_acx_cca_threshold(struct wl1251 *wl) wl1251_debug(DEBUG_ACX, "acx cca threshold"); detection = kzalloc(sizeof(*detection), GFP_KERNEL); - if (!detection) { - ret = -ENOMEM; - goto out; - } + if (!detection) + return -ENOMEM; detection->rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D; detection->tx_energy_detection = 0; @@ -682,7 +637,6 @@ int wl1251_acx_cca_threshold(struct wl1251 *wl) if (ret < 0) wl1251_warning("failed to set cca threshold: %d", ret); -out: kfree(detection); return ret; } @@ -695,10 +649,8 @@ int wl1251_acx_bcn_dtim_options(struct wl1251 *wl) wl1251_debug(DEBUG_ACX, "acx bcn dtim options"); bb = kzalloc(sizeof(*bb), GFP_KERNEL); - if (!bb) { - ret = -ENOMEM; - goto out; - } + if (!bb) + return -ENOMEM; bb->beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE; bb->broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE; @@ -724,10 +676,8 @@ int wl1251_acx_aid(struct wl1251 *wl, u16 aid) wl1251_debug(DEBUG_ACX, "acx aid"); acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL); - if (!acx_aid) { - ret = -ENOMEM; - goto out; - } + if (!acx_aid) + return -ENOMEM; acx_aid->aid = aid; @@ -750,10 +700,8 @@ int wl1251_acx_event_mbox_mask(struct wl1251 *wl, u32 event_mask) wl1251_debug(DEBUG_ACX, "acx event mbox mask"); mask = kzalloc(sizeof(*mask), GFP_KERNEL); - if (!mask) { - ret = -ENOMEM; - goto out; - } + if (!mask) + return -ENOMEM; /* high event mask is unused */ mask->high_event_mask = 0xffffffff; @@ -805,10 +753,8 @@ int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble) wl1251_debug(DEBUG_ACX, "acx_set_preamble"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } + if (!acx) + return -ENOMEM; acx->preamble = preamble; @@ -832,10 +778,8 @@ int wl1251_acx_cts_protect(struct wl1251 *wl, wl1251_debug(DEBUG_ACX, "acx_set_ctsprotect"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } + if (!acx) + return -ENOMEM; acx->ctsprotect = ctsprotect; @@ -856,10 +800,8 @@ int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime) int ret; tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL); - if (!tsf_info) { - ret = -ENOMEM; - goto out; - } + if (!tsf_info) + return -ENOMEM; ret = wl1251_cmd_interrogate(wl, ACX_TSF_INFO, tsf_info, sizeof(*tsf_info)); @@ -900,11 +842,8 @@ int wl1251_acx_rate_policies(struct wl1251 *wl) wl1251_debug(DEBUG_ACX, "acx rate policies"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); - - if (!acx) { - ret = -ENOMEM; - goto out; - } + if (!acx) + return -ENOMEM; /* configure one default (one-size-fits-all) rate class */ acx->rate_class_cnt = 1; @@ -932,10 +871,8 @@ int wl1251_acx_mem_cfg(struct wl1251 *wl) wl1251_debug(DEBUG_ACX, "acx mem cfg"); mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); - if (!mem_conf) { - ret = -ENOMEM; - goto out; - } + if (!mem_conf) + return -ENOMEM; /* memory config */ mem_conf->mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS); @@ -979,10 +916,8 @@ int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim) wl1251_debug(DEBUG_ACX, "acx tbtt and dtim"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } + if (!acx) + return -ENOMEM; acx->tbtt = tbtt; acx->dtim = dtim; @@ -1008,10 +943,8 @@ int wl1251_acx_bet_enable(struct wl1251 *wl, enum wl1251_acx_bet_mode mode, wl1251_debug(DEBUG_ACX, "acx bet enable"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } + if (!acx) + return -ENOMEM; acx->enable = mode; acx->max_consecutive = max_consecutive; @@ -1037,11 +970,8 @@ int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max, "aifs %d txop %d", ac, cw_min, cw_max, aifs, txop); acx = kzalloc(sizeof(*acx), GFP_KERNEL); - - if (!acx) { - ret = -ENOMEM; - goto out; - } + if (!acx) + return -ENOMEM; acx->ac = ac; acx->cw_min = cw_min; @@ -1073,11 +1003,8 @@ int wl1251_acx_tid_cfg(struct wl1251 *wl, u8 queue, ps_scheme, ack_policy); acx = kzalloc(sizeof(*acx), GFP_KERNEL); - - if (!acx) { - ret = -ENOMEM; - goto out; - } + if (!acx) + return -ENOMEM; acx->queue = queue; acx->type = type; -- cgit v1.2.3-70-g09d2 From 5f5deff34e4f9339e1e18a5af92fb1b79233783f Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Fri, 25 Oct 2013 12:37:54 +0200 Subject: iwl3945: do not print RFKILL message We can mess logs if user space try to open device again and again if RFKILL switch is on. Do not print message and return ERFKILL error instead to indicate where the problem is. Note that iwl4965 handle this problem differently, it allows to open device when radio is disabled. Reported-by: Dietmar Rudolph Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville --- drivers/net/wireless/iwlegacy/3945-mac.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c index 5c3bcedd679..0487461ae4d 100644 --- a/drivers/net/wireless/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/iwlegacy/3945-mac.c @@ -2396,8 +2396,7 @@ __il3945_up(struct il_priv *il) clear_bit(S_RFKILL, &il->status); else { set_bit(S_RFKILL, &il->status); - IL_WARN("Radio disabled by HW RF Kill switch\n"); - return -ENODEV; + return -ERFKILL; } _il_wr(il, CSR_INT, 0xFFFFFFFF); -- cgit v1.2.3-70-g09d2 From 809c5255d87580d14ad746f059f73231d94b50a7 Mon Sep 17 00:00:00 2001 From: Solomon Peachy Date: Fri, 25 Oct 2013 18:15:42 -0400 Subject: cw1200: Make the "scan failed" message into a warning The reason that a scan failed for some reason (typically bad parameters) should be logged even when debugging is turned off. Signed-off-by: Solomon Peachy Signed-off-by: John W. Linville --- drivers/net/wireless/cw1200/scan.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/cw1200/scan.c b/drivers/net/wireless/cw1200/scan.c index 8c017bfd2ff..9afcd4ce336 100644 --- a/drivers/net/wireless/cw1200/scan.c +++ b/drivers/net/wireless/cw1200/scan.c @@ -173,8 +173,9 @@ void cw1200_scan_work(struct work_struct *work) cw1200_set_pm(priv, &priv->powersave_mode); if (priv->scan.status < 0) - wiphy_dbg(priv->hw->wiphy, "[SCAN] Scan failed (%d).\n", - priv->scan.status); + wiphy_warn(priv->hw->wiphy, + "[SCAN] Scan failed (%d).\n", + priv->scan.status); else if (priv->scan.req) wiphy_dbg(priv->hw->wiphy, "[SCAN] Scan completed.\n"); -- cgit v1.2.3-70-g09d2 From cf1ad8f94766a22b55f6515ac28b8edb0504e1d6 Mon Sep 17 00:00:00 2001 From: Solomon Peachy Date: Fri, 25 Oct 2013 18:15:43 -0400 Subject: wireless: cw1200: Use consistent internal locking conventions The cw1200_irq_handler() function expects the hwbus lock to be held when it is called. On the SDIO platform, this lock is implemented in terms of sdio_claim_host/sdio_release_host. This trivial patch makes it explicit that we are performing the hwbus lock rather than something SDIO-specific. Signed-off-by: Solomon Peachy Signed-off-by: John W. Linville --- drivers/net/wireless/cw1200/cw1200_sdio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/cw1200/cw1200_sdio.c b/drivers/net/wireless/cw1200/cw1200_sdio.c index ebdcdf44f15..d3acc85932a 100644 --- a/drivers/net/wireless/cw1200/cw1200_sdio.c +++ b/drivers/net/wireless/cw1200/cw1200_sdio.c @@ -108,9 +108,9 @@ static irqreturn_t cw1200_gpio_irq(int irq, void *dev_id) struct hwbus_priv *self = dev_id; if (self->core) { - sdio_claim_host(self->func); + cw1200_sdio_lock(self); cw1200_irq_handler(self->core); - sdio_release_host(self->func); + cw1200_sdio_unlock(self); return IRQ_HANDLED; } else { return IRQ_NONE; -- cgit v1.2.3-70-g09d2 From 685cc47174f730e68867d83b7db5e36283255e6d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 29 Oct 2013 19:34:25 +0100 Subject: brcm80211: fix usage of freq_reg_info() freq_reg_info() expects KHz and not MHz, fix this. In this case we'll now be getting the no-ir flags cleared on channels for any channel when the country IE trusts that channel. @@ struct ieee80211_channel *ch; struct wiphy *wiphy; const struct ieee80211_reg_rule *rule; @@ -rule = freq_reg_info(wiphy, ch->center_freq); +rule = freq_reg_info(wiphy, MHZ_TO_KHZ(ch->center_freq)); Generated-by: Coccinelle SmPL Cc: Julia Lawall Cc: Peter Senna Tschudin Cc: Seth Forshee Cc: Arend van Spriel Reported-by: Mihir Shete Signed-off-by: Luis R. Rodriguez Acked-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmsmac/channel.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/brcm80211/brcmsmac/channel.c index ef05df04136..635ae034c7e 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/channel.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.c @@ -679,7 +679,8 @@ brcms_reg_apply_beaconing_flags(struct wiphy *wiphy, continue; if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) { - rule = freq_reg_info(wiphy, ch->center_freq); + rule = freq_reg_info(wiphy, + MHZ_TO_KHZ(ch->center_freq)); if (IS_ERR(rule)) continue; -- cgit v1.2.3-70-g09d2 From 856a4ef9f01e9f4b42c96dd70268f4864a93f72c Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 29 Oct 2013 19:34:26 +0100 Subject: rtlwifi: fix usage of freq_reg_info() freq_reg_info() expects KHz and not MHz, fix this. In this case we'll now be getting the no-ir flags cleared on channels for any channel when the country IE trusts that channel. @@ struct ieee80211_channel *ch; struct wiphy *wiphy; const struct ieee80211_reg_rule *rule; @@ -rule = freq_reg_info(wiphy, ch->center_freq); +rule = freq_reg_info(wiphy, MHZ_TO_KHZ(ch->center_freq)); Generated-by: Coccinelle SmPL Cc: Julia Lawall Cc: Peter Senna Tschudin Cc: Larry Finger Reported-by: Mihir Shete Signed-off-by: Luis R. Rodriguez Acked-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/regd.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/regd.c b/drivers/net/wireless/rtlwifi/regd.c index 89e36568e70..a4eb9b27143 100644 --- a/drivers/net/wireless/rtlwifi/regd.c +++ b/drivers/net/wireless/rtlwifi/regd.c @@ -168,7 +168,8 @@ static void _rtl_reg_apply_beaconing_flags(struct wiphy *wiphy, (ch->flags & IEEE80211_CHAN_RADAR)) continue; if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) { - reg_rule = freq_reg_info(wiphy, ch->center_freq); + reg_rule = freq_reg_info(wiphy, + MHZ_TO_KHZ(ch->center_freq)); if (IS_ERR(reg_rule)) continue; @@ -226,7 +227,7 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy, */ ch = &sband->channels[11]; /* CH 12 */ - reg_rule = freq_reg_info(wiphy, ch->center_freq); + reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(ch->center_freq)); if (!IS_ERR(reg_rule)) { if (!(reg_rule->flags & NL80211_RRF_NO_IR)) if (ch->flags & IEEE80211_CHAN_NO_IR) @@ -234,7 +235,7 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy, } ch = &sband->channels[12]; /* CH 13 */ - reg_rule = freq_reg_info(wiphy, ch->center_freq); + reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(ch->center_freq)); if (!IS_ERR(reg_rule)) { if (!(reg_rule->flags & NL80211_RRF_NO_IR)) if (ch->flags & IEEE80211_CHAN_NO_IR) -- cgit v1.2.3-70-g09d2 From 9b0fa73d1e85b4e4aa6b5281e4438b5180d261bb Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 29 Oct 2013 17:06:41 -0500 Subject: rtl8187: Increase RX queue depth Under heavy load, the relatively small number of RX queue entries are completely filled. With an increase from 16 to 32 entries, this condition rarely happens. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8187/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/rtl818x/rtl8187/dev.c b/drivers/net/wireless/rtl818x/rtl8187/dev.c index 9a6edb0c014..ec9aa5b6738 100644 --- a/drivers/net/wireless/rtl818x/rtl8187/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187/dev.c @@ -416,7 +416,7 @@ static int rtl8187_init_urbs(struct ieee80211_hw *dev) struct rtl8187_rx_info *info; int ret = 0; - while (skb_queue_len(&priv->rx_queue) < 16) { + while (skb_queue_len(&priv->rx_queue) < 32) { skb = __dev_alloc_skb(RTL8187_MAX_RX, GFP_KERNEL); if (!skb) { ret = -ENOMEM; -- cgit v1.2.3-70-g09d2 From b3e3f87160c1654e0478d0cb52e5e9b8790535f2 Mon Sep 17 00:00:00 2001 From: Chun-Yeow Yeoh Date: Thu, 31 Oct 2013 14:07:45 +0800 Subject: wcn36xx: enable beacon change using BSS_CHANGED_BEACON Enable the beacon changed using BSS_CHANGED_BEACON. This is especially useful for mesh mode. Signed-off-by: Chun-Yeow Yeoh Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wcn36xx/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 7839b31e482..e64a6784079 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -641,7 +641,8 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, dev_kfree_skb(skb); } - if (changed & BSS_CHANGED_BEACON_ENABLED) { + if (changed & BSS_CHANGED_BEACON_ENABLED || + changed & BSS_CHANGED_BEACON) { wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss changed beacon enabled %d\n", bss_conf->enable_beacon); -- cgit v1.2.3-70-g09d2 From 684e55f53ec0fda8933f2caeb439e4f7a803002a Mon Sep 17 00:00:00 2001 From: Eugene Krasnikov Date: Fri, 8 Nov 2013 17:34:39 +0000 Subject: wcn36xx: Fix logging macro with unnecessary semicolon The wcn36xx_err macro should not end in a semicolon as there are 2 consecutive semicolons in the preprocessed output. Signed-off-by: Joe Perches Signed-off-by: Eugene Krasnikov Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wcn36xx/wcn36xx.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h index 58b63833e8e..8fa5cbace5a 100644 --- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h +++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h @@ -54,7 +54,7 @@ enum wcn36xx_debug_mask { }; #define wcn36xx_err(fmt, arg...) \ - printk(KERN_ERR pr_fmt("ERROR " fmt), ##arg); + printk(KERN_ERR pr_fmt("ERROR " fmt), ##arg) #define wcn36xx_warn(fmt, arg...) \ printk(KERN_WARNING pr_fmt("WARNING " fmt), ##arg) -- cgit v1.2.3-70-g09d2 From dc14b02c0dd87ca7bbb9d566ac209e4aaedddad5 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 12 Nov 2013 11:02:20 -0600 Subject: rtlwifi: Remove unused calls to rtl_is_special_data() When routine rtl_is_special_data() is called with false as its last argument, and the returned value is not tested, the call is essentially an extended no-op. Accordingly, these calls may be removed. Signed-off-by: Larry Finger Reported-by: Mark Cave-Ayland Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/pci.c | 2 -- drivers/net/wireless/rtlwifi/usb.c | 4 ---- 2 files changed, 6 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index 0f494444bcd..8707d1a9499 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -688,8 +688,6 @@ static void _rtl_receive_one(struct ieee80211_hw *hw, struct sk_buff *skb, rtlpriv->stats.rxbytesunicast += skb->len; } - rtl_is_special_data(hw, skb, false); - if (ieee80211_is_data(fc)) { rtlpriv->cfg->ops->led_control(hw, LED_CTL_RX); diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index 6e2b5c5c83c..ec385e46d56 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -475,8 +475,6 @@ static void _rtl_usb_rx_process_agg(struct ieee80211_hw *hw, rtlpriv->stats.rxbytesunicast += skb->len; } - rtl_is_special_data(hw, skb, false); - if (ieee80211_is_data(fc)) { rtlpriv->cfg->ops->led_control(hw, LED_CTL_RX); @@ -517,8 +515,6 @@ static void _rtl_usb_rx_process_noagg(struct ieee80211_hw *hw, rtlpriv->stats.rxbytesunicast += skb->len; } - rtl_is_special_data(hw, skb, false); - if (ieee80211_is_data(fc)) { rtlpriv->cfg->ops->led_control(hw, LED_CTL_RX); -- cgit v1.2.3-70-g09d2 From ac0ef8139bc4f6493b6bb560bfeb31b883b7e8ae Mon Sep 17 00:00:00 2001 From: Kevin Lo Date: Thu, 14 Nov 2013 13:53:44 +0800 Subject: rt2x00: rt2800lib: no need to write RF register 3 twice for RT5592 In rt2800_init_rfcsr_5592(), there's no need to write RF register 3 twice. Signed-off-by: Kevin Lo Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 7848b39078c..5ee5b296ad2 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -6610,7 +6610,6 @@ static void rt2800_init_rfcsr_5592(struct rt2x00_dev *rt2x00dev) rt2800_rfcsr_write(rt2x00dev, 1, 0x3F); rt2800_rfcsr_write(rt2x00dev, 3, 0x08); - rt2800_rfcsr_write(rt2x00dev, 3, 0x08); rt2800_rfcsr_write(rt2x00dev, 5, 0x10); rt2800_rfcsr_write(rt2x00dev, 6, 0xE4); rt2800_rfcsr_write(rt2x00dev, 7, 0x00); -- cgit v1.2.3-70-g09d2 From 8fd77aec1a9d6f4328fc0244f21932114e066df3 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 18 Nov 2013 11:11:25 -0600 Subject: rtlwifi: rtl8192c: Prevent reconnect attempts if not connected This driver has a watchdog timer that attempts to reconnect when beacon frames are not seen for 6 seconds. This patch disables that reconnect whenever the device has never been connected. Signed-off-by: Larry Finger Cc: Stable Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/base.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index ff784072fb4..fcf9b621918 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c @@ -1437,7 +1437,8 @@ void rtl_watchdog_wq_callback(void *data) /* if we can't recv beacon for 6s, we should * reconnect this AP */ - if (rtlpriv->link_info.roam_times >= 3) { + if ((rtlpriv->link_info.roam_times >= 3) && + !is_zero_ether_addr(rtlpriv->mac80211.bssid)) { RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "AP off, try to reconnect now\n"); rtlpriv->link_info.roam_times = 0; -- cgit v1.2.3-70-g09d2 From 62009b7f12793c932aaba0df946b04cb4a77d022 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 18 Nov 2013 11:11:26 -0600 Subject: rtlwifi: rtl8192cu: Add new firmware Vendor driver rtl8188C_8192C_8192D_usb_linux_v3.4.2_3727.20120404 introduced new firmware for these chips. The code try for the new file, and fall back to the original firmware if the new file is not available. Signed-off-by: Larry Finger Cc: Stable Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/core.c | 10 ++++++++++ drivers/net/wireless/rtlwifi/rtl8192cu/sw.c | 16 +++++++++++++--- drivers/net/wireless/rtlwifi/wifi.h | 1 + 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index 210ce7cd94d..8dc4d930859 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c @@ -46,10 +46,20 @@ void rtl_fw_cb(const struct firmware *firmware, void *context) "Firmware callback routine entered!\n"); complete(&rtlpriv->firmware_loading_complete); if (!firmware) { + if (rtlpriv->cfg->alt_fw_name) { + err = request_firmware(&firmware, + rtlpriv->cfg->alt_fw_name, + rtlpriv->io.dev); + pr_info("Loading alternative firmware %s\n", + rtlpriv->cfg->alt_fw_name); + if (!err) + goto found_alt; + } pr_err("Firmware %s not available\n", rtlpriv->cfg->fw_name); rtlpriv->max_fw_size = 0; return; } +found_alt: if (firmware->size > rtlpriv->max_fw_size) { RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Firmware is too big!\n"); diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c index 9936de716ad..8501954cfb4 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c @@ -50,6 +50,9 @@ MODULE_AUTHOR("Larry Finger "); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Realtek 8192C/8188C 802.11n USB wireless"); MODULE_FIRMWARE("rtlwifi/rtl8192cufw.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8192cufw_A.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8192cufw_B.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8192cufw_TMSC.bin"); static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw) { @@ -69,14 +72,21 @@ static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw) "Can't alloc buffer for fw\n"); return 1; } - + if (IS_VENDOR_UMC_A_CUT(rtlpriv->rtlhal.version) && + !IS_92C_SERIAL(rtlpriv->rtlhal.version)) { + rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cufw_A.bin"; + } else if (IS_81xxC_VENDOR_UMC_B_CUT(rtlpriv->rtlhal.version)) { + rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cufw_B.bin"; + } else { + rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cufw_TMSC.bin"; + } + /* provide name of alternative file */ + rtlpriv->cfg->alt_fw_name = "rtlwifi/rtl8192cufw.bin"; pr_info("Loading firmware %s\n", rtlpriv->cfg->fw_name); rtlpriv->max_fw_size = 0x4000; err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name, rtlpriv->io.dev, GFP_KERNEL, hw, rtl_fw_cb); - - return err; } diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 0c65386fa30..0aa89fd89f3 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -1804,6 +1804,7 @@ struct rtl_hal_cfg { bool write_readback; char *name; char *fw_name; + char *alt_fw_name; struct rtl_hal_ops *ops; struct rtl_mod_params *mod_params; struct rtl_hal_usbint_cfg *usb_interface_cfg; -- cgit v1.2.3-70-g09d2 From b9a758a8c905fc59e783ae91ad645452d877ea88 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 18 Nov 2013 11:11:27 -0600 Subject: rtlwifi: Redo register save locations The initial USB driver did not use some register save locations in the private data storage. To save some memory, a union was used to overlay these variables with USB I/O components. In an update of the gain-control code, these register save locations are now needed for USB drivers. Signed-off-by: Larry Finger Cc: Stable Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/wifi.h | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 0aa89fd89f3..8c647391bed 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -1033,6 +1033,7 @@ struct rtl_ht_agg { struct rssi_sta { long undec_sm_pwdb; + long undec_sm_cck; }; struct rtl_tid_data { @@ -1323,8 +1324,10 @@ struct fast_ant_training { struct rtl_dm { /*PHY status for Dynamic Management */ long entry_min_undec_sm_pwdb; + long undec_sm_cck; long undec_sm_pwdb; /*out dm */ long entry_max_undec_sm_pwdb; + s32 ofdm_pkt_cnt; bool dm_initialgain_enable; bool dynamic_txpower_enable; bool current_turbo_edca; @@ -1339,6 +1342,7 @@ struct rtl_dm { bool inform_fw_driverctrldm; bool current_mrc_switch; u8 txpowercount; + u8 powerindex_backup[6]; u8 thermalvalue_rxgain; u8 thermalvalue_iqk; @@ -1350,7 +1354,9 @@ struct rtl_dm { bool done_txpower; u8 dynamic_txhighpower_lvl; /*Tx high power level */ u8 dm_flag; /*Indicate each dynamic mechanism's status. */ + u8 dm_flag_tmp; u8 dm_type; + u8 dm_rssi_sel; u8 txpower_track_control; bool interrupt_migration; bool disable_tx_int; @@ -1949,6 +1955,7 @@ struct dig_t { u8 pre_ccastate; u8 cur_ccasate; u8 large_fa_hit; + u8 dig_dynamic_min; u8 forbidden_igi; u8 dig_state; u8 dig_highpwrstate; @@ -2029,22 +2036,15 @@ struct rtl_priv { struct dig_t dm_digtable; struct ps_t dm_pstable; - /* section shared by individual drivers */ - union { - struct { /* data buffer pointer for USB reads */ - __le32 *usb_data; - int usb_data_index; - bool initialized; - }; - struct { /* section for 8723ae */ - bool reg_init; /* true if regs saved */ - u32 reg_874; - u32 reg_c70; - u32 reg_85c; - u32 reg_a74; - bool bt_operation_on; - }; - }; + u32 reg_874; + u32 reg_c70; + u32 reg_85c; + u32 reg_a74; + bool reg_init; /* true if regs saved */ + bool bt_operation_on; + __le32 *usb_data; + int usb_data_index; + bool initialized; bool enter_ps; /* true when entering PS */ u8 rate_mask[5]; -- cgit v1.2.3-70-g09d2 From 619ce76f8bb850b57032501a39f26aa6c6731c70 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 18 Nov 2013 11:11:28 -0600 Subject: rtlwifi: Set the link state The present code fails to set the linked state when an interface is added. Signed-off-by: Larry Finger Cc: Stable Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index 8dc4d930859..2d337a0c3df 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c @@ -194,6 +194,7 @@ static int rtl_op_add_interface(struct ieee80211_hw *hw, rtlpriv->cfg->maps [RTL_IBSS_INT_MASKS]); } + mac->link_state = MAC80211_LINKED; break; case NL80211_IFTYPE_ADHOC: RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, -- cgit v1.2.3-70-g09d2 From c908c74e005de780fddbe8cb6fcd44803f5d4b74 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 18 Nov 2013 11:11:29 -0600 Subject: rtlwifi: rtl8192c: Add new definitions in the dm_common header Changes in the gain-control mechanism will require some changes in the header. Signed-off-by: Larry Finger Cc: Stable Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h index 518e208c018..4f232a06363 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h +++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h @@ -91,6 +91,17 @@ #define TX_POWER_NEAR_FIELD_THRESH_LVL2 74 #define TX_POWER_NEAR_FIELD_THRESH_LVL1 67 +#define DYNAMIC_FUNC_DISABLE 0x0 +#define DYNAMIC_FUNC_DIG BIT(0) +#define DYNAMIC_FUNC_HP BIT(1) +#define DYNAMIC_FUNC_SS BIT(2) /*Tx Power Tracking*/ +#define DYNAMIC_FUNC_BT BIT(3) +#define DYNAMIC_FUNC_ANT_DIV BIT(4) + +#define RSSI_CCK 0 +#define RSSI_OFDM 1 +#define RSSI_DEFAULT 2 + struct swat_t { u8 failure_cnt; u8 try_flag; @@ -167,5 +178,8 @@ void rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw); void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery); void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw); void rtl92c_dm_bt_coexist(struct ieee80211_hw *hw); +void dm_savepowerindex(struct ieee80211_hw *hw); +void dm_writepowerindex(struct ieee80211_hw *hw, u8 value); +void dm_restorepowerindex(struct ieee80211_hw *hw); #endif -- cgit v1.2.3-70-g09d2 From dc6405712268fe514d3dd89aa936c4397b0871b9 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 18 Nov 2013 11:11:30 -0600 Subject: rtlwifi: Increase the RX queue length for USB drivers The current number of RX buffers queued is 32, which is too small under heavy load. That number is doubled. Signed-off-by: Larry Finger Cc: Stable Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index ec385e46d56..767b6832bbd 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -549,7 +549,7 @@ static void _rtl_rx_pre_process(struct ieee80211_hw *hw, struct sk_buff *skb) } } -#define __RX_SKB_MAX_QUEUED 32 +#define __RX_SKB_MAX_QUEUED 64 static void _rtl_rx_work(unsigned long param) { -- cgit v1.2.3-70-g09d2 From 65b9cc97c6852fae19dc5c7745e9abc8dd380aad Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 18 Nov 2013 11:11:31 -0600 Subject: rtlwifi: Update beacon statistics for USB driver The USB drivers were not updating the beacon statistics, which led to false beacon loss indications. Signed-off-by: Larry Finger Cc: Stable Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/usb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index 767b6832bbd..4933f02ce1d 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -481,6 +481,8 @@ static void _rtl_usb_rx_process_agg(struct ieee80211_hw *hw, if (unicast) rtlpriv->link_info.num_rx_inperiod++; } + /* static bcn for roaming */ + rtl_beacon_statistic(hw, skb); } } -- cgit v1.2.3-70-g09d2 From 97204e93f01868eeba6ae5c4f3270f32905bb418 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 18 Nov 2013 11:11:32 -0600 Subject: rtlwifi: rtl8192c: Add routines to save/restore power index registers Signed-off-by: Larry Finger Cc: Stable Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c | 36 +++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c index e9caa5d4cff..9fc4b64d6bf 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c @@ -158,6 +158,42 @@ static const u8 cckswing_table_ch14[CCK_TABLE_SIZE][8] = { {0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00} }; +static u32 power_index_reg[6] = {0xc90, 0xc91, 0xc92, 0xc98, 0xc99, 0xc9a}; + +void dm_restorepowerindex(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 index; + + for (index = 0; index < 6; index++) + rtl_write_byte(rtlpriv, power_index_reg[index], + rtlpriv->dm.powerindex_backup[index]); +} +EXPORT_SYMBOL_GPL(dm_restorepowerindex); + +void dm_writepowerindex(struct ieee80211_hw *hw, u8 value) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 index; + + for (index = 0; index < 6; index++) + rtl_write_byte(rtlpriv, power_index_reg[index], value); +} +EXPORT_SYMBOL_GPL(dm_writepowerindex); + +void dm_savepowerindex(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 index; + u8 tmp; + + for (index = 0; index < 6; index++) { + tmp = rtl_read_byte(rtlpriv, power_index_reg[index]); + rtlpriv->dm.powerindex_backup[index] = tmp; + } +} +EXPORT_SYMBOL_GPL(dm_savepowerindex); + static void rtl92c_dm_diginit(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); -- cgit v1.2.3-70-g09d2 From 9806eacf5de27ab01d680c5d75c92a3a89734e4f Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 18 Nov 2013 11:11:33 -0600 Subject: rtlwifi: rtl8192cu: Update the power index registers This patch uses the newly introduced power index register routines. Signed-off-by: Larry Finger Cc: Stable Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8192cu/dm.c | 9 +++++++++ drivers/net/wireless/rtlwifi/rtl8192cu/dm.h | 3 +++ 2 files changed, 12 insertions(+) diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/dm.c b/drivers/net/wireless/rtlwifi/rtl8192cu/dm.c index 16a0b9e59ac..c16209a336e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/dm.c @@ -101,6 +101,15 @@ void rtl92cu_dm_dynamic_txpower(struct ieee80211_hw *hw) "PHY_SetTxPowerLevel8192S() Channel = %d\n", rtlphy->current_channel); rtl92c_phy_set_txpower_level(hw, rtlphy->current_channel); + if (rtlpriv->dm.dynamic_txhighpower_lvl == + TXHIGHPWRLEVEL_NORMAL) + dm_restorepowerindex(hw); + else if (rtlpriv->dm.dynamic_txhighpower_lvl == + TXHIGHPWRLEVEL_LEVEL1) + dm_writepowerindex(hw, 0x14); + else if (rtlpriv->dm.dynamic_txhighpower_lvl == + TXHIGHPWRLEVEL_LEVEL2) + dm_writepowerindex(hw, 0x10); } rtlpriv->dm.last_dtp_lvl = rtlpriv->dm.dynamic_txhighpower_lvl; diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/dm.h b/drivers/net/wireless/rtlwifi/rtl8192cu/dm.h index d947e7d350b..fafa6bac2a3 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/dm.h +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/dm.h @@ -30,3 +30,6 @@ #include "../rtl8192ce/dm.h" void rtl92cu_dm_dynamic_txpower(struct ieee80211_hw *hw); +void dm_savepowerindex(struct ieee80211_hw *hw); +void dm_writepowerindex(struct ieee80211_hw *hw, u8 value); +void dm_restorepowerindex(struct ieee80211_hw *hw); -- cgit v1.2.3-70-g09d2 From e9b0784bb9de3152e787ee779868c626b137fb3b Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 18 Nov 2013 11:11:34 -0600 Subject: rtlwifi: rtl8192cu: Fix some code in RF handling Signed-off-by: Larry Finger Cc: Stable Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8192cu/rf.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c index 2119313a737..b878d56d2f4 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c @@ -85,17 +85,15 @@ void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, if (mac->act_scanning) { tx_agc[RF90_PATH_A] = 0x3f3f3f3f; tx_agc[RF90_PATH_B] = 0x3f3f3f3f; - if (turbo_scanoff) { - for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) { - tx_agc[idx1] = ppowerlevel[idx1] | - (ppowerlevel[idx1] << 8) | - (ppowerlevel[idx1] << 16) | - (ppowerlevel[idx1] << 24); - if (rtlhal->interface == INTF_USB) { - if (tx_agc[idx1] > 0x20 && - rtlefuse->external_pa) - tx_agc[idx1] = 0x20; - } + for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) { + tx_agc[idx1] = ppowerlevel[idx1] | + (ppowerlevel[idx1] << 8) | + (ppowerlevel[idx1] << 16) | + (ppowerlevel[idx1] << 24); + if (rtlhal->interface == INTF_USB) { + if (tx_agc[idx1] > 0x20 && + rtlefuse->external_pa) + tx_agc[idx1] = 0x20; } } } else { @@ -107,7 +105,7 @@ void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, TXHIGHPWRLEVEL_LEVEL2) { tx_agc[RF90_PATH_A] = 0x00000000; tx_agc[RF90_PATH_B] = 0x00000000; - } else{ + } else { for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) { tx_agc[idx1] = ppowerlevel[idx1] | (ppowerlevel[idx1] << 8) | @@ -373,7 +371,12 @@ static void _rtl92c_write_ofdm_power_reg(struct ieee80211_hw *hw, regoffset == RTXAGC_B_MCS07_MCS04) regoffset = 0xc98; for (i = 0; i < 3; i++) { - writeVal = (writeVal > 6) ? (writeVal - 6) : 0; + if (i != 2) + writeVal = (writeVal > 8) ? + (writeVal - 8) : 0; + else + writeVal = (writeVal > 6) ? + (writeVal - 6) : 0; rtl_write_byte(rtlpriv, (u32)(regoffset + i), (u8)writeVal); } -- cgit v1.2.3-70-g09d2 From d82403a9f407217b6aed5260aa92a120e8e98310 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 18 Nov 2013 11:11:35 -0600 Subject: rtlwifi: Add missing code to PWDB statics routine Signed-off-by: Larry Finger Cc: Stable Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/stats.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/net/wireless/rtlwifi/stats.c b/drivers/net/wireless/rtlwifi/stats.c index 8ed31744a05..4f083fc1d36 100644 --- a/drivers/net/wireless/rtlwifi/stats.c +++ b/drivers/net/wireless/rtlwifi/stats.c @@ -176,6 +176,7 @@ static void rtl_process_pwdb(struct ieee80211_hw *hw, struct rtl_stats *pstatus) struct rtl_sta_info *drv_priv = NULL; struct ieee80211_sta *sta = NULL; long undec_sm_pwdb; + long undec_sm_cck; rcu_read_lock(); if (rtlpriv->mac80211.opmode != NL80211_IFTYPE_STATION) @@ -185,12 +186,16 @@ static void rtl_process_pwdb(struct ieee80211_hw *hw, struct rtl_stats *pstatus) if (sta) { drv_priv = (struct rtl_sta_info *) sta->drv_priv; undec_sm_pwdb = drv_priv->rssi_stat.undec_sm_pwdb; + undec_sm_cck = drv_priv->rssi_stat.undec_sm_cck; } else { undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb; + undec_sm_cck = rtlpriv->dm.undec_sm_cck; } if (undec_sm_pwdb < 0) undec_sm_pwdb = pstatus->rx_pwdb_all; + if (undec_sm_cck < 0) + undec_sm_cck = pstatus->rx_pwdb_all; if (pstatus->rx_pwdb_all > (u32) undec_sm_pwdb) { undec_sm_pwdb = (((undec_sm_pwdb) * (RX_SMOOTH_FACTOR - 1)) + @@ -200,6 +205,15 @@ static void rtl_process_pwdb(struct ieee80211_hw *hw, struct rtl_stats *pstatus) undec_sm_pwdb = (((undec_sm_pwdb) * (RX_SMOOTH_FACTOR - 1)) + (pstatus->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); } + if (pstatus->rx_pwdb_all > (u32) undec_sm_cck) { + undec_sm_cck = (((undec_sm_pwdb) * + (RX_SMOOTH_FACTOR - 1)) + + (pstatus->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); + undec_sm_cck = undec_sm_cck + 1; + } else { + undec_sm_pwdb = (((undec_sm_cck) * (RX_SMOOTH_FACTOR - 1)) + + (pstatus->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); + } if (sta) { drv_priv->rssi_stat.undec_sm_pwdb = undec_sm_pwdb; -- cgit v1.2.3-70-g09d2 From 796e453436b183057e2d7d9b2bcff88d0bf53ba7 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 18 Nov 2013 11:11:36 -0600 Subject: rtlwifi: rtl8192c: Update dynamic gain calculations The vendor driver contained a number of improvements in the gain settings for the rtl8192c{e,u} devices. This patch implements them in the kernel driver. Signed-off-by: Larry Finger Cc: Stable Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c | 291 ++++++++++++++-------- 1 file changed, 193 insertions(+), 98 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c index 9fc4b64d6bf..fd7e4a7c94d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c @@ -216,7 +216,12 @@ static void rtl92c_dm_diginit(struct ieee80211_hw *hw) dm_digtable->back_range_max = DM_DIG_BACKOFF_MAX; dm_digtable->back_range_min = DM_DIG_BACKOFF_MIN; dm_digtable->pre_cck_pd_state = CCK_PD_STAGE_MAX; - dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_MAX; + dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_LowRssi; + + dm_digtable->forbidden_igi = DM_DIG_MIN; + dm_digtable->large_fa_hit = 0; + dm_digtable->recover_cnt = 0; + dm_digtable->dig_dynamic_min = 0x25; } static u8 rtl92c_dm_initial_gain_min_pwdb(struct ieee80211_hw *hw) @@ -242,7 +247,9 @@ static u8 rtl92c_dm_initial_gain_min_pwdb(struct ieee80211_hw *hw) rssi_val_min = rtlpriv->dm.entry_min_undec_sm_pwdb; } - return (u8) rssi_val_min; + if (rssi_val_min > 100) + rssi_val_min = 100; + return (u8)rssi_val_min; } static void rtl92c_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw) @@ -260,9 +267,17 @@ static void rtl92c_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw) ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER3, MASKDWORD); falsealm_cnt->cnt_mcs_fail = (ret_value & 0xffff); + + ret_value = rtl_get_bbreg(hw, ROFDM0_FRAMESYNC, MASKDWORD); + falsealm_cnt->cnt_fast_fsync_fail = (ret_value & 0xffff); + falsealm_cnt->cnt_sb_search_fail = ((ret_value & 0xffff0000) >> 16); + falsealm_cnt->cnt_ofdm_fail = falsealm_cnt->cnt_parity_fail + - falsealm_cnt->cnt_rate_illegal + - falsealm_cnt->cnt_crc8_fail + falsealm_cnt->cnt_mcs_fail; + falsealm_cnt->cnt_rate_illegal + + falsealm_cnt->cnt_crc8_fail + + falsealm_cnt->cnt_mcs_fail + + falsealm_cnt->cnt_fast_fsync_fail + + falsealm_cnt->cnt_sb_search_fail; rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, BIT(14), 1); ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERLOWER, MASKBYTE0); @@ -307,12 +322,14 @@ static void rtl92c_dm_ctrl_initgain_by_fa(struct ieee80211_hw *hw) value_igi++; else if (rtlpriv->falsealm_cnt.cnt_all >= DM_DIG_FA_TH2) value_igi += 2; + if (value_igi > DM_DIG_FA_UPPER) value_igi = DM_DIG_FA_UPPER; else if (value_igi < DM_DIG_FA_LOWER) value_igi = DM_DIG_FA_LOWER; + if (rtlpriv->falsealm_cnt.cnt_all > 10000) - value_igi = 0x32; + value_igi = DM_DIG_FA_UPPER; dm_digtable->cur_igvalue = value_igi; rtl92c_dm_write_dig(hw); @@ -322,32 +339,80 @@ static void rtl92c_dm_ctrl_initgain_by_rssi(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct dig_t *digtable = &rtlpriv->dm_digtable; + u32 isbt; + + /* modify DIG lower bound, deal with abnorally large false alarm */ + if (rtlpriv->falsealm_cnt.cnt_all > 10000) { + digtable->large_fa_hit++; + if (digtable->forbidden_igi < digtable->cur_igvalue) { + digtable->forbidden_igi = digtable->cur_igvalue; + digtable->large_fa_hit = 1; + } - if (rtlpriv->falsealm_cnt.cnt_all > digtable->fa_highthresh) { - if ((digtable->back_val - 2) < digtable->back_range_min) - digtable->back_val = digtable->back_range_min; - else - digtable->back_val -= 2; - } else if (rtlpriv->falsealm_cnt.cnt_all < digtable->fa_lowthresh) { - if ((digtable->back_val + 2) > digtable->back_range_max) - digtable->back_val = digtable->back_range_max; - else - digtable->back_val += 2; + if (digtable->large_fa_hit >= 3) { + if ((digtable->forbidden_igi + 1) > + digtable->rx_gain_max) + digtable->rx_gain_min = digtable->rx_gain_max; + else + digtable->rx_gain_min = (digtable->forbidden_igi + 1); + digtable->recover_cnt = 3600; /* 3600=2hr */ + } + } else { + /* Recovery mechanism for IGI lower bound */ + if (digtable->recover_cnt != 0) { + digtable->recover_cnt--; + } else { + if (digtable->large_fa_hit == 0) { + if ((digtable->forbidden_igi-1) < DM_DIG_MIN) { + digtable->forbidden_igi = DM_DIG_MIN; + digtable->rx_gain_min = DM_DIG_MIN; + } else { + digtable->forbidden_igi--; + digtable->rx_gain_min = digtable->forbidden_igi + 1; + } + } else if (digtable->large_fa_hit == 3) { + digtable->large_fa_hit = 0; + } + } + } + if (rtlpriv->falsealm_cnt.cnt_all < 250) { + isbt = rtl_read_byte(rtlpriv, 0x4fd) & 0x01; + + if (!isbt) { + if (rtlpriv->falsealm_cnt.cnt_all > + digtable->fa_lowthresh) { + if ((digtable->back_val - 2) < + digtable->back_range_min) + digtable->back_val = digtable->back_range_min; + else + digtable->back_val -= 2; + } else if (rtlpriv->falsealm_cnt.cnt_all < + digtable->fa_lowthresh) { + if ((digtable->back_val + 2) > + digtable->back_range_max) + digtable->back_val = digtable->back_range_max; + else + digtable->back_val += 2; + } + } else { + digtable->back_val = DM_DIG_BACKOFF_DEFAULT; + } + } else { + /* Adjust initial gain by false alarm */ + if (rtlpriv->falsealm_cnt.cnt_all > 1000) + digtable->cur_igvalue = digtable->pre_igvalue + 2; + else if (rtlpriv->falsealm_cnt.cnt_all > 750) + digtable->cur_igvalue = digtable->pre_igvalue + 1; + else if (rtlpriv->falsealm_cnt.cnt_all < 500) + digtable->cur_igvalue = digtable->pre_igvalue - 1; } - if ((digtable->rssi_val_min + 10 - digtable->back_val) > - digtable->rx_gain_max) + /* Check initial gain by upper/lower bound */ + if (digtable->cur_igvalue > digtable->rx_gain_max) digtable->cur_igvalue = digtable->rx_gain_max; - else if ((digtable->rssi_val_min + 10 - - digtable->back_val) < digtable->rx_gain_min) - digtable->cur_igvalue = digtable->rx_gain_min; - else - digtable->cur_igvalue = digtable->rssi_val_min + 10 - - digtable->back_val; - RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, - "rssi_val_min = %x back_val %x\n", - digtable->rssi_val_min, digtable->back_val); + if (digtable->cur_igvalue < digtable->rx_gain_min) + digtable->cur_igvalue = digtable->rx_gain_min; rtl92c_dm_write_dig(hw); } @@ -365,7 +430,7 @@ static void rtl92c_dm_initial_gain_multi_sta(struct ieee80211_hw *hw) multi_sta = true; if (!multi_sta || - dm_digtable->cursta_cstate != DIG_STA_DISCONNECT) { + dm_digtable->cursta_cstate == DIG_STA_DISCONNECT) { initialized = false; dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; return; @@ -411,7 +476,6 @@ static void rtl92c_dm_initial_gain_sta(struct ieee80211_hw *hw) RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, "presta_cstate = %x, cursta_cstate = %x\n", dm_digtable->presta_cstate, dm_digtable->cursta_cstate); - if (dm_digtable->presta_cstate == dm_digtable->cursta_cstate || dm_digtable->cursta_cstate == DIG_STA_BEFORE_CONNECT || dm_digtable->cursta_cstate == DIG_STA_CONNECT) { @@ -419,6 +483,8 @@ static void rtl92c_dm_initial_gain_sta(struct ieee80211_hw *hw) if (dm_digtable->cursta_cstate != DIG_STA_DISCONNECT) { dm_digtable->rssi_val_min = rtl92c_dm_initial_gain_min_pwdb(hw); + if (dm_digtable->rssi_val_min > 100) + dm_digtable->rssi_val_min = 100; rtl92c_dm_ctrl_initgain_by_rssi(hw); } } else { @@ -434,11 +500,12 @@ static void rtl92c_dm_initial_gain_sta(struct ieee80211_hw *hw) static void rtl92c_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); struct dig_t *dm_digtable = &rtlpriv->dm_digtable; if (dm_digtable->cursta_cstate == DIG_STA_CONNECT) { dm_digtable->rssi_val_min = rtl92c_dm_initial_gain_min_pwdb(hw); + if (dm_digtable->rssi_val_min > 100) + dm_digtable->rssi_val_min = 100; if (dm_digtable->pre_cck_pd_state == CCK_PD_STAGE_LowRssi) { if (dm_digtable->rssi_val_min <= 25) @@ -460,48 +527,14 @@ static void rtl92c_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw) } if (dm_digtable->pre_cck_pd_state != dm_digtable->cur_cck_pd_state) { - if (dm_digtable->cur_cck_pd_state == CCK_PD_STAGE_LowRssi) { - if (rtlpriv->falsealm_cnt.cnt_cck_fail > 800) - dm_digtable->cur_cck_fa_state = - CCK_FA_STAGE_High; - else - dm_digtable->cur_cck_fa_state = CCK_FA_STAGE_Low; - - if (dm_digtable->pre_cck_fa_state != - dm_digtable->cur_cck_fa_state) { - if (dm_digtable->cur_cck_fa_state == - CCK_FA_STAGE_Low) - rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, - 0x83); - else - rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, - 0xcd); - - dm_digtable->pre_cck_fa_state = - dm_digtable->cur_cck_fa_state; - } - - rtl_set_bbreg(hw, RCCK0_SYSTEM, MASKBYTE1, 0x40); - - if (IS_92C_SERIAL(rtlhal->version)) - rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, - MASKBYTE2, 0xd7); - } else { + if ((dm_digtable->cur_cck_pd_state == CCK_PD_STAGE_LowRssi) || + (dm_digtable->cur_cck_pd_state == CCK_PD_STAGE_MAX)) + rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0x83); + else rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0xcd); - rtl_set_bbreg(hw, RCCK0_SYSTEM, MASKBYTE1, 0x47); - if (IS_92C_SERIAL(rtlhal->version)) - rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, - MASKBYTE2, 0xd3); - } dm_digtable->pre_cck_pd_state = dm_digtable->cur_cck_pd_state; } - - RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, "CCKPDStage=%x\n", - dm_digtable->cur_cck_pd_state); - - RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, "is92C=%x\n", - IS_92C_SERIAL(rtlhal->version)); } static void rtl92c_dm_ctrl_initgain_by_twoport(struct ieee80211_hw *hw) @@ -518,6 +551,8 @@ static void rtl92c_dm_ctrl_initgain_by_twoport(struct ieee80211_hw *hw) else dm_digtable->cursta_cstate = DIG_STA_DISCONNECT; + dm_digtable->curmultista_cstate = DIG_MULTISTA_DISCONNECT; + rtl92c_dm_initial_gain_sta(hw); rtl92c_dm_initial_gain_multi_sta(hw); rtl92c_dm_cck_packet_detection_thresh(hw); @@ -529,23 +564,26 @@ static void rtl92c_dm_ctrl_initgain_by_twoport(struct ieee80211_hw *hw) static void rtl92c_dm_dig(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct dig_t *dm_digtable = &rtlpriv->dm_digtable; if (rtlpriv->dm.dm_initialgain_enable == false) return; - if (dm_digtable->dig_enable_flag == false) + if (!rtlpriv->dm.dm_flag & DYNAMIC_FUNC_DIG) return; rtl92c_dm_ctrl_initgain_by_twoport(hw); - } static void rtl92c_dm_init_dynamic_txpower(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); - rtlpriv->dm.dynamic_txpower_enable = false; - + if (rtlpriv->rtlhal.interface == INTF_USB && + rtlpriv->rtlhal.board_type & 0x1) { + dm_savepowerindex(hw); + rtlpriv->dm.dynamic_txpower_enable = true; + } else { + rtlpriv->dm.dynamic_txpower_enable = false; + } rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL; rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; } @@ -560,9 +598,14 @@ void rtl92c_dm_write_dig(struct ieee80211_hw *hw) dm_digtable->cur_igvalue, dm_digtable->pre_igvalue, dm_digtable->back_val); - dm_digtable->cur_igvalue += 2; - if (dm_digtable->cur_igvalue > 0x3f) - dm_digtable->cur_igvalue = 0x3f; + if (rtlpriv->rtlhal.interface == INTF_USB && + !dm_digtable->dig_enable_flag) { + dm_digtable->pre_igvalue = 0x17; + return; + } + dm_digtable->cur_igvalue -= 1; + if (dm_digtable->cur_igvalue < DM_DIG_MIN) + dm_digtable->cur_igvalue = DM_DIG_MIN; if (dm_digtable->pre_igvalue != dm_digtable->cur_igvalue) { rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f, @@ -572,11 +615,47 @@ void rtl92c_dm_write_dig(struct ieee80211_hw *hw) dm_digtable->pre_igvalue = dm_digtable->cur_igvalue; } + RT_TRACE(rtlpriv, COMP_DIG, DBG_WARNING, + "dig values 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + dm_digtable->cur_igvalue, dm_digtable->pre_igvalue, + dm_digtable->rssi_val_min, dm_digtable->back_val, + dm_digtable->rx_gain_max, dm_digtable->rx_gain_min, + dm_digtable->large_fa_hit, dm_digtable->forbidden_igi); } EXPORT_SYMBOL(rtl92c_dm_write_dig); static void rtl92c_dm_pwdb_monitor(struct ieee80211_hw *hw) { + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + long tmpentry_max_pwdb = 0, tmpentry_min_pwdb = 0xff; + + if (mac->link_state != MAC80211_LINKED) + return; + + if (mac->opmode == NL80211_IFTYPE_ADHOC || + mac->opmode == NL80211_IFTYPE_AP) { + /* TODO: Handle ADHOC and AP Mode */ + } + + if (tmpentry_max_pwdb != 0) + rtlpriv->dm.entry_max_undec_sm_pwdb = tmpentry_max_pwdb; + else + rtlpriv->dm.entry_max_undec_sm_pwdb = 0; + + if (tmpentry_min_pwdb != 0xff) + rtlpriv->dm.entry_min_undec_sm_pwdb = tmpentry_min_pwdb; + else + rtlpriv->dm.entry_min_undec_sm_pwdb = 0; + +/* TODO: + * if (mac->opmode == NL80211_IFTYPE_STATION) { + * if (rtlpriv->rtlhal.fw_ready) { + * u32 param = (u32)(rtlpriv->dm.undec_sm_pwdb << 16); + * rtl8192c_set_rssi_cmd(hw, param); + * } + * } + */ } void rtl92c_dm_init_edca_turbo(struct ieee80211_hw *hw) @@ -786,6 +865,7 @@ static void rtl92c_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw rtlpriv->dm.ofdm_index[i] = ofdm_index_old[i]; rtlpriv->dm.cck_index = cck_index_old; } + /* Handle USB High PA boards */ delta = (thermalvalue > rtlpriv->dm.thermalvalue) ? (thermalvalue - rtlpriv->dm.thermalvalue) : @@ -1176,22 +1256,22 @@ void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct ps_t *dm_pstable = &rtlpriv->dm_pstable; - static u8 initialize; - static u32 reg_874, reg_c70, reg_85c, reg_a74; - if (initialize == 0) { - reg_874 = (rtl_get_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, - MASKDWORD) & 0x1CC000) >> 14; + if (!rtlpriv->reg_init) { + rtlpriv->reg_874 = (rtl_get_bbreg(hw, + RFPGA0_XCD_RFINTERFACESW, + MASKDWORD) & 0x1CC000) >> 14; - reg_c70 = (rtl_get_bbreg(hw, ROFDM0_AGCPARAMETER1, - MASKDWORD) & BIT(3)) >> 3; + rtlpriv->reg_c70 = (rtl_get_bbreg(hw, ROFDM0_AGCPARAMETER1, + MASKDWORD) & BIT(3)) >> 3; - reg_85c = (rtl_get_bbreg(hw, RFPGA0_XCD_SWITCHCONTROL, - MASKDWORD) & 0xFF000000) >> 24; + rtlpriv->reg_85c = (rtl_get_bbreg(hw, RFPGA0_XCD_SWITCHCONTROL, + MASKDWORD) & 0xFF000000) >> 24; - reg_a74 = (rtl_get_bbreg(hw, 0xa74, MASKDWORD) & 0xF000) >> 12; + rtlpriv->reg_a74 = (rtl_get_bbreg(hw, 0xa74, MASKDWORD) & + 0xF000) >> 12; - initialize = 1; + rtlpriv->reg_init = true; } if (!bforce_in_normal) { @@ -1228,12 +1308,12 @@ void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal) rtl_set_bbreg(hw, 0x818, BIT(28), 0x1); } else { rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, - 0x1CC000, reg_874); + 0x1CC000, rtlpriv->reg_874); rtl_set_bbreg(hw, ROFDM0_AGCPARAMETER1, BIT(3), - reg_c70); + rtlpriv->reg_c70); rtl_set_bbreg(hw, RFPGA0_XCD_SWITCHCONTROL, 0xFF000000, - reg_85c); - rtl_set_bbreg(hw, 0xa74, 0xF000, reg_a74); + rtlpriv->reg_85c); + rtl_set_bbreg(hw, 0xa74, 0xF000, rtlpriv->reg_a74); rtl_set_bbreg(hw, 0x818, BIT(28), 0x0); } @@ -1249,6 +1329,7 @@ static void rtl92c_dm_dynamic_bb_powersaving(struct ieee80211_hw *hw) struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + /* Determine the minimum RSSI */ if (((mac->link_state == MAC80211_NOLINK)) && (rtlpriv->dm.entry_min_undec_sm_pwdb == 0)) { dm_pstable->rssi_val_min = 0; @@ -1277,6 +1358,7 @@ static void rtl92c_dm_dynamic_bb_powersaving(struct ieee80211_hw *hw) dm_pstable->rssi_val_min); } + /* Power Saving for 92C */ if (IS_92C_SERIAL(rtlhal->version)) ;/* rtl92c_dm_1r_cca(hw); */ else @@ -1288,12 +1370,23 @@ void rtl92c_dm_init(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER; + rtlpriv->dm.dm_flag = DYNAMIC_FUNC_DISABLE | DYNAMIC_FUNC_DIG; + rtlpriv->dm.undec_sm_pwdb = -1; + rtlpriv->dm.undec_sm_cck = -1; + rtlpriv->dm.dm_initialgain_enable = true; rtl92c_dm_diginit(hw); + + rtlpriv->dm.dm_flag |= HAL_DM_HIPWR_DISABLE; rtl92c_dm_init_dynamic_txpower(hw); + rtl92c_dm_init_edca_turbo(hw); rtl92c_dm_init_rate_adaptive_mask(hw); + rtlpriv->dm.dm_flag |= DYNAMIC_FUNC_SS; rtl92c_dm_initialize_txpower_tracking(hw); rtl92c_dm_init_dynamic_bb_powersaving(hw); + + rtlpriv->dm.ofdm_pkt_cnt = 0; + rtlpriv->dm.dm_rssi_sel = RSSI_DEFAULT; } EXPORT_SYMBOL(rtl92c_dm_init); @@ -1344,7 +1437,7 @@ void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw) } if (undec_sm_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL2) { - rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1; + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL2; RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x0)\n"); } else if ((undec_sm_pwdb < (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) && @@ -1364,8 +1457,16 @@ void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw) "PHY_SetTxPowerLevel8192S() Channel = %d\n", rtlphy->current_channel); rtl92c_phy_set_txpower_level(hw, rtlphy->current_channel); + if (rtlpriv->dm.dynamic_txhighpower_lvl == + TXHIGHPWRLEVEL_NORMAL) + dm_restorepowerindex(hw); + else if (rtlpriv->dm.dynamic_txhighpower_lvl == + TXHIGHPWRLEVEL_LEVEL1) + dm_writepowerindex(hw, 0x14); + else if (rtlpriv->dm.dynamic_txhighpower_lvl == + TXHIGHPWRLEVEL_LEVEL2) + dm_writepowerindex(hw, 0x10); } - rtlpriv->dm.last_dtp_lvl = rtlpriv->dm.dynamic_txhighpower_lvl; } @@ -1436,12 +1537,6 @@ u8 rtl92c_bt_rssi_state_change(struct ieee80211_hw *hw) else curr_bt_rssi_state &= (~BT_RSSI_STATE_SPECIAL_LOW); - /* Set Tx Power according to BT status. */ - if (undec_sm_pwdb >= 30) - curr_bt_rssi_state |= BT_RSSI_STATE_TXPOWER_LOW; - else if (undec_sm_pwdb < 25) - curr_bt_rssi_state &= (~BT_RSSI_STATE_TXPOWER_LOW); - /* Check BT state related to BT_Idle in B/G mode. */ if (undec_sm_pwdb < 15) curr_bt_rssi_state |= BT_RSSI_STATE_BG_EDCA_LOW; -- cgit v1.2.3-70-g09d2 From d3af1ce1388b00f8335ce3f9720032168d41e3c7 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 18 Nov 2013 13:06:55 -0600 Subject: rtlwifi: Bring _rtl92c_phy_iq_calibrate() in line with the vendor driver Bring _rtl92c_phy_iq_calibrate() in line with the vendor driver function _PHY_IQCalibrate(). Also fix incorrect initialisation for rtl8192cu. Signed-of-by: Mark Cave-Ayland Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c | 39 ++++++++++++++++------ drivers/net/wireless/rtlwifi/rtl8192cu/hw.c | 2 +- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c index 0c0e78263a6..9e32ac8a442 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c @@ -1147,6 +1147,12 @@ static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, 0x522, 0x550, 0x551, 0x040 }; + u32 iqk_bb_reg_92C[9] = { + 0xc04, 0xc08, 0x874, 0xb68, + 0xb6c, 0x870, 0x860, 0x864, + 0x800 + }; + const u32 retrycount = 2; if (t == 0) { @@ -1157,6 +1163,8 @@ static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, rtlphy->adda_backup, 16); _rtl92c_phy_save_mac_registers(hw, iqk_mac_reg, rtlphy->iqk_mac_backup); + _rtl92c_phy_save_adda_registers(hw, iqk_bb_reg_92C, + rtlphy->iqk_bb_backup, 9); } _rtl92c_phy_path_adda_on(hw, adda_reg, true, is2t); if (t == 0) { @@ -1167,14 +1175,18 @@ static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, if (!rtlphy->rfpi_enable) _rtl92c_phy_pi_mode_switch(hw, true); - if (t == 0) { - rtlphy->reg_c04 = rtl_get_bbreg(hw, 0xc04, MASKDWORD); - rtlphy->reg_c08 = rtl_get_bbreg(hw, 0xc08, MASKDWORD); - rtlphy->reg_874 = rtl_get_bbreg(hw, 0x874, MASKDWORD); - } + + rtl_set_bbreg(hw, 0x800, BIT(24), 0x0); + rtl_set_bbreg(hw, 0xc04, MASKDWORD, 0x03a05600); rtl_set_bbreg(hw, 0xc08, MASKDWORD, 0x000800e4); rtl_set_bbreg(hw, 0x874, MASKDWORD, 0x22204000); + + rtl_set_bbreg(hw, 0x870, BIT(10), 0x1); + rtl_set_bbreg(hw, 0x870, BIT(26), 0x1); + rtl_set_bbreg(hw, 0x860, BIT(10), 0x0); + rtl_set_bbreg(hw, 0x864, BIT(10), 0x0); + if (is2t) { rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00010000); rtl_set_bbreg(hw, 0x844, MASKDWORD, 0x00010000); @@ -1239,13 +1251,9 @@ static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, 0x3FF0000) >> 16; } } - rtl_set_bbreg(hw, 0xc04, MASKDWORD, rtlphy->reg_c04); - rtl_set_bbreg(hw, 0x874, MASKDWORD, rtlphy->reg_874); - rtl_set_bbreg(hw, 0xc08, MASKDWORD, rtlphy->reg_c08); + rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0); - rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00032ed3); - if (is2t) - rtl_set_bbreg(hw, 0x844, MASKDWORD, 0x00032ed3); + if (t != 0) { if (!rtlphy->rfpi_enable) _rtl92c_phy_pi_mode_switch(hw, false); @@ -1253,6 +1261,15 @@ static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, rtlphy->adda_backup, 16); _rtl92c_phy_reload_mac_registers(hw, iqk_mac_reg, rtlphy->iqk_mac_backup); + _rtl92c_phy_reload_adda_registers(hw, iqk_bb_reg_92C, + rtlphy->iqk_bb_backup, 9); + + rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00032ed3); + if (is2t) + rtl_set_bbreg(hw, 0x844, MASKDWORD, 0x00032ed3); + + rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x01008c00); + rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x01008c00); } } diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c index 189ba124a8c..468bf73cc88 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c @@ -1022,7 +1022,7 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw) if (ppsc->rfpwr_state == ERFON) { rtl92c_phy_set_rfpath_switch(hw, 1); if (iqk_initialized) { - rtl92c_phy_iq_calibrate(hw, false); + rtl92c_phy_iq_calibrate(hw, true); } else { rtl92c_phy_iq_calibrate(hw, false); iqk_initialized = true; -- cgit v1.2.3-70-g09d2 From 8a7192080f45f2e7858bc4448f45a9d05f7f4da3 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 18 Nov 2013 13:06:56 -0600 Subject: rtlwifi: rtl8192cu: Bring rtl92cu_phy_bb_config() up to date The latest vendor driver contains some changes not in the kernel version. Signed-off-by: Mark Cave-Ayland Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8192cu/phy.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c index 34e56308301..0c09240eadc 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c @@ -120,6 +120,7 @@ bool rtl92cu_phy_bb_config(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); u16 regval; + u32 regval32; u8 b_reg_hwparafile = 1; _rtl92c_phy_init_bb_rf_register_definition(hw); @@ -135,8 +136,11 @@ bool rtl92cu_phy_bb_config(struct ieee80211_hw *hw) } else if (IS_HARDWARE_TYPE_8192CU(rtlhal)) { rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, FEN_USBA | FEN_USBD | FEN_BB_GLB_RSTn | FEN_BBRSTB); - rtl_write_byte(rtlpriv, REG_LDOHCI12_CTRL, 0x0f); } + regval32 = rtl_read_dword(rtlpriv, 0x87c); + rtl_write_dword(rtlpriv, 0x87c, regval32 & (~BIT(31))); + if (IS_HARDWARE_TYPE_8192CU(rtlhal)) + rtl_write_byte(rtlpriv, REG_LDOHCI12_CTRL, 0x0f); rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL + 1, 0x80); if (b_reg_hwparafile == 1) rtstatus = _rtl92c_phy_bb8192c_config_parafile(hw); -- cgit v1.2.3-70-g09d2 From 18a7424f8c76ff7acdda49e4346571cc2a69b7f9 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 18 Nov 2013 13:06:57 -0600 Subject: rtlwifi: rtl8192cu: Update table.c The latest vendor driver has some new values. Signed-off-by: Larry Finger Signed-off-by: Mark Cave-Ayland Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8192cu/table.c | 40 +++++++++++++------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/table.c b/drivers/net/wireless/rtlwifi/rtl8192cu/table.c index 966be519edb..7903c154de0 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/table.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/table.c @@ -36,7 +36,7 @@ u32 RTL8192CUPHY_REG_2TARRAY[RTL8192CUPHY_REG_2TARRAY_LENGTH] = { 0x804, 0x00000003, 0x808, 0x0000fc00, 0x80c, 0x0000000a, - 0x810, 0x10005388, + 0x810, 0x10000330, 0x814, 0x020c3d10, 0x818, 0x02200385, 0x81c, 0x00000000, @@ -110,22 +110,22 @@ u32 RTL8192CUPHY_REG_2TARRAY[RTL8192CUPHY_REG_2TARRAY_LENGTH] = { 0xc44, 0x000100b7, 0xc48, 0xec020107, 0xc4c, 0x007f037f, - 0xc50, 0x6954341e, + 0xc50, 0x69543420, 0xc54, 0x43bc0094, - 0xc58, 0x6954341e, + 0xc58, 0x69543420, 0xc5c, 0x433c0094, 0xc60, 0x00000000, 0xc64, 0x5116848b, 0xc68, 0x47c00bff, 0xc6c, 0x00000036, 0xc70, 0x2c7f000d, - 0xc74, 0x0186115b, + 0xc74, 0x2186115b, 0xc78, 0x0000001f, 0xc7c, 0x00b99612, 0xc80, 0x40000100, 0xc84, 0x20f60000, 0xc88, 0x40000100, - 0xc8c, 0x20200000, + 0xc8c, 0xa0e40000, 0xc90, 0x00121820, 0xc94, 0x00000000, 0xc98, 0x00121820, @@ -226,7 +226,7 @@ u32 RTL8192CUPHY_REG_1TARRAY[RTL8192CUPHY_REG_1TARRAY_LENGTH] = { 0x804, 0x00000001, 0x808, 0x0000fc00, 0x80c, 0x0000000a, - 0x810, 0x10005388, + 0x810, 0x10000330, 0x814, 0x020c3d10, 0x818, 0x02200385, 0x81c, 0x00000000, @@ -300,9 +300,9 @@ u32 RTL8192CUPHY_REG_1TARRAY[RTL8192CUPHY_REG_1TARRAY_LENGTH] = { 0xc44, 0x000100b7, 0xc48, 0xec020107, 0xc4c, 0x007f037f, - 0xc50, 0x6954341e, + 0xc50, 0x69543420, 0xc54, 0x43bc0094, - 0xc58, 0x6954341e, + 0xc58, 0x69543420, 0xc5c, 0x433c0094, 0xc60, 0x00000000, 0xc64, 0x5116848b, @@ -340,7 +340,7 @@ u32 RTL8192CUPHY_REG_1TARRAY[RTL8192CUPHY_REG_1TARRAY_LENGTH] = { 0xce4, 0x00000000, 0xce8, 0x37644302, 0xcec, 0x2f97d40c, - 0xd00, 0x00080740, + 0xd00, 0x00000740, 0xd04, 0x00020401, 0xd08, 0x0000907f, 0xd0c, 0x20010201, @@ -633,17 +633,17 @@ u32 RTL8192CURADIOA_2TARRAY[RTL8192CURADIOA_2TARRAYLENGTH] = { 0x012, 0x00071000, 0x012, 0x000b0000, 0x012, 0x000fc000, - 0x013, 0x000287af, + 0x013, 0x000287b3, 0x013, 0x000244b7, 0x013, 0x000204ab, 0x013, 0x0001c49f, 0x013, 0x00018493, - 0x013, 0x00014297, - 0x013, 0x00010295, - 0x013, 0x0000c298, - 0x013, 0x0000819c, - 0x013, 0x000040a8, - 0x013, 0x0000001c, + 0x013, 0x0001429b, + 0x013, 0x00010299, + 0x013, 0x0000c29c, + 0x013, 0x000081a0, + 0x013, 0x000040ac, + 0x013, 0x00000020, 0x014, 0x0001944c, 0x014, 0x00059444, 0x014, 0x0009944c, @@ -932,10 +932,10 @@ u32 RTL8192CUMAC_2T_ARRAY[RTL8192CUMAC_2T_ARRAYLENGTH] = { 0x608, 0x0000000e, 0x609, 0x0000002a, 0x652, 0x00000020, - 0x63c, 0x0000000a, - 0x63d, 0x0000000e, - 0x63e, 0x0000000a, - 0x63f, 0x0000000e, + 0x63c, 0x00000008, + 0x63d, 0x00000008, + 0x63e, 0x0000000c, + 0x63f, 0x0000000c, 0x66e, 0x00000005, 0x700, 0x00000021, 0x701, 0x00000043, -- cgit v1.2.3-70-g09d2 From eddc633a3abcffbbe2fb1eb460670f0c63b11211 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Tue, 19 Nov 2013 01:45:08 +0400 Subject: libertas sdio: claim device before calling sdio_disable_func() There is a failure path in if_sdio_power_on(), where sdio_disable_func() is called without claiming the device. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/if_sdio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index 828e7f4fc63..58c6ee5de98 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -907,8 +907,8 @@ static int if_sdio_power_on(struct if_sdio_card *card) sdio_release_host(func); ret = if_sdio_prog_firmware(card); if (ret) { - sdio_disable_func(func); - return ret; + sdio_claim_host(func); + goto disable; } return 0; -- cgit v1.2.3-70-g09d2 From 42bc702e76fc459dfb3f2fb50c99bd7f680eb2b4 Mon Sep 17 00:00:00 2001 From: Chun-Yeow Yeoh Date: Wed, 20 Nov 2013 17:57:01 +0800 Subject: wcn36xx: set self STA default HT parameters These default HT parameters are required for self STA entry. In example, set the HT capable of self STA entry for bss configuration in mesh allows the MCS rate to be used. Otherwise, only legacy rate will be used. Signed-off-by: Chun-Yeow Yeoh Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wcn36xx/smd.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index de9eb2cfbf4..7216152f4c0 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -115,6 +115,22 @@ static void wcn36xx_smd_set_sta_ht_params(struct ieee80211_sta *sta, } } +static void wcn36xx_smd_set_sta_default_ht_params( + struct wcn36xx_hal_config_sta_params *sta_params) +{ + sta_params->ht_capable = 1; + sta_params->tx_channel_width_set = 1; + sta_params->lsig_txop_protection = 1; + sta_params->max_ampdu_size = 3; + sta_params->max_ampdu_density = 5; + sta_params->max_amsdu_size = 0; + sta_params->sgi_20Mhz = 1; + sta_params->sgi_40mhz = 1; + sta_params->green_field_capable = 1; + sta_params->delayed_ba_support = 0; + sta_params->dsss_cck_mode_40mhz = 1; +} + static void wcn36xx_smd_set_sta_params(struct wcn36xx *wcn, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -172,6 +188,7 @@ static void wcn36xx_smd_set_sta_params(struct wcn36xx *wcn, sizeof(priv_sta->supported_rates)); } else { wcn36xx_set_default_rates(&sta_params->supported_rates); + wcn36xx_smd_set_sta_default_ht_params(sta_params); } } -- cgit v1.2.3-70-g09d2 From fc70ff7207a42e3d1f3d76317fe5e3169391dc47 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 24 Nov 2013 17:56:51 +0100 Subject: ath9k: fix retry chain initialization in tx99 code Initialize first chain attempt counter to 1 in ath9k_build_tx99_skb(). Otherwise multi-retry chain is initialized to {idx,count} = {-1, 0} in rate_control_fill_sta_table() and tx99 transmission rate is not configured in rate_control_apply_mask() since first chain idx is set to -1 Signed-off-by: Lorenzo Bianconi Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/tx99.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c index c65c37fe101..57d775783ec 100644 --- a/drivers/net/wireless/ath/ath9k/tx99.c +++ b/drivers/net/wireless/ath/ath9k/tx99.c @@ -76,6 +76,7 @@ static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc) tx_info->band = hw->conf.chandef.chan->band; tx_info->flags = IEEE80211_TX_CTL_NO_ACK; tx_info->control.vif = sc->tx99_vif; + tx_info->control.rates[0].count = 1; memcpy(skb->data + sizeof(*hdr), PN9Data, sizeof(PN9Data)); -- cgit v1.2.3-70-g09d2 From cb500a7c299f03e0a8061ca408e68b13ffe8d35d Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 24 Nov 2013 22:03:41 +0100 Subject: brcmsmac: remove dependency on CRC8 and CRC_CCITT There is no code in brcmsmac that uses a function from CRC8 or CRC_CCITT any more. Building brcmsmac with these two disabled works without any problems. This was probably only used by the bus code which was replaced by bcma some time ago. Signed-off-by: Hauke Mehrtens Acked-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/Kconfig | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/brcm80211/Kconfig b/drivers/net/wireless/brcm80211/Kconfig index d9d85e93d09..57918579d55 100644 --- a/drivers/net/wireless/brcm80211/Kconfig +++ b/drivers/net/wireless/brcm80211/Kconfig @@ -8,8 +8,6 @@ config BRCMSMAC select BCMA select BRCMUTIL select FW_LOADER - select CRC_CCITT - select CRC8 select CORDIC ---help--- This module adds support for PCIe wireless adapters based on Broadcom -- cgit v1.2.3-70-g09d2 From 8e27f360c52470981149359bf7d6ce000ad628f1 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Mon, 25 Nov 2013 10:49:53 +0900 Subject: wireless: ipw2100: remove unnecessary pci_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2x00/ipw2100.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 813c9af0ebd..3aba49259ef 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -6362,7 +6362,6 @@ out: &ipw2100_attribute_group); free_libipw(dev, 0); - pci_set_drvdata(pci_dev, NULL); } pci_iounmap(pci_dev, ioaddr); -- cgit v1.2.3-70-g09d2 From c44354d232ff80d5e6e55c3730a7079c5c3566fb Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Mon, 25 Nov 2013 10:51:09 +0900 Subject: wireless: prism54: remove unnecessary pci_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Signed-off-by: John W. Linville --- drivers/net/wireless/prism54/islpci_dev.c | 1 - drivers/net/wireless/prism54/islpci_hotplug.c | 2 -- 2 files changed, 3 deletions(-) diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c index e05d9b4c831..7fa2898d061 100644 --- a/drivers/net/wireless/prism54/islpci_dev.c +++ b/drivers/net/wireless/prism54/islpci_dev.c @@ -914,7 +914,6 @@ islpci_setup(struct pci_dev *pdev) do_islpci_free_memory: islpci_free_memory(priv); do_free_netdev: - pci_set_drvdata(pdev, NULL); free_netdev(ndev); priv = NULL; return NULL; diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c index 9e68e0cb718..d7b9e637642 100644 --- a/drivers/net/wireless/prism54/islpci_hotplug.c +++ b/drivers/net/wireless/prism54/islpci_hotplug.c @@ -199,7 +199,6 @@ prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id) do_unregister_netdev: unregister_netdev(ndev); islpci_free_memory(priv); - pci_set_drvdata(pdev, NULL); free_netdev(ndev); priv = NULL; do_pci_clear_mwi: @@ -247,7 +246,6 @@ prism54_remove(struct pci_dev *pdev) /* free the PCI memory and unmap the remapped page */ islpci_free_memory(priv); - pci_set_drvdata(pdev, NULL); free_netdev(ndev); priv = NULL; -- cgit v1.2.3-70-g09d2 From 515adc14cb860f1fb83f48acc6558baec10386f4 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Mon, 25 Nov 2013 10:52:33 +0900 Subject: wireless: rt2x00: remove unnecessary pci_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00pci.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index 25da20e7e1f..af721831dcb 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -156,8 +156,6 @@ exit_release_regions: exit_disable_device: pci_disable_device(pci_dev); - pci_set_drvdata(pci_dev, NULL); - return retval; } EXPORT_SYMBOL_GPL(rt2x00pci_probe); @@ -177,7 +175,6 @@ void rt2x00pci_remove(struct pci_dev *pci_dev) /* * Free the PCI device data. */ - pci_set_drvdata(pci_dev, NULL); pci_disable_device(pci_dev); pci_release_regions(pci_dev); } -- cgit v1.2.3-70-g09d2 From 85f66a0e9bddb37570788ae040a9755d64127a2e Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Mon, 25 Nov 2013 11:11:15 +0900 Subject: wireless: libertas: remove unnecessary spi_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/if_spi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index 83669151bb8..f11728a866f 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -93,7 +93,6 @@ static void free_if_spi_card(struct if_spi_card *card) list_del(&packet->list); kfree(packet); } - spi_set_drvdata(card->spi, NULL); kfree(card); } -- cgit v1.2.3-70-g09d2 From 0a7a109e134c619245e6e77dd93260fa0b427684 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Mon, 25 Nov 2013 12:37:24 +0900 Subject: bcma: pci: remove unnecessary pci_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Signed-off-by: John W. Linville --- drivers/bcma/host_pci.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c index 6fb98b53533..12a4ff75135 100644 --- a/drivers/bcma/host_pci.c +++ b/drivers/bcma/host_pci.c @@ -238,7 +238,6 @@ static void bcma_host_pci_remove(struct pci_dev *dev) pci_release_regions(dev); pci_disable_device(dev); kfree(bus); - pci_set_drvdata(dev, NULL); } #ifdef CONFIG_PM_SLEEP -- cgit v1.2.3-70-g09d2 From f699273d6a624266ebc9198774f06ee64a3847a1 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 25 Nov 2013 10:45:28 -0600 Subject: rtlwifi: rtl8188ee: Fix typo in code The static analyser "cppcheck" shows the following typo: drivers/net/wireless/rtlwifi/rtl8188ee/dm.c:1081]: (style) Same expression on both sides of '!='. Signed-off-by: Larry Finger Reported-by: David Binderman Cc: David Binderman Cc: Stable [3.10+] Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8188ee/dm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c index 21a5cf06067..a6184b6e1d5 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c @@ -1078,7 +1078,7 @@ static void rtl88e_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw rtldm->swing_flag_ofdm = true; } - if (rtldm->swing_idx_cck != rtldm->swing_idx_cck) { + if (rtldm->swing_idx_cck_cur != rtldm->swing_idx_cck) { rtldm->swing_idx_cck_cur = rtldm->swing_idx_cck; rtldm->swing_flag_cck = true; } -- cgit v1.2.3-70-g09d2 From cddc6046391db27c543a422e8964502546ae1dd1 Mon Sep 17 00:00:00 2001 From: Chun-Yeow Yeoh Date: Fri, 29 Nov 2013 23:47:30 +0800 Subject: wcn36xx: fix typo error Signed-off-by: Chun-Yeow Yeoh Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wcn36xx/hal.h | 2 +- drivers/net/wireless/ath/wcn36xx/smd.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/wcn36xx/hal.h b/drivers/net/wireless/ath/wcn36xx/hal.h index c02dbc61872..3c2ef0c32f7 100644 --- a/drivers/net/wireless/ath/wcn36xx/hal.h +++ b/drivers/net/wireless/ath/wcn36xx/hal.h @@ -2644,7 +2644,7 @@ struct wcn36xx_hal_trigger_ba_rsp_candidate { struct add_ba_info ba_info[STACFG_MAX_TC]; } __packed; -struct wcn36xx_hal_trigget_ba_req_candidate { +struct wcn36xx_hal_trigger_ba_req_candidate { u8 sta_index; u8 tid_bitmap; } __packed; diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index 7216152f4c0..ddb5b2f7a4b 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -1855,7 +1855,7 @@ out: int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index) { struct wcn36xx_hal_trigger_ba_req_msg msg_body; - struct wcn36xx_hal_trigget_ba_req_candidate *candidate; + struct wcn36xx_hal_trigger_ba_req_candidate *candidate; int ret = 0; mutex_lock(&wcn->hal_mutex); @@ -1866,7 +1866,7 @@ int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index) msg_body.header.len += sizeof(*candidate); PREPARE_HAL_BUF(wcn->hal_buf, msg_body); - candidate = (struct wcn36xx_hal_trigget_ba_req_candidate *) + candidate = (struct wcn36xx_hal_trigger_ba_req_candidate *) (wcn->hal_buf + sizeof(msg_body)); candidate->sta_index = sta_index; candidate->tid_bitmap = 1; -- cgit v1.2.3-70-g09d2 From d44040de6a991999b466adefc7588e479680b98d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 21 Oct 2013 19:14:47 +0200 Subject: ath: fix logic on ath_reg_apply_active_scan_flags() The existing logic removes the passive scan flag from channels 12 and 13 when a regulatory hint coming from something other than a country IE has been passed. This is incorrect, the original intention was to ensure we always have passive scan enabled for these two channels for a specific set of custom world regulatory domains. Cc: smihir@qti.qualcomm.com Cc: tushnimb@qca.qualcomm.com Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/regd.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index d3bbf48522b..3d596e25ba8 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -249,16 +249,16 @@ ath_reg_apply_active_scan_flags(struct wiphy *wiphy, return; /* - * If no country IE has been received always enable active scan - * on these channels. This is only done for specific regulatory SKUs + * If no country IE has been received always enable passive scan + * and no-ibss on these channels. This is only done for specific + * regulatory SKUs. */ if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) { ch = &sband->channels[11]; /* CH 12 */ - if (ch->flags & IEEE80211_CHAN_NO_IR) - ch->flags &= ~IEEE80211_CHAN_NO_IR; + ch->flags |= IEEE80211_CHAN_NO_IR; + ch = &sband->channels[12]; /* CH 13 */ - if (ch->flags & IEEE80211_CHAN_NO_IR) - ch->flags &= ~IEEE80211_CHAN_NO_IR; + ch->flags |= IEEE80211_CHAN_NO_IR; return; } -- cgit v1.2.3-70-g09d2 From bc0aa0691806dc30cf1a69fe50ae90cf8f752977 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 21 Oct 2013 19:14:48 +0200 Subject: ath: clean up ath_reg_apply_active_scan_flags() The routine ath_reg_apply_active_scan_flags() can be a bit hard to read, this cleans it up by adding helpers for the two cases of clearing IR flags or adding them. This approach also makes no assumptions on the index of channels 12 and 13 so it should be portable accross different drivers. Cc: smihir@qti.qualcomm.com Cc: tushnimb@qca.qualcomm.com Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/regd.c | 101 +++++++++++++++++++++++++--------------- 1 file changed, 63 insertions(+), 38 deletions(-) diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 3d596e25ba8..f4bb9295b6c 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -178,6 +178,47 @@ static bool ath_is_radar_freq(u16 center_freq) return (center_freq >= 5260 && center_freq <= 5700); } +static void ath_force_clear_no_ir_chan(struct wiphy *wiphy, + struct ieee80211_channel *ch) +{ + const struct ieee80211_reg_rule *reg_rule; + + reg_rule = freq_reg_info(wiphy, ch->center_freq); + if (IS_ERR(reg_rule)) + return; + + if (!(reg_rule->flags & NL80211_RRF_NO_IR)) + if (ch->flags & IEEE80211_CHAN_NO_IR) + ch->flags &= ~IEEE80211_CHAN_NO_IR; +} + +static void ath_force_clear_no_ir_freq(struct wiphy *wiphy, u16 center_freq) +{ + struct ieee80211_channel *ch; + + ch = ieee80211_get_channel(wiphy, center_freq); + if (!ch) + return; + + ath_force_clear_no_ir_chan(wiphy, ch); +} + +static void ath_force_no_ir_chan(struct ieee80211_channel *ch) +{ + ch->flags |= IEEE80211_CHAN_NO_IR; +} + +static void ath_force_no_ir_freq(struct wiphy *wiphy, u16 center_freq) +{ + struct ieee80211_channel *ch; + + ch = ieee80211_get_channel(wiphy, center_freq); + if (!ch) + return; + + ath_force_no_ir_chan(ch); +} + /* * N.B: These exception rules do not apply radar freqs. * @@ -235,54 +276,38 @@ ath_reg_apply_beaconing_flags(struct wiphy *wiphy, } -/* Allows active scan scan on Ch 12 and 13 */ +/** + * ath_reg_apply_active_scan_flags() + * @wiphy: the wiphy to use + * @initiator: the regulatory hint initiator + * + * If no country IE has been received always enable passive scan + * and no-ibss on these channels. This is only done for specific + * regulatory SKUs. + * + * If a country IE has been received check its rule for this + * channel first before enabling active scan. The passive scan + * would have been enforced by the initial processing of our + * custom regulatory domain. + */ static void ath_reg_apply_active_scan_flags(struct wiphy *wiphy, enum nl80211_reg_initiator initiator) { struct ieee80211_supported_band *sband; - struct ieee80211_channel *ch; - const struct ieee80211_reg_rule *reg_rule; sband = wiphy->bands[IEEE80211_BAND_2GHZ]; if (!sband) return; - /* - * If no country IE has been received always enable passive scan - * and no-ibss on these channels. This is only done for specific - * regulatory SKUs. - */ - if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) { - ch = &sband->channels[11]; /* CH 12 */ - ch->flags |= IEEE80211_CHAN_NO_IR; - - ch = &sband->channels[12]; /* CH 13 */ - ch->flags |= IEEE80211_CHAN_NO_IR; - return; - } - - /* - * If a country IE has been received check its rule for this - * channel first before enabling active scan. The passive scan - * would have been enforced by the initial processing of our - * custom regulatory domain. - */ - - ch = &sband->channels[11]; /* CH 12 */ - reg_rule = freq_reg_info(wiphy, ch->center_freq); - if (!IS_ERR(reg_rule)) { - if (!(reg_rule->flags & NL80211_RRF_NO_IR)) - if (ch->flags & IEEE80211_CHAN_NO_IR) - ch->flags &= ~IEEE80211_CHAN_NO_IR; - } - - ch = &sband->channels[12]; /* CH 13 */ - reg_rule = freq_reg_info(wiphy, ch->center_freq); - if (!IS_ERR(reg_rule)) { - if (!(reg_rule->flags & NL80211_RRF_NO_IR)) - if (ch->flags & IEEE80211_CHAN_NO_IR) - ch->flags &= ~IEEE80211_CHAN_NO_IR; + switch(initiator) { + case NL80211_REGDOM_SET_BY_COUNTRY_IE: + ath_force_clear_no_ir_freq(wiphy, 2467); + ath_force_clear_no_ir_freq(wiphy, 2472); + break; + default: + ath_force_no_ir_freq(wiphy, 2467); + ath_force_no_ir_freq(wiphy, 2472); } } -- cgit v1.2.3-70-g09d2 From f33cbc4f4350003a0cfb12be07750f3a95965867 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 21 Oct 2013 19:14:49 +0200 Subject: ath: rename ath_reg_apply_active_scan_flags() to ath_reg_apply_ir_flags() This also applies the no-ibss flag to the channels or clears it. The idea here is to clarify no initiated radiation should be allowed on these channels. Cc: smihir@qti.qualcomm.com Cc: tushnimb@qca.qualcomm.com Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/regd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index f4bb9295b6c..a5cbaca41b7 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -277,7 +277,7 @@ ath_reg_apply_beaconing_flags(struct wiphy *wiphy, } /** - * ath_reg_apply_active_scan_flags() + * ath_reg_apply_ir_flags() * @wiphy: the wiphy to use * @initiator: the regulatory hint initiator * @@ -291,7 +291,7 @@ ath_reg_apply_beaconing_flags(struct wiphy *wiphy, * custom regulatory domain. */ static void -ath_reg_apply_active_scan_flags(struct wiphy *wiphy, +ath_reg_apply_ir_flags(struct wiphy *wiphy, enum nl80211_reg_initiator initiator) { struct ieee80211_supported_band *sband; @@ -357,7 +357,7 @@ static void ath_reg_apply_world_flags(struct wiphy *wiphy, break; case 0x68: ath_reg_apply_beaconing_flags(wiphy, initiator); - ath_reg_apply_active_scan_flags(wiphy, initiator); + ath_reg_apply_ir_flags(wiphy, initiator); break; } } -- cgit v1.2.3-70-g09d2 From 6c3af5888eb1df139c81bf74024f5d63ab336b04 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 21 Oct 2013 19:14:50 +0200 Subject: ath: simplify ath_reg_apply_beaconing_flags() Simplify ath_reg_apply_beaconing_flags() by making use of thew new no-ir helper. Cc: smihir@qti.qualcomm.com Cc: tushnimb@qca.qualcomm.com Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/regd.c | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index a5cbaca41b7..817340acfb5 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -220,13 +220,11 @@ static void ath_force_no_ir_freq(struct wiphy *wiphy, u16 center_freq) } /* - * N.B: These exception rules do not apply radar freqs. + * These exception rules do not apply radar frequencies. * - * - We enable adhoc (or beaconing) if allowed by 11d - * - We enable active scan if the channel is allowed by 11d + * - We enable initiating radiation if the country IE says its fine: * - If no country IE has been processed and a we determine we have - * received a beacon on a channel we can enable active scan and - * adhoc (or beaconing). + * received a beacon on a channel we can enable initiating radiation. */ static void ath_reg_apply_beaconing_flags(struct wiphy *wiphy, @@ -234,7 +232,6 @@ ath_reg_apply_beaconing_flags(struct wiphy *wiphy, { enum ieee80211_band band; struct ieee80211_supported_band *sband; - const struct ieee80211_reg_rule *reg_rule; struct ieee80211_channel *ch; unsigned int i; @@ -253,21 +250,13 @@ ath_reg_apply_beaconing_flags(struct wiphy *wiphy, (ch->flags & IEEE80211_CHAN_RADAR)) continue; - if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) { - reg_rule = freq_reg_info(wiphy, ch->center_freq); - if (IS_ERR(reg_rule)) - continue; - /* - * If 11d had a rule for this channel ensure - * we enable adhoc/beaconing if it allows us to - * use it. Note that we would have disabled it - * by applying our static world regdomain by - * default during init, prior to calling our - * regulatory_hint(). - */ - if (!(reg_rule->flags & NL80211_RRF_NO_IR)) - ch->flags &= ~IEEE80211_CHAN_NO_IR; - } else { + /* + * If the country IE says initiating radiation + * is OK we trust that. + */ + if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) + ath_force_clear_no_ir_chan(wiphy, ch); + else { if (ch->beacon_found) ch->flags &= ~IEEE80211_CHAN_NO_IR; } -- cgit v1.2.3-70-g09d2 From 07782d94d90b9ab94a97b1a1841575251484e5bb Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 21 Oct 2013 19:14:51 +0200 Subject: ath: move the channel for ath_reg_apply_beaconing_flags() into helper While at it convert this into a switch statement, this makes it easier and manage. Cc: smihir@qti.qualcomm.com Cc: tushnimb@qca.qualcomm.com Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/regd.c | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 817340acfb5..b02b43e690d 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -219,6 +219,25 @@ static void ath_force_no_ir_freq(struct wiphy *wiphy, u16 center_freq) ath_force_no_ir_chan(ch); } +static void +__ath_reg_apply_beaconing_flags(struct wiphy *wiphy, + enum nl80211_reg_initiator initiator, + struct ieee80211_channel *ch) +{ + if (ath_is_radar_freq(ch->center_freq) || + (ch->flags & IEEE80211_CHAN_RADAR)) + return; + + switch (initiator) { + case NL80211_REGDOM_SET_BY_COUNTRY_IE: + ath_force_clear_no_ir_chan(wiphy, ch); + break; + default: + if (ch->beacon_found) + ch->flags &= ~IEEE80211_CHAN_NO_IR; + } +} + /* * These exception rules do not apply radar frequencies. * @@ -236,33 +255,15 @@ ath_reg_apply_beaconing_flags(struct wiphy *wiphy, unsigned int i; for (band = 0; band < IEEE80211_NUM_BANDS; band++) { - if (!wiphy->bands[band]) continue; - sband = wiphy->bands[band]; - for (i = 0; i < sband->n_channels; i++) { - ch = &sband->channels[i]; + __ath_reg_apply_beaconing_flags(wiphy, initiator, ch); - if (ath_is_radar_freq(ch->center_freq) || - (ch->flags & IEEE80211_CHAN_RADAR)) - continue; - - /* - * If the country IE says initiating radiation - * is OK we trust that. - */ - if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) - ath_force_clear_no_ir_chan(wiphy, ch); - else { - if (ch->beacon_found) - ch->flags &= ~IEEE80211_CHAN_NO_IR; - } } } - } /** -- cgit v1.2.3-70-g09d2 From 62452a99d0b225a0f5d34d34b2aef63d7b44157b Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 29 Oct 2013 19:34:24 +0100 Subject: ath: fix usage of freq_reg_info() freq_reg_info() expects KHz and not MHz, fix this. In this case we'll now be getting the no-ir flags cleared on channels for any channel when the country IE trusts that channel. @@ struct ieee80211_channel *ch; struct wiphy *wiphy; const struct ieee80211_reg_rule *rule; @@ -rule = freq_reg_info(wiphy, ch->center_freq); +rule = freq_reg_info(wiphy, MHZ_TO_KHZ(ch->center_freq)); Generated-by: Coccinelle SmPL Cc: Julia Lawall Cc: Peter Senna Tschudin Reported-by: Mihir Shete Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/regd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index b02b43e690d..3baafa5b8ce 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -183,7 +183,7 @@ static void ath_force_clear_no_ir_chan(struct wiphy *wiphy, { const struct ieee80211_reg_rule *reg_rule; - reg_rule = freq_reg_info(wiphy, ch->center_freq); + reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(ch->center_freq)); if (IS_ERR(reg_rule)) return; -- cgit v1.2.3-70-g09d2 From a44ea6ffbbf716cca9c2abaa4a3a3a9a9ce7c75a Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 29 Oct 2013 23:39:04 +0100 Subject: ath: move dynamic_country_user_possible() to the top This will be used later. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/regd.c | 144 ++++++++++++++++++++-------------------- 1 file changed, 72 insertions(+), 72 deletions(-) diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 3baafa5b8ce..e7d01723ea0 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -114,6 +114,78 @@ static const struct ieee80211_regdomain ath_world_regdom_67_68_6A_6C = { } }; +static bool dynamic_country_user_possible(struct ath_regulatory *reg) +{ + if (config_enabled(CONFIG_ATH_REG_DYNAMIC_USER_CERT_TESTING)) + return true; + + switch (reg->country_code) { + case CTRY_UNITED_STATES: + case CTRY_JAPAN1: + case CTRY_JAPAN2: + case CTRY_JAPAN3: + case CTRY_JAPAN4: + case CTRY_JAPAN5: + case CTRY_JAPAN6: + case CTRY_JAPAN7: + case CTRY_JAPAN8: + case CTRY_JAPAN9: + case CTRY_JAPAN10: + case CTRY_JAPAN11: + case CTRY_JAPAN12: + case CTRY_JAPAN13: + case CTRY_JAPAN14: + case CTRY_JAPAN15: + case CTRY_JAPAN16: + case CTRY_JAPAN17: + case CTRY_JAPAN18: + case CTRY_JAPAN19: + case CTRY_JAPAN20: + case CTRY_JAPAN21: + case CTRY_JAPAN22: + case CTRY_JAPAN23: + case CTRY_JAPAN24: + case CTRY_JAPAN25: + case CTRY_JAPAN26: + case CTRY_JAPAN27: + case CTRY_JAPAN28: + case CTRY_JAPAN29: + case CTRY_JAPAN30: + case CTRY_JAPAN31: + case CTRY_JAPAN32: + case CTRY_JAPAN33: + case CTRY_JAPAN34: + case CTRY_JAPAN35: + case CTRY_JAPAN36: + case CTRY_JAPAN37: + case CTRY_JAPAN38: + case CTRY_JAPAN39: + case CTRY_JAPAN40: + case CTRY_JAPAN41: + case CTRY_JAPAN42: + case CTRY_JAPAN43: + case CTRY_JAPAN44: + case CTRY_JAPAN45: + case CTRY_JAPAN46: + case CTRY_JAPAN47: + case CTRY_JAPAN48: + case CTRY_JAPAN49: + case CTRY_JAPAN50: + case CTRY_JAPAN51: + case CTRY_JAPAN52: + case CTRY_JAPAN53: + case CTRY_JAPAN54: + case CTRY_JAPAN55: + case CTRY_JAPAN56: + case CTRY_JAPAN57: + case CTRY_JAPAN58: + case CTRY_JAPAN59: + return false; + } + + return true; +} + static inline bool is_wwr_sku(u16 regd) { return ((regd & COUNTRY_ERD_FLAG) != COUNTRY_ERD_FLAG) && @@ -401,78 +473,6 @@ static void ath_reg_dyn_country(struct wiphy *wiphy, reg_initiator_name(request->initiator)); } -static bool dynamic_country_user_possible(struct ath_regulatory *reg) -{ - if (config_enabled(CONFIG_ATH_REG_DYNAMIC_USER_CERT_TESTING)) - return true; - - switch (reg->country_code) { - case CTRY_UNITED_STATES: - case CTRY_JAPAN1: - case CTRY_JAPAN2: - case CTRY_JAPAN3: - case CTRY_JAPAN4: - case CTRY_JAPAN5: - case CTRY_JAPAN6: - case CTRY_JAPAN7: - case CTRY_JAPAN8: - case CTRY_JAPAN9: - case CTRY_JAPAN10: - case CTRY_JAPAN11: - case CTRY_JAPAN12: - case CTRY_JAPAN13: - case CTRY_JAPAN14: - case CTRY_JAPAN15: - case CTRY_JAPAN16: - case CTRY_JAPAN17: - case CTRY_JAPAN18: - case CTRY_JAPAN19: - case CTRY_JAPAN20: - case CTRY_JAPAN21: - case CTRY_JAPAN22: - case CTRY_JAPAN23: - case CTRY_JAPAN24: - case CTRY_JAPAN25: - case CTRY_JAPAN26: - case CTRY_JAPAN27: - case CTRY_JAPAN28: - case CTRY_JAPAN29: - case CTRY_JAPAN30: - case CTRY_JAPAN31: - case CTRY_JAPAN32: - case CTRY_JAPAN33: - case CTRY_JAPAN34: - case CTRY_JAPAN35: - case CTRY_JAPAN36: - case CTRY_JAPAN37: - case CTRY_JAPAN38: - case CTRY_JAPAN39: - case CTRY_JAPAN40: - case CTRY_JAPAN41: - case CTRY_JAPAN42: - case CTRY_JAPAN43: - case CTRY_JAPAN44: - case CTRY_JAPAN45: - case CTRY_JAPAN46: - case CTRY_JAPAN47: - case CTRY_JAPAN48: - case CTRY_JAPAN49: - case CTRY_JAPAN50: - case CTRY_JAPAN51: - case CTRY_JAPAN52: - case CTRY_JAPAN53: - case CTRY_JAPAN54: - case CTRY_JAPAN55: - case CTRY_JAPAN56: - case CTRY_JAPAN57: - case CTRY_JAPAN58: - case CTRY_JAPAN59: - return false; - } - - return true; -} - static void ath_reg_dyn_country_user(struct wiphy *wiphy, struct ath_regulatory *reg, struct regulatory_request *request) -- cgit v1.2.3-70-g09d2 From ba94c049e555d1701d547025f7d547a582833d03 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 29 Oct 2013 23:39:05 +0100 Subject: ath: dynamic user allow check helper to the top This will be used later. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/regd.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index e7d01723ea0..4a6c232c6c9 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -186,6 +186,15 @@ static bool dynamic_country_user_possible(struct ath_regulatory *reg) return true; } +static bool ath_reg_dyn_country_user_allow(struct ath_regulatory *reg) +{ + if (!config_enabled(CONFIG_ATH_REG_DYNAMIC_USER_REG_HINTS)) + return false; + if (!dynamic_country_user_possible(reg)) + return false; + return true; +} + static inline bool is_wwr_sku(u16 regd) { return ((regd & COUNTRY_ERD_FLAG) != COUNTRY_ERD_FLAG) && @@ -473,17 +482,6 @@ static void ath_reg_dyn_country(struct wiphy *wiphy, reg_initiator_name(request->initiator)); } -static void ath_reg_dyn_country_user(struct wiphy *wiphy, - struct ath_regulatory *reg, - struct regulatory_request *request) -{ - if (!config_enabled(CONFIG_ATH_REG_DYNAMIC_USER_REG_HINTS)) - return; - if (!dynamic_country_user_possible(reg)) - return; - ath_reg_dyn_country(wiphy, reg, request); -} - void ath_reg_notifier_apply(struct wiphy *wiphy, struct regulatory_request *request, struct ath_regulatory *reg) @@ -516,7 +514,8 @@ void ath_reg_notifier_apply(struct wiphy *wiphy, case NL80211_REGDOM_SET_BY_DRIVER: break; case NL80211_REGDOM_SET_BY_USER: - ath_reg_dyn_country_user(wiphy, reg, request); + if (ath_reg_dyn_country_user_allow(reg)) + ath_reg_dyn_country(wiphy, reg, request); break; case NL80211_REGDOM_SET_BY_COUNTRY_IE: ath_reg_dyn_country(wiphy, reg, request); -- cgit v1.2.3-70-g09d2 From 251c9ba19143caa5eb5b6ec52c77c70c9d7b3d8f Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 30 Oct 2013 00:10:07 +0100 Subject: ath: fix dynamic user regulatory domain support As it stands dynamic user regulatory domain support is only possible for a few programmed regulatory domains as a few countries do not allow for this. The existing code however only would take advantage of the feature if a custom world regulatory domain is used though as that's when we clear beconing flags. We need to lift this restriction as otherwise this feature is pointless. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/regd.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 4a6c232c6c9..9e154732afa 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -302,6 +302,7 @@ static void ath_force_no_ir_freq(struct wiphy *wiphy, u16 center_freq) static void __ath_reg_apply_beaconing_flags(struct wiphy *wiphy, + struct ath_regulatory *reg, enum nl80211_reg_initiator initiator, struct ieee80211_channel *ch) { @@ -313,6 +314,10 @@ __ath_reg_apply_beaconing_flags(struct wiphy *wiphy, case NL80211_REGDOM_SET_BY_COUNTRY_IE: ath_force_clear_no_ir_chan(wiphy, ch); break; + case NL80211_REGDOM_SET_BY_USER: + if (ath_reg_dyn_country_user_allow(reg)) + ath_force_clear_no_ir_chan(wiphy, ch); + break; default: if (ch->beacon_found) ch->flags &= ~IEEE80211_CHAN_NO_IR; @@ -328,6 +333,7 @@ __ath_reg_apply_beaconing_flags(struct wiphy *wiphy, */ static void ath_reg_apply_beaconing_flags(struct wiphy *wiphy, + struct ath_regulatory *reg, enum nl80211_reg_initiator initiator) { enum ieee80211_band band; @@ -341,8 +347,8 @@ ath_reg_apply_beaconing_flags(struct wiphy *wiphy, sband = wiphy->bands[band]; for (i = 0; i < sband->n_channels; i++) { ch = &sband->channels[i]; - __ath_reg_apply_beaconing_flags(wiphy, initiator, ch); - + __ath_reg_apply_beaconing_flags(wiphy, reg, + initiator, ch); } } } @@ -363,7 +369,8 @@ ath_reg_apply_beaconing_flags(struct wiphy *wiphy, */ static void ath_reg_apply_ir_flags(struct wiphy *wiphy, - enum nl80211_reg_initiator initiator) + struct ath_regulatory *reg, + enum nl80211_reg_initiator initiator) { struct ieee80211_supported_band *sband; @@ -376,6 +383,12 @@ ath_reg_apply_ir_flags(struct wiphy *wiphy, ath_force_clear_no_ir_freq(wiphy, 2467); ath_force_clear_no_ir_freq(wiphy, 2472); break; + case NL80211_REGDOM_SET_BY_USER: + if (!ath_reg_dyn_country_user_allow(reg)) + break; + ath_force_clear_no_ir_freq(wiphy, 2467); + ath_force_clear_no_ir_freq(wiphy, 2472); + break; default: ath_force_no_ir_freq(wiphy, 2467); ath_force_no_ir_freq(wiphy, 2472); @@ -424,12 +437,15 @@ static void ath_reg_apply_world_flags(struct wiphy *wiphy, case 0x66: case 0x67: case 0x6C: - ath_reg_apply_beaconing_flags(wiphy, initiator); + ath_reg_apply_beaconing_flags(wiphy, reg, initiator); break; case 0x68: - ath_reg_apply_beaconing_flags(wiphy, initiator); - ath_reg_apply_ir_flags(wiphy, initiator); + ath_reg_apply_beaconing_flags(wiphy, reg, initiator); + ath_reg_apply_ir_flags(wiphy, reg, initiator); break; + default: + if (ath_reg_dyn_country_user_allow(reg)) + ath_reg_apply_beaconing_flags(wiphy, reg, initiator); } } -- cgit v1.2.3-70-g09d2 From d70f2cf520cf8c86c6b467fc5dcea524ec51dc2f Mon Sep 17 00:00:00 2001 From: Kevin Wallace Date: Tue, 3 Dec 2013 02:55:22 -0800 Subject: macvlan: Support creating macvtaps from macvlans When running in a network namespace whose only link to the outside world is a macvlan device, not being able to create a macvtap off of it is a real pain. So modify macvtap creation to automatically forward a creation of a macvtap on a macvlan to become a creation of a macvtap on the underlying network device, just like is currently done with macvlan-on-macvlan devices. v2: Use netif_is_macvlan and macvlan_dev_real_dev helpers to make it more clear what we're doing. Signed-off-by: Kevin Wallace Signed-off-by: David S. Miller --- drivers/net/macvlan.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index acf93798dc6..cfb91570cdd 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -820,13 +820,11 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev, if (lowerdev == NULL) return -ENODEV; - /* When creating macvlans on top of other macvlans - use + /* When creating macvlans or macvtaps on top of other macvlans - use * the real device as the lowerdev. */ - if (lowerdev->rtnl_link_ops == dev->rtnl_link_ops) { - struct macvlan_dev *lowervlan = netdev_priv(lowerdev); - lowerdev = lowervlan->lowerdev; - } + if (netif_is_macvlan(lowerdev)) + lowerdev = macvlan_dev_real_dev(lowerdev); if (!tb[IFLA_MTU]) dev->mtu = lowerdev->mtu; -- cgit v1.2.3-70-g09d2 From e682adf021be796940be6cc10c07be7f7398c220 Mon Sep 17 00:00:00 2001 From: Fan Du Date: Thu, 7 Nov 2013 17:47:48 +0800 Subject: xfrm: Try to honor policy index if it's supplied by user xfrm code always searches for unused policy index for newly created policy regardless whether or not user space policy index hint supplied. This patch enables such feature so that using "ip xfrm ... index=xxx" can be used by user to set specific policy index. Currently this beahvior is broken, so this patch make it happen as expected. Signed-off-by: Fan Du Signed-off-by: Steffen Klassert --- net/xfrm/xfrm_policy.c | 16 +++++++++++----- net/xfrm/xfrm_user.c | 10 +++++++++- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 9a91f7431c4..a5bbdfb2874 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -538,7 +538,7 @@ static void xfrm_hash_resize(struct work_struct *work) /* Generate new index... KAME seems to generate them ordered by cost * of an absolute inpredictability of ordering of rules. This will not pass. */ -static u32 xfrm_gen_index(struct net *net, int dir) +static u32 xfrm_gen_index(struct net *net, int dir, u32 index) { static u32 idx_generator; @@ -548,8 +548,14 @@ static u32 xfrm_gen_index(struct net *net, int dir) u32 idx; int found; - idx = (idx_generator | dir); - idx_generator += 8; + if (!index) { + idx = (idx_generator | dir); + idx_generator += 8; + } else { + idx = index; + index = 0; + } + if (idx == 0) idx = 8; list = net->xfrm.policy_byidx + idx_hash(net, idx); @@ -672,7 +678,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) xfrm_policy_requeue(delpol, policy); __xfrm_policy_unlink(delpol, dir); } - policy->index = delpol ? delpol->index : xfrm_gen_index(net, dir); + policy->index = delpol ? delpol->index : xfrm_gen_index(net, dir, policy->index); hlist_add_head(&policy->byidx, net->xfrm.policy_byidx+idx_hash(net, policy->index)); policy->curlft.add_time = get_seconds(); policy->curlft.use_time = 0; @@ -1192,7 +1198,7 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) sk->sk_policy[dir] = pol; if (pol) { pol->curlft.add_time = get_seconds(); - pol->index = xfrm_gen_index(net, XFRM_POLICY_MAX+dir); + pol->index = xfrm_gen_index(net, XFRM_POLICY_MAX+dir, 0); __xfrm_policy_link(pol, XFRM_POLICY_MAX+dir); } if (old_pol) { diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index f964d4c00ff..4e0546e9bb0 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -1189,6 +1189,8 @@ static int verify_policy_type(u8 type) static int verify_newpolicy_info(struct xfrm_userpolicy_info *p) { + int ret; + switch (p->share) { case XFRM_SHARE_ANY: case XFRM_SHARE_SESSION: @@ -1224,7 +1226,13 @@ static int verify_newpolicy_info(struct xfrm_userpolicy_info *p) return -EINVAL; } - return verify_policy_dir(p->dir); + ret = verify_policy_dir(p->dir); + if (ret) + return ret; + if (p->index && ((p->index & XFRM_POLICY_MAX) != p->dir)) + return -EINVAL; + + return 0; } static int copy_from_user_sec_ctx(struct xfrm_policy *pol, struct nlattr **attrs) -- cgit v1.2.3-70-g09d2 From 8d549c4f5d92d80fc6f888fd314e10972ae0ec37 Mon Sep 17 00:00:00 2001 From: Fan Du Date: Thu, 7 Nov 2013 17:47:49 +0800 Subject: xfrm: Using the right namespace to migrate key info because the home agent could surely be run on a different net namespace other than init_net. The original behavior could lead into inconsistent of key info. Signed-off-by: Fan Du Signed-off-by: Steffen Klassert --- include/net/xfrm.h | 2 +- net/key/af_key.c | 3 ++- net/xfrm/xfrm_policy.c | 10 +++++----- net/xfrm/xfrm_user.c | 3 ++- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 6b82fdf4ba7..5b522c5f018 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -1581,7 +1581,7 @@ struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x, struct xfrm_migrate *m); int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, struct xfrm_migrate *m, int num_bundles, - struct xfrm_kmaddress *k); + struct xfrm_kmaddress *k, struct net *net); #endif int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport); diff --git a/net/key/af_key.c b/net/key/af_key.c index 545f047868a..3fa811c4691 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -2485,6 +2485,7 @@ static int pfkey_migrate(struct sock *sk, struct sk_buff *skb, struct xfrm_selector sel; struct xfrm_migrate m[XFRM_MAX_DEPTH]; struct xfrm_kmaddress k; + struct net *net = sock_net(sk); if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC - 1], ext_hdrs[SADB_EXT_ADDRESS_DST - 1]) || @@ -2558,7 +2559,7 @@ static int pfkey_migrate(struct sock *sk, struct sk_buff *skb, } return xfrm_migrate(&sel, dir, XFRM_POLICY_TYPE_MAIN, m, i, - kma ? &k : NULL); + kma ? &k : NULL, net); out: return err; diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index a5bbdfb2874..907fd2fa70b 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -3076,14 +3076,14 @@ static bool xfrm_migrate_selector_match(const struct xfrm_selector *sel_cmp, } static struct xfrm_policy * xfrm_migrate_policy_find(const struct xfrm_selector *sel, - u8 dir, u8 type) + u8 dir, u8 type, struct net *net) { struct xfrm_policy *pol, *ret = NULL; struct hlist_head *chain; u32 priority = ~0U; read_lock_bh(&xfrm_policy_lock); - chain = policy_hash_direct(&init_net, &sel->daddr, &sel->saddr, sel->family, dir); + chain = policy_hash_direct(net, &sel->daddr, &sel->saddr, sel->family, dir); hlist_for_each_entry(pol, chain, bydst) { if (xfrm_migrate_selector_match(sel, &pol->selector) && pol->type == type) { @@ -3092,7 +3092,7 @@ static struct xfrm_policy * xfrm_migrate_policy_find(const struct xfrm_selector break; } } - chain = &init_net.xfrm.policy_inexact[dir]; + chain = &net->xfrm.policy_inexact[dir]; hlist_for_each_entry(pol, chain, bydst) { if (xfrm_migrate_selector_match(sel, &pol->selector) && pol->type == type && @@ -3216,7 +3216,7 @@ static int xfrm_migrate_check(const struct xfrm_migrate *m, int num_migrate) int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, struct xfrm_migrate *m, int num_migrate, - struct xfrm_kmaddress *k) + struct xfrm_kmaddress *k, struct net *net) { int i, err, nx_cur = 0, nx_new = 0; struct xfrm_policy *pol = NULL; @@ -3229,7 +3229,7 @@ int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, goto out; /* Stage 1 - find policy */ - if ((pol = xfrm_migrate_policy_find(sel, dir, type)) == NULL) { + if ((pol = xfrm_migrate_policy_find(sel, dir, type, net)) == NULL) { err = -ENOENT; goto out; } diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 4e0546e9bb0..840cc8d9fbe 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -2137,6 +2137,7 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh, u8 type; int err; int n = 0; + struct net *net = sock_net(skb->sk); if (attrs[XFRMA_MIGRATE] == NULL) return -EINVAL; @@ -2154,7 +2155,7 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh, if (!n) return 0; - xfrm_migrate(&pi->sel, pi->dir, type, m, n, kmp); + xfrm_migrate(&pi->sel, pi->dir, type, m, n, kmp, net); return 0; } -- cgit v1.2.3-70-g09d2 From 283bc9f35bbbcb0e9ab4e6d2427da7f9f710d52d Mon Sep 17 00:00:00 2001 From: Fan Du Date: Thu, 7 Nov 2013 17:47:50 +0800 Subject: xfrm: Namespacify xfrm state/policy locks By semantics, xfrm layer is fully name space aware, so will the locks, e.g. xfrm_state/pocliy_lock. Ensure exclusive access into state/policy link list for different name space with one global lock is not right in terms of semantics aspect at first place, as they are indeed mutually independent with each other, but also more seriously causes scalability problem. One practical scenario is on a Open Network Stack, more than hundreds of lxc tenants acts as routers within one host, a global xfrm_state/policy_lock becomes the bottleneck. But onces those locks are decoupled in a per-namespace fashion, locks contend is just with in specific name space scope, without causing additional SPD/SAD access delay for other name space. Also this patch improve scalability while as without changing original xfrm behavior. Signed-off-by: Fan Du Signed-off-by: Steffen Klassert --- include/net/netns/xfrm.h | 4 ++ include/net/xfrm.h | 11 +++-- net/key/af_key.c | 15 ++++--- net/xfrm/xfrm_policy.c | 104 +++++++++++++++++++++++++---------------------- net/xfrm/xfrm_state.c | 104 ++++++++++++++++++++++++----------------------- net/xfrm/xfrm_user.c | 14 +++++-- 6 files changed, 138 insertions(+), 114 deletions(-) diff --git a/include/net/netns/xfrm.h b/include/net/netns/xfrm.h index 5299e69a32a..ea28404e9d7 100644 --- a/include/net/netns/xfrm.h +++ b/include/net/netns/xfrm.h @@ -59,6 +59,10 @@ struct netns_xfrm { #if IS_ENABLED(CONFIG_IPV6) struct dst_ops xfrm6_dst_ops; #endif + spinlock_t xfrm_state_lock; + spinlock_t xfrm_policy_sk_bundle_lock; + rwlock_t xfrm_policy_lock; + struct mutex xfrm_cfg_mutex; }; #endif diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 5b522c5f018..59f5d0a6c7f 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -53,7 +53,6 @@ #define XFRM_INC_STATS_USER(net, field) ((void)(net)) #endif -extern struct mutex xfrm_cfg_mutex; /* Organization of SPD aka "XFRM rules" ------------------------------------ @@ -1409,7 +1408,7 @@ static inline void xfrm_sysctl_fini(struct net *net) void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto); int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk, int (*func)(struct xfrm_state *, int, void*), void *); -void xfrm_state_walk_done(struct xfrm_state_walk *walk); +void xfrm_state_walk_done(struct xfrm_state_walk *walk, struct net *net); struct xfrm_state *xfrm_state_alloc(struct net *net); struct xfrm_state *xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr, @@ -1436,12 +1435,12 @@ struct xfrm_state *xfrm_state_lookup_byaddr(struct net *net, u32 mark, unsigned short family); #ifdef CONFIG_XFRM_SUB_POLICY int xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n, - unsigned short family); + unsigned short family, struct net *net); int xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n, unsigned short family); #else static inline int xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, - int n, unsigned short family) + int n, unsigned short family, struct net *net) { return -ENOSYS; } @@ -1553,7 +1552,7 @@ void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type); int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk, int (*func)(struct xfrm_policy *, int, int, void*), void *); -void xfrm_policy_walk_done(struct xfrm_policy_walk *walk); +void xfrm_policy_walk_done(struct xfrm_policy_walk *walk, struct net *net); int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl); struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type, int dir, @@ -1576,7 +1575,7 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol); int km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, const struct xfrm_migrate *m, int num_bundles, const struct xfrm_kmaddress *k); -struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m); +struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net); struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x, struct xfrm_migrate *m); int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, diff --git a/net/key/af_key.c b/net/key/af_key.c index 3fa811c4691..9a039acf37e 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -1785,7 +1785,9 @@ static int pfkey_dump_sa(struct pfkey_sock *pfk) static void pfkey_dump_sa_done(struct pfkey_sock *pfk) { - xfrm_state_walk_done(&pfk->dump.u.state); + struct net *net = sock_net(&pfk->sk); + + xfrm_state_walk_done(&pfk->dump.u.state, net); } static int pfkey_dump(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs) @@ -1861,7 +1863,7 @@ static u32 gen_reqid(struct net *net) reqid = IPSEC_MANUAL_REQID_MAX+1; xfrm_policy_walk_init(&walk, XFRM_POLICY_TYPE_MAIN); rc = xfrm_policy_walk(net, &walk, check_reqid, (void*)&reqid); - xfrm_policy_walk_done(&walk); + xfrm_policy_walk_done(&walk, net); if (rc != -EEXIST) return reqid; } while (reqid != start); @@ -2660,7 +2662,9 @@ static int pfkey_dump_sp(struct pfkey_sock *pfk) static void pfkey_dump_sp_done(struct pfkey_sock *pfk) { - xfrm_policy_walk_done(&pfk->dump.u.policy); + struct net *net = sock_net((struct sock *)pfk); + + xfrm_policy_walk_done(&pfk->dump.u.policy, net); } static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs) @@ -3570,6 +3574,7 @@ static int pfkey_sendmsg(struct kiocb *kiocb, struct sk_buff *skb = NULL; struct sadb_msg *hdr = NULL; int err; + struct net *net = sock_net(sk); err = -EOPNOTSUPP; if (msg->msg_flags & MSG_OOB) @@ -3592,9 +3597,9 @@ static int pfkey_sendmsg(struct kiocb *kiocb, if (!hdr) goto out; - mutex_lock(&xfrm_cfg_mutex); + mutex_lock(&net->xfrm.xfrm_cfg_mutex); err = pfkey_process(sk, skb, hdr); - mutex_unlock(&xfrm_cfg_mutex); + mutex_unlock(&net->xfrm.xfrm_cfg_mutex); out: if (err && hdr && pfkey_error(hdr, err, sk) == 0) diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 907fd2fa70b..73b04d3df44 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -39,12 +39,7 @@ #define XFRM_QUEUE_TMO_MAX ((unsigned)(60*HZ)) #define XFRM_MAX_QUEUE_LEN 100 -DEFINE_MUTEX(xfrm_cfg_mutex); -EXPORT_SYMBOL(xfrm_cfg_mutex); - -static DEFINE_SPINLOCK(xfrm_policy_sk_bundle_lock); static struct dst_entry *xfrm_policy_sk_bundles; -static DEFINE_RWLOCK(xfrm_policy_lock); static DEFINE_SPINLOCK(xfrm_policy_afinfo_lock); static struct xfrm_policy_afinfo __rcu *xfrm_policy_afinfo[NPROTO] @@ -438,7 +433,7 @@ static void xfrm_bydst_resize(struct net *net, int dir) if (!ndst) return; - write_lock_bh(&xfrm_policy_lock); + write_lock_bh(&net->xfrm.xfrm_policy_lock); for (i = hmask; i >= 0; i--) xfrm_dst_hash_transfer(odst + i, ndst, nhashmask); @@ -446,7 +441,7 @@ static void xfrm_bydst_resize(struct net *net, int dir) net->xfrm.policy_bydst[dir].table = ndst; net->xfrm.policy_bydst[dir].hmask = nhashmask; - write_unlock_bh(&xfrm_policy_lock); + write_unlock_bh(&net->xfrm.xfrm_policy_lock); xfrm_hash_free(odst, (hmask + 1) * sizeof(struct hlist_head)); } @@ -463,7 +458,7 @@ static void xfrm_byidx_resize(struct net *net, int total) if (!nidx) return; - write_lock_bh(&xfrm_policy_lock); + write_lock_bh(&net->xfrm.xfrm_policy_lock); for (i = hmask; i >= 0; i--) xfrm_idx_hash_transfer(oidx + i, nidx, nhashmask); @@ -471,7 +466,7 @@ static void xfrm_byidx_resize(struct net *net, int total) net->xfrm.policy_byidx = nidx; net->xfrm.policy_idx_hmask = nhashmask; - write_unlock_bh(&xfrm_policy_lock); + write_unlock_bh(&net->xfrm.xfrm_policy_lock); xfrm_hash_free(oidx, (hmask + 1) * sizeof(struct hlist_head)); } @@ -504,7 +499,7 @@ static inline int xfrm_byidx_should_resize(struct net *net, int total) void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si) { - read_lock_bh(&xfrm_policy_lock); + read_lock_bh(&net->xfrm.xfrm_policy_lock); si->incnt = net->xfrm.policy_count[XFRM_POLICY_IN]; si->outcnt = net->xfrm.policy_count[XFRM_POLICY_OUT]; si->fwdcnt = net->xfrm.policy_count[XFRM_POLICY_FWD]; @@ -513,7 +508,7 @@ void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si) si->fwdscnt = net->xfrm.policy_count[XFRM_POLICY_FWD+XFRM_POLICY_MAX]; si->spdhcnt = net->xfrm.policy_idx_hmask; si->spdhmcnt = xfrm_policy_hashmax; - read_unlock_bh(&xfrm_policy_lock); + read_unlock_bh(&net->xfrm.xfrm_policy_lock); } EXPORT_SYMBOL(xfrm_spd_getinfo); @@ -636,7 +631,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) struct hlist_head *chain; struct hlist_node *newpos; - write_lock_bh(&xfrm_policy_lock); + write_lock_bh(&net->xfrm.xfrm_policy_lock); chain = policy_hash_bysel(net, &policy->selector, policy->family, dir); delpol = NULL; newpos = NULL; @@ -647,7 +642,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) xfrm_sec_ctx_match(pol->security, policy->security) && !WARN_ON(delpol)) { if (excl) { - write_unlock_bh(&xfrm_policy_lock); + write_unlock_bh(&net->xfrm.xfrm_policy_lock); return -EEXIST; } delpol = pol; @@ -685,7 +680,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) if (!mod_timer(&policy->timer, jiffies + HZ)) xfrm_pol_hold(policy); list_add(&policy->walk.all, &net->xfrm.policy_all); - write_unlock_bh(&xfrm_policy_lock); + write_unlock_bh(&net->xfrm.xfrm_policy_lock); if (delpol) xfrm_policy_kill(delpol); @@ -705,7 +700,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type, struct hlist_head *chain; *err = 0; - write_lock_bh(&xfrm_policy_lock); + write_lock_bh(&net->xfrm.xfrm_policy_lock); chain = policy_hash_bysel(net, sel, sel->family, dir); ret = NULL; hlist_for_each_entry(pol, chain, bydst) { @@ -718,7 +713,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type, *err = security_xfrm_policy_delete( pol->security); if (*err) { - write_unlock_bh(&xfrm_policy_lock); + write_unlock_bh(&net->xfrm.xfrm_policy_lock); return pol; } __xfrm_policy_unlink(pol, dir); @@ -727,7 +722,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type, break; } } - write_unlock_bh(&xfrm_policy_lock); + write_unlock_bh(&net->xfrm.xfrm_policy_lock); if (ret && delete) xfrm_policy_kill(ret); @@ -746,7 +741,7 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type, return NULL; *err = 0; - write_lock_bh(&xfrm_policy_lock); + write_lock_bh(&net->xfrm.xfrm_policy_lock); chain = net->xfrm.policy_byidx + idx_hash(net, id); ret = NULL; hlist_for_each_entry(pol, chain, byidx) { @@ -757,7 +752,7 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type, *err = security_xfrm_policy_delete( pol->security); if (*err) { - write_unlock_bh(&xfrm_policy_lock); + write_unlock_bh(&net->xfrm.xfrm_policy_lock); return pol; } __xfrm_policy_unlink(pol, dir); @@ -766,7 +761,7 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type, break; } } - write_unlock_bh(&xfrm_policy_lock); + write_unlock_bh(&net->xfrm.xfrm_policy_lock); if (ret && delete) xfrm_policy_kill(ret); @@ -829,7 +824,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) { int dir, err = 0, cnt = 0; - write_lock_bh(&xfrm_policy_lock); + write_lock_bh(&net->xfrm.xfrm_policy_lock); err = xfrm_policy_flush_secctx_check(net, type, audit_info); if (err) @@ -845,7 +840,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) if (pol->type != type) continue; __xfrm_policy_unlink(pol, dir); - write_unlock_bh(&xfrm_policy_lock); + write_unlock_bh(&net->xfrm.xfrm_policy_lock); cnt++; xfrm_audit_policy_delete(pol, 1, audit_info->loginuid, @@ -854,7 +849,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) xfrm_policy_kill(pol); - write_lock_bh(&xfrm_policy_lock); + write_lock_bh(&net->xfrm.xfrm_policy_lock); goto again1; } @@ -866,7 +861,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) if (pol->type != type) continue; __xfrm_policy_unlink(pol, dir); - write_unlock_bh(&xfrm_policy_lock); + write_unlock_bh(&net->xfrm.xfrm_policy_lock); cnt++; xfrm_audit_policy_delete(pol, 1, @@ -875,7 +870,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) audit_info->secid); xfrm_policy_kill(pol); - write_lock_bh(&xfrm_policy_lock); + write_lock_bh(&net->xfrm.xfrm_policy_lock); goto again2; } } @@ -884,7 +879,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) if (!cnt) err = -ESRCH; out: - write_unlock_bh(&xfrm_policy_lock); + write_unlock_bh(&net->xfrm.xfrm_policy_lock); return err; } EXPORT_SYMBOL(xfrm_policy_flush); @@ -904,7 +899,7 @@ int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk, if (list_empty(&walk->walk.all) && walk->seq != 0) return 0; - write_lock_bh(&xfrm_policy_lock); + write_lock_bh(&net->xfrm.xfrm_policy_lock); if (list_empty(&walk->walk.all)) x = list_first_entry(&net->xfrm.policy_all, struct xfrm_policy_walk_entry, all); else @@ -930,7 +925,7 @@ int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk, } list_del_init(&walk->walk.all); out: - write_unlock_bh(&xfrm_policy_lock); + write_unlock_bh(&net->xfrm.xfrm_policy_lock); return error; } EXPORT_SYMBOL(xfrm_policy_walk); @@ -944,14 +939,14 @@ void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type) } EXPORT_SYMBOL(xfrm_policy_walk_init); -void xfrm_policy_walk_done(struct xfrm_policy_walk *walk) +void xfrm_policy_walk_done(struct xfrm_policy_walk *walk, struct net *net) { if (list_empty(&walk->walk.all)) return; - write_lock_bh(&xfrm_policy_lock); + write_lock_bh(&net->xfrm.xfrm_policy_lock); /*FIXME where is net? */ list_del(&walk->walk.all); - write_unlock_bh(&xfrm_policy_lock); + write_unlock_bh(&net->xfrm.xfrm_policy_lock); } EXPORT_SYMBOL(xfrm_policy_walk_done); @@ -996,7 +991,7 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type, if (unlikely(!daddr || !saddr)) return NULL; - read_lock_bh(&xfrm_policy_lock); + read_lock_bh(&net->xfrm.xfrm_policy_lock); chain = policy_hash_direct(net, daddr, saddr, family, dir); ret = NULL; hlist_for_each_entry(pol, chain, bydst) { @@ -1032,7 +1027,7 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type, if (ret) xfrm_pol_hold(ret); fail: - read_unlock_bh(&xfrm_policy_lock); + read_unlock_bh(&net->xfrm.xfrm_policy_lock); return ret; } @@ -1109,8 +1104,9 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, const struct flowi *fl) { struct xfrm_policy *pol; + struct net *net = sock_net(sk); - read_lock_bh(&xfrm_policy_lock); + read_lock_bh(&net->xfrm.xfrm_policy_lock); if ((pol = sk->sk_policy[dir]) != NULL) { bool match = xfrm_selector_match(&pol->selector, fl, sk->sk_family); @@ -1134,7 +1130,7 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, pol = NULL; } out: - read_unlock_bh(&xfrm_policy_lock); + read_unlock_bh(&net->xfrm.xfrm_policy_lock); return pol; } @@ -1172,9 +1168,11 @@ static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, int xfrm_policy_delete(struct xfrm_policy *pol, int dir) { - write_lock_bh(&xfrm_policy_lock); + struct net *net = xp_net(pol); + + write_lock_bh(&net->xfrm.xfrm_policy_lock); pol = __xfrm_policy_unlink(pol, dir); - write_unlock_bh(&xfrm_policy_lock); + write_unlock_bh(&net->xfrm.xfrm_policy_lock); if (pol) { xfrm_policy_kill(pol); return 0; @@ -1193,7 +1191,7 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) return -EINVAL; #endif - write_lock_bh(&xfrm_policy_lock); + write_lock_bh(&net->xfrm.xfrm_policy_lock); old_pol = sk->sk_policy[dir]; sk->sk_policy[dir] = pol; if (pol) { @@ -1210,7 +1208,7 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) */ __xfrm_policy_unlink(old_pol, XFRM_POLICY_MAX+dir); } - write_unlock_bh(&xfrm_policy_lock); + write_unlock_bh(&net->xfrm.xfrm_policy_lock); if (old_pol) { xfrm_policy_kill(old_pol); @@ -1221,6 +1219,7 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) static struct xfrm_policy *clone_policy(const struct xfrm_policy *old, int dir) { struct xfrm_policy *newp = xfrm_policy_alloc(xp_net(old), GFP_ATOMIC); + struct net *net = xp_net(old); if (newp) { newp->selector = old->selector; @@ -1239,9 +1238,9 @@ static struct xfrm_policy *clone_policy(const struct xfrm_policy *old, int dir) newp->type = old->type; memcpy(newp->xfrm_vec, old->xfrm_vec, newp->xfrm_nr*sizeof(struct xfrm_tmpl)); - write_lock_bh(&xfrm_policy_lock); + write_lock_bh(&net->xfrm.xfrm_policy_lock); __xfrm_policy_link(newp, XFRM_POLICY_MAX+dir); - write_unlock_bh(&xfrm_policy_lock); + write_unlock_bh(&net->xfrm.xfrm_policy_lock); xfrm_pol_put(newp); } return newp; @@ -2112,10 +2111,10 @@ restart: dst_hold(&xdst->u.dst); - spin_lock_bh(&xfrm_policy_sk_bundle_lock); + spin_lock_bh(&net->xfrm.xfrm_policy_sk_bundle_lock); xdst->u.dst.next = xfrm_policy_sk_bundles; xfrm_policy_sk_bundles = &xdst->u.dst; - spin_unlock_bh(&xfrm_policy_sk_bundle_lock); + spin_unlock_bh(&net->xfrm.xfrm_policy_sk_bundle_lock); route = xdst->route; } @@ -2440,7 +2439,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, } xfrm_nr = ti; if (npols > 1) { - xfrm_tmpl_sort(stp, tpp, xfrm_nr, family); + xfrm_tmpl_sort(stp, tpp, xfrm_nr, family, net); tpp = stp; } @@ -2569,10 +2568,10 @@ static void __xfrm_garbage_collect(struct net *net) { struct dst_entry *head, *next; - spin_lock_bh(&xfrm_policy_sk_bundle_lock); + spin_lock_bh(&net->xfrm.xfrm_policy_sk_bundle_lock); head = xfrm_policy_sk_bundles; xfrm_policy_sk_bundles = NULL; - spin_unlock_bh(&xfrm_policy_sk_bundle_lock); + spin_unlock_bh(&net->xfrm.xfrm_policy_sk_bundle_lock); while (head) { next = head->next; @@ -2956,6 +2955,13 @@ static int __net_init xfrm_net_init(struct net *net) rv = xfrm_sysctl_init(net); if (rv < 0) goto out_sysctl; + + /* Initialize the per-net locks here */ + spin_lock_init(&net->xfrm.xfrm_state_lock); + rwlock_init(&net->xfrm.xfrm_policy_lock); + spin_lock_init(&net->xfrm.xfrm_policy_sk_bundle_lock); + mutex_init(&net->xfrm.xfrm_cfg_mutex); + return 0; out_sysctl: @@ -3082,7 +3088,7 @@ static struct xfrm_policy * xfrm_migrate_policy_find(const struct xfrm_selector struct hlist_head *chain; u32 priority = ~0U; - read_lock_bh(&xfrm_policy_lock); + read_lock_bh(&net->xfrm.xfrm_policy_lock); /*FIXME*/ chain = policy_hash_direct(net, &sel->daddr, &sel->saddr, sel->family, dir); hlist_for_each_entry(pol, chain, bydst) { if (xfrm_migrate_selector_match(sel, &pol->selector) && @@ -3105,7 +3111,7 @@ static struct xfrm_policy * xfrm_migrate_policy_find(const struct xfrm_selector if (ret) xfrm_pol_hold(ret); - read_unlock_bh(&xfrm_policy_lock); + read_unlock_bh(&net->xfrm.xfrm_policy_lock); return ret; } @@ -3236,7 +3242,7 @@ int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, /* Stage 2 - find and update state(s) */ for (i = 0, mp = m; i < num_migrate; i++, mp++) { - if ((x = xfrm_migrate_state_find(mp))) { + if ((x = xfrm_migrate_state_find(mp, net))) { x_cur[nx_cur] = x; nx_cur++; if ((xc = xfrm_state_migrate(x, mp))) { diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 68c2f357a18..290479d0746 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -35,8 +35,6 @@ destination/tunnel endpoint. (output) */ -static DEFINE_SPINLOCK(xfrm_state_lock); - static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024; static inline unsigned int xfrm_dst_hash(struct net *net, @@ -127,7 +125,7 @@ static void xfrm_hash_resize(struct work_struct *work) goto out_unlock; } - spin_lock_bh(&xfrm_state_lock); + spin_lock_bh(&net->xfrm.xfrm_state_lock); nhashmask = (nsize / sizeof(struct hlist_head)) - 1U; for (i = net->xfrm.state_hmask; i >= 0; i--) @@ -144,7 +142,7 @@ static void xfrm_hash_resize(struct work_struct *work) net->xfrm.state_byspi = nspi; net->xfrm.state_hmask = nhashmask; - spin_unlock_bh(&xfrm_state_lock); + spin_unlock_bh(&net->xfrm.xfrm_state_lock); osize = (ohashmask + 1) * sizeof(struct hlist_head); xfrm_hash_free(odst, osize); @@ -535,14 +533,14 @@ int __xfrm_state_delete(struct xfrm_state *x) if (x->km.state != XFRM_STATE_DEAD) { x->km.state = XFRM_STATE_DEAD; - spin_lock(&xfrm_state_lock); + spin_lock(&net->xfrm.xfrm_state_lock); list_del(&x->km.all); hlist_del(&x->bydst); hlist_del(&x->bysrc); if (x->id.spi) hlist_del(&x->byspi); net->xfrm.state_num--; - spin_unlock(&xfrm_state_lock); + spin_unlock(&net->xfrm.xfrm_state_lock); /* All xfrm_state objects are created by xfrm_state_alloc. * The xfrm_state_alloc call gives a reference, and that @@ -603,7 +601,7 @@ int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info) { int i, err = 0, cnt = 0; - spin_lock_bh(&xfrm_state_lock); + spin_lock_bh(&net->xfrm.xfrm_state_lock); err = xfrm_state_flush_secctx_check(net, proto, audit_info); if (err) goto out; @@ -616,7 +614,7 @@ restart: if (!xfrm_state_kern(x) && xfrm_id_proto_match(x->id.proto, proto)) { xfrm_state_hold(x); - spin_unlock_bh(&xfrm_state_lock); + spin_unlock_bh(&net->xfrm.xfrm_state_lock); err = xfrm_state_delete(x); xfrm_audit_state_delete(x, err ? 0 : 1, @@ -627,7 +625,7 @@ restart: if (!err) cnt++; - spin_lock_bh(&xfrm_state_lock); + spin_lock_bh(&net->xfrm.xfrm_state_lock); goto restart; } } @@ -636,7 +634,7 @@ restart: err = 0; out: - spin_unlock_bh(&xfrm_state_lock); + spin_unlock_bh(&net->xfrm.xfrm_state_lock); wake_up(&net->xfrm.km_waitq); return err; } @@ -644,11 +642,11 @@ EXPORT_SYMBOL(xfrm_state_flush); void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si) { - spin_lock_bh(&xfrm_state_lock); + spin_lock_bh(&net->xfrm.xfrm_state_lock); si->sadcnt = net->xfrm.state_num; si->sadhcnt = net->xfrm.state_hmask; si->sadhmcnt = xfrm_state_hashmax; - spin_unlock_bh(&xfrm_state_lock); + spin_unlock_bh(&net->xfrm.xfrm_state_lock); } EXPORT_SYMBOL(xfrm_sad_getinfo); @@ -801,7 +799,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr, to_put = NULL; - spin_lock_bh(&xfrm_state_lock); + spin_lock_bh(&net->xfrm.xfrm_state_lock); h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, encap_family); hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { if (x->props.family == encap_family && @@ -886,7 +884,7 @@ out: xfrm_state_hold(x); else *err = acquire_in_progress ? -EAGAIN : error; - spin_unlock_bh(&xfrm_state_lock); + spin_unlock_bh(&net->xfrm.xfrm_state_lock); if (to_put) xfrm_state_put(to_put); return x; @@ -900,7 +898,7 @@ xfrm_stateonly_find(struct net *net, u32 mark, unsigned int h; struct xfrm_state *rx = NULL, *x = NULL; - spin_lock(&xfrm_state_lock); + spin_lock(&net->xfrm.xfrm_state_lock); h = xfrm_dst_hash(net, daddr, saddr, reqid, family); hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { if (x->props.family == family && @@ -918,7 +916,7 @@ xfrm_stateonly_find(struct net *net, u32 mark, if (rx) xfrm_state_hold(rx); - spin_unlock(&xfrm_state_lock); + spin_unlock(&net->xfrm.xfrm_state_lock); return rx; @@ -957,7 +955,7 @@ static void __xfrm_state_insert(struct xfrm_state *x) xfrm_hash_grow_check(net, x->bydst.next != NULL); } -/* xfrm_state_lock is held */ +/* net->xfrm.xfrm_state_lock is held */ static void __xfrm_state_bump_genids(struct xfrm_state *xnew) { struct net *net = xs_net(xnew); @@ -980,14 +978,16 @@ static void __xfrm_state_bump_genids(struct xfrm_state *xnew) void xfrm_state_insert(struct xfrm_state *x) { - spin_lock_bh(&xfrm_state_lock); + struct net *net = xs_net(x); + + spin_lock_bh(&net->xfrm.xfrm_state_lock); __xfrm_state_bump_genids(x); __xfrm_state_insert(x); - spin_unlock_bh(&xfrm_state_lock); + spin_unlock_bh(&net->xfrm.xfrm_state_lock); } EXPORT_SYMBOL(xfrm_state_insert); -/* xfrm_state_lock is held */ +/* net->xfrm.xfrm_state_lock is held */ static struct xfrm_state *__find_acq_core(struct net *net, const struct xfrm_mark *m, unsigned short family, u8 mode, @@ -1079,7 +1079,7 @@ int xfrm_state_add(struct xfrm_state *x) to_put = NULL; - spin_lock_bh(&xfrm_state_lock); + spin_lock_bh(&net->xfrm.xfrm_state_lock); x1 = __xfrm_state_locate(x, use_spi, family); if (x1) { @@ -1108,7 +1108,7 @@ int xfrm_state_add(struct xfrm_state *x) err = 0; out: - spin_unlock_bh(&xfrm_state_lock); + spin_unlock_bh(&net->xfrm.xfrm_state_lock); if (x1) { xfrm_state_delete(x1); @@ -1203,16 +1203,16 @@ out: return NULL; } -/* xfrm_state_lock is held */ -struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m) +/* net->xfrm.xfrm_state_lock is held */ +struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net) { unsigned int h; struct xfrm_state *x; if (m->reqid) { - h = xfrm_dst_hash(&init_net, &m->old_daddr, &m->old_saddr, + h = xfrm_dst_hash(net, &m->old_daddr, &m->old_saddr, m->reqid, m->old_family); - hlist_for_each_entry(x, init_net.xfrm.state_bydst+h, bydst) { + hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { if (x->props.mode != m->mode || x->id.proto != m->proto) continue; @@ -1227,9 +1227,9 @@ struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m) return x; } } else { - h = xfrm_src_hash(&init_net, &m->old_daddr, &m->old_saddr, + h = xfrm_src_hash(net, &m->old_daddr, &m->old_saddr, m->old_family); - hlist_for_each_entry(x, init_net.xfrm.state_bysrc+h, bysrc) { + hlist_for_each_entry(x, net->xfrm.state_bysrc+h, bysrc) { if (x->props.mode != m->mode || x->id.proto != m->proto) continue; @@ -1283,10 +1283,11 @@ int xfrm_state_update(struct xfrm_state *x) struct xfrm_state *x1, *to_put; int err; int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); + struct net *net = xs_net(x); to_put = NULL; - spin_lock_bh(&xfrm_state_lock); + spin_lock_bh(&net->xfrm.xfrm_state_lock); x1 = __xfrm_state_locate(x, use_spi, x->props.family); err = -ESRCH; @@ -1306,7 +1307,7 @@ int xfrm_state_update(struct xfrm_state *x) err = 0; out: - spin_unlock_bh(&xfrm_state_lock); + spin_unlock_bh(&net->xfrm.xfrm_state_lock); if (to_put) xfrm_state_put(to_put); @@ -1377,9 +1378,9 @@ xfrm_state_lookup(struct net *net, u32 mark, const xfrm_address_t *daddr, __be32 { struct xfrm_state *x; - spin_lock_bh(&xfrm_state_lock); + spin_lock_bh(&net->xfrm.xfrm_state_lock); x = __xfrm_state_lookup(net, mark, daddr, spi, proto, family); - spin_unlock_bh(&xfrm_state_lock); + spin_unlock_bh(&net->xfrm.xfrm_state_lock); return x; } EXPORT_SYMBOL(xfrm_state_lookup); @@ -1391,9 +1392,9 @@ xfrm_state_lookup_byaddr(struct net *net, u32 mark, { struct xfrm_state *x; - spin_lock_bh(&xfrm_state_lock); + spin_lock_bh(&net->xfrm.xfrm_state_lock); x = __xfrm_state_lookup_byaddr(net, mark, daddr, saddr, proto, family); - spin_unlock_bh(&xfrm_state_lock); + spin_unlock_bh(&net->xfrm.xfrm_state_lock); return x; } EXPORT_SYMBOL(xfrm_state_lookup_byaddr); @@ -1405,9 +1406,9 @@ xfrm_find_acq(struct net *net, const struct xfrm_mark *mark, u8 mode, u32 reqid, { struct xfrm_state *x; - spin_lock_bh(&xfrm_state_lock); + spin_lock_bh(&net->xfrm.xfrm_state_lock); x = __find_acq_core(net, mark, family, mode, reqid, proto, daddr, saddr, create); - spin_unlock_bh(&xfrm_state_lock); + spin_unlock_bh(&net->xfrm.xfrm_state_lock); return x; } @@ -1416,17 +1417,17 @@ EXPORT_SYMBOL(xfrm_find_acq); #ifdef CONFIG_XFRM_SUB_POLICY int xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n, - unsigned short family) + unsigned short family, struct net *net) { int err = 0; struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); if (!afinfo) return -EAFNOSUPPORT; - spin_lock_bh(&xfrm_state_lock); + spin_lock_bh(&net->xfrm.xfrm_state_lock); /*FIXME*/ if (afinfo->tmpl_sort) err = afinfo->tmpl_sort(dst, src, n); - spin_unlock_bh(&xfrm_state_lock); + spin_unlock_bh(&net->xfrm.xfrm_state_lock); xfrm_state_put_afinfo(afinfo); return err; } @@ -1438,13 +1439,15 @@ xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n, { int err = 0; struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); + struct net *net = xs_net(*dst); + if (!afinfo) return -EAFNOSUPPORT; - spin_lock_bh(&xfrm_state_lock); + spin_lock_bh(&net->xfrm.xfrm_state_lock); if (afinfo->state_sort) err = afinfo->state_sort(dst, src, n); - spin_unlock_bh(&xfrm_state_lock); + spin_unlock_bh(&net->xfrm.xfrm_state_lock); xfrm_state_put_afinfo(afinfo); return err; } @@ -1476,9 +1479,9 @@ struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq) { struct xfrm_state *x; - spin_lock_bh(&xfrm_state_lock); + spin_lock_bh(&net->xfrm.xfrm_state_lock); x = __xfrm_find_acq_byseq(net, mark, seq); - spin_unlock_bh(&xfrm_state_lock); + spin_unlock_bh(&net->xfrm.xfrm_state_lock); return x; } EXPORT_SYMBOL(xfrm_find_acq_byseq); @@ -1536,10 +1539,10 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) } } if (x->id.spi) { - spin_lock_bh(&xfrm_state_lock); + spin_lock_bh(&net->xfrm.xfrm_state_lock); h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, x->props.family); hlist_add_head(&x->byspi, net->xfrm.state_byspi+h); - spin_unlock_bh(&xfrm_state_lock); + spin_unlock_bh(&net->xfrm.xfrm_state_lock); err = 0; } @@ -1562,7 +1565,7 @@ int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk, if (walk->seq != 0 && list_empty(&walk->all)) return 0; - spin_lock_bh(&xfrm_state_lock); + spin_lock_bh(&net->xfrm.xfrm_state_lock); if (list_empty(&walk->all)) x = list_first_entry(&net->xfrm.state_all, struct xfrm_state_walk, all); else @@ -1586,7 +1589,7 @@ int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk, } list_del_init(&walk->all); out: - spin_unlock_bh(&xfrm_state_lock); + spin_unlock_bh(&net->xfrm.xfrm_state_lock); return err; } EXPORT_SYMBOL(xfrm_state_walk); @@ -1600,14 +1603,14 @@ void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto) } EXPORT_SYMBOL(xfrm_state_walk_init); -void xfrm_state_walk_done(struct xfrm_state_walk *walk) +void xfrm_state_walk_done(struct xfrm_state_walk *walk, struct net *net) { if (list_empty(&walk->all)) return; - spin_lock_bh(&xfrm_state_lock); + spin_lock_bh(&net->xfrm.xfrm_state_lock); list_del(&walk->all); - spin_unlock_bh(&xfrm_state_lock); + spin_unlock_bh(&net->xfrm.xfrm_state_lock); } EXPORT_SYMBOL(xfrm_state_walk_done); @@ -2026,6 +2029,7 @@ int __net_init xfrm_state_init(struct net *net) INIT_HLIST_HEAD(&net->xfrm.state_gc_list); INIT_WORK(&net->xfrm.state_gc_work, xfrm_state_gc_task); init_waitqueue_head(&net->xfrm.km_waitq); + spin_lock_init(&net->xfrm.xfrm_state_lock); return 0; out_byspi: diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 840cc8d9fbe..16c84608e81 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -877,7 +877,10 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr) static int xfrm_dump_sa_done(struct netlink_callback *cb) { struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1]; - xfrm_state_walk_done(walk); + struct sock *sk = cb->skb->sk; + struct net *net = sock_net(sk); + + xfrm_state_walk_done(walk, net); return 0; } @@ -1555,8 +1558,9 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr static int xfrm_dump_policy_done(struct netlink_callback *cb) { struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1]; + struct net *net = sock_net(cb->skb->sk); - xfrm_policy_walk_done(walk); + xfrm_policy_walk_done(walk, net); return 0; } @@ -2403,9 +2407,11 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) static void xfrm_netlink_rcv(struct sk_buff *skb) { - mutex_lock(&xfrm_cfg_mutex); + struct net *net = sock_net(skb->sk); + + mutex_lock(&net->xfrm.xfrm_cfg_mutex); netlink_rcv_skb(skb, &xfrm_user_rcv_msg); - mutex_unlock(&xfrm_cfg_mutex); + mutex_unlock(&net->xfrm.xfrm_cfg_mutex); } static inline size_t xfrm_expire_msgsize(void) -- cgit v1.2.3-70-g09d2 From f1324ea50b2e48d30fbeac591771fdceac9315ca Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 6 Dec 2013 07:08:52 +0200 Subject: Bluetooth: Use min_t for calculating chan->mps Since there's a nice convenient helper for calculating the minimum of two values, let's use that one. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 6e6f308af03..35feb9d6c32 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -505,11 +505,7 @@ static void l2cap_le_flowctl_init(struct l2cap_chan *chan) chan->sdu_len = 0; chan->tx_credits = 0; chan->rx_credits = le_max_credits; - - if (chan->imtu < L2CAP_LE_DEFAULT_MPS) - chan->mps = chan->imtu; - else - chan->mps = L2CAP_LE_DEFAULT_MPS; + chan->mps = min_t(u16, chan->imtu, L2CAP_LE_DEFAULT_MPS); skb_queue_head_init(&chan->tx_q); } -- cgit v1.2.3-70-g09d2 From c8afe8d0ad796b6dae545ceeed652b2c52ca7cf6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 6 Dec 2013 07:08:53 +0200 Subject: Bluetooth: Fix valid LE PSM check The range of valid LE PSMs is 0x0001-0x00ff so the check should be for "less than or equal to" instead of "less than". Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 35feb9d6c32..ae0054ccee5 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1851,7 +1851,7 @@ static bool is_valid_psm(u16 psm, u8 dst_type) return false; if (bdaddr_type_is_le(dst_type)) - return (psm < 0x00ff); + return (psm <= 0x00ff); /* PSM must be odd and lsb of upper byte must be 0 */ return ((psm & 0x0101) == 0x0001); -- cgit v1.2.3-70-g09d2 From 5b8ef3415a21f173ab115e90ec92c071a03f22d7 Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Tue, 27 Aug 2013 13:43:30 +0200 Subject: xfrm: Remove ancient sleeping when the SA is in acquire state We now queue packets to the policy if the states are not yet resolved, this replaces the ancient sleeping code. Also the sleeping can cause indefinite task hangs if the needed state does not get resolved. Signed-off-by: Steffen Klassert --- include/net/netns/xfrm.h | 2 -- net/key/af_key.c | 5 ++--- net/xfrm/xfrm_policy.c | 21 ++------------------- net/xfrm/xfrm_state.c | 21 +-------------------- 4 files changed, 5 insertions(+), 44 deletions(-) diff --git a/include/net/netns/xfrm.h b/include/net/netns/xfrm.h index ea28404e9d7..1006a265beb 100644 --- a/include/net/netns/xfrm.h +++ b/include/net/netns/xfrm.h @@ -33,8 +33,6 @@ struct netns_xfrm { struct hlist_head state_gc_list; struct work_struct state_gc_work; - wait_queue_head_t km_waitq; - struct list_head policy_all; struct hlist_head *policy_byidx; unsigned int policy_idx_hmask; diff --git a/net/key/af_key.c b/net/key/af_key.c index 9a039acf37e..5beabd8ba77 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -1380,10 +1380,9 @@ static int pfkey_acquire(struct sock *sk, struct sk_buff *skb, const struct sadb return 0; spin_lock_bh(&x->lock); - if (x->km.state == XFRM_STATE_ACQ) { + if (x->km.state == XFRM_STATE_ACQ) x->km.state = XFRM_STATE_ERROR; - wake_up(&net->xfrm.km_waitq); - } + spin_unlock_bh(&x->lock); xfrm_state_put(x); return 0; diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 73b04d3df44..a7487f34e81 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1901,8 +1901,7 @@ static struct xfrm_dst *xfrm_create_dummy_bundle(struct net *net, if (IS_ERR(xdst)) return xdst; - if (net->xfrm.sysctl_larval_drop || num_xfrms <= 0 || - (fl->flowi_flags & FLOWI_FLAG_CAN_SLEEP)) + if (net->xfrm.sysctl_larval_drop || num_xfrms <= 0) return xdst; dst1 = &xdst->u.dst; @@ -2077,7 +2076,6 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig, u8 dir = policy_to_flow_dir(XFRM_POLICY_OUT); int i, err, num_pols, num_xfrms = 0, drop_pols = 0; -restart: dst = NULL; xdst = NULL; route = NULL; @@ -2157,23 +2155,8 @@ restart: return make_blackhole(net, family, dst_orig); } - if (fl->flowi_flags & FLOWI_FLAG_CAN_SLEEP) { - DECLARE_WAITQUEUE(wait, current); - add_wait_queue(&net->xfrm.km_waitq, &wait); - set_current_state(TASK_INTERRUPTIBLE); - schedule(); - set_current_state(TASK_RUNNING); - remove_wait_queue(&net->xfrm.km_waitq, &wait); - - if (!signal_pending(current)) { - dst_release(dst); - goto restart; - } - - err = -ERESTART; - } else - err = -EAGAIN; + err = -EAGAIN; XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES); goto error; diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 290479d0746..e845066547c 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -372,8 +372,6 @@ static void xfrm_state_gc_task(struct work_struct *work) hlist_for_each_entry_safe(x, tmp, &gc_list, gclist) xfrm_state_gc_destroy(x); - - wake_up(&net->xfrm.km_waitq); } static inline unsigned long make_jiffies(long secs) @@ -388,7 +386,6 @@ static enum hrtimer_restart xfrm_timer_handler(struct hrtimer * me) { struct tasklet_hrtimer *thr = container_of(me, struct tasklet_hrtimer, timer); struct xfrm_state *x = container_of(thr, struct xfrm_state, mtimer); - struct net *net = xs_net(x); unsigned long now = get_seconds(); long next = LONG_MAX; int warn = 0; @@ -458,12 +455,8 @@ resched: goto out; expired: - if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) { + if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) x->km.state = XFRM_STATE_EXPIRED; - wake_up(&net->xfrm.km_waitq); - next = 2; - goto resched; - } err = __xfrm_state_delete(x); if (!err) @@ -635,7 +628,6 @@ restart: out: spin_unlock_bh(&net->xfrm.xfrm_state_lock); - wake_up(&net->xfrm.km_waitq); return err; } EXPORT_SYMBOL(xfrm_state_flush); @@ -948,8 +940,6 @@ static void __xfrm_state_insert(struct xfrm_state *x) if (x->replay_maxage) mod_timer(&x->rtimer, jiffies + x->replay_maxage); - wake_up(&net->xfrm.km_waitq); - net->xfrm.state_num++; xfrm_hash_grow_check(net, x->bydst.next != NULL); @@ -1658,16 +1648,12 @@ EXPORT_SYMBOL(km_state_notify); void km_state_expired(struct xfrm_state *x, int hard, u32 portid) { - struct net *net = xs_net(x); struct km_event c; c.data.hard = hard; c.portid = portid; c.event = XFRM_MSG_EXPIRE; km_state_notify(x, &c); - - if (hard) - wake_up(&net->xfrm.km_waitq); } EXPORT_SYMBOL(km_state_expired); @@ -1710,16 +1696,12 @@ EXPORT_SYMBOL(km_new_mapping); void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 portid) { - struct net *net = xp_net(pol); struct km_event c; c.data.hard = hard; c.portid = portid; c.event = XFRM_MSG_POLEXPIRE; km_policy_notify(pol, dir, &c); - - if (hard) - wake_up(&net->xfrm.km_waitq); } EXPORT_SYMBOL(km_policy_expired); @@ -2028,7 +2010,6 @@ int __net_init xfrm_state_init(struct net *net) INIT_WORK(&net->xfrm.state_hash_work, xfrm_hash_resize); INIT_HLIST_HEAD(&net->xfrm.state_gc_list); INIT_WORK(&net->xfrm.state_gc_work, xfrm_state_gc_task); - init_waitqueue_head(&net->xfrm.km_waitq); spin_lock_init(&net->xfrm.xfrm_state_lock); return 0; -- cgit v1.2.3-70-g09d2 From 0e0d44ab4275549998567cd4700b43f7496eb62b Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Wed, 28 Aug 2013 08:04:14 +0200 Subject: net: Remove FLOWI_FLAG_CAN_SLEEP FLOWI_FLAG_CAN_SLEEP was used to notify xfrm about the posibility to sleep until the needed states are resolved. This code is gone, so FLOWI_FLAG_CAN_SLEEP is not needed anymore. Signed-off-by: Steffen Klassert --- include/net/flow.h | 3 +-- include/net/ipv6.h | 6 ++---- include/net/route.h | 8 +++----- net/dccp/ipv4.c | 2 +- net/dccp/ipv6.c | 8 ++++---- net/decnet/dn_route.c | 2 -- net/ipv4/af_inet.c | 2 +- net/ipv4/datagram.c | 2 +- net/ipv4/raw.c | 2 +- net/ipv4/tcp_ipv4.c | 2 +- net/ipv4/udp.c | 2 +- net/ipv6/af_inet6.c | 2 +- net/ipv6/datagram.c | 2 +- net/ipv6/inet6_connection_sock.c | 4 ++-- net/ipv6/ip6_output.c | 12 ++---------- net/ipv6/ping.c | 2 +- net/ipv6/raw.c | 2 +- net/ipv6/syncookies.c | 2 +- net/ipv6/tcp_ipv6.c | 4 ++-- net/ipv6/udp.c | 2 +- net/l2tp/l2tp_ip6.c | 2 +- net/sctp/ipv6.c | 4 ++-- 22 files changed, 31 insertions(+), 46 deletions(-) diff --git a/include/net/flow.h b/include/net/flow.h index 65ce471d2ab..d23e7fa2042 100644 --- a/include/net/flow.h +++ b/include/net/flow.h @@ -20,8 +20,7 @@ struct flowi_common { __u8 flowic_proto; __u8 flowic_flags; #define FLOWI_FLAG_ANYSRC 0x01 -#define FLOWI_FLAG_CAN_SLEEP 0x02 -#define FLOWI_FLAG_KNOWN_NH 0x04 +#define FLOWI_FLAG_KNOWN_NH 0x02 __u32 flowic_secid; }; diff --git a/include/net/ipv6.h b/include/net/ipv6.h index eb198acaac1..26c4199ddc3 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -711,11 +711,9 @@ void ip6_flush_pending_frames(struct sock *sk); int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi6 *fl6); struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, - const struct in6_addr *final_dst, - bool can_sleep); + const struct in6_addr *final_dst); struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, - const struct in6_addr *final_dst, - bool can_sleep); + const struct in6_addr *final_dst); struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *orig_dst); diff --git a/include/net/route.h b/include/net/route.h index f68c167280a..638e3ebf76f 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -239,14 +239,12 @@ static inline char rt_tos2priority(u8 tos) static inline void ip_route_connect_init(struct flowi4 *fl4, __be32 dst, __be32 src, u32 tos, int oif, u8 protocol, __be16 sport, __be16 dport, - struct sock *sk, bool can_sleep) + struct sock *sk) { __u8 flow_flags = 0; if (inet_sk(sk)->transparent) flow_flags |= FLOWI_FLAG_ANYSRC; - if (can_sleep) - flow_flags |= FLOWI_FLAG_CAN_SLEEP; flowi4_init_output(fl4, oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE, protocol, flow_flags, dst, src, dport, sport); @@ -256,13 +254,13 @@ static inline struct rtable *ip_route_connect(struct flowi4 *fl4, __be32 dst, __be32 src, u32 tos, int oif, u8 protocol, __be16 sport, __be16 dport, - struct sock *sk, bool can_sleep) + struct sock *sk) { struct net *net = sock_net(sk); struct rtable *rt; ip_route_connect_init(fl4, dst, src, tos, oif, protocol, - sport, dport, sk, can_sleep); + sport, dport, sk); if (!dst || !src) { rt = __ip_route_output_key(net, fl4); diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index d9f65fc66db..88299c29101 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -75,7 +75,7 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) rt = ip_route_connect(fl4, nexthop, inet->inet_saddr, RT_CONN_FLAGS(sk), sk->sk_bound_dev_if, IPPROTO_DCCP, - orig_sport, orig_dport, sk, true); + orig_sport, orig_dport, sk); if (IS_ERR(rt)) return PTR_ERR(rt); diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 4ac71ff7c2e..699a2d2a35e 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -237,7 +237,7 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req) final_p = fl6_update_dst(&fl6, np->opt, &final); - dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false); + dst = ip6_dst_lookup_flow(sk, &fl6, final_p); if (IS_ERR(dst)) { err = PTR_ERR(dst); dst = NULL; @@ -301,7 +301,7 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) security_skb_classify_flow(rxskb, flowi6_to_flowi(&fl6)); /* sk = NULL, but it is safe for now. RST socket required. */ - dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL, false); + dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL); if (!IS_ERR(dst)) { skb_dst_set(skb, dst); ip6_xmit(ctl_sk, skb, &fl6, NULL, 0); @@ -512,7 +512,7 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk, fl6.fl6_sport = htons(ireq->ir_num); security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); - dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false); + dst = ip6_dst_lookup_flow(sk, &fl6, final_p); if (IS_ERR(dst)) goto out; } @@ -932,7 +932,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, final_p = fl6_update_dst(&fl6, np->opt, &final); - dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true); + dst = ip6_dst_lookup_flow(sk, &fl6, final_p); if (IS_ERR(dst)) { err = PTR_ERR(dst); goto failure; diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index fe32388ea24..ad2efa5b861 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -1288,8 +1288,6 @@ int dn_route_output_sock(struct dst_entry __rcu **pprt, struct flowidn *fl, stru err = __dn_route_output_key(pprt, fl, flags & MSG_TRYHARD); if (err == 0 && fl->flowidn_proto) { - if (!(flags & MSG_DONTWAIT)) - fl->flowidn_flags |= FLOWI_FLAG_CAN_SLEEP; *pprt = xfrm_lookup(&init_net, *pprt, flowidn_to_flowi(fl), sk, 0); if (IS_ERR(*pprt)) { diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 70011e029ac..4f6d50bda09 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1133,7 +1133,7 @@ static int inet_sk_reselect_saddr(struct sock *sk) fl4 = &inet->cork.fl.u.ip4; rt = ip_route_connect(fl4, daddr, 0, RT_CONN_FLAGS(sk), sk->sk_bound_dev_if, sk->sk_protocol, - inet->inet_sport, inet->inet_dport, sk, false); + inet->inet_sport, inet->inet_dport, sk); if (IS_ERR(rt)) return PTR_ERR(rt); diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c index 19e36376d2a..8b5134c582f 100644 --- a/net/ipv4/datagram.c +++ b/net/ipv4/datagram.c @@ -53,7 +53,7 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) rt = ip_route_connect(fl4, usin->sin_addr.s_addr, saddr, RT_CONN_FLAGS(sk), oif, sk->sk_protocol, - inet->inet_sport, usin->sin_port, sk, true); + inet->inet_sport, usin->sin_port, sk); if (IS_ERR(rt)) { err = PTR_ERR(rt); if (err == -ENETUNREACH) diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 23c3e5b5bb5..81e6cfd5a36 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -575,7 +575,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE, inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol, - inet_sk_flowi_flags(sk) | FLOWI_FLAG_CAN_SLEEP | + inet_sk_flowi_flags(sk) | (inet->hdrincl ? FLOWI_FLAG_KNOWN_NH : 0), daddr, saddr, 0, 0); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 06721392475..bbaf8cb45eb 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -173,7 +173,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) rt = ip_route_connect(fl4, nexthop, inet->inet_saddr, RT_CONN_FLAGS(sk), sk->sk_bound_dev_if, IPPROTO_TCP, - orig_sport, orig_dport, sk, true); + orig_sport, orig_dport, sk); if (IS_ERR(rt)) { err = PTR_ERR(rt); if (err == -ENETUNREACH) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 44f6a20fa29..480fb95df2b 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -990,7 +990,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, fl4 = &fl4_stack; flowi4_init_output(fl4, ipc.oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE, sk->sk_protocol, - inet_sk_flowi_flags(sk)|FLOWI_FLAG_CAN_SLEEP, + inet_sk_flowi_flags(sk), faddr, saddr, dport, inet->inet_sport); security_sk_classify_flow(sk, flowi4_to_flowi(fl4)); diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 4fbdb7046d2..c33f98a4cf7 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -661,7 +661,7 @@ int inet6_sk_rebuild_header(struct sock *sk) final_p = fl6_update_dst(&fl6, np->opt, &final); - dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false); + dst = ip6_dst_lookup_flow(sk, &fl6, final_p); if (IS_ERR(dst)) { sk->sk_route_caps = 0; sk->sk_err_soft = -PTR_ERR(dst); diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 8dfe1f4d3c1..d7ef682cd98 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -171,7 +171,7 @@ ipv4_connected: opt = flowlabel ? flowlabel->opt : np->opt; final_p = fl6_update_dst(&fl6, opt, &final); - dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true); + dst = ip6_dst_lookup_flow(sk, &fl6, final_p); err = 0; if (IS_ERR(dst)) { err = PTR_ERR(dst); diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index 77bb8afb141..c9138189415 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c @@ -86,7 +86,7 @@ struct dst_entry *inet6_csk_route_req(struct sock *sk, fl6->fl6_sport = htons(ireq->ir_num); security_req_classify_flow(req, flowi6_to_flowi(fl6)); - dst = ip6_dst_lookup_flow(sk, fl6, final_p, false); + dst = ip6_dst_lookup_flow(sk, fl6, final_p); if (IS_ERR(dst)) return NULL; @@ -216,7 +216,7 @@ static struct dst_entry *inet6_csk_route_socket(struct sock *sk, dst = __inet6_csk_dst_check(sk, np->dst_cookie); if (!dst) { - dst = ip6_dst_lookup_flow(sk, fl6, final_p, false); + dst = ip6_dst_lookup_flow(sk, fl6, final_p); if (!IS_ERR(dst)) __inet6_csk_dst_store(sk, dst, NULL, NULL); diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 4acdb63495d..3915cd88365 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -938,7 +938,6 @@ EXPORT_SYMBOL_GPL(ip6_dst_lookup); * @sk: socket which provides route info * @fl6: flow to lookup * @final_dst: final destination address for ipsec lookup - * @can_sleep: we are in a sleepable context * * This function performs a route lookup on the given flow. * @@ -946,8 +945,7 @@ EXPORT_SYMBOL_GPL(ip6_dst_lookup); * error code. */ struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, - const struct in6_addr *final_dst, - bool can_sleep) + const struct in6_addr *final_dst) { struct dst_entry *dst = NULL; int err; @@ -957,8 +955,6 @@ struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, return ERR_PTR(err); if (final_dst) fl6->daddr = *final_dst; - if (can_sleep) - fl6->flowi6_flags |= FLOWI_FLAG_CAN_SLEEP; return xfrm_lookup(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0); } @@ -969,7 +965,6 @@ EXPORT_SYMBOL_GPL(ip6_dst_lookup_flow); * @sk: socket which provides the dst cache and route info * @fl6: flow to lookup * @final_dst: final destination address for ipsec lookup - * @can_sleep: we are in a sleepable context * * This function performs a route lookup on the given flow with the * possibility of using the cached route in the socket if it is valid. @@ -980,8 +975,7 @@ EXPORT_SYMBOL_GPL(ip6_dst_lookup_flow); * error code. */ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, - const struct in6_addr *final_dst, - bool can_sleep) + const struct in6_addr *final_dst) { struct dst_entry *dst = sk_dst_check(sk, inet6_sk(sk)->dst_cookie); int err; @@ -993,8 +987,6 @@ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, return ERR_PTR(err); if (final_dst) fl6->daddr = *final_dst; - if (can_sleep) - fl6->flowi6_flags |= FLOWI_FLAG_CAN_SLEEP; return xfrm_lookup(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0); } diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c index a83243c3d65..15d23b8c212 100644 --- a/net/ipv6/ping.c +++ b/net/ipv6/ping.c @@ -145,7 +145,7 @@ int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, else if (!fl6.flowi6_oif) fl6.flowi6_oif = np->ucast_oif; - dst = ip6_sk_dst_lookup_flow(sk, &fl6, daddr, 1); + dst = ip6_sk_dst_lookup_flow(sk, &fl6, daddr); if (IS_ERR(dst)) return PTR_ERR(dst); rt = (struct rt6_info *) dst; diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 7fb4e14c467..4945fb6d60a 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -865,7 +865,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, fl6.flowi6_oif = np->ucast_oif; security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); - dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true); + dst = ip6_dst_lookup_flow(sk, &fl6, final_p); if (IS_ERR(dst)) { err = PTR_ERR(dst); goto out; diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 535a3ad262f..bb53a5e73c1 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -247,7 +247,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) fl6.fl6_sport = inet_sk(sk)->inet_sport; security_req_classify_flow(req, flowi6_to_flowi(&fl6)); - dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false); + dst = ip6_dst_lookup_flow(sk, &fl6, final_p); if (IS_ERR(dst)) goto out_free; } diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 0740f93a114..f14456f40d0 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -258,7 +258,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); - dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true); + dst = ip6_dst_lookup_flow(sk, &fl6, final_p); if (IS_ERR(dst)) { err = PTR_ERR(dst); goto failure; @@ -801,7 +801,7 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, * Underlying function will use this to retrieve the network * namespace */ - dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL, false); + dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL); if (!IS_ERR(dst)) { skb_dst_set(buff, dst); ip6_xmit(ctl_sk, buff, &fl6, NULL, tclass); diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index bcd5699313c..ec3eb7f3f87 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1221,7 +1221,7 @@ do_udp_sendmsg: security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); - dst = ip6_sk_dst_lookup_flow(sk, &fl6, final_p, true); + dst = ip6_sk_dst_lookup_flow(sk, &fl6, final_p); if (IS_ERR(dst)) { err = PTR_ERR(dst); dst = NULL; diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c index d9b437e5500..0c231f67604 100644 --- a/net/l2tp/l2tp_ip6.c +++ b/net/l2tp/l2tp_ip6.c @@ -598,7 +598,7 @@ static int l2tp_ip6_sendmsg(struct kiocb *iocb, struct sock *sk, security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); - dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true); + dst = ip6_dst_lookup_flow(sk, &fl6, final_p); if (IS_ERR(dst)) { err = PTR_ERR(dst); goto out; diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 7567e6f1a92..dd15caec154 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -263,7 +263,7 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, } final_p = fl6_update_dst(fl6, np->opt, &final); - dst = ip6_dst_lookup_flow(sk, fl6, final_p, false); + dst = ip6_dst_lookup_flow(sk, fl6, final_p); if (!asoc || saddr) goto out; @@ -322,7 +322,7 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, fl6->saddr = baddr->v6.sin6_addr; fl6->fl6_sport = baddr->v6.sin6_port; final_p = fl6_update_dst(fl6, np->opt, &final); - dst = ip6_dst_lookup_flow(sk, fl6, final_p, false); + dst = ip6_dst_lookup_flow(sk, fl6, final_p); } out: -- cgit v1.2.3-70-g09d2 From 71bd4b8ec0bf5fbeea54270b390bebe8e108fbf8 Mon Sep 17 00:00:00 2001 From: Christopher Pau Date: Sat, 16 Nov 2013 10:00:33 +0000 Subject: i40e: set pf_id based on device and function numbers pf_id needs to be encoded for cards with ARI enabled, which allows for larger function numbers than 8. Commit-Id: I23fa7df9dabf3878cc08c9b2151729c8539f5f17 Signed-off-by: Christopher Pau Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_common.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index 1e4ea134975..9e868eac8e1 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -297,7 +297,11 @@ i40e_status i40e_pf_reset(struct i40e_hw *hw) } /* Determine the PF number based on the PCI fn */ - hw->pf_id = (u8)hw->bus.func; + reg = rd32(hw, I40E_GLPCI_CAPSUP); + if (reg & I40E_GLPCI_CAPSUP_ARI_EN_MASK) + hw->pf_id = (u8)((hw->bus.device << 3) | hw->bus.func); + else + hw->pf_id = (u8)hw->bus.func; /* If there was a Global Reset in progress when we got here, * we don't need to do the PF Reset -- cgit v1.2.3-70-g09d2 From 5807822f84a2e2420d6db2359409894ea7c69880 Mon Sep 17 00:00:00 2001 From: Anjali Singhai jain Date: Sat, 16 Nov 2013 10:00:34 +0000 Subject: i40e: register file updates Hardware definitions changed slightly so sync up the defines file with the updated state of the hardware. Change-Id: I8349d91630a3208df306bd1dc88f028c87be2248 Signed-off-by: Anjali Singhai Jain Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_register.h | 134 ++++++++---------------- 1 file changed, 44 insertions(+), 90 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_register.h b/drivers/net/ethernet/intel/i40e/i40e_register.h index 6bd333cde28..db4958bea58 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_register.h +++ b/drivers/net/ethernet/intel/i40e/i40e_register.h @@ -28,6 +28,10 @@ #ifndef _I40E_REGISTER_H_ #define _I40E_REGISTER_H_ +#define I40E_GL_GP_FUSE(_i) (0x0009400C + ((_i) * 4)) /* _i=0...28 */ +#define I40E_GL_GP_FUSE_MAX_INDEX 28 +#define I40E_GL_GP_FUSE_GL_GP_FUSE_SHIFT 0 +#define I40E_GL_GP_FUSE_GL_GP_FUSE_MASK (0xFFFFFFFF << I40E_GL_GP_FUSE_GL_GP_FUSE_SHIFT) #define I40E_GLPCI_PM_MUX_NPQ 0x0009C4F4 #define I40E_GLPCI_PM_MUX_NPQ_NPQ_NUM_PORT_SEL_SHIFT 0 #define I40E_GLPCI_PM_MUX_NPQ_NPQ_NUM_PORT_SEL_MASK (0x7 << I40E_GLPCI_PM_MUX_NPQ_NPQ_NUM_PORT_SEL_SHIFT) @@ -38,6 +42,11 @@ #define I40E_GLPCI_PM_MUX_PFB_PFB_PORT_SEL_MASK (0x1F << I40E_GLPCI_PM_MUX_PFB_PFB_PORT_SEL_SHIFT) #define I40E_GLPCI_PM_MUX_PFB_INNER_PORT_SEL_SHIFT 16 #define I40E_GLPCI_PM_MUX_PFB_INNER_PORT_SEL_MASK (0x7 << I40E_GLPCI_PM_MUX_PFB_INNER_PORT_SEL_SHIFT) +#define I40E_GLPCI_PQ_MAX_USED_SPC 0x0009C4EC +#define I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_12_SHIFT 0 +#define I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_12_MASK (0xFF << I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_12_SHIFT) +#define I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_13_SHIFT 8 +#define I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_13_MASK (0xFF << I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_13_SHIFT) #define I40E_GLPCI_SPARE_BITS_0 0x0009C4F8 #define I40E_GLPCI_SPARE_BITS_0_SPARE_BITS_SHIFT 0 #define I40E_GLPCI_SPARE_BITS_0_SPARE_BITS_MASK (0xFFFFFFFF << I40E_GLPCI_SPARE_BITS_0_SPARE_BITS_SHIFT) @@ -50,6 +59,10 @@ #define I40E_PFPCI_VF_FLUSH_DONE 0x0009C600 #define I40E_PFPCI_VF_FLUSH_DONE_FLUSH_DONE_SHIFT 0 #define I40E_PFPCI_VF_FLUSH_DONE_FLUSH_DONE_MASK (0x1 << I40E_PFPCI_VF_FLUSH_DONE_FLUSH_DONE_SHIFT) +#define I40E_PFPCI_VF_FLUSH_DONE1(_VF) (0x0009C600 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_PFPCI_VF_FLUSH_DONE1_MAX_INDEX 127 +#define I40E_PFPCI_VF_FLUSH_DONE1_FLUSH_DONE_SHIFT 0 +#define I40E_PFPCI_VF_FLUSH_DONE1_FLUSH_DONE_MASK (0x1 << I40E_PFPCI_VF_FLUSH_DONE1_FLUSH_DONE_SHIFT) #define I40E_PFPCI_VM_FLUSH_DONE 0x0009C880 #define I40E_PFPCI_VM_FLUSH_DONE_FLUSH_DONE_SHIFT 0 #define I40E_PFPCI_VM_FLUSH_DONE_FLUSH_DONE_MASK (0x1 << I40E_PFPCI_VM_FLUSH_DONE_FLUSH_DONE_SHIFT) @@ -837,7 +850,7 @@ #define I40E_GLHMC_PEQ1FLCNT_FPMPEQ1FLCNT_MASK (0x1FFFFFFF << I40E_GLHMC_PEQ1FLCNT_FPMPEQ1FLCNT_SHIFT) #define I40E_GLHMC_PEQ1FLMAX 0x000C2058 #define I40E_GLHMC_PEQ1FLMAX_PMPEQ1FLMAX_SHIFT 0 -#define I40E_GLHMC_PEQ1FLMAX_PMPEQ1FLMAX_MASK (0x3FFFFF << I40E_GLHMC_PEQ1FLMAX_PMPEQ1FLMAX_SHIFT) +#define I40E_GLHMC_PEQ1FLMAX_PMPEQ1FLMAX_MASK (0x3FFFFFF << I40E_GLHMC_PEQ1FLMAX_PMPEQ1FLMAX_SHIFT) #define I40E_GLHMC_PEQ1MAX 0x000C2054 #define I40E_GLHMC_PEQ1MAX_PMPEQ1MAX_SHIFT 0 #define I40E_GLHMC_PEQ1MAX_PMPEQ1MAX_MASK (0x3FFFFFF << I40E_GLHMC_PEQ1MAX_PMPEQ1MAX_SHIFT) @@ -903,7 +916,7 @@ #define I40E_GLHMC_PEXFFLCNT_FPMPEXFFLCNT_MASK (0x1FFFFFFF << I40E_GLHMC_PEXFFLCNT_FPMPEXFFLCNT_SHIFT) #define I40E_GLHMC_PEXFFLMAX 0x000C204c #define I40E_GLHMC_PEXFFLMAX_PMPEXFFLMAX_SHIFT 0 -#define I40E_GLHMC_PEXFFLMAX_PMPEXFFLMAX_MASK (0x3FFFFF << I40E_GLHMC_PEXFFLMAX_PMPEXFFLMAX_SHIFT) +#define I40E_GLHMC_PEXFFLMAX_PMPEXFFLMAX_MASK (0x1FFFFFF << I40E_GLHMC_PEXFFLMAX_PMPEXFFLMAX_SHIFT) #define I40E_GLHMC_PEXFMAX 0x000C2048 #define I40E_GLHMC_PEXFMAX_PMPEXFMAX_SHIFT 0 #define I40E_GLHMC_PEXFMAX_PMPEXFMAX_MASK (0x3FFFFFF << I40E_GLHMC_PEXFMAX_PMPEXFMAX_SHIFT) @@ -1636,7 +1649,7 @@ #define I40E_VSILAN_QBASE_VSIQTABLE_ENA_SHIFT 11 #define I40E_VSILAN_QBASE_VSIQTABLE_ENA_MASK (0x1 << I40E_VSILAN_QBASE_VSIQTABLE_ENA_SHIFT) #define I40E_VSILAN_QTABLE(_i, _VSI) (0x00200000 + ((_i) * 2048 + (_VSI) * 4)) -#define I40E_VSILAN_QTABLE_MAX_INDEX 15 +#define I40E_VSILAN_QTABLE_MAX_INDEX 7 #define I40E_VSILAN_QTABLE_QINDEX_0_SHIFT 0 #define I40E_VSILAN_QTABLE_QINDEX_0_MASK (0x7FF << I40E_VSILAN_QTABLE_QINDEX_0_SHIFT) #define I40E_VSILAN_QTABLE_QINDEX_1_SHIFT 16 @@ -1773,16 +1786,20 @@ #define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE0_SHIFT 14 #define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE0_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE0_SHIFT) #define I40E_GL_MNG_FWSM 0x000B6134 -#define I40E_GL_MNG_FWSM_FW_MODES_SHIFT 0 -#define I40E_GL_MNG_FWSM_FW_MODES_MASK (0x3FF << I40E_GL_MNG_FWSM_FW_MODES_SHIFT) -#define I40E_GL_MNG_FWSM_EEP_RELOAD_IND_SHIFT 10 +#define I40E_GL_MNG_FWSM_FW_MODES_SHIFT 1 +#define I40E_GL_MNG_FWSM_FW_MODES_MASK (0x7 << I40E_GL_MNG_FWSM_FW_MODES_SHIFT) +#define I40E_GL_MNG_FWSM_EEP_RELOAD_IND_SHIFT 6 #define I40E_GL_MNG_FWSM_EEP_RELOAD_IND_MASK (0x1 << I40E_GL_MNG_FWSM_EEP_RELOAD_IND_SHIFT) #define I40E_GL_MNG_FWSM_CRC_ERROR_MODULE_SHIFT 11 #define I40E_GL_MNG_FWSM_CRC_ERROR_MODULE_MASK (0xF << I40E_GL_MNG_FWSM_CRC_ERROR_MODULE_SHIFT) #define I40E_GL_MNG_FWSM_FW_STATUS_VALID_SHIFT 15 #define I40E_GL_MNG_FWSM_FW_STATUS_VALID_MASK (0x1 << I40E_GL_MNG_FWSM_FW_STATUS_VALID_SHIFT) +#define I40E_GL_MNG_FWSM_RESET_CNT_SHIFT 16 +#define I40E_GL_MNG_FWSM_RESET_CNT_MASK (0x7 << I40E_GL_MNG_FWSM_RESET_CNT_SHIFT) #define I40E_GL_MNG_FWSM_EXT_ERR_IND_SHIFT 19 #define I40E_GL_MNG_FWSM_EXT_ERR_IND_MASK (0x3F << I40E_GL_MNG_FWSM_EXT_ERR_IND_SHIFT) +#define I40E_GL_MNG_FWSM_RSVD_SHIFT 25 +#define I40E_GL_MNG_FWSM_RSVD_MASK (0x1 << I40E_GL_MNG_FWSM_RSVD_SHIFT) #define I40E_GL_MNG_FWSM_PHY_SERDES0_CONFIG_ERR_SHIFT 26 #define I40E_GL_MNG_FWSM_PHY_SERDES0_CONFIG_ERR_MASK (0x1 << I40E_GL_MNG_FWSM_PHY_SERDES0_CONFIG_ERR_SHIFT) #define I40E_GL_MNG_FWSM_PHY_SERDES1_CONFIG_ERR_SHIFT 27 @@ -2380,8 +2397,7 @@ #define I40E_PFPE_IPCONFIG0_PEIPID_MASK (0xFFFF << I40E_PFPE_IPCONFIG0_PEIPID_SHIFT) #define I40E_PFPE_IPCONFIG0_USEENTIREIDRANGE_SHIFT 16 #define I40E_PFPE_IPCONFIG0_USEENTIREIDRANGE_MASK (0x1 << I40E_PFPE_IPCONFIG0_USEENTIREIDRANGE_SHIFT) -#define I40E_PFPE_IPCONFIG0_USEUPPERIDRANGE_SHIFT 17 -#define I40E_PFPE_IPCONFIG0_USEUPPERIDRANGE_MASK (0x1 << I40E_PFPE_IPCONFIG0_USEUPPERIDRANGE_SHIFT) + #define I40E_PFPE_MRTEIDXMASK 0x00008600 #define I40E_PFPE_MRTEIDXMASK_MRTEIDXMASKBITS_SHIFT 0 #define I40E_PFPE_MRTEIDXMASK_MRTEIDXMASKBITS_MASK (0x1F << I40E_PFPE_MRTEIDXMASK_MRTEIDXMASKBITS_SHIFT) @@ -2460,8 +2476,6 @@ #define I40E_VFPE_IPCONFIG0_PEIPID_MASK (0xFFFF << I40E_VFPE_IPCONFIG0_PEIPID_SHIFT) #define I40E_VFPE_IPCONFIG0_USEENTIREIDRANGE_SHIFT 16 #define I40E_VFPE_IPCONFIG0_USEENTIREIDRANGE_MASK (0x1 << I40E_VFPE_IPCONFIG0_USEENTIREIDRANGE_SHIFT) -#define I40E_VFPE_IPCONFIG0_USEUPPERIDRANGE_SHIFT 17 -#define I40E_VFPE_IPCONFIG0_USEUPPERIDRANGE_MASK (0x1 << I40E_VFPE_IPCONFIG0_USEUPPERIDRANGE_SHIFT) #define I40E_VFPE_MRTEIDXMASK(_VF) (0x00003000 + ((_VF) * 4)) /* _i=0...127 */ #define I40E_VFPE_MRTEIDXMASK_MAX_INDEX 127 #define I40E_VFPE_MRTEIDXMASK_MRTEIDXMASKBITS_SHIFT 0 @@ -3141,30 +3155,6 @@ #define I40E_GLPES_VFUDPTXPKTSLO_MAX_INDEX 31 #define I40E_GLPES_VFUDPTXPKTSLO_UDPTXPKTSLO_SHIFT 0 #define I40E_GLPES_VFUDPTXPKTSLO_UDPTXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFUDPTXPKTSLO_UDPTXPKTSLO_SHIFT) -#define I40E_GLPM_DMACR 0x000881F4 -#define I40E_GLPM_DMACR_DMACWT_SHIFT 0 -#define I40E_GLPM_DMACR_DMACWT_MASK (0xFFFF << I40E_GLPM_DMACR_DMACWT_SHIFT) -#define I40E_GLPM_DMACR_EXIT_DC_SHIFT 29 -#define I40E_GLPM_DMACR_EXIT_DC_MASK (0x1 << I40E_GLPM_DMACR_EXIT_DC_SHIFT) -#define I40E_GLPM_DMACR_LX_COALESCING_INDICATION_SHIFT 30 -#define I40E_GLPM_DMACR_LX_COALESCING_INDICATION_MASK (0x1 << I40E_GLPM_DMACR_LX_COALESCING_INDICATION_SHIFT) -#define I40E_GLPM_DMACR_DMAC_EN_SHIFT 31 -#define I40E_GLPM_DMACR_DMAC_EN_MASK (0x1 << I40E_GLPM_DMACR_DMAC_EN_SHIFT) -#define I40E_GLPM_LTRC 0x000BE500 -#define I40E_GLPM_LTRC_SLTRV_SHIFT 0 -#define I40E_GLPM_LTRC_SLTRV_MASK (0x3FF << I40E_GLPM_LTRC_SLTRV_SHIFT) -#define I40E_GLPM_LTRC_SSCALE_SHIFT 10 -#define I40E_GLPM_LTRC_SSCALE_MASK (0x7 << I40E_GLPM_LTRC_SSCALE_SHIFT) -#define I40E_GLPM_LTRC_LTRS_REQUIREMENT_SHIFT 15 -#define I40E_GLPM_LTRC_LTRS_REQUIREMENT_MASK (0x1 << I40E_GLPM_LTRC_LTRS_REQUIREMENT_SHIFT) -#define I40E_GLPM_LTRC_NSLTRV_SHIFT 16 -#define I40E_GLPM_LTRC_NSLTRV_MASK (0x3FF << I40E_GLPM_LTRC_NSLTRV_SHIFT) -#define I40E_GLPM_LTRC_NSSCALE_SHIFT 26 -#define I40E_GLPM_LTRC_NSSCALE_MASK (0x7 << I40E_GLPM_LTRC_NSSCALE_SHIFT) -#define I40E_GLPM_LTRC_LTR_SEND_SHIFT 30 -#define I40E_GLPM_LTRC_LTR_SEND_MASK (0x1 << I40E_GLPM_LTRC_LTR_SEND_SHIFT) -#define I40E_GLPM_LTRC_LTRNS_REQUIREMENT_SHIFT 31 -#define I40E_GLPM_LTRC_LTRNS_REQUIREMENT_MASK (0x1 << I40E_GLPM_LTRC_LTRNS_REQUIREMENT_SHIFT) #define I40E_PRTPM_EEE_STAT 0x001E4320 #define I40E_PRTPM_EEE_STAT_EEE_NEG_SHIFT 29 #define I40E_PRTPM_EEE_STAT_EEE_NEG_MASK (0x1 << I40E_PRTPM_EEE_STAT_EEE_NEG_SHIFT) @@ -3201,9 +3191,6 @@ #define I40E_PRTPM_GC_LCDMP_MASK (0x1 << I40E_PRTPM_GC_LCDMP_SHIFT) #define I40E_PRTPM_GC_LPLU_ASSERTED_SHIFT 31 #define I40E_PRTPM_GC_LPLU_ASSERTED_MASK (0x1 << I40E_PRTPM_GC_LPLU_ASSERTED_SHIFT) -#define I40E_PRTPM_HPTC 0x000AC800 -#define I40E_PRTPM_HPTC_HIGH_PRI_TC_SHIFT 0 -#define I40E_PRTPM_HPTC_HIGH_PRI_TC_MASK (0xFF << I40E_PRTPM_HPTC_HIGH_PRI_TC_SHIFT) #define I40E_PRTPM_RLPIC 0x001E43A0 #define I40E_PRTPM_RLPIC_ERLPIC_SHIFT 0 #define I40E_PRTPM_RLPIC_ERLPIC_MASK (0xFFFFFFFF << I40E_PRTPM_RLPIC_ERLPIC_SHIFT) @@ -3265,8 +3252,8 @@ #define I40E_GLQF_CTL_HTOEP_FCOE_MASK (0x1 << I40E_GLQF_CTL_HTOEP_FCOE_SHIFT) #define I40E_GLQF_CTL_PCNT_ALLOC_SHIFT 3 #define I40E_GLQF_CTL_PCNT_ALLOC_MASK (0x7 << I40E_GLQF_CTL_PCNT_ALLOC_SHIFT) -#define I40E_GLQF_CTL_DDPLPEN_SHIFT 7 -#define I40E_GLQF_CTL_DDPLPEN_MASK (0x1 << I40E_GLQF_CTL_DDPLPEN_SHIFT) +#define I40E_GLQF_CTL_RSVD_SHIFT 7 +#define I40E_GLQF_CTL_RSVD_MASK (0x1 << I40E_GLQF_CTL_RSVD_SHIFT) #define I40E_GLQF_CTL_MAXPEBLEN_SHIFT 8 #define I40E_GLQF_CTL_MAXPEBLEN_MASK (0x7 << I40E_GLQF_CTL_MAXPEBLEN_SHIFT) #define I40E_GLQF_CTL_MAXFCBLEN_SHIFT 11 @@ -3416,9 +3403,9 @@ #define I40E_PRTQF_FLX_PIT(_i) (0x00255200 + ((_i) * 32)) /* _i=0...8 */ #define I40E_PRTQF_FLX_PIT_MAX_INDEX 8 #define I40E_PRTQF_FLX_PIT_SOURCE_OFF_SHIFT 0 -#define I40E_PRTQF_FLX_PIT_SOURCE_OFF_MASK (0x3F << I40E_PRTQF_FLX_PIT_SOURCE_OFF_SHIFT) -#define I40E_PRTQF_FLX_PIT_FSIZE_SHIFT 6 -#define I40E_PRTQF_FLX_PIT_FSIZE_MASK (0xF << I40E_PRTQF_FLX_PIT_FSIZE_SHIFT) +#define I40E_PRTQF_FLX_PIT_SOURCE_OFF_MASK (0x1F << I40E_PRTQF_FLX_PIT_SOURCE_OFF_SHIFT) +#define I40E_PRTQF_FLX_PIT_FSIZE_SHIFT 5 +#define I40E_PRTQF_FLX_PIT_FSIZE_MASK (0x1F << I40E_PRTQF_FLX_PIT_FSIZE_SHIFT) #define I40E_PRTQF_FLX_PIT_DEST_OFF_SHIFT 10 #define I40E_PRTQF_FLX_PIT_DEST_OFF_MASK (0x3F << I40E_PRTQF_FLX_PIT_DEST_OFF_SHIFT) #define I40E_VFQF_HENA1(_i, _VF) (0x00230800 + ((_i) * 1024 + (_VF) * 4)) @@ -3504,7 +3491,7 @@ #define I40E_VSIQF_CTL_PEMFRAG_ENA_SHIFT 5 #define I40E_VSIQF_CTL_PEMFRAG_ENA_MASK (0x1 << I40E_VSIQF_CTL_PEMFRAG_ENA_SHIFT) #define I40E_VSIQF_TCREGION(_i, _VSI) (0x00206000 + ((_i) * 2048 + (_VSI) * 4)) -#define I40E_VSIQF_TCREGION_MAX_INDEX 7 +#define I40E_VSIQF_TCREGION_MAX_INDEX 3 #define I40E_VSIQF_TCREGION_TC_OFFSET_SHIFT 0 #define I40E_VSIQF_TCREGION_TC_OFFSET_MASK (0x1FF << I40E_VSIQF_TCREGION_TC_OFFSET_SHIFT) #define I40E_VSIQF_TCREGION_TC_SIZE_SHIFT 9 @@ -3521,10 +3508,7 @@ #define I40E_GL_FCOEDDPC_MAX_INDEX 143 #define I40E_GL_FCOEDDPC_FCOEDDPC_SHIFT 0 #define I40E_GL_FCOEDDPC_FCOEDDPC_MASK (0xFFFFFFFF << I40E_GL_FCOEDDPC_FCOEDDPC_SHIFT) -#define I40E_GL_FCOEDDPEC(_i) (0x00314900 + ((_i) * 8)) /* _i=0...143 */ -#define I40E_GL_FCOEDDPEC_MAX_INDEX 143 -#define I40E_GL_FCOEDDPEC_CFOEDDPEC_SHIFT 0 -#define I40E_GL_FCOEDDPEC_CFOEDDPEC_MASK (0xFFFFFFFF << I40E_GL_FCOEDDPEC_CFOEDDPEC_SHIFT) +/* _i=0...143 */ #define I40E_GL_FCOEDIFEC(_i) (0x00318480 + ((_i) * 8)) /* _i=0...143 */ #define I40E_GL_FCOEDIFEC_MAX_INDEX 143 #define I40E_GL_FCOEDIFEC_FCOEDIFRC_SHIFT 0 @@ -4276,46 +4260,10 @@ #define I40E_PFPM_APM 0x000B8080 #define I40E_PFPM_APM_APME_SHIFT 0 #define I40E_PFPM_APM_APME_MASK (0x1 << I40E_PFPM_APM_APME_SHIFT) -#define I40E_PFPM_FHFT_DATA(_i, _j) (0x00060000 + ((_i) * 4096 + (_j) * 128)) -#define I40E_PFPM_FHFT_DATA_MAX_INDEX 7 -#define I40E_PFPM_FHFT_DATA_DWORD_SHIFT 0 -#define I40E_PFPM_FHFT_DATA_DWORD_MASK (0xFFFFFFFF << I40E_PFPM_FHFT_DATA_DWORD_SHIFT) #define I40E_PFPM_FHFT_LENGTH(_i) (0x0006A000 + ((_i) * 128)) /* _i=0...7 */ #define I40E_PFPM_FHFT_LENGTH_MAX_INDEX 7 #define I40E_PFPM_FHFT_LENGTH_LENGTH_SHIFT 0 #define I40E_PFPM_FHFT_LENGTH_LENGTH_MASK (0xFF << I40E_PFPM_FHFT_LENGTH_LENGTH_SHIFT) -#define I40E_PFPM_FHFT_MASK(_i, _j) (0x00068000 + ((_i) * 1024 + (_j) * 128)) -#define I40E_PFPM_FHFT_MASK_MAX_INDEX 7 -#define I40E_PFPM_FHFT_MASK_MASK_SHIFT 0 -#define I40E_PFPM_FHFT_MASK_MASK_MASK (0xFFFF << I40E_PFPM_FHFT_MASK_MASK_SHIFT) -#define I40E_PFPM_PROXYFC 0x00245A80 -#define I40E_PFPM_PROXYFC_PPROXYE_SHIFT 0 -#define I40E_PFPM_PROXYFC_PPROXYE_MASK (0x1 << I40E_PFPM_PROXYFC_PPROXYE_SHIFT) -#define I40E_PFPM_PROXYFC_EX_SHIFT 1 -#define I40E_PFPM_PROXYFC_EX_MASK (0x1 << I40E_PFPM_PROXYFC_EX_SHIFT) -#define I40E_PFPM_PROXYFC_ARP_SHIFT 4 -#define I40E_PFPM_PROXYFC_ARP_MASK (0x1 << I40E_PFPM_PROXYFC_ARP_SHIFT) -#define I40E_PFPM_PROXYFC_ARP_DIRECTED_SHIFT 5 -#define I40E_PFPM_PROXYFC_ARP_DIRECTED_MASK (0x1 << I40E_PFPM_PROXYFC_ARP_DIRECTED_SHIFT) -#define I40E_PFPM_PROXYFC_NS_SHIFT 9 -#define I40E_PFPM_PROXYFC_NS_MASK (0x1 << I40E_PFPM_PROXYFC_NS_SHIFT) -#define I40E_PFPM_PROXYFC_NS_DIRECTED_SHIFT 10 -#define I40E_PFPM_PROXYFC_NS_DIRECTED_MASK (0x1 << I40E_PFPM_PROXYFC_NS_DIRECTED_SHIFT) -#define I40E_PFPM_PROXYFC_MLD_SHIFT 12 -#define I40E_PFPM_PROXYFC_MLD_MASK (0x1 << I40E_PFPM_PROXYFC_MLD_SHIFT) -#define I40E_PFPM_PROXYS 0x00245B80 -#define I40E_PFPM_PROXYS_EX_SHIFT 1 -#define I40E_PFPM_PROXYS_EX_MASK (0x1 << I40E_PFPM_PROXYS_EX_SHIFT) -#define I40E_PFPM_PROXYS_ARP_SHIFT 4 -#define I40E_PFPM_PROXYS_ARP_MASK (0x1 << I40E_PFPM_PROXYS_ARP_SHIFT) -#define I40E_PFPM_PROXYS_ARP_DIRECTED_SHIFT 5 -#define I40E_PFPM_PROXYS_ARP_DIRECTED_MASK (0x1 << I40E_PFPM_PROXYS_ARP_DIRECTED_SHIFT) -#define I40E_PFPM_PROXYS_NS_SHIFT 9 -#define I40E_PFPM_PROXYS_NS_MASK (0x1 << I40E_PFPM_PROXYS_NS_SHIFT) -#define I40E_PFPM_PROXYS_NS_DIRECTED_SHIFT 10 -#define I40E_PFPM_PROXYS_NS_DIRECTED_MASK (0x1 << I40E_PFPM_PROXYS_NS_DIRECTED_SHIFT) -#define I40E_PFPM_PROXYS_MLD_SHIFT 12 -#define I40E_PFPM_PROXYS_MLD_MASK (0x1 << I40E_PFPM_PROXYS_MLD_SHIFT) #define I40E_PFPM_WUC 0x0006B200 #define I40E_PFPM_WUC_EN_APM_D0_SHIFT 5 #define I40E_PFPM_WUC_EN_APM_D0_MASK (0x1 << I40E_PFPM_WUC_EN_APM_D0_SHIFT) @@ -4536,21 +4484,21 @@ #define I40E_VFMSIX_PBA 0x00002000 #define I40E_VFMSIX_PBA_PENBIT_SHIFT 0 #define I40E_VFMSIX_PBA_PENBIT_MASK (0xFFFFFFFF << I40E_VFMSIX_PBA_PENBIT_SHIFT) -#define I40E_VFMSIX_TADD(_i) (0x00000008 + ((_i) * 16)) /* _i=0...16 */ +#define I40E_VFMSIX_TADD(_i) (0x00000000 + ((_i) * 16)) /* _i=0...16 */ #define I40E_VFMSIX_TADD_MAX_INDEX 16 #define I40E_VFMSIX_TADD_MSIXTADD10_SHIFT 0 #define I40E_VFMSIX_TADD_MSIXTADD10_MASK (0x3 << I40E_VFMSIX_TADD_MSIXTADD10_SHIFT) #define I40E_VFMSIX_TADD_MSIXTADD_SHIFT 2 #define I40E_VFMSIX_TADD_MSIXTADD_MASK (0x3FFFFFFF << I40E_VFMSIX_TADD_MSIXTADD_SHIFT) -#define I40E_VFMSIX_TMSG(_i) (0x0000000C + ((_i) * 16)) /* _i=0...16 */ +#define I40E_VFMSIX_TMSG(_i) (0x00000008 + ((_i) * 16)) /* _i=0...16 */ #define I40E_VFMSIX_TMSG_MAX_INDEX 16 #define I40E_VFMSIX_TMSG_MSIXTMSG_SHIFT 0 #define I40E_VFMSIX_TMSG_MSIXTMSG_MASK (0xFFFFFFFF << I40E_VFMSIX_TMSG_MSIXTMSG_SHIFT) -#define I40E_VFMSIX_TUADD(_i) (0x00000000 + ((_i) * 16)) /* _i=0...16 */ +#define I40E_VFMSIX_TUADD(_i) (0x00000004 + ((_i) * 16)) /* _i=0...16 */ #define I40E_VFMSIX_TUADD_MAX_INDEX 16 #define I40E_VFMSIX_TUADD_MSIXTUADD_SHIFT 0 #define I40E_VFMSIX_TUADD_MSIXTUADD_MASK (0xFFFFFFFF << I40E_VFMSIX_TUADD_MSIXTUADD_SHIFT) -#define I40E_VFMSIX_TVCTRL(_i) (0x00000004 + ((_i) * 16)) /* _i=0...16 */ +#define I40E_VFMSIX_TVCTRL(_i) (0x0000000C + ((_i) * 16)) /* _i=0...16 */ #define I40E_VFMSIX_TVCTRL_MAX_INDEX 16 #define I40E_VFMSIX_TVCTRL_MASK_SHIFT 0 #define I40E_VFMSIX_TVCTRL_MASK_MASK (0x1 << I40E_VFMSIX_TVCTRL_MASK_SHIFT) @@ -4610,8 +4558,6 @@ #define I40E_VFPE_IPCONFIG01_PEIPID_MASK (0xFFFF << I40E_VFPE_IPCONFIG01_PEIPID_SHIFT) #define I40E_VFPE_IPCONFIG01_USEENTIREIDRANGE_SHIFT 16 #define I40E_VFPE_IPCONFIG01_USEENTIREIDRANGE_MASK (0x1 << I40E_VFPE_IPCONFIG01_USEENTIREIDRANGE_SHIFT) -#define I40E_VFPE_IPCONFIG01_USEUPPERIDRANGE_SHIFT 17 -#define I40E_VFPE_IPCONFIG01_USEUPPERIDRANGE_MASK (0x1 << I40E_VFPE_IPCONFIG01_USEUPPERIDRANGE_SHIFT) #define I40E_VFPE_MRTEIDXMASK1 0x00009000 #define I40E_VFPE_MRTEIDXMASK1_MRTEIDXMASKBITS_SHIFT 0 #define I40E_VFPE_MRTEIDXMASK1_MRTEIDXMASKBITS_MASK (0x1F << I40E_VFPE_MRTEIDXMASK1_MRTEIDXMASKBITS_SHIFT) @@ -4684,5 +4630,13 @@ #define I40E_VFQF_HREGION_OVERRIDE_ENA_7_MASK (0x1 << I40E_VFQF_HREGION_OVERRIDE_ENA_7_SHIFT) #define I40E_VFQF_HREGION_REGION_7_SHIFT 29 #define I40E_VFQF_HREGION_REGION_7_MASK (0x7 << I40E_VFQF_HREGION_REGION_7_SHIFT) - +#define I40E_RCU_PST_FOC_ACCESS_STATUS 0x00270110 +#define I40E_RCU_PST_FOC_ACCESS_STATUS_WR_ACCESS_CNT_SHIFT 0 +#define I40E_RCU_PST_FOC_ACCESS_STATUS_WR_ACCESS_CNT_MASK (0xFF << I40E_RCU_PST_FOC_ACCESS_STATUS_WR_ACCESS_CNT_SHIFT) +#define I40E_RCU_PST_FOC_ACCESS_STATUS_RD_ACCESS_CNT_SHIFT 8 +#define I40E_RCU_PST_FOC_ACCESS_STATUS_RD_ACCESS_CNT_MASK (0xFF << I40E_RCU_PST_FOC_ACCESS_STATUS_RD_ACCESS_CNT_SHIFT) +#define I40E_RCU_PST_FOC_ACCESS_STATUS_ERR_CNT_SHIFT 16 +#define I40E_RCU_PST_FOC_ACCESS_STATUS_ERR_CNT_MASK (0xFF << I40E_RCU_PST_FOC_ACCESS_STATUS_ERR_CNT_SHIFT) +#define I40E_RCU_PST_FOC_ACCESS_STATUS_LAST_ERR_CODE_SHIFT 24 +#define I40E_RCU_PST_FOC_ACCESS_STATUS_LAST_ERR_CODE_MASK (0x7 << I40E_RCU_PST_FOC_ACCESS_STATUS_LAST_ERR_CODE_SHIFT) #endif -- cgit v1.2.3-70-g09d2 From 26d7178f5ba164e329f137b00a542fd67b850051 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Sat, 16 Nov 2013 10:00:35 +0000 Subject: i40e: clear AQ head and tail registers During admin queue shutdown clear some more registers explicitly. Change-Id: Ifb235c691e1c55e76bf66e0642207f464153d05a Signed-off-by: Shannon Nelson Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_adminq.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c index cfef7fc32cd..2bf73dda160 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c @@ -466,10 +466,15 @@ static i40e_status i40e_shutdown_asq(struct i40e_hw *hw) return I40E_ERR_NOT_READY; /* Stop firmware AdminQ processing */ - if (hw->mac.type == I40E_MAC_VF) + if (hw->mac.type == I40E_MAC_VF) { wr32(hw, I40E_VF_ATQLEN1, 0); - else + wr32(hw, I40E_VF_ATQH1, 0); + wr32(hw, I40E_VF_ATQT1, 0); + } else { wr32(hw, I40E_PF_ATQLEN, 0); + wr32(hw, I40E_PF_ATQH, 0); + wr32(hw, I40E_PF_ATQT, 0); + } /* make sure lock is available */ mutex_lock(&hw->aq.asq_mutex); @@ -500,10 +505,15 @@ static i40e_status i40e_shutdown_arq(struct i40e_hw *hw) return I40E_ERR_NOT_READY; /* Stop firmware AdminQ processing */ - if (hw->mac.type == I40E_MAC_VF) + if (hw->mac.type == I40E_MAC_VF) { wr32(hw, I40E_VF_ARQLEN1, 0); - else + wr32(hw, I40E_VF_ARQH1, 0); + wr32(hw, I40E_VF_ARQT1, 0); + } else { wr32(hw, I40E_PF_ARQLEN, 0); + wr32(hw, I40E_PF_ARQH, 0); + wr32(hw, I40E_PF_ARQT, 0); + } /* make sure lock is available */ mutex_lock(&hw->aq.arq_mutex); -- cgit v1.2.3-70-g09d2 From 17e6a845dc808f9e9cb3085517fd851d1ccc2bc3 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Sat, 16 Nov 2013 10:00:36 +0000 Subject: i40e: simplify aq head-tail-len setups Use more virtual registers to simplify code flows. Change-Id: I32cff3818c5ca3a3792487ba4fed8f1d0ea6145a Signed-off-by: Shannon Nelson Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_adminq.c | 50 ++++++++------------------- drivers/net/ethernet/intel/i40e/i40e_adminq.h | 1 + 2 files changed, 15 insertions(+), 36 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c index 2bf73dda160..92c01ad9de1 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c @@ -43,13 +43,17 @@ static void i40e_adminq_init_regs(struct i40e_hw *hw) if (hw->mac.type == I40E_MAC_VF) { hw->aq.asq.tail = I40E_VF_ATQT1; hw->aq.asq.head = I40E_VF_ATQH1; + hw->aq.asq.len = I40E_VF_ATQLEN1; hw->aq.arq.tail = I40E_VF_ARQT1; hw->aq.arq.head = I40E_VF_ARQH1; + hw->aq.arq.len = I40E_VF_ARQLEN1; } else { hw->aq.asq.tail = I40E_PF_ATQT; hw->aq.asq.head = I40E_PF_ATQH; + hw->aq.asq.len = I40E_PF_ATQLEN; hw->aq.arq.tail = I40E_PF_ARQT; hw->aq.arq.head = I40E_PF_ARQH; + hw->aq.arq.len = I40E_PF_ARQLEN; } } @@ -466,15 +470,9 @@ static i40e_status i40e_shutdown_asq(struct i40e_hw *hw) return I40E_ERR_NOT_READY; /* Stop firmware AdminQ processing */ - if (hw->mac.type == I40E_MAC_VF) { - wr32(hw, I40E_VF_ATQLEN1, 0); - wr32(hw, I40E_VF_ATQH1, 0); - wr32(hw, I40E_VF_ATQT1, 0); - } else { - wr32(hw, I40E_PF_ATQLEN, 0); - wr32(hw, I40E_PF_ATQH, 0); - wr32(hw, I40E_PF_ATQT, 0); - } + wr32(hw, hw->aq.asq.head, 0); + wr32(hw, hw->aq.asq.tail, 0); + wr32(hw, hw->aq.asq.len, 0); /* make sure lock is available */ mutex_lock(&hw->aq.asq_mutex); @@ -505,15 +503,9 @@ static i40e_status i40e_shutdown_arq(struct i40e_hw *hw) return I40E_ERR_NOT_READY; /* Stop firmware AdminQ processing */ - if (hw->mac.type == I40E_MAC_VF) { - wr32(hw, I40E_VF_ARQLEN1, 0); - wr32(hw, I40E_VF_ARQH1, 0); - wr32(hw, I40E_VF_ARQT1, 0); - } else { - wr32(hw, I40E_PF_ARQLEN, 0); - wr32(hw, I40E_PF_ARQH, 0); - wr32(hw, I40E_PF_ARQT, 0); - } + wr32(hw, hw->aq.arq.head, 0); + wr32(hw, hw->aq.arq.tail, 0); + wr32(hw, hw->aq.arq.len, 0); /* make sure lock is available */ mutex_lock(&hw->aq.arq_mutex); @@ -966,27 +958,13 @@ void i40e_resume_aq(struct i40e_hw *hw) hw->aq.asq.next_to_clean = 0; i40e_config_asq_regs(hw); - reg = hw->aq.num_asq_entries; - - if (hw->mac.type == I40E_MAC_VF) { - reg |= I40E_VF_ATQLEN_ATQENABLE_MASK; - wr32(hw, I40E_VF_ATQLEN1, reg); - } else { - reg |= I40E_PF_ATQLEN_ATQENABLE_MASK; - wr32(hw, I40E_PF_ATQLEN, reg); - } + reg = hw->aq.num_asq_entries | I40E_PF_ATQLEN_ATQENABLE_MASK; + wr32(hw, hw->aq.asq.len, reg); hw->aq.arq.next_to_use = 0; hw->aq.arq.next_to_clean = 0; i40e_config_arq_regs(hw); - reg = hw->aq.num_arq_entries; - - if (hw->mac.type == I40E_MAC_VF) { - reg |= I40E_VF_ATQLEN_ATQENABLE_MASK; - wr32(hw, I40E_VF_ARQLEN1, reg); - } else { - reg |= I40E_PF_ATQLEN_ATQENABLE_MASK; - wr32(hw, I40E_PF_ARQLEN, reg); - } + reg = hw->aq.num_arq_entries | I40E_PF_ATQLEN_ATQENABLE_MASK; + wr32(hw, hw->aq.arq.len, reg); } diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.h b/drivers/net/ethernet/intel/i40e/i40e_adminq.h index 22e5ed683e4..f8c2c44e233 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.h +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.h @@ -56,6 +56,7 @@ struct i40e_adminq_ring { /* used for queue tracking */ u32 head; u32 tail; + u32 len; }; /* ASQ transaction details */ -- cgit v1.2.3-70-g09d2 From fe31070444268e7b70279bd4a1403625820793b0 Mon Sep 17 00:00:00 2001 From: Anjali Singhai jain Date: Sat, 16 Nov 2013 10:00:37 +0000 Subject: i40e: firmware version fields offsets update The version bits reported by the hardware changed, so fix up the offsets to print the version correctly. Change-Id: I8a8207b401ea88f6da024aebafe7d3826ee6512c Signed-off-by: Anjali Singhai Jain Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 17 +++++++++-------- drivers/net/ethernet/intel/i40e/i40e_main.c | 7 +++++++ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 1ca9834cdfd..b82f501602c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -81,11 +81,14 @@ #define I40E_DEFAULT_MSG_ENABLE 4 #define I40E_NVM_VERSION_LO_SHIFT 0 -#define I40E_NVM_VERSION_LO_MASK (0xf << I40E_NVM_VERSION_LO_SHIFT) -#define I40E_NVM_VERSION_MID_SHIFT 4 -#define I40E_NVM_VERSION_MID_MASK (0xff << I40E_NVM_VERSION_MID_SHIFT) -#define I40E_NVM_VERSION_HI_SHIFT 12 -#define I40E_NVM_VERSION_HI_MASK (0xf << I40E_NVM_VERSION_HI_SHIFT) +#define I40E_NVM_VERSION_LO_MASK (0xff << I40E_NVM_VERSION_LO_SHIFT) +#define I40E_NVM_VERSION_HI_SHIFT 8 +#define I40E_NVM_VERSION_HI_MASK (0xff << I40E_NVM_VERSION_HI_SHIFT) + +/* The values in here are decimal coded as hex as is the case in the NVM map*/ +#define I40E_CURRENT_NVM_VERSION_HI 0x2 +#define I40E_CURRENT_NVM_VERSION_LO 0x1 + /* magic for getting defines into strings */ #define STRINGIFY(foo) #foo @@ -441,13 +444,11 @@ static inline char *i40e_fw_version_str(struct i40e_hw *hw) static char buf[32]; snprintf(buf, sizeof(buf), - "f%d.%d a%d.%d n%02d.%02d.%02d e%08x", + "f%d.%d a%d.%d n%02x.%02x e%08x", hw->aq.fw_maj_ver, hw->aq.fw_min_ver, hw->aq.api_maj_ver, hw->aq.api_min_ver, (hw->nvm.version & I40E_NVM_VERSION_HI_MASK) >> I40E_NVM_VERSION_HI_SHIFT, - (hw->nvm.version & I40E_NVM_VERSION_MID_MASK) - >> I40E_NVM_VERSION_MID_SHIFT, (hw->nvm.version & I40E_NVM_VERSION_LO_MASK) >> I40E_NVM_VERSION_LO_SHIFT, hw->nvm.eetrack); diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index be15938ba21..6e0f2cb3ae1 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -7141,6 +7141,13 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err = i40e_init_adminq(hw); dev_info(&pdev->dev, "%s\n", i40e_fw_version_str(hw)); + if (((hw->nvm.version & I40E_NVM_VERSION_HI_MASK) + >> I40E_NVM_VERSION_HI_SHIFT) != I40E_CURRENT_NVM_VERSION_HI) { + dev_info(&pdev->dev, + "warning: NVM version not supported, supported version: %02x.%02x\n", + I40E_CURRENT_NVM_VERSION_HI, + I40E_CURRENT_NVM_VERSION_LO); + } if (err) { dev_info(&pdev->dev, "init_adminq failed: %d expecting API %02x.%02x\n", -- cgit v1.2.3-70-g09d2 From 54692b403c7a1353f7b851efd69bdfe91966c1d9 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Sat, 16 Nov 2013 10:00:38 +0000 Subject: i40e: allow one more vector for VFs The number of vectors per VF as reported by the hardware does not include vector 0, so we need to account for this when checking to see if the VF is configuring a valid vector. Change-Id: I051d8bebae8f4722239f5a3fa5e1de4cf0f4e817 Signed-off-by: Mitch Williams Signed-off-by: Jesse Brandeburg Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 07596982a47..d98cc9b351f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -70,7 +70,7 @@ static inline bool i40e_vc_isvalid_vector_id(struct i40e_vf *vf, u8 vector_id) { struct i40e_pf *pf = vf->pf; - return vector_id < pf->hw.func_caps.num_msix_vectors_vf; + return vector_id <= pf->hw.func_caps.num_msix_vectors_vf; } /***********************vf resource mgmt routines*****************/ -- cgit v1.2.3-70-g09d2 From d52cf0a948267afc1d330ff1603a704a55c9f9fc Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Sat, 16 Nov 2013 10:00:39 +0000 Subject: i40e: select reset counters correctly The indication for telling which reset happened is a value, not a bit pattern, so select by ==, not &. Change-Id: Ie04097388ff16b85015d6ab1236d7511ef653e8c Signed-off-by: Shannon Nelson Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 6e0f2cb3ae1..2dd4be523bb 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -2790,11 +2790,11 @@ static irqreturn_t i40e_intr(int irq, void *data) val = rd32(hw, I40E_GLGEN_RSTAT); val = (val & I40E_GLGEN_RSTAT_RESET_TYPE_MASK) >> I40E_GLGEN_RSTAT_RESET_TYPE_SHIFT; - if (val & I40E_RESET_CORER) + if (val == I40E_RESET_CORER) pf->corer_count++; - else if (val & I40E_RESET_GLOBR) + else if (val == I40E_RESET_GLOBR) pf->globr_count++; - else if (val & I40E_RESET_EMPR) + else if (val == I40E_RESET_EMPR) pf->empr_count++; } -- cgit v1.2.3-70-g09d2 From d4946cf555c62590dbdcf1f17376025f6368cadd Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Sat, 16 Nov 2013 10:00:40 +0000 Subject: i40e: retry call on timeout If the admin queue times out, retry some more to make driver load and reset more robust. Change-Id: I45c977b3d10a62c770d6072659ec27834849ca33 Signed-off-by: Shannon Nelson Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_adminq.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c index 92c01ad9de1..30f32f3a86b 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c @@ -535,8 +535,9 @@ static i40e_status i40e_shutdown_arq(struct i40e_hw *hw) **/ i40e_status i40e_init_adminq(struct i40e_hw *hw) { - u16 eetrack_lo, eetrack_hi; i40e_status ret_code; + u16 eetrack_lo, eetrack_hi; + int retry = 0; /* verify input for valid configuration */ if ((hw->aq.num_arq_entries == 0) || @@ -564,11 +565,24 @@ i40e_status i40e_init_adminq(struct i40e_hw *hw) if (ret_code) goto init_adminq_free_asq; - ret_code = i40e_aq_get_firmware_version(hw, - &hw->aq.fw_maj_ver, &hw->aq.fw_min_ver, - &hw->aq.api_maj_ver, &hw->aq.api_min_ver, - NULL); - if (ret_code) + /* There are some cases where the firmware may not be quite ready + * for AdminQ operations, so we retry the AdminQ setup a few times + * if we see timeouts in this first AQ call. + */ + do { + ret_code = i40e_aq_get_firmware_version(hw, + &hw->aq.fw_maj_ver, + &hw->aq.fw_min_ver, + &hw->aq.api_maj_ver, + &hw->aq.api_min_ver, + NULL); + if (ret_code != I40E_ERR_ADMIN_QUEUE_TIMEOUT) + break; + retry++; + msleep(100); + i40e_resume_aq(hw); + } while (retry < 10); + if (ret_code != I40E_SUCCESS) goto init_adminq_free_arq; if (hw->aq.api_maj_ver != I40E_FW_API_VERSION_MAJOR || -- cgit v1.2.3-70-g09d2 From 7e68edf9e364783cddf7ba2ccf75bc8d62ff9bda Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Sat, 16 Nov 2013 10:00:41 +0000 Subject: i40e: properly add VF MAC addresses The code that added new MAC addresses from the VFs did not, in fact, work. Due to inverse logic, the only addresses that could be added were addresses that already had been added. Change-Id: Idce9169bd2f36e2c5ee10b130587a65705465d31 Signed-off-by: Mitch Williams Signed-off-by: Jesse Brandeburg Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index d98cc9b351f..59973012c35 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -1603,7 +1603,7 @@ static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) struct i40e_mac_filter *f; f = i40e_find_mac(vsi, al->list[i].addr, true, false); - if (f) { + if (!f) { if (i40e_is_vsi_in_vlan(vsi)) f = i40e_put_mac_in_vlan(vsi, al->list[i].addr, true, false); -- cgit v1.2.3-70-g09d2 From 4f28c7276043ceec6c668292d0341fa9a45aaaeb Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Sat, 16 Nov 2013 10:00:42 +0000 Subject: i40e: fix debugging messages Clean up some messages that had arguments reversed. Change-Id: I0f38a4f01132a2918d61dbaf23de1e1eaed5e56d Signed-off-by: Mitch Williams Signed-off-by: Jesse Brandeburg Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 59973012c35..e7bdd47bafc 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -620,13 +620,13 @@ int i40e_reset_vf(struct i40e_vf *vf, bool flr) if (ret) dev_info(&pf->pdev->dev, "Queue control check failed on Tx queue %d of VSI %d VF %d\n", - vf->lan_vsi_index, j, vf->vf_id); + j, vf->lan_vsi_index, vf->vf_id); ret = i40e_ctrl_vsi_rx_queue(vf, vf->lan_vsi_index, j, I40E_QUEUE_CTRL_FASTDISABLECHECK); if (ret) dev_info(&pf->pdev->dev, "Queue control check failed on Rx queue %d of VSI %d VF %d\n", - vf->lan_vsi_index, j, vf->vf_id); + j, vf->lan_vsi_index, vf->vf_id); } /* clear the irq settings */ -- cgit v1.2.3-70-g09d2 From 2759997b0c84e5483482d5486df780da7935086b Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Sat, 16 Nov 2013 10:00:43 +0000 Subject: i40e: default debug mask setting Set the debug mask by default. Change-Id: I10346ccb1a47f79747eb2108a83af059e947f1e2 Signed-off-by: Shannon Nelson Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 2dd4be523bb..db626e04db2 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -5579,6 +5579,7 @@ static int i40e_sw_init(struct i40e_pf *pf) pf->msg_enable = netif_msg_init(I40E_DEFAULT_MSG_ENABLE, (NETIF_MSG_DRV|NETIF_MSG_PROBE|NETIF_MSG_LINK)); + pf->hw.debug_mask = pf->msg_enable | I40E_DEBUG_DIAG; if (debug != -1 && debug != I40E_DEFAULT_MSG_ENABLE) { if (I40E_DEBUG_USER & debug) pf->hw.debug_mask = debug; -- cgit v1.2.3-70-g09d2 From cd92e72f2d0a5b576f025f693cfd306cebd8b84a Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Sat, 16 Nov 2013 10:00:44 +0000 Subject: i40e: add interrupt test Add a quick ethtool test for interrupts using the SW interrupt. Also, change the loopback test (for now) to not report failure. Change-Id: Id8ef154b82475e3163087a8d1df01dfec4d529fc Signed-off-by: Shannon Nelson Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 1 + drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 10 ++++++++-- drivers/net/ethernet/intel/i40e/i40e_main.c | 5 +++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index b82f501602c..8806cab28c6 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -250,6 +250,7 @@ struct i40e_pf { u16 globr_count; /* Global reset count */ u16 empr_count; /* EMP reset count */ u16 pfr_count; /* PF reset count */ + u16 sw_int_count; /* SW interrupt count */ struct mutex switch_mutex; u16 lan_vsi; /* our default LAN VSI */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 1b86138fa9e..8f5d538c11c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -734,14 +734,20 @@ static int i40e_eeprom_test(struct i40e_pf *pf, u64 *data) static int i40e_intr_test(struct i40e_pf *pf, u64 *data) { - *data = -ENOSYS; + u16 swc_old = pf->sw_int_count; + + wr32(&pf->hw, I40E_PFINT_DYN_CTL0, + (I40E_PFINT_DYN_CTL0_INTENA_MASK | + I40E_PFINT_DYN_CTL0_SWINT_TRIG_MASK)); + usleep_range(1000, 2000); + *data = (swc_old == pf->sw_int_count); return *data; } static int i40e_loopback_test(struct i40e_pf *pf, u64 *data) { - *data = -ENOSYS; + *data = 0; return *data; } diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index db626e04db2..d60673ebf13 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -2752,6 +2752,11 @@ static irqreturn_t i40e_intr(int irq, void *data) ena_mask = rd32(hw, I40E_PFINT_ICR0_ENA); + /* if interrupt but no bits showing, must be SWINT */ + if (((icr0 & ~I40E_PFINT_ICR0_INTEVENT_MASK) == 0) || + (icr0 & I40E_PFINT_ICR0_SWINT_MASK)) + pf->sw_int_count++; + /* only q0 is used in MSI/Legacy mode, and none are used in MSIX */ if (icr0 & I40E_PFINT_ICR0_QUEUE_0_MASK) { -- cgit v1.2.3-70-g09d2 From 7823fe341da4660c9aab9fec8fbff94e3070ceaf Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Sat, 16 Nov 2013 10:00:45 +0000 Subject: i40e: add support for triggering EMPR Allow debugfs to trigger a reset called EMPR. Change-Id: I2f6600a8242759ec60c8198d03f70c2b774e0740 Signed-off-by: Shannon Nelson Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 1 + drivers/net/ethernet/intel/i40e/i40e_debugfs.c | 4 ++++ drivers/net/ethernet/intel/i40e/i40e_main.c | 18 ++++++++++++++++++ 3 files changed, 23 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 8806cab28c6..df685bc72ec 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -130,6 +130,7 @@ enum i40e_state_t { __I40E_PF_RESET_REQUESTED, __I40E_CORE_RESET_REQUESTED, __I40E_GLOBAL_RESET_REQUESTED, + __I40E_EMP_RESET_REQUESTED, __I40E_FILTER_OVERFLOW_PROMISC, }; diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c index ef4cb1cf31f..9c675b5f146 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c +++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c @@ -1472,6 +1472,10 @@ static ssize_t i40e_dbg_command_write(struct file *filp, dev_info(&pf->pdev->dev, "forcing GlobR\n"); i40e_do_reset(pf, (1 << __I40E_GLOBAL_RESET_REQUESTED)); + } else if (strncmp(cmd_buf, "empr", 4) == 0) { + dev_info(&pf->pdev->dev, "forcing EMPR\n"); + i40e_do_reset(pf, (1 << __I40E_EMP_RESET_REQUESTED)); + } else if (strncmp(cmd_buf, "read", 4) == 0) { u32 address; u32 value; diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index d60673ebf13..5d234a13abc 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -4056,6 +4056,24 @@ void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags) wr32(&pf->hw, I40E_GLGEN_RTRIG, val); i40e_flush(&pf->hw); + } else if (reset_flags & (1 << __I40E_EMP_RESET_REQUESTED)) { + + /* Request a Firmware Reset + * + * Same as Global reset, plus restarting the + * embedded firmware engine. + */ + /* enable EMP Reset */ + val = rd32(&pf->hw, I40E_GLGEN_RSTENA_EMP); + val |= I40E_GLGEN_RSTENA_EMP_EMP_RST_ENA_MASK; + wr32(&pf->hw, I40E_GLGEN_RSTENA_EMP, val); + + /* force the reset */ + val = rd32(&pf->hw, I40E_GLGEN_RTRIG); + val |= I40E_GLGEN_RTRIG_EMPFWR_MASK; + wr32(&pf->hw, I40E_GLGEN_RTRIG, val); + i40e_flush(&pf->hw); + } else if (reset_flags & (1 << __I40E_PF_RESET_REQUESTED)) { /* Request a PF Reset -- cgit v1.2.3-70-g09d2 From b7b580a5324f5e14ede59bd094a43a9d8ce3fecf Mon Sep 17 00:00:00 2001 From: Kamil Krawczyk Date: Sat, 16 Nov 2013 10:00:46 +0000 Subject: i40e: restrict diag test length The diagnostics test needs some slightly different limits in order to succeed. Change-Id: Ia1c49148af92fa4be20778a819f69350381bf865 Signed-off-by: Kamil Krawczyk Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_diag.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_diag.c b/drivers/net/ethernet/intel/i40e/i40e_diag.c index de255143bde..dc6c41fade9 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_diag.c +++ b/drivers/net/ethernet/intel/i40e/i40e_diag.c @@ -68,16 +68,16 @@ static i40e_status i40e_diag_reg_pattern_test(struct i40e_hw *hw, struct i40e_diag_reg_test_info i40e_reg_list[] = { /* offset mask elements stride */ - {I40E_QTX_CTL(0), 0x0000FFBF, 64, I40E_QTX_CTL(1) - I40E_QTX_CTL(0)}, + {I40E_QTX_CTL(0), 0x0000FFBF, 4, I40E_QTX_CTL(1) - I40E_QTX_CTL(0)}, {I40E_PFINT_ITR0(0), 0x00000FFF, 3, I40E_PFINT_ITR0(1) - I40E_PFINT_ITR0(0)}, {I40E_PFINT_ITRN(0, 0), 0x00000FFF, 64, I40E_PFINT_ITRN(0, 1) - I40E_PFINT_ITRN(0, 0)}, {I40E_PFINT_ITRN(1, 0), 0x00000FFF, 64, I40E_PFINT_ITRN(1, 1) - I40E_PFINT_ITRN(1, 0)}, {I40E_PFINT_ITRN(2, 0), 0x00000FFF, 64, I40E_PFINT_ITRN(2, 1) - I40E_PFINT_ITRN(2, 0)}, {I40E_PFINT_STAT_CTL0, 0x0000000C, 1, 0}, {I40E_PFINT_LNKLST0, 0x00001FFF, 1, 0}, - {I40E_PFINT_LNKLSTN(0), 0x000007FF, 511, I40E_PFINT_LNKLSTN(1) - I40E_PFINT_LNKLSTN(0)}, - {I40E_QINT_TQCTL(0), 0x000000FF, I40E_QINT_TQCTL_MAX_INDEX + 1, I40E_QINT_TQCTL(1) - I40E_QINT_TQCTL(0)}, - {I40E_QINT_RQCTL(0), 0x000000FF, I40E_QINT_RQCTL_MAX_INDEX + 1, I40E_QINT_RQCTL(1) - I40E_QINT_RQCTL(0)}, + {I40E_PFINT_LNKLSTN(0), 0x000007FF, 64, I40E_PFINT_LNKLSTN(1) - I40E_PFINT_LNKLSTN(0)}, + {I40E_QINT_TQCTL(0), 0x000000FF, 64, I40E_QINT_TQCTL(1) - I40E_QINT_TQCTL(0)}, + {I40E_QINT_RQCTL(0), 0x000000FF, 64, I40E_QINT_RQCTL(1) - I40E_QINT_RQCTL(0)}, {I40E_PFINT_ICR0_ENA, 0xF7F20000, 1, 0}, { 0 } }; -- cgit v1.2.3-70-g09d2 From 91612c331070bfd4f20d7bf7dafccde8c45893ac Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Sat, 16 Nov 2013 10:00:47 +0000 Subject: i40e: sync header files with hardware Update the PCTYPE table fix fcoe HMC object sizes Change-Id: I1f12cd2653168859661e8700f929b7c65b0e21b7 Signed-off-by: Anjali Singhai Jain Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_lan_hmc.h | 4 ++-- drivers/net/ethernet/intel/i40e/i40e_type.h | 11 ++++------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.h b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.h index 00ff3500607..f8afbcb053c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.h +++ b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.h @@ -113,8 +113,8 @@ enum i40e_hmc_lan_object_size { #define I40E_HMC_L2OBJ_BASE_ALIGNMENT 512 #define I40E_HMC_OBJ_SIZE_TXQ 128 #define I40E_HMC_OBJ_SIZE_RXQ 32 -#define I40E_HMC_OBJ_SIZE_FCOE_CNTX 128 -#define I40E_HMC_OBJ_SIZE_FCOE_FILT 32 +#define I40E_HMC_OBJ_SIZE_FCOE_CNTX 64 +#define I40E_HMC_OBJ_SIZE_FCOE_FILT 64 enum i40e_hmc_lan_rsrc_type { I40E_HMC_LAN_FULL = 0, diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index f3f22b20f02..5f81bd52e6f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -852,10 +852,7 @@ struct i40e_filter_program_desc { /* Packet Classifier Types for filters */ enum i40e_filter_pctype { - /* Note: Value 0-25 are reserved for future use */ - I40E_FILTER_PCTYPE_IPV4_TEREDO_UDP = 26, - I40E_FILTER_PCTYPE_IPV6_TEREDO_UDP = 27, - I40E_FILTER_PCTYPE_NONF_IPV4_1588_UDP = 28, + /* Note: Values 0-28 are reserved for future use */ I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP = 29, I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP = 30, I40E_FILTER_PCTYPE_NONF_IPV4_UDP = 31, @@ -864,8 +861,7 @@ enum i40e_filter_pctype { I40E_FILTER_PCTYPE_NONF_IPV4_SCTP = 34, I40E_FILTER_PCTYPE_NONF_IPV4_OTHER = 35, I40E_FILTER_PCTYPE_FRAG_IPV4 = 36, - /* Note: Value 37 is reserved for future use */ - I40E_FILTER_PCTYPE_NONF_IPV6_1588_UDP = 38, + /* Note: Values 37-38 are reserved for future use */ I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP = 39, I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP = 40, I40E_FILTER_PCTYPE_NONF_IPV6_UDP = 41, @@ -877,7 +873,8 @@ enum i40e_filter_pctype { /* Note: Value 47 is reserved for future use */ I40E_FILTER_PCTYPE_FCOE_OX = 48, I40E_FILTER_PCTYPE_FCOE_RX = 49, - /* Note: Value 50-62 are reserved for future use */ + I40E_FILTER_PCTYPE_FCOE_OTHER = 50, + /* Note: Values 51-62 are reserved for future use */ I40E_FILTER_PCTYPE_L2_PAYLOAD = 63, }; -- cgit v1.2.3-70-g09d2 From 0ab75ae81da249988bf3c7a38e0a48d4b9be1e0c Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Fri, 6 Dec 2013 06:28:43 -0800 Subject: ethernet: Fix FSF address in file headers Several files refer to an old address for the Free Software Foundation in the file header comment. Resolve by replacing the address with the URL so that we do not have to keep updating the header comments anytime the address changes. CC: Santosh Raspatur CC: Dimitris Michailidis CC: Michael Chan CC: Santiago Leon CC: Sebastian Hesselbarth CC: Olof Johansson CC: Manish Chopra CC: Sony Chacko CC: Rajesh Borundia CC: Nicolas Pitre CC: Steve Glendinning Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/amd8111e.c | 4 +--- drivers/net/ethernet/amd/amd8111e.h | 4 +--- drivers/net/ethernet/amd/au1000_eth.c | 3 +-- drivers/net/ethernet/amd/au1000_eth.h | 3 +-- drivers/net/ethernet/broadcom/sb1250-mac.c | 3 +-- drivers/net/ethernet/chelsio/cxgb/common.h | 3 +-- drivers/net/ethernet/chelsio/cxgb/cphy.h | 3 +-- drivers/net/ethernet/chelsio/cxgb/cpl5_cmd.h | 3 +-- drivers/net/ethernet/chelsio/cxgb/cxgb2.c | 3 +-- drivers/net/ethernet/chelsio/cxgb/elmer0.h | 3 +-- drivers/net/ethernet/chelsio/cxgb/espi.c | 3 +-- drivers/net/ethernet/chelsio/cxgb/espi.h | 3 +-- drivers/net/ethernet/chelsio/cxgb/gmac.h | 3 +-- drivers/net/ethernet/chelsio/cxgb/mv88x201x.c | 3 +-- drivers/net/ethernet/chelsio/cxgb/pm3393.c | 3 +-- drivers/net/ethernet/chelsio/cxgb/regs.h | 3 +-- drivers/net/ethernet/chelsio/cxgb/sge.c | 3 +-- drivers/net/ethernet/chelsio/cxgb/sge.h | 3 +-- drivers/net/ethernet/chelsio/cxgb/subr.c | 3 +-- drivers/net/ethernet/chelsio/cxgb/suni1x10gexp_regs.h | 3 +-- drivers/net/ethernet/ibm/ibmveth.c | 3 +-- drivers/net/ethernet/ibm/ibmveth.h | 3 +-- drivers/net/ethernet/lantiq_etop.c | 3 +-- drivers/net/ethernet/marvell/mv643xx_eth.c | 3 +-- drivers/net/ethernet/marvell/pxa168_eth.c | 3 +-- drivers/net/ethernet/natsemi/ns83820.c | 3 +-- drivers/net/ethernet/netx-eth.c | 3 +-- drivers/net/ethernet/nvidia/forcedeth.c | 3 +-- drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h | 3 +-- drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_api.c | 3 +-- drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_api.h | 3 +-- drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c | 3 +-- drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c | 3 +-- drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_param.c | 3 +-- drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_phy.c | 3 +-- drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_phy.h | 3 +-- drivers/net/ethernet/pasemi/pasemi_mac.c | 3 +-- drivers/net/ethernet/pasemi/pasemi_mac.h | 3 +-- drivers/net/ethernet/pasemi/pasemi_mac_ethtool.c | 3 +-- drivers/net/ethernet/qlogic/netxen/Makefile | 4 +--- drivers/net/ethernet/qlogic/netxen/netxen_nic.h | 4 +--- drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c | 4 +--- drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c | 4 +--- drivers/net/ethernet/qlogic/netxen/netxen_nic_hdr.h | 4 +--- drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c | 4 +--- drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.h | 4 +--- drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c | 4 +--- drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c | 4 +--- drivers/net/ethernet/smsc/smc911x.c | 3 +-- drivers/net/ethernet/smsc/smc911x.h | 3 +-- drivers/net/ethernet/smsc/smc91x.c | 3 +-- drivers/net/ethernet/smsc/smc91x.h | 3 +-- drivers/net/ethernet/smsc/smsc911x.c | 3 +-- drivers/net/ethernet/smsc/smsc911x.h | 3 +-- drivers/net/ethernet/smsc/smsc9420.c | 3 +-- drivers/net/ethernet/smsc/smsc9420.h | 3 +-- drivers/net/ethernet/sun/cassini.c | 4 +--- drivers/net/ethernet/sun/cassini.h | 4 +--- drivers/net/ethernet/tundra/tsi108_eth.h | 4 +--- drivers/net/ethernet/xircom/xirc2ps_cs.c | 3 +-- 60 files changed, 60 insertions(+), 134 deletions(-) diff --git a/drivers/net/ethernet/amd/amd8111e.c b/drivers/net/ethernet/amd/amd8111e.c index d042511bdc1..d6beba0bc01 100644 --- a/drivers/net/ethernet/amd/amd8111e.c +++ b/drivers/net/ethernet/amd/amd8111e.c @@ -24,9 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA + * along with this program; if not, see . Module Name: diff --git a/drivers/net/ethernet/amd/amd8111e.h b/drivers/net/ethernet/amd/amd8111e.h index 8baa3527ba7..b1fae36360d 100644 --- a/drivers/net/ethernet/amd/amd8111e.h +++ b/drivers/net/ethernet/amd/amd8111e.h @@ -13,9 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA + * along with this program; if not, see . Module Name: diff --git a/drivers/net/ethernet/amd/au1000_eth.c b/drivers/net/ethernet/amd/au1000_eth.c index 427c148bb64..2eee5764805 100644 --- a/drivers/net/ethernet/amd/au1000_eth.c +++ b/drivers/net/ethernet/amd/au1000_eth.c @@ -27,8 +27,7 @@ * for more details. * * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * with this program; if not, see . * * ######################################################################## * diff --git a/drivers/net/ethernet/amd/au1000_eth.h b/drivers/net/ethernet/amd/au1000_eth.h index 4b7f7ad62bb..ca53024f017 100644 --- a/drivers/net/ethernet/amd/au1000_eth.h +++ b/drivers/net/ethernet/amd/au1000_eth.h @@ -18,8 +18,7 @@ * for more details. * * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * with this program; if not, see . * * ######################################################################## * diff --git a/drivers/net/ethernet/broadcom/sb1250-mac.c b/drivers/net/ethernet/broadcom/sb1250-mac.c index c2777712da9..31a076d8670 100644 --- a/drivers/net/ethernet/broadcom/sb1250-mac.c +++ b/drivers/net/ethernet/broadcom/sb1250-mac.c @@ -13,8 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . * * * This driver is designed for the Broadcom SiByte SOC built-in diff --git a/drivers/net/ethernet/chelsio/cxgb/common.h b/drivers/net/ethernet/chelsio/cxgb/common.h index 8abb46b3903..5dd20f7285e 100644 --- a/drivers/net/ethernet/chelsio/cxgb/common.h +++ b/drivers/net/ethernet/chelsio/cxgb/common.h @@ -11,8 +11,7 @@ * published by the Free Software Foundation. * * * * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * with this program; if not, see . * * * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * diff --git a/drivers/net/ethernet/chelsio/cxgb/cphy.h b/drivers/net/ethernet/chelsio/cxgb/cphy.h index 1f095a9fc73..a4d2a4c08d3 100644 --- a/drivers/net/ethernet/chelsio/cxgb/cphy.h +++ b/drivers/net/ethernet/chelsio/cxgb/cphy.h @@ -11,8 +11,7 @@ * published by the Free Software Foundation. * * * * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * with this program; if not, see . * * * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * diff --git a/drivers/net/ethernet/chelsio/cxgb/cpl5_cmd.h b/drivers/net/ethernet/chelsio/cxgb/cpl5_cmd.h index e36d45b78cc..5249686afe7 100644 --- a/drivers/net/ethernet/chelsio/cxgb/cpl5_cmd.h +++ b/drivers/net/ethernet/chelsio/cxgb/cpl5_cmd.h @@ -11,8 +11,7 @@ * published by the Free Software Foundation. * * * * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * with this program; if not, see . * * * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * diff --git a/drivers/net/ethernet/chelsio/cxgb/cxgb2.c b/drivers/net/ethernet/chelsio/cxgb/cxgb2.c index 1d021059f09..e5987139a1a 100644 --- a/drivers/net/ethernet/chelsio/cxgb/cxgb2.c +++ b/drivers/net/ethernet/chelsio/cxgb/cxgb2.c @@ -11,8 +11,7 @@ * published by the Free Software Foundation. * * * * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * with this program; if not, see . * * * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * diff --git a/drivers/net/ethernet/chelsio/cxgb/elmer0.h b/drivers/net/ethernet/chelsio/cxgb/elmer0.h index eef655c827d..81526ad3633 100644 --- a/drivers/net/ethernet/chelsio/cxgb/elmer0.h +++ b/drivers/net/ethernet/chelsio/cxgb/elmer0.h @@ -11,8 +11,7 @@ * published by the Free Software Foundation. * * * * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * with this program; if not, see . * * * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * diff --git a/drivers/net/ethernet/chelsio/cxgb/espi.c b/drivers/net/ethernet/chelsio/cxgb/espi.c index 639ff195573..3e182eee799 100644 --- a/drivers/net/ethernet/chelsio/cxgb/espi.c +++ b/drivers/net/ethernet/chelsio/cxgb/espi.c @@ -12,8 +12,7 @@ * published by the Free Software Foundation. * * * * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * with this program; if not, see . * * * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * diff --git a/drivers/net/ethernet/chelsio/cxgb/espi.h b/drivers/net/ethernet/chelsio/cxgb/espi.h index 5694aad4fbc..162de5259df 100644 --- a/drivers/net/ethernet/chelsio/cxgb/espi.h +++ b/drivers/net/ethernet/chelsio/cxgb/espi.h @@ -11,8 +11,7 @@ * published by the Free Software Foundation. * * * * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * with this program; if not, see . * * * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * diff --git a/drivers/net/ethernet/chelsio/cxgb/gmac.h b/drivers/net/ethernet/chelsio/cxgb/gmac.h index d42337457cf..dfa77491a91 100644 --- a/drivers/net/ethernet/chelsio/cxgb/gmac.h +++ b/drivers/net/ethernet/chelsio/cxgb/gmac.h @@ -12,8 +12,7 @@ * published by the Free Software Foundation. * * * * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * with this program; if not, see . * * * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * diff --git a/drivers/net/ethernet/chelsio/cxgb/mv88x201x.c b/drivers/net/ethernet/chelsio/cxgb/mv88x201x.c index f7136b2fd1e..d0cf611551a 100644 --- a/drivers/net/ethernet/chelsio/cxgb/mv88x201x.c +++ b/drivers/net/ethernet/chelsio/cxgb/mv88x201x.c @@ -12,8 +12,7 @@ * published by the Free Software Foundation. * * * * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * with this program; if not, see . * * * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * diff --git a/drivers/net/ethernet/chelsio/cxgb/pm3393.c b/drivers/net/ethernet/chelsio/cxgb/pm3393.c index eb33a31b08a..ec5e05052d9 100644 --- a/drivers/net/ethernet/chelsio/cxgb/pm3393.c +++ b/drivers/net/ethernet/chelsio/cxgb/pm3393.c @@ -12,8 +12,7 @@ * published by the Free Software Foundation. * * * * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * with this program; if not, see . * * * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * diff --git a/drivers/net/ethernet/chelsio/cxgb/regs.h b/drivers/net/ethernet/chelsio/cxgb/regs.h index c80bf4d6d0a..964ce59ee16 100644 --- a/drivers/net/ethernet/chelsio/cxgb/regs.h +++ b/drivers/net/ethernet/chelsio/cxgb/regs.h @@ -11,8 +11,7 @@ * published by the Free Software Foundation. * * * * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * with this program; if not, see . * * * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * diff --git a/drivers/net/ethernet/chelsio/cxgb/sge.c b/drivers/net/ethernet/chelsio/cxgb/sge.c index 8061fb0ef7e..0341537cdd3 100644 --- a/drivers/net/ethernet/chelsio/cxgb/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb/sge.c @@ -12,8 +12,7 @@ * published by the Free Software Foundation. * * * * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * with this program; if not, see . * * * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * diff --git a/drivers/net/ethernet/chelsio/cxgb/sge.h b/drivers/net/ethernet/chelsio/cxgb/sge.h index b9bf16b385f..a1ba591b343 100644 --- a/drivers/net/ethernet/chelsio/cxgb/sge.h +++ b/drivers/net/ethernet/chelsio/cxgb/sge.h @@ -11,8 +11,7 @@ * published by the Free Software Foundation. * * * * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * with this program; if not, see . * * * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * diff --git a/drivers/net/ethernet/chelsio/cxgb/subr.c b/drivers/net/ethernet/chelsio/cxgb/subr.c index e0a03a31e7c..816719314cc 100644 --- a/drivers/net/ethernet/chelsio/cxgb/subr.c +++ b/drivers/net/ethernet/chelsio/cxgb/subr.c @@ -12,8 +12,7 @@ * published by the Free Software Foundation. * * * * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * with this program; if not, see . * * * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * diff --git a/drivers/net/ethernet/chelsio/cxgb/suni1x10gexp_regs.h b/drivers/net/ethernet/chelsio/cxgb/suni1x10gexp_regs.h index d0f87d82566..7f79cc7ceb7 100644 --- a/drivers/net/ethernet/chelsio/cxgb/suni1x10gexp_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb/suni1x10gexp_regs.h @@ -12,8 +12,7 @@ * published by the Free Software Foundation. * * * * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * with this program; if not, see . * * * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c index 952d795230a..cde0fd941f0 100644 --- a/drivers/net/ethernet/ibm/ibmveth.c +++ b/drivers/net/ethernet/ibm/ibmveth.c @@ -12,8 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . * * Copyright (C) IBM Corporation, 2003, 2010 * diff --git a/drivers/net/ethernet/ibm/ibmveth.h b/drivers/net/ethernet/ibm/ibmveth.h index 84066bafe05..451ba7949e1 100644 --- a/drivers/net/ethernet/ibm/ibmveth.h +++ b/drivers/net/ethernet/ibm/ibmveth.h @@ -12,8 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . * * Copyright (C) IBM Corporation, 2003, 2010 * diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c index 6a6c1f76d8e..974a007c427 100644 --- a/drivers/net/ethernet/lantiq_etop.c +++ b/drivers/net/ethernet/lantiq_etop.c @@ -9,8 +9,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . * * Copyright (C) 2011 John Crispin */ diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c index 61088a6a942..fa905052fbf 100644 --- a/drivers/net/ethernet/marvell/mv643xx_eth.c +++ b/drivers/net/ethernet/marvell/mv643xx_eth.c @@ -33,8 +33,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/net/ethernet/marvell/pxa168_eth.c b/drivers/net/ethernet/marvell/pxa168_eth.c index fff62460185..2ad32417a52 100644 --- a/drivers/net/ethernet/marvell/pxa168_eth.c +++ b/drivers/net/ethernet/marvell/pxa168_eth.c @@ -19,8 +19,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #include diff --git a/drivers/net/ethernet/natsemi/ns83820.c b/drivers/net/ethernet/natsemi/ns83820.c index d3b47003a57..5213e73f0ea 100644 --- a/drivers/net/ethernet/natsemi/ns83820.c +++ b/drivers/net/ethernet/natsemi/ns83820.c @@ -22,8 +22,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * * * ChangeLog diff --git a/drivers/net/ethernet/netx-eth.c b/drivers/net/ethernet/netx-eth.c index e6f0a4366f9..31eb911e476 100644 --- a/drivers/net/ethernet/netx-eth.c +++ b/drivers/net/ethernet/netx-eth.c @@ -13,8 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ #include diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c index 2d045be4b5c..ab67babbfdd 100644 --- a/drivers/net/ethernet/nvidia/forcedeth.c +++ b/drivers/net/ethernet/nvidia/forcedeth.c @@ -26,8 +26,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * * Known bugs: * We suspect that on some hardware no TX done interrupts are generated. diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h index 2a9003071d5..2a55d6d53ee 100644 --- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h +++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h @@ -14,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #ifndef _PCH_GBE_H_ diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_api.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_api.c index ff3ad70935a..51250363566 100644 --- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_api.c +++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_api.c @@ -14,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #include "pch_gbe.h" #include "pch_gbe_phy.h" diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_api.h b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_api.h index 94aaac5b057..91ce07c8306 100644 --- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_api.h +++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_api.h @@ -14,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #ifndef _PCH_GBE_API_H_ #define _PCH_GBE_API_H_ diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c index f0ceb89af93..826f0ccdc23 100644 --- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c +++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c @@ -14,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #include "pch_gbe.h" #include "pch_gbe_api.h" diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c index 27ffe0ebf0a..464e91058c8 100644 --- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c +++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c @@ -14,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #include "pch_gbe.h" diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_param.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_param.c index cf7c9b3a255..08d4be61606 100644 --- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_param.c +++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_param.c @@ -14,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #include "pch_gbe.h" diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_phy.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_phy.c index 8b7ff75fc8e..a5cad5ea943 100644 --- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_phy.c +++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_phy.c @@ -14,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #include "pch_gbe.h" diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_phy.h b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_phy.h index 0cbe69206e0..95ad0151ad0 100644 --- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_phy.h +++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_phy.h @@ -14,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #ifndef _PCH_GBE_PHY_H_ #define _PCH_GBE_PHY_H_ diff --git a/drivers/net/ethernet/pasemi/pasemi_mac.c b/drivers/net/ethernet/pasemi/pasemi_mac.c index dbaa49e58b0..0734758ff5b 100644 --- a/drivers/net/ethernet/pasemi/pasemi_mac.c +++ b/drivers/net/ethernet/pasemi/pasemi_mac.c @@ -13,8 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ #include diff --git a/drivers/net/ethernet/pasemi/pasemi_mac.h b/drivers/net/ethernet/pasemi/pasemi_mac.h index f2749d46c12..a5807703ab9 100644 --- a/drivers/net/ethernet/pasemi/pasemi_mac.h +++ b/drivers/net/ethernet/pasemi/pasemi_mac.h @@ -14,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ #ifndef PASEMI_MAC_H diff --git a/drivers/net/ethernet/pasemi/pasemi_mac_ethtool.c b/drivers/net/ethernet/pasemi/pasemi_mac_ethtool.c index 4825959a0ef..25fae568261 100644 --- a/drivers/net/ethernet/pasemi/pasemi_mac_ethtool.c +++ b/drivers/net/ethernet/pasemi/pasemi_mac_ethtool.c @@ -13,8 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ diff --git a/drivers/net/ethernet/qlogic/netxen/Makefile b/drivers/net/ethernet/qlogic/netxen/Makefile index 861a0590b1f..e14e60c8838 100644 --- a/drivers/net/ethernet/qlogic/netxen/Makefile +++ b/drivers/net/ethernet/qlogic/netxen/Makefile @@ -13,9 +13,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, -# MA 02111-1307, USA. +# along with this program; if not, see . # # The full GNU General Public License is included in this distribution # in the file called "COPYING". diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic.h b/drivers/net/ethernet/qlogic/netxen/netxen_nic.h index 9adcdbb4947..6e426ae9469 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic.h +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic.h @@ -14,9 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, - * MA 02111-1307, USA. + * along with this program; if not, see . * * The full GNU General Public License is included in this distribution * in the file called "COPYING". diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c index 1bcaf45aa86..6f6be57f469 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c @@ -14,9 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, - * MA 02111-1307, USA. + * along with this program; if not, see . * * The full GNU General Public License is included in this distribution * in the file called "COPYING". diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c index 4ca2c196c98..87e073c6e29 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c @@ -14,9 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, - * MA 02111-1307, USA. + * along with this program; if not, see . * * The full GNU General Public License is included in this distribution * in the file called "COPYING". diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_hdr.h b/drivers/net/ethernet/qlogic/netxen/netxen_nic_hdr.h index 0c64c82b9ac..a310c2f6502 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_hdr.h +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_hdr.h @@ -14,9 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, - * MA 02111-1307, USA. + * along with this program; if not, see . * * The full GNU General Public License is included in this distribution * in the file called "COPYING". diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c index 67efe754367..b72b6bea326 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c @@ -14,9 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, - * MA 02111-1307, USA. + * along with this program; if not, see . * * The full GNU General Public License is included in this distribution * in the file called "COPYING". diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.h b/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.h index e2c5b6f2df0..7433c4d2160 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.h +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.h @@ -14,9 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, - * MA 02111-1307, USA. + * along with this program; if not, see . * * The full GNU General Public License is included in this distribution * in the file called "COPYING". diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c index 7692dfd4f26..3010abb55fb 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c @@ -14,9 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, - * MA 02111-1307, USA. + * along with this program; if not, see . * * The full GNU General Public License is included in this distribution * in the file called "COPYING". diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c index 3bec8cfebf9..70849dea32b 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c @@ -14,9 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, - * MA 02111-1307, USA. + * along with this program; if not, see . * * The full GNU General Public License is included in this distribution * in the file called "COPYING". diff --git a/drivers/net/ethernet/smsc/smc911x.c b/drivers/net/ethernet/smsc/smc911x.c index 0f096a89005..5a4278d1f7d 100644 --- a/drivers/net/ethernet/smsc/smc911x.c +++ b/drivers/net/ethernet/smsc/smc911x.c @@ -17,8 +17,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * * Arguments: * watchdog = TX watchdog timeout diff --git a/drivers/net/ethernet/smsc/smc911x.h b/drivers/net/ethernet/smsc/smc911x.h index 9965da39281..04b35f55df9 100644 --- a/drivers/net/ethernet/smsc/smc911x.h +++ b/drivers/net/ethernet/smsc/smc911x.h @@ -15,8 +15,7 @@ . GNU General Public License for more details. . . You should have received a copy of the GNU General Public License - . along with this program; if not, write to the Free Software - . Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + . along with this program; if not, see . . . Information contained in this file was obtained from the LAN9118 . manual from SMC. To get a copy, if you really want one, you can find diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c index 0c9b5d94154..b84c4ddf7ad 100644 --- a/drivers/net/ethernet/smsc/smc91x.c +++ b/drivers/net/ethernet/smsc/smc91x.c @@ -19,8 +19,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * * Arguments: * io = for the base address diff --git a/drivers/net/ethernet/smsc/smc91x.h b/drivers/net/ethernet/smsc/smc91x.h index 749654b976b..47dce918eb0 100644 --- a/drivers/net/ethernet/smsc/smc91x.h +++ b/drivers/net/ethernet/smsc/smc91x.h @@ -18,8 +18,7 @@ . GNU General Public License for more details. . . You should have received a copy of the GNU General Public License - . along with this program; if not, write to the Free Software - . Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + . along with this program; if not, see . . . Information contained in this file was obtained from the LAN91C111 . manual from SMC. To get a copy, if you really want one, you can find diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c index 8564f23a679..6382b7c416f 100644 --- a/drivers/net/ethernet/smsc/smsc911x.c +++ b/drivers/net/ethernet/smsc/smsc911x.c @@ -14,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . * *************************************************************************** * Rewritten, heavily based on smsc911x simple driver by SMSC. diff --git a/drivers/net/ethernet/smsc/smsc911x.h b/drivers/net/ethernet/smsc/smsc911x.h index 9ad5e5d39a0..23953957fed 100644 --- a/drivers/net/ethernet/smsc/smsc911x.h +++ b/drivers/net/ethernet/smsc/smsc911x.h @@ -14,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . * ***************************************************************************/ #ifndef __SMSC911X_H__ diff --git a/drivers/net/ethernet/smsc/smsc9420.c b/drivers/net/ethernet/smsc/smsc9420.c index f433d97aa09..9d6effe5f69 100644 --- a/drivers/net/ethernet/smsc/smsc9420.c +++ b/drivers/net/ethernet/smsc/smsc9420.c @@ -13,8 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . * *************************************************************************** */ diff --git a/drivers/net/ethernet/smsc/smsc9420.h b/drivers/net/ethernet/smsc/smsc9420.h index e441402f77a..c63c76381af 100644 --- a/drivers/net/ethernet/smsc/smsc9420.h +++ b/drivers/net/ethernet/smsc/smsc9420.h @@ -13,8 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . * *************************************************************************** */ diff --git a/drivers/net/ethernet/sun/cassini.c b/drivers/net/ethernet/sun/cassini.c index b4d50d74ba1..df8d383acf4 100644 --- a/drivers/net/ethernet/sun/cassini.c +++ b/drivers/net/ethernet/sun/cassini.c @@ -14,9 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. + * along with this program; if not, see . * * This driver uses the sungem driver (c) David Miller * (davem@redhat.com) as its basis. diff --git a/drivers/net/ethernet/sun/cassini.h b/drivers/net/ethernet/sun/cassini.h index b361424d5f5..882ce168a79 100644 --- a/drivers/net/ethernet/sun/cassini.h +++ b/drivers/net/ethernet/sun/cassini.h @@ -15,9 +15,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. + * along with this program; if not, see . * * vendor id: 0x108E (Sun Microsystems, Inc.) * device id: 0xabba (Cassini) diff --git a/drivers/net/ethernet/tundra/tsi108_eth.h b/drivers/net/ethernet/tundra/tsi108_eth.h index 5fee7d78dc6..4a03c594b2b 100644 --- a/drivers/net/ethernet/tundra/tsi108_eth.h +++ b/drivers/net/ethernet/tundra/tsi108_eth.h @@ -16,9 +16,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . */ /* diff --git a/drivers/net/ethernet/xircom/xirc2ps_cs.c b/drivers/net/ethernet/xircom/xirc2ps_cs.c index bdd20b888cf..7c81ffb861e 100644 --- a/drivers/net/ethernet/xircom/xirc2ps_cs.c +++ b/drivers/net/ethernet/xircom/xirc2ps_cs.c @@ -27,8 +27,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * along with this program; if not, see . * * * ALTERNATIVELY, this driver may be distributed under the terms of -- cgit v1.2.3-70-g09d2 From e8478de32ead801a09a073c4286abf892d907465 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Fri, 6 Dec 2013 06:28:44 -0800 Subject: irda: Fix FSF address in file headers Several files refer to an old address for the Free Software Foundation in the file header comment. Resolve by replacing the address with the URL so that we do not have to keep updating the header comments anytime the address changes. CC: Samuel Ortiz Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/irda/au1k_ir.c | 3 +-- drivers/net/irda/esi-sir.c | 4 +--- drivers/net/irda/litelink-sir.c | 4 +--- drivers/net/irda/ma600-sir.c | 4 +--- drivers/net/irda/old_belkin-sir.c | 4 +--- drivers/net/irda/smsc-ircc2.c | 4 +--- drivers/net/irda/smsc-ircc2.h | 4 +--- drivers/net/irda/via-ircc.c | 3 +-- drivers/net/irda/via-ircc.h | 3 +-- drivers/net/irda/vlsi_ir.c | 4 +--- drivers/net/irda/vlsi_ir.h | 4 +--- 11 files changed, 11 insertions(+), 30 deletions(-) diff --git a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c index 7a1f684edcb..5b7a665c6d8 100644 --- a/drivers/net/irda/au1k_ir.c +++ b/drivers/net/irda/au1k_ir.c @@ -15,8 +15,7 @@ * for more details. * * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * with this program; if not, see . */ #include diff --git a/drivers/net/irda/esi-sir.c b/drivers/net/irda/esi-sir.c index a908df7c4b9..019a3e848bc 100644 --- a/drivers/net/irda/esi-sir.c +++ b/drivers/net/irda/esi-sir.c @@ -25,9 +25,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * ********************************************************************/ diff --git a/drivers/net/irda/litelink-sir.c b/drivers/net/irda/litelink-sir.c index d6d9d2e5ad4..6827777cbee 100644 --- a/drivers/net/irda/litelink-sir.c +++ b/drivers/net/irda/litelink-sir.c @@ -22,9 +22,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * ********************************************************************/ diff --git a/drivers/net/irda/ma600-sir.c b/drivers/net/irda/ma600-sir.c index e9121645237..a9a81358477 100644 --- a/drivers/net/irda/ma600-sir.c +++ b/drivers/net/irda/ma600-sir.c @@ -25,9 +25,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * ********************************************************************/ diff --git a/drivers/net/irda/old_belkin-sir.c b/drivers/net/irda/old_belkin-sir.c index 75714bc7103..f237136f382 100644 --- a/drivers/net/irda/old_belkin-sir.c +++ b/drivers/net/irda/old_belkin-sir.c @@ -22,9 +22,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * ********************************************************************/ diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index 0dcdf1592f6..282120430f1 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -34,9 +34,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * ********************************************************************/ diff --git a/drivers/net/irda/smsc-ircc2.h b/drivers/net/irda/smsc-ircc2.h index 317b7fd69bb..4829fa22cb2 100644 --- a/drivers/net/irda/smsc-ircc2.h +++ b/drivers/net/irda/smsc-ircc2.h @@ -25,9 +25,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * ********************************************************************/ diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c index 9abaec27f96..26cb45d5970 100644 --- a/drivers/net/irda/via-ircc.c +++ b/drivers/net/irda/via-ircc.c @@ -17,8 +17,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +this program; if not, see . F01 Oct/02/02: Modify code for V0.11(move out back to back transfer) F02 Oct/28/02: Add SB device ID for 3147 and 3177. diff --git a/drivers/net/irda/via-ircc.h b/drivers/net/irda/via-ircc.h index f903a6a2dcb..7ce820ecc36 100644 --- a/drivers/net/irda/via-ircc.h +++ b/drivers/net/irda/via-ircc.h @@ -18,8 +18,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +this program; if not, see . * Comment: * jul/08/2002 : Rx buffer length should use Rx ring ptr. diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index c5bd58b4d8a..cc9b8665e73 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -15,9 +15,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * ********************************************************************/ diff --git a/drivers/net/irda/vlsi_ir.h b/drivers/net/irda/vlsi_ir.h index a076eb12534..56399204e68 100644 --- a/drivers/net/irda/vlsi_ir.h +++ b/drivers/net/irda/vlsi_ir.h @@ -18,9 +18,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * ********************************************************************/ -- cgit v1.2.3-70-g09d2 From 9cb00073d754249604f735a79734fa58df92a456 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Fri, 6 Dec 2013 06:28:46 -0800 Subject: usb: Fix FSF address in file headers Several files refer to an old address for the Free Software Foundation in the file header comment. Resolve by replacing the address with the URL so that we do not have to keep updating the header comments anytime the address changes. CC: Oliver Neukum CC: Steve Glendinning CC: Oliver Neukum Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/usb/asix.h | 3 +-- drivers/net/usb/asix_common.c | 3 +-- drivers/net/usb/asix_devices.c | 3 +-- drivers/net/usb/ax88172a.c | 3 +-- drivers/net/usb/ax88179_178a.c | 3 +-- drivers/net/usb/catc.c | 3 +-- drivers/net/usb/cdc_eem.c | 3 +-- drivers/net/usb/cdc_ether.c | 3 +-- drivers/net/usb/cdc_subset.c | 3 +-- drivers/net/usb/cx82310_eth.c | 3 +-- drivers/net/usb/gl620a.c | 3 +-- drivers/net/usb/int51x1.c | 3 +-- drivers/net/usb/kaweth.c | 3 +-- drivers/net/usb/lg-vl600.c | 3 +-- drivers/net/usb/mcs7830.c | 3 +-- drivers/net/usb/net1080.c | 3 +-- drivers/net/usb/plusb.c | 3 +-- drivers/net/usb/rndis_host.c | 3 +-- drivers/net/usb/sierra_net.c | 3 +-- drivers/net/usb/smsc75xx.c | 3 +-- drivers/net/usb/smsc75xx.h | 3 +-- drivers/net/usb/smsc95xx.c | 3 +-- drivers/net/usb/smsc95xx.h | 3 +-- drivers/net/usb/usbnet.c | 3 +-- drivers/net/usb/zaurus.c | 3 +-- 25 files changed, 25 insertions(+), 50 deletions(-) diff --git a/drivers/net/usb/asix.h b/drivers/net/usb/asix.h index bdaa12d07a1..bad857aacd1 100644 --- a/drivers/net/usb/asix.h +++ b/drivers/net/usb/asix.h @@ -16,8 +16,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ #ifndef _ASIX_H diff --git a/drivers/net/usb/asix_common.c b/drivers/net/usb/asix_common.c index 577c72d5f36..5c55f11572b 100644 --- a/drivers/net/usb/asix_common.c +++ b/drivers/net/usb/asix_common.c @@ -16,8 +16,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ #include "asix.h" diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c index 386a3df5367..9765a7d4766 100644 --- a/drivers/net/usb/asix_devices.c +++ b/drivers/net/usb/asix_devices.c @@ -16,8 +16,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ #include "asix.h" diff --git a/drivers/net/usb/ax88172a.c b/drivers/net/usb/ax88172a.c index 723b3879ecc..5f18fcb8dcc 100644 --- a/drivers/net/usb/ax88172a.c +++ b/drivers/net/usb/ax88172a.c @@ -21,8 +21,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ #include "asix.h" diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c index 8e8d0fcd497..d6f64dad05b 100644 --- a/drivers/net/usb/ax88179_178a.c +++ b/drivers/net/usb/ax88179_178a.c @@ -14,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #include diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c index df507e6dbb9..da6b8a5dcc0 100644 --- a/drivers/net/usb/catc.c +++ b/drivers/net/usb/catc.c @@ -24,8 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to , or by paper mail: diff --git a/drivers/net/usb/cdc_eem.c b/drivers/net/usb/cdc_eem.c index 08d55b6bf27..57fd7170ae6 100644 --- a/drivers/net/usb/cdc_eem.c +++ b/drivers/net/usb/cdc_eem.c @@ -14,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ #include diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index 2023f3ea891..4b1c0f3f727 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -14,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ // #define DEBUG // error path messages, extra info diff --git a/drivers/net/usb/cdc_subset.c b/drivers/net/usb/cdc_subset.c index 0d1fe89ae0b..3b2593a7602 100644 --- a/drivers/net/usb/cdc_subset.c +++ b/drivers/net/usb/cdc_subset.c @@ -13,8 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ #include diff --git a/drivers/net/usb/cx82310_eth.c b/drivers/net/usb/cx82310_eth.c index 1e207f086b7..5233e6d070e 100644 --- a/drivers/net/usb/cx82310_eth.c +++ b/drivers/net/usb/cx82310_eth.c @@ -14,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ #include diff --git a/drivers/net/usb/gl620a.c b/drivers/net/usb/gl620a.c index a7e3f4e55bf..3569da1135c 100644 --- a/drivers/net/usb/gl620a.c +++ b/drivers/net/usb/gl620a.c @@ -14,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ // #define DEBUG // error path messages, extra info diff --git a/drivers/net/usb/int51x1.c b/drivers/net/usb/int51x1.c index ace9e74ffbd..4ff70b22c6e 100644 --- a/drivers/net/usb/int51x1.c +++ b/drivers/net/usb/int51x1.c @@ -20,8 +20,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ #include diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index afb117c16d2..250fc21d978 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -25,8 +25,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . * ****************************************************************/ diff --git a/drivers/net/usb/lg-vl600.c b/drivers/net/usb/lg-vl600.c index 808d6506da4..acfcc32b323 100644 --- a/drivers/net/usb/lg-vl600.c +++ b/drivers/net/usb/lg-vl600.c @@ -15,8 +15,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ #include #include diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c index 03832d3780a..aea68bc3358 100644 --- a/drivers/net/usb/mcs7830.c +++ b/drivers/net/usb/mcs7830.c @@ -36,8 +36,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ #include diff --git a/drivers/net/usb/net1080.c b/drivers/net/usb/net1080.c index 93e0716a118..8b2493f05a1 100644 --- a/drivers/net/usb/net1080.c +++ b/drivers/net/usb/net1080.c @@ -13,8 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ // #define DEBUG // error path messages, extra info diff --git a/drivers/net/usb/plusb.c b/drivers/net/usb/plusb.c index 0fcc8e65a06..ee705b7bba0 100644 --- a/drivers/net/usb/plusb.c +++ b/drivers/net/usb/plusb.c @@ -13,8 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ // #define DEBUG // error path messages, extra info diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c index cc49aac7022..72aee8516ca 100644 --- a/drivers/net/usb/rndis_host.c +++ b/drivers/net/usb/rndis_host.c @@ -13,8 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ #include #include diff --git a/drivers/net/usb/sierra_net.c b/drivers/net/usb/sierra_net.c index a79e9d33492..a251588762e 100644 --- a/drivers/net/usb/sierra_net.c +++ b/drivers/net/usb/sierra_net.c @@ -21,8 +21,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ #define DRIVER_VERSION "v.2.0" diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c index 66ebbacf066..0217b282e7e 100644 --- a/drivers/net/usb/smsc75xx.c +++ b/drivers/net/usb/smsc75xx.c @@ -13,8 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . * *****************************************************************************/ diff --git a/drivers/net/usb/smsc75xx.h b/drivers/net/usb/smsc75xx.h index 67eba39e6ee..2c7ea8fd184 100644 --- a/drivers/net/usb/smsc75xx.h +++ b/drivers/net/usb/smsc75xx.h @@ -13,8 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . * *****************************************************************************/ diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 3f38ba868f6..96f5eee20fa 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -13,8 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . * *****************************************************************************/ diff --git a/drivers/net/usb/smsc95xx.h b/drivers/net/usb/smsc95xx.h index f360ee37255..526faa0c44e 100644 --- a/drivers/net/usb/smsc95xx.h +++ b/drivers/net/usb/smsc95xx.h @@ -13,8 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . * *****************************************************************************/ diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 8494bb53ebd..56c175ebae3 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -14,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ /* diff --git a/drivers/net/usb/zaurus.c b/drivers/net/usb/zaurus.c index 35c90307d47..25d1e667a06 100644 --- a/drivers/net/usb/zaurus.c +++ b/drivers/net/usb/zaurus.c @@ -13,8 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ // #define DEBUG // error path messages, extra info -- cgit v1.2.3-70-g09d2 From adf8d3ff6e982621c8cc2e8cac8e68d19fba6ac0 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Fri, 6 Dec 2013 06:28:47 -0800 Subject: drivers/net/*: Fix FSF address in file headers Several files refer to an old address for the Free Software Foundation in the file header comment. Resolve by replacing the address with the URL so that we do not have to keep updating the header comments anytime the address changes. CC: Jay Vosburgh CC: Veaceslav Falico CC: Andy Gospodarek CC: Haiyang Zhang CC: "K. Y. Srinivasan" CC: Paul Mackerras CC: Ian Campbell CC: Wei Liu CC: Rusty Russell CC: "Michael S. Tsirkin" Signed-off-by: Jeff Kirsher Acked-by: Wei Liu Signed-off-by: David S. Miller --- drivers/net/bonding/bond_alb.c | 3 +-- drivers/net/bonding/bond_alb.h | 3 +-- drivers/net/bonding/bond_sysfs.c | 3 +-- drivers/net/hamradio/mkiss.c | 3 +-- drivers/net/hyperv/hyperv_net.h | 3 +-- drivers/net/hyperv/netvsc.c | 3 +-- drivers/net/hyperv/netvsc_drv.c | 3 +-- drivers/net/hyperv/rndis_filter.c | 3 +-- drivers/net/ppp/ppp_mppe.c | 3 +-- drivers/net/virtio_net.c | 3 +-- drivers/net/xen-netback/xenbus.c | 3 +-- 11 files changed, 11 insertions(+), 22 deletions(-) diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 02872405d35..2250b063ab8 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -12,8 +12,7 @@ * for more details. * * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * with this program; if not, see . * * The full GNU General Public License is included in this distribution in the * file called LICENSE. diff --git a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h index 4226044efd0..e09dd4bfaff 100644 --- a/drivers/net/bonding/bond_alb.h +++ b/drivers/net/bonding/bond_alb.h @@ -12,8 +12,7 @@ * for more details. * * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * with this program; if not, see . * * The full GNU General Public License is included in this distribution in the * file called LICENSE. diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index abf5e106edc..c778a26fb4d 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -12,8 +12,7 @@ * for more details. * * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * with this program; if not, see . * * The full GNU General Public License is included in this distribution in the * file called LICENSE. diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index 8e01c457015..8a6c720a4cc 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -9,8 +9,7 @@ * for more details. * * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * with this program; if not, see . * * Copyright (C) Hans Alblas PE1AYX * Copyright (C) 2004, 05 Ralf Baechle DL5RB diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index e6fe0d80d61..a26eecb1212 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -12,8 +12,7 @@ * more details. * * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307 USA. + * this program; if not, see . * * Authors: * Haiyang Zhang diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 2b0480416b3..93b485b9624 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -11,8 +11,7 @@ * more details. * * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307 USA. + * this program; if not, see . * * Authors: * Haiyang Zhang diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 524f713f601..9184c82d5c5 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -11,8 +11,7 @@ * more details. * * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307 USA. + * this program; if not, see . * * Authors: * Haiyang Zhang diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index 0775f0aefd1..1084e5de3ce 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -11,8 +11,7 @@ * more details. * * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307 USA. + * this program; if not, see . * * Authors: * Haiyang Zhang diff --git a/drivers/net/ppp/ppp_mppe.c b/drivers/net/ppp/ppp_mppe.c index 9a1849a83e2..911b21602ff 100644 --- a/drivers/net/ppp/ppp_mppe.c +++ b/drivers/net/ppp/ppp_mppe.c @@ -27,8 +27,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * * * Changelog: diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 916241d16c6..5c24288814d 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -13,8 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ //#define DEBUG #include diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c index f0358992b04..7a206cffb06 100644 --- a/drivers/net/xen-netback/xenbus.c +++ b/drivers/net/xen-netback/xenbus.c @@ -15,8 +15,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ #include "common.h" -- cgit v1.2.3-70-g09d2 From 4b2f13a25133b115eb56771bd4a8e71a82aea968 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Fri, 6 Dec 2013 06:28:48 -0800 Subject: sctp: Fix FSF address in file headers Several files refer to an old address for the Free Software Foundation in the file header comment. Resolve by replacing the address with the URL so that we do not have to keep updating the header comments anytime the address changes. CC: Vlad Yasevich CC: Neil Horman Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- include/linux/sctp.h | 5 ++--- include/net/sctp/sctp.h | 5 ++--- include/net/sctp/sm.h | 5 ++--- include/net/sctp/structs.h | 5 ++--- include/net/sctp/tsnmap.h | 5 ++--- include/net/sctp/ulpevent.h | 5 ++--- include/net/sctp/ulpqueue.h | 5 ++--- include/uapi/linux/sctp.h | 5 ++--- net/sctp/associola.c | 5 ++--- net/sctp/auth.c | 5 ++--- net/sctp/bind_addr.c | 5 ++--- net/sctp/chunk.c | 5 ++--- net/sctp/command.c | 5 ++--- net/sctp/debug.c | 5 ++--- net/sctp/endpointola.c | 5 ++--- net/sctp/input.c | 5 ++--- net/sctp/inqueue.c | 5 ++--- net/sctp/ipv6.c | 5 ++--- net/sctp/objcnt.c | 5 ++--- net/sctp/output.c | 5 ++--- net/sctp/outqueue.c | 5 ++--- net/sctp/primitive.c | 5 ++--- net/sctp/proc.c | 5 ++--- net/sctp/protocol.c | 5 ++--- net/sctp/sm_make_chunk.c | 5 ++--- net/sctp/sm_sideeffect.c | 5 ++--- net/sctp/sm_statefuns.c | 5 ++--- net/sctp/sm_statetable.c | 5 ++--- net/sctp/socket.c | 5 ++--- net/sctp/ssnmap.c | 5 ++--- net/sctp/sysctl.c | 5 ++--- net/sctp/transport.c | 5 ++--- net/sctp/tsnmap.c | 5 ++--- net/sctp/ulpevent.c | 5 ++--- net/sctp/ulpqueue.c | 5 ++--- 35 files changed, 70 insertions(+), 105 deletions(-) diff --git a/include/linux/sctp.h b/include/linux/sctp.h index 3bfe8d6ee24..c4c5eba26d9 100644 --- a/include/linux/sctp.h +++ b/include/linux/sctp.h @@ -23,9 +23,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index c5fe80697f8..610a8c8738f 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -21,9 +21,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h index 4ef75af340b..7f4eeb340a5 100644 --- a/include/net/sctp/sm.h +++ b/include/net/sctp/sm.h @@ -21,9 +21,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email addresses: diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index ea0ca5f6e62..e416d6ac9c7 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -19,9 +19,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email addresses: diff --git a/include/net/sctp/tsnmap.h b/include/net/sctp/tsnmap.h index 54bbbe54730..31b8dbaad45 100644 --- a/include/net/sctp/tsnmap.h +++ b/include/net/sctp/tsnmap.h @@ -22,9 +22,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/include/net/sctp/ulpevent.h b/include/net/sctp/ulpevent.h index 27b9f5c9015..daacb32b55b 100644 --- a/include/net/sctp/ulpevent.h +++ b/include/net/sctp/ulpevent.h @@ -25,9 +25,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/include/net/sctp/ulpqueue.h b/include/net/sctp/ulpqueue.h index b0cf5d54d71..e0dce07b879 100644 --- a/include/net/sctp/ulpqueue.h +++ b/include/net/sctp/ulpqueue.h @@ -24,9 +24,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email addresses: diff --git a/include/uapi/linux/sctp.h b/include/uapi/linux/sctp.h index ca451e99b28..266022a2be4 100644 --- a/include/uapi/linux/sctp.h +++ b/include/uapi/linux/sctp.h @@ -22,9 +22,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 68a27f9796d..66882a26713 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -22,9 +22,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/auth.c b/net/sctp/auth.c index 46b5977978a..5c9f64c1c90 100644 --- a/net/sctp/auth.c +++ b/net/sctp/auth.c @@ -16,9 +16,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c index 077bb070052..871cdf9567e 100644 --- a/net/sctp/bind_addr.c +++ b/net/sctp/bind_addr.c @@ -21,9 +21,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c index f2044fcb9dd..5573e425b0c 100644 --- a/net/sctp/chunk.c +++ b/net/sctp/chunk.c @@ -18,9 +18,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/command.c b/net/sctp/command.c index 3d9a9ff69c0..dd737585161 100644 --- a/net/sctp/command.c +++ b/net/sctp/command.c @@ -19,9 +19,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/debug.c b/net/sctp/debug.c index e89015d8935..95d7b15dad2 100644 --- a/net/sctp/debug.c +++ b/net/sctp/debug.c @@ -22,9 +22,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index 09b8daac87c..6ffb6c1b13b 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c @@ -23,9 +23,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/input.c b/net/sctp/input.c index 98b69bbecdd..66038533ca5 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -23,9 +23,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c index 5856932fdc3..4de12afa13d 100644 --- a/net/sctp/inqueue.c +++ b/net/sctp/inqueue.c @@ -24,9 +24,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 7567e6f1a92..32db816ffba 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -21,9 +21,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/objcnt.c b/net/sctp/objcnt.c index 647396baa56..0c28e8a5532 100644 --- a/net/sctp/objcnt.c +++ b/net/sctp/objcnt.c @@ -20,9 +20,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/output.c b/net/sctp/output.c index 0e2644d0a77..6371337e1fe 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -20,9 +20,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index f51ba985a36..b6b09f3f1a8 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -22,9 +22,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/primitive.c b/net/sctp/primitive.c index ce1ffd81177..ab8d9f96a17 100644 --- a/net/sctp/primitive.c +++ b/net/sctp/primitive.c @@ -23,9 +23,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/proc.c b/net/sctp/proc.c index 0c064215684..de32e14f739 100644 --- a/net/sctp/proc.c +++ b/net/sctp/proc.c @@ -16,9 +16,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 5e17092f4ad..19bd4c5bdae 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -23,9 +23,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index fe690320b1e..d9aaf9641aa 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -23,9 +23,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 1a6eef39ab2..02b7ad1ff46 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -22,9 +22,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index dfe3f36ff2a..dd0eba919a8 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -22,9 +22,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/sm_statetable.c b/net/sctp/sm_statetable.c index c5999b2dde7..a4f17437fb2 100644 --- a/net/sctp/sm_statetable.c +++ b/net/sctp/sm_statetable.c @@ -22,9 +22,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 72046b9729a..191cd925780 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -28,9 +28,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/ssnmap.c b/net/sctp/ssnmap.c index 6007124aefa..b9c8521c1a9 100644 --- a/net/sctp/ssnmap.c +++ b/net/sctp/ssnmap.c @@ -18,9 +18,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index 6b36561a1b3..80b17b5df6b 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c @@ -19,9 +19,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/transport.c b/net/sctp/transport.c index e332efb124c..1d4f3ac29ba 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -24,9 +24,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/tsnmap.c b/net/sctp/tsnmap.c index fbda2002828..7635f9f2311 100644 --- a/net/sctp/tsnmap.c +++ b/net/sctp/tsnmap.c @@ -21,9 +21,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index 81089ed6545..85c64658bd0 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c @@ -22,9 +22,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c index 1c1484ed605..a67470083be 100644 --- a/net/sctp/ulpqueue.c +++ b/net/sctp/ulpqueue.c @@ -21,9 +21,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): -- cgit v1.2.3-70-g09d2 From a99421d9b1bf332d8eaebfe0ff17096a9f84d50b Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Fri, 6 Dec 2013 09:13:39 -0800 Subject: ipv4/ipv6: Fix FSF address in file headers Several files refer to an old address for the Free Software Foundation in the file header comment. Resolve by replacing the address with the URL so that we do not have to keep updating the header comments anytime the address changes. CC: Alexey Kuznetsov CC: James Morris CC: Hideaki YOSHIFUJI CC: Patrick McHardy Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- net/ipv4/cipso_ipv4.c | 3 +-- net/ipv4/netfilter/nf_nat_snmp_basic.c | 3 +-- net/ipv6/ah6.c | 3 +-- net/ipv6/esp6.c | 3 +-- net/ipv6/ipcomp6.c | 3 +-- net/ipv6/mip6.c | 3 +-- net/ipv6/tunnel6.c | 3 +-- net/ipv6/xfrm6_mode_ro.c | 3 +-- net/ipv6/xfrm6_tunnel.c | 3 +-- 9 files changed, 9 insertions(+), 18 deletions(-) diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index 667c1d4ca98..4b59b6e488d 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -31,8 +31,7 @@ * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/net/ipv4/netfilter/nf_nat_snmp_basic.c b/net/ipv4/netfilter/nf_nat_snmp_basic.c index 5f011cc89cd..61a942265e8 100644 --- a/net/ipv4/netfilter/nf_nat_snmp_basic.c +++ b/net/ipv4/netfilter/nf_nat_snmp_basic.c @@ -34,8 +34,7 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * * Author: James Morris * diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index 82e1da3a40b..81e496a2e00 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -12,8 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * * Authors * diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index b8719df0366..6eef8a7e35f 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -12,8 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * * Authors * diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index ce507d9e1c9..da9becb42e8 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c @@ -16,8 +16,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ /* * [Memo] diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c index 9ac01dc9402..db9b6cbc9db 100644 --- a/net/ipv6/mip6.c +++ b/net/ipv6/mip6.c @@ -13,8 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ /* * Authors: diff --git a/net/ipv6/tunnel6.c b/net/ipv6/tunnel6.c index 4b0f50d9a96..2c4e4c5c761 100644 --- a/net/ipv6/tunnel6.c +++ b/net/ipv6/tunnel6.c @@ -12,8 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * * Authors Mitsuru KANDA * YOSHIFUJI Hideaki diff --git a/net/ipv6/xfrm6_mode_ro.c b/net/ipv6/xfrm6_mode_ro.c index 63d5d493098..0e015906f9c 100644 --- a/net/ipv6/xfrm6_mode_ro.c +++ b/net/ipv6/xfrm6_mode_ro.c @@ -15,8 +15,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ /* * Authors: diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index de2bcfaaf75..1c66465a42d 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c @@ -12,8 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * * Authors Mitsuru KANDA * YOSHIFUJI Hideaki -- cgit v1.2.3-70-g09d2 From a6227e26d946bc56df47ca5fe418660a07ef8288 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Fri, 6 Dec 2013 09:13:40 -0800 Subject: include/net/: Fix FSF address in file headers Several files refer to an old address for the Free Software Foundation in the file header comment. Resolve by replacing the address with the URL so that we do not have to keep updating the header comments anytime the address changes. Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- include/net/cipso_ipv4.h | 3 +-- include/net/dcbevent.h | 3 +-- include/net/dcbnl.h | 3 +-- include/net/irda/discovery.h | 4 +--- include/net/irda/ircomm_core.h | 4 +--- include/net/irda/ircomm_event.h | 4 +--- include/net/irda/ircomm_lmp.h | 4 +--- include/net/irda/ircomm_param.h | 4 +--- include/net/irda/ircomm_ttp.h | 4 +--- include/net/irda/ircomm_tty.h | 4 +--- include/net/irda/ircomm_tty_attach.h | 4 +--- include/net/irda/irda_device.h | 4 +--- include/net/irda/irlap_event.h | 4 +--- include/net/irda/irlap_frame.h | 4 +--- include/net/irda/parameters.h | 4 +--- include/net/irda/qos.h | 4 +--- include/net/mip6.h | 3 +-- include/net/netlabel.h | 3 +-- include/net/nfc/hci.h | 4 +--- include/net/nfc/llc.h | 4 +--- include/net/nfc/nci.h | 3 +-- include/net/nfc/nci_core.h | 3 +-- include/net/nfc/nfc.h | 4 +--- include/net/sctp/auth.h | 5 ++--- include/net/sctp/checksum.h | 5 ++--- include/net/sctp/command.h | 5 ++--- include/net/sctp/constants.h | 5 ++--- include/net/tc_act/tc_skbedit.h | 3 +-- 28 files changed, 32 insertions(+), 76 deletions(-) diff --git a/include/net/cipso_ipv4.h b/include/net/cipso_ipv4.h index a8c2ef6d3b9..2179d071f68 100644 --- a/include/net/cipso_ipv4.h +++ b/include/net/cipso_ipv4.h @@ -26,8 +26,7 @@ * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/include/net/dcbevent.h b/include/net/dcbevent.h index d2f3041c0df..aec07c8a660 100644 --- a/include/net/dcbevent.h +++ b/include/net/dcbevent.h @@ -11,8 +11,7 @@ * more details. * * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307 USA. + * this program; if not, see . * * Author: John Fastabend */ diff --git a/include/net/dcbnl.h b/include/net/dcbnl.h index fc5d5dcebb0..a975edf21b2 100644 --- a/include/net/dcbnl.h +++ b/include/net/dcbnl.h @@ -11,8 +11,7 @@ * more details. * * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307 USA. + * this program; if not, see . * * Author: Lucy Liu */ diff --git a/include/net/irda/discovery.h b/include/net/irda/discovery.h index 0ce93398720..63ae3253056 100644 --- a/include/net/irda/discovery.h +++ b/include/net/irda/discovery.h @@ -23,9 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * ********************************************************************/ diff --git a/include/net/irda/ircomm_core.h b/include/net/irda/ircomm_core.h index 69b610acd2d..2a580ce9eda 100644 --- a/include/net/irda/ircomm_core.h +++ b/include/net/irda/ircomm_core.h @@ -22,9 +22,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * ********************************************************************/ diff --git a/include/net/irda/ircomm_event.h b/include/net/irda/ircomm_event.h index bc0c6f31f1c..5bbc32998d5 100644 --- a/include/net/irda/ircomm_event.h +++ b/include/net/irda/ircomm_event.h @@ -22,9 +22,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * ********************************************************************/ diff --git a/include/net/irda/ircomm_lmp.h b/include/net/irda/ircomm_lmp.h index ae02106be59..5042a5021a0 100644 --- a/include/net/irda/ircomm_lmp.h +++ b/include/net/irda/ircomm_lmp.h @@ -22,9 +22,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * ********************************************************************/ diff --git a/include/net/irda/ircomm_param.h b/include/net/irda/ircomm_param.h index e6678800c41..1f67432321c 100644 --- a/include/net/irda/ircomm_param.h +++ b/include/net/irda/ircomm_param.h @@ -22,9 +22,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * ********************************************************************/ diff --git a/include/net/irda/ircomm_ttp.h b/include/net/irda/ircomm_ttp.h index 403081ed725..c5627288bca 100644 --- a/include/net/irda/ircomm_ttp.h +++ b/include/net/irda/ircomm_ttp.h @@ -22,9 +22,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * ********************************************************************/ diff --git a/include/net/irda/ircomm_tty.h b/include/net/irda/ircomm_tty.h index 0224402260a..8d4f588974b 100644 --- a/include/net/irda/ircomm_tty.h +++ b/include/net/irda/ircomm_tty.h @@ -22,9 +22,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * ********************************************************************/ diff --git a/include/net/irda/ircomm_tty_attach.h b/include/net/irda/ircomm_tty_attach.h index 0a63bbb972d..20dcbdf258c 100644 --- a/include/net/irda/ircomm_tty_attach.h +++ b/include/net/irda/ircomm_tty_attach.h @@ -22,9 +22,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * ********************************************************************/ diff --git a/include/net/irda/irda_device.h b/include/net/irda/irda_device.h index 11417475a6c..664bf817841 100644 --- a/include/net/irda/irda_device.h +++ b/include/net/irda/irda_device.h @@ -24,9 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * ********************************************************************/ diff --git a/include/net/irda/irlap_event.h b/include/net/irda/irlap_event.h index f9d88da97af..e4325fee126 100644 --- a/include/net/irda/irlap_event.h +++ b/include/net/irda/irlap_event.h @@ -25,9 +25,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * ********************************************************************/ diff --git a/include/net/irda/irlap_frame.h b/include/net/irda/irlap_frame.h index 57173ae398a..cbc12a926e5 100644 --- a/include/net/irda/irlap_frame.h +++ b/include/net/irda/irlap_frame.h @@ -24,9 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * ********************************************************************/ diff --git a/include/net/irda/parameters.h b/include/net/irda/parameters.h index c0d938847bd..42713c931d1 100644 --- a/include/net/irda/parameters.h +++ b/include/net/irda/parameters.h @@ -22,9 +22,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * * Michel Dänzer , 10/2001 * - simplify irda_pv_t to avoid endianness issues diff --git a/include/net/irda/qos.h b/include/net/irda/qos.h index cc577dc0a0e..05a5a249956 100644 --- a/include/net/irda/qos.h +++ b/include/net/irda/qos.h @@ -22,9 +22,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * ********************************************************************/ diff --git a/include/net/mip6.h b/include/net/mip6.h index 26ba99b5a4b..0386b618908 100644 --- a/include/net/mip6.h +++ b/include/net/mip6.h @@ -13,8 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ /* * Authors: diff --git a/include/net/netlabel.h b/include/net/netlabel.h index 2c95d55f791..24948bedb64 100644 --- a/include/net/netlabel.h +++ b/include/net/netlabel.h @@ -22,8 +22,7 @@ * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h index 2eca2960ca9..03c4650b548 100644 --- a/include/net/nfc/hci.h +++ b/include/net/nfc/hci.h @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #ifndef __NET_HCI_H diff --git a/include/net/nfc/llc.h b/include/net/nfc/llc.h index 400ab7ae749..c25fbdee0d6 100644 --- a/include/net/nfc/llc.h +++ b/include/net/nfc/llc.h @@ -13,9 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #ifndef __NFC_LLC_H_ diff --git a/include/net/nfc/nci.h b/include/net/nfc/nci.h index e5aa5acafea..fbfa4e471ab 100644 --- a/include/net/nfc/nci.h +++ b/include/net/nfc/nci.h @@ -20,8 +20,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/include/net/nfc/nci_core.h b/include/net/nfc/nci_core.h index 6126f1f992b..0ff070e8f8d 100644 --- a/include/net/nfc/nci_core.h +++ b/include/net/nfc/nci_core.h @@ -21,8 +21,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h index 82fc4e43fc6..e80894bca1d 100644 --- a/include/net/nfc/nfc.h +++ b/include/net/nfc/nfc.h @@ -16,9 +16,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #ifndef __NET_NFC_H diff --git a/include/net/sctp/auth.h b/include/net/sctp/auth.h index aa80bef3c9d..f2d58aa37a6 100644 --- a/include/net/sctp/auth.h +++ b/include/net/sctp/auth.h @@ -16,9 +16,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/include/net/sctp/checksum.h b/include/net/sctp/checksum.h index 6bd44fe94c2..4a5b9a306c6 100644 --- a/include/net/sctp/checksum.h +++ b/include/net/sctp/checksum.h @@ -19,9 +19,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/include/net/sctp/command.h b/include/net/sctp/command.h index 832f2191489..4b7cd695e43 100644 --- a/include/net/sctp/command.h +++ b/include/net/sctp/command.h @@ -19,9 +19,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h index 2f0a565a0fd..307728f622e 100644 --- a/include/net/sctp/constants.h +++ b/include/net/sctp/constants.h @@ -19,9 +19,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/include/net/tc_act/tc_skbedit.h b/include/net/tc_act/tc_skbedit.h index e103fe02f37..dd5d86fab03 100644 --- a/include/net/tc_act/tc_skbedit.h +++ b/include/net/tc_act/tc_skbedit.h @@ -11,8 +11,7 @@ * more details. * * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307 USA. + * this program; if not, see . * * Author: Alexander Duyck */ -- cgit v1.2.3-70-g09d2 From d484ff154c7a9623ecfe4a5ceb91c981fa227476 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Fri, 6 Dec 2013 09:13:41 -0800 Subject: netlabel: Fix FSF address in file headers Several files refer to an old address for the Free Software Foundation in the file header comment. Resolve by replacing the address with the URL so that we do not have to keep updating the header comments anytime the address changes. CC: Paul Moore Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- net/netlabel/netlabel_addrlist.c | 3 +-- net/netlabel/netlabel_addrlist.h | 3 +-- net/netlabel/netlabel_cipso_v4.c | 3 +-- net/netlabel/netlabel_cipso_v4.h | 3 +-- net/netlabel/netlabel_domainhash.c | 3 +-- net/netlabel/netlabel_domainhash.h | 3 +-- net/netlabel/netlabel_kapi.c | 3 +-- net/netlabel/netlabel_mgmt.c | 3 +-- net/netlabel/netlabel_mgmt.h | 3 +-- net/netlabel/netlabel_unlabeled.c | 3 +-- net/netlabel/netlabel_unlabeled.h | 3 +-- net/netlabel/netlabel_user.c | 3 +-- net/netlabel/netlabel_user.h | 3 +-- 13 files changed, 13 insertions(+), 26 deletions(-) diff --git a/net/netlabel/netlabel_addrlist.c b/net/netlabel/netlabel_addrlist.c index 6f1701322fb..d0a3acfa574 100644 --- a/net/netlabel/netlabel_addrlist.c +++ b/net/netlabel/netlabel_addrlist.c @@ -24,8 +24,7 @@ * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/net/netlabel/netlabel_addrlist.h b/net/netlabel/netlabel_addrlist.h index a1287ce1813..d0f38bc9af6 100644 --- a/net/netlabel/netlabel_addrlist.h +++ b/net/netlabel/netlabel_addrlist.h @@ -24,8 +24,7 @@ * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c index 69345cebe3a..c2f2a53a487 100644 --- a/net/netlabel/netlabel_cipso_v4.c +++ b/net/netlabel/netlabel_cipso_v4.c @@ -23,8 +23,7 @@ * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/net/netlabel/netlabel_cipso_v4.h b/net/netlabel/netlabel_cipso_v4.h index d24d774bfd6..875826808b0 100644 --- a/net/netlabel/netlabel_cipso_v4.h +++ b/net/netlabel/netlabel_cipso_v4.h @@ -23,8 +23,7 @@ * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/net/netlabel/netlabel_domainhash.c b/net/netlabel/netlabel_domainhash.c index 85d842e6e43..f0cb92f3dda 100644 --- a/net/netlabel/netlabel_domainhash.c +++ b/net/netlabel/netlabel_domainhash.c @@ -24,8 +24,7 @@ * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/net/netlabel/netlabel_domainhash.h b/net/netlabel/netlabel_domainhash.h index b9be0eed898..680caf4dff5 100644 --- a/net/netlabel/netlabel_domainhash.h +++ b/net/netlabel/netlabel_domainhash.h @@ -24,8 +24,7 @@ * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c index dce1bebf7ae..3045a964f39 100644 --- a/net/netlabel/netlabel_kapi.c +++ b/net/netlabel/netlabel_kapi.c @@ -23,8 +23,7 @@ * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c index 8ef83ee97c6..e66e977ef2f 100644 --- a/net/netlabel/netlabel_mgmt.c +++ b/net/netlabel/netlabel_mgmt.c @@ -23,8 +23,7 @@ * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/net/netlabel/netlabel_mgmt.h b/net/netlabel/netlabel_mgmt.h index 5a9f31ce579..8b6e1ab62b4 100644 --- a/net/netlabel/netlabel_mgmt.h +++ b/net/netlabel/netlabel_mgmt.h @@ -23,8 +23,7 @@ * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c index 43817d73ccf..78a63c18779 100644 --- a/net/netlabel/netlabel_unlabeled.c +++ b/net/netlabel/netlabel_unlabeled.c @@ -23,8 +23,7 @@ * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/net/netlabel/netlabel_unlabeled.h b/net/netlabel/netlabel_unlabeled.h index 700af49022a..3a9e5dc9511 100644 --- a/net/netlabel/netlabel_unlabeled.h +++ b/net/netlabel/netlabel_unlabeled.h @@ -23,8 +23,7 @@ * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c index 9650c4ad5f8..1e779bb7fa4 100644 --- a/net/netlabel/netlabel_user.c +++ b/net/netlabel/netlabel_user.c @@ -23,8 +23,7 @@ * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/net/netlabel/netlabel_user.h b/net/netlabel/netlabel_user.h index 81969785e27..4a397cde1a4 100644 --- a/net/netlabel/netlabel_user.h +++ b/net/netlabel/netlabel_user.h @@ -23,8 +23,7 @@ * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ -- cgit v1.2.3-70-g09d2 From e664eabd18c4581b21ea6f62e2e599df5a719a5b Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Fri, 6 Dec 2013 09:13:42 -0800 Subject: netfilter: Fix FSF address in file headers Several files refer to an old address for the Free Software Foundation in the file header comment. Resolve by replacing the address with the URL so that we do not have to keep updating the header comments anytime the address changes. CC: netfilter@vger.kernel.org CC: Pablo Neira Ayuso CC: Patrick McHardy CC: Jozsef Kadlecsik Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- include/uapi/linux/netfilter/xt_osf.h | 3 +-- net/bridge/netfilter/ebt_vlan.c | 3 +-- net/netfilter/ipvs/ip_vs_nfct.c | 3 +-- net/netfilter/xt_connmark.c | 3 +-- net/netfilter/xt_osf.c | 3 +-- 5 files changed, 5 insertions(+), 10 deletions(-) diff --git a/include/uapi/linux/netfilter/xt_osf.h b/include/uapi/linux/netfilter/xt_osf.h index 18afa495f97..5d66caeba3e 100644 --- a/include/uapi/linux/netfilter/xt_osf.h +++ b/include/uapi/linux/netfilter/xt_osf.h @@ -13,8 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ #ifndef _XT_OSF_H diff --git a/net/bridge/netfilter/ebt_vlan.c b/net/bridge/netfilter/ebt_vlan.c index eae67bf0446..8d3f8c7651f 100644 --- a/net/bridge/netfilter/ebt_vlan.c +++ b/net/bridge/netfilter/ebt_vlan.c @@ -14,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ #include diff --git a/net/netfilter/ipvs/ip_vs_nfct.c b/net/netfilter/ipvs/ip_vs_nfct.c index c8beafd401a..d5f41514f57 100644 --- a/net/netfilter/ipvs/ip_vs_nfct.c +++ b/net/netfilter/ipvs/ip_vs_nfct.c @@ -19,8 +19,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * * * Authors: diff --git a/net/netfilter/xt_connmark.c b/net/netfilter/xt_connmark.c index 7278145e6a6..69f78e96fdb 100644 --- a/net/netfilter/xt_connmark.c +++ b/net/netfilter/xt_connmark.c @@ -17,8 +17,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ #include diff --git a/net/netfilter/xt_osf.c b/net/netfilter/xt_osf.c index 647d989a01e..7174611bd67 100644 --- a/net/netfilter/xt_osf.c +++ b/net/netfilter/xt_osf.c @@ -13,8 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include -- cgit v1.2.3-70-g09d2 From d37705092fb1bad8dade186451f3cca754a5d1d1 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Fri, 6 Dec 2013 09:13:43 -0800 Subject: net/irda: Fix FSF address in file headers Several files refer to an old address for the Free Software Foundation in the file header comment. Resolve by replacing the address with the URL so that we do not have to keep updating the header comments anytime the address changes. CC: Samuel Ortiz Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- net/irda/af_irda.c | 4 +--- net/irda/discovery.c | 4 +--- net/irda/ircomm/ircomm_core.c | 4 +--- net/irda/ircomm/ircomm_event.c | 4 +--- net/irda/ircomm/ircomm_lmp.c | 4 +--- net/irda/ircomm/ircomm_param.c | 4 +--- net/irda/ircomm/ircomm_ttp.c | 4 +--- net/irda/ircomm/ircomm_tty.c | 4 +--- net/irda/ircomm/ircomm_tty_attach.c | 4 +--- net/irda/ircomm/ircomm_tty_ioctl.c | 4 +--- net/irda/irda_device.c | 4 +--- net/irda/irlap.c | 4 +--- net/irda/parameters.c | 4 +--- net/irda/qos.c | 4 +--- 14 files changed, 14 insertions(+), 42 deletions(-) diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c index de7db23049f..73baf9b346b 100644 --- a/net/irda/af_irda.c +++ b/net/irda/af_irda.c @@ -25,9 +25,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * * Linux-IrDA now supports four different types of IrDA sockets: * diff --git a/net/irda/discovery.c b/net/irda/discovery.c index b0b56a339a8..6786e7f193d 100644 --- a/net/irda/discovery.c +++ b/net/irda/discovery.c @@ -24,9 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * ********************************************************************/ diff --git a/net/irda/ircomm/ircomm_core.c b/net/irda/ircomm/ircomm_core.c index b797daac063..4490a675b1b 100644 --- a/net/irda/ircomm/ircomm_core.c +++ b/net/irda/ircomm/ircomm_core.c @@ -23,9 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * ********************************************************************/ diff --git a/net/irda/ircomm/ircomm_event.c b/net/irda/ircomm/ircomm_event.c index d78554fedba..b172c652232 100644 --- a/net/irda/ircomm/ircomm_event.c +++ b/net/irda/ircomm/ircomm_event.c @@ -22,9 +22,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * ********************************************************************/ diff --git a/net/irda/ircomm/ircomm_lmp.c b/net/irda/ircomm/ircomm_lmp.c index 3b8095c771d..6536114adf3 100644 --- a/net/irda/ircomm/ircomm_lmp.c +++ b/net/irda/ircomm/ircomm_lmp.c @@ -24,9 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * ********************************************************************/ diff --git a/net/irda/ircomm/ircomm_param.c b/net/irda/ircomm/ircomm_param.c index 30893912835..f80b1a6a244 100644 --- a/net/irda/ircomm/ircomm_param.c +++ b/net/irda/ircomm/ircomm_param.c @@ -22,9 +22,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * ********************************************************************/ diff --git a/net/irda/ircomm/ircomm_ttp.c b/net/irda/ircomm/ircomm_ttp.c index 6e6509f22f6..d362d711b79 100644 --- a/net/irda/ircomm/ircomm_ttp.c +++ b/net/irda/ircomm/ircomm_ttp.c @@ -23,9 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * ********************************************************************/ diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 41ac7938268..2ba8b9705bb 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -24,9 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * ********************************************************************/ diff --git a/net/irda/ircomm/ircomm_tty_attach.c b/net/irda/ircomm/ircomm_tty_attach.c index a2a508f5f26..2ee87bf387c 100644 --- a/net/irda/ircomm/ircomm_tty_attach.c +++ b/net/irda/ircomm/ircomm_tty_attach.c @@ -23,9 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * ********************************************************************/ diff --git a/net/irda/ircomm/ircomm_tty_ioctl.c b/net/irda/ircomm/ircomm_tty_ioctl.c index b343f50dc8d..ce943853c38 100644 --- a/net/irda/ircomm/ircomm_tty_ioctl.c +++ b/net/irda/ircomm/ircomm_tty_ioctl.c @@ -22,9 +22,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * ********************************************************************/ diff --git a/net/irda/irda_device.c b/net/irda/irda_device.c index 14653b8d664..365b895da84 100644 --- a/net/irda/irda_device.c +++ b/net/irda/irda_device.c @@ -23,9 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * ********************************************************************/ diff --git a/net/irda/irlap.c b/net/irda/irlap.c index 005b424494a..a778df55f5d 100644 --- a/net/irda/irlap.c +++ b/net/irda/irlap.c @@ -23,9 +23,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * ********************************************************************/ diff --git a/net/irda/parameters.c b/net/irda/parameters.c index 71cd38c1a67..6d0869716bf 100644 --- a/net/irda/parameters.c +++ b/net/irda/parameters.c @@ -22,9 +22,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * ********************************************************************/ diff --git a/net/irda/qos.c b/net/irda/qos.c index 798ffd9a705..11a7cc0cbc2 100644 --- a/net/irda/qos.c +++ b/net/irda/qos.c @@ -24,9 +24,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * along with this program; if not, see . * ********************************************************************/ -- cgit v1.2.3-70-g09d2 From c057b190b82063c57cb8b2b575a00520f9976e2b Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Fri, 6 Dec 2013 09:13:44 -0800 Subject: net/*: Fix FSF address in file headers Several files refer to an old address for the Free Software Foundation in the file header comment. Resolve by replacing the address with the URL so that we do not have to keep updating the header comments anytime the address changes. CC: John Fastabend CC: Alex Duyck CC: Marcel Holtmann CC: Gustavo Padovan CC: Johan Hedberg CC: Jamal Hadi Salim Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- net/bluetooth/bnep/bnep.h | 3 +-- net/dcb/dcbevent.c | 3 +-- net/dcb/dcbnl.c | 3 +-- net/dns_resolver/dns_key.c | 3 +-- net/dns_resolver/dns_query.c | 3 +-- net/dns_resolver/internal.h | 3 +-- net/sched/act_skbedit.c | 3 +-- net/sched/sch_multiq.c | 3 +-- 8 files changed, 8 insertions(+), 16 deletions(-) diff --git a/net/bluetooth/bnep/bnep.h b/net/bluetooth/bnep/bnep.h index e7ee5314f39..5a5b16f365e 100644 --- a/net/bluetooth/bnep/bnep.h +++ b/net/bluetooth/bnep/bnep.h @@ -12,8 +12,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + along with this program; if not, see . */ #ifndef _BNEP_H diff --git a/net/dcb/dcbevent.c b/net/dcb/dcbevent.c index 4f72fc40bf0..a520d8004d8 100644 --- a/net/dcb/dcbevent.c +++ b/net/dcb/dcbevent.c @@ -11,8 +11,7 @@ * more details. * * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307 USA. + * this program; if not, see . * * Author: John Fastabend */ diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c index 40d5829ed36..66fbe1948fb 100644 --- a/net/dcb/dcbnl.c +++ b/net/dcb/dcbnl.c @@ -11,8 +11,7 @@ * more details. * * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307 USA. + * this program; if not, see . * * Author: Lucy Liu */ diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c index f347a2ca7d7..bf858433904 100644 --- a/net/dns_resolver/dns_key.c +++ b/net/dns_resolver/dns_key.c @@ -19,8 +19,7 @@ * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this library; if not, see . */ #include #include diff --git a/net/dns_resolver/dns_query.c b/net/dns_resolver/dns_query.c index c32be292c7e..e7b6d53eef8 100644 --- a/net/dns_resolver/dns_query.c +++ b/net/dns_resolver/dns_query.c @@ -32,8 +32,7 @@ * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this library; if not, see . */ #include diff --git a/net/dns_resolver/internal.h b/net/dns_resolver/internal.h index 17c7886b5b3..7af1ed39c00 100644 --- a/net/dns_resolver/internal.h +++ b/net/dns_resolver/internal.h @@ -15,8 +15,7 @@ * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this library; if not, see . */ #include diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c index cb4221171f9..9119b73527c 100644 --- a/net/sched/act_skbedit.c +++ b/net/sched/act_skbedit.c @@ -11,8 +11,7 @@ * more details. * * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307 USA. + * this program; if not, see . * * Author: Alexander Duyck */ diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c index 2a2b096d9a6..afb050a735f 100644 --- a/net/sched/sch_multiq.c +++ b/net/sched/sch_multiq.c @@ -11,8 +11,7 @@ * more details. * * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307 USA. + * this program; if not, see . * * Author: Alexander Duyck */ -- cgit v1.2.3-70-g09d2 From 92d4ea6e412a023434b477c04fd5632aefb233d4 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Thu, 5 Dec 2013 20:42:58 -0800 Subject: tun: spelling fixes Fix spelling errors in tun driver. Signed-off-by: Stephen Hemminger Acked-by: Jason Wang Signed-off-by: David S. Miller --- drivers/net/tun.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 782e38bfc1e..5ac2877a89c 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -110,7 +110,7 @@ struct tap_filter { unsigned char addr[FLT_EXACT_COUNT][ETH_ALEN]; }; -/* DEFAULT_MAX_NUM_RSS_QUEUES were choosed to let the rx/tx queues allocated for +/* DEFAULT_MAX_NUM_RSS_QUEUES were chosen to let the rx/tx queues allocated for * the netdevice to be fit in one page. So we can make sure the success of * memory allocation. TODO: increase the limit. */ #define MAX_TAP_QUEUES DEFAULT_MAX_NUM_RSS_QUEUES @@ -119,7 +119,7 @@ struct tap_filter { #define TUN_FLOW_EXPIRE (3 * HZ) /* A tun_file connects an open character device to a tuntap netdevice. It - * also contains all socket related strctures (except sock_fprog and tap_filter) + * also contains all socket related structures (except sock_fprog and tap_filter) * to serve as one transmit queue for tuntap device. The sock_fprog and * tap_filter were kept in tun_struct since they were used for filtering for the * netdevice not for a specific queue (at least I didn't see the requirement for @@ -342,7 +342,7 @@ unlock: } /* We try to identify a flow through its rxhash first. The reason that - * we do not check rxq no. is becuase some cards(e.g 82599), chooses + * we do not check rxq no. is because some cards(e.g 82599), chooses * the rxq based on the txq where the last packet of the flow comes. As * the userspace application move between processors, we may get a * different rxq no. here. If we could not get rxhash, then we would @@ -531,7 +531,7 @@ static int tun_attach(struct tun_struct *tun, struct file *file, bool skip_filte err = 0; - /* Re-attach the filter to presist device */ + /* Re-attach the filter to persist device */ if (!skip_filter && (tun->filter_attached == true)) { err = sk_attach_filter(&tun->fprog, tfile->socket.sk); if (!err) @@ -819,9 +819,9 @@ static void tun_poll_controller(struct net_device *dev) * Tun only receives frames when: * 1) the char device endpoint gets data from user space * 2) the tun socket gets a sendmsg call from user space - * Since both of those are syncronous operations, we are guaranteed + * Since both of those are synchronous operations, we are guaranteed * never to have pending data when we poll for it - * so theres nothing to do here but return. + * so there is nothing to do here but return. * We need this though so netpoll recognizes us as an interface that * supports polling, which enables bridge devices in virt setups to * still use netconsole -- cgit v1.2.3-70-g09d2 From 22781a5b9cd8aa58908eec8e269643559335f455 Mon Sep 17 00:00:00 2001 From: Duan Jiong Date: Fri, 6 Dec 2013 13:29:36 +0800 Subject: packet: use macro GET_PBDQC_FROM_RB to simplify the codes Signed-off-by: Duan Jiong Signed-off-by: David S. Miller --- net/packet/af_packet.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index ba2548bd85b..c235da94001 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -437,7 +437,8 @@ static void prb_shutdown_retire_blk_timer(struct packet_sock *po, { struct tpacket_kbdq_core *pkc; - pkc = tx_ring ? &po->tx_ring.prb_bdqc : &po->rx_ring.prb_bdqc; + pkc = tx_ring ? GET_PBDQC_FROM_RB(&po->tx_ring) : + GET_PBDQC_FROM_RB(&po->rx_ring); spin_lock_bh(&rb_queue->lock); pkc->delete_blk_timer = 1; @@ -463,7 +464,8 @@ static void prb_setup_retire_blk_timer(struct packet_sock *po, int tx_ring) if (tx_ring) BUG(); - pkc = tx_ring ? &po->tx_ring.prb_bdqc : &po->rx_ring.prb_bdqc; + pkc = tx_ring ? GET_PBDQC_FROM_RB(&po->tx_ring) : + GET_PBDQC_FROM_RB(&po->rx_ring); prb_init_blk_timer(po, pkc, prb_retire_rx_blk_timer_expired); } @@ -521,7 +523,7 @@ static void init_prb_bdqc(struct packet_sock *po, struct pgv *pg_vec, union tpacket_req_u *req_u, int tx_ring) { - struct tpacket_kbdq_core *p1 = &rb->prb_bdqc; + struct tpacket_kbdq_core *p1 = GET_PBDQC_FROM_RB(rb); struct tpacket_block_desc *pbd; memset(p1, 0x0, sizeof(*p1)); @@ -585,7 +587,7 @@ static void _prb_refresh_rx_retire_blk_timer(struct tpacket_kbdq_core *pkc) static void prb_retire_rx_blk_timer_expired(unsigned long data) { struct packet_sock *po = (struct packet_sock *)data; - struct tpacket_kbdq_core *pkc = &po->rx_ring.prb_bdqc; + struct tpacket_kbdq_core *pkc = GET_PBDQC_FROM_RB(&po->rx_ring); unsigned int frozen; struct tpacket_block_desc *pbd; -- cgit v1.2.3-70-g09d2 From 15c77d8b3be5a7f451035e6487127f58e5f872fa Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 5 Dec 2013 21:38:06 -0800 Subject: ipv6: consistent use of IP6_INC_STATS_BH() in ip6_forward() ip6_forward() runs from softirq context, we can use the SNMP macros assuming this. Use same indentation for all IP6_INC_STATS_BH() calls. Signed-off-by: Eric Dumazet Acked-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- net/ipv6/ip6_output.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 4acdb63495d..9a311cc7967 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -336,7 +336,8 @@ int ip6_forward(struct sk_buff *skb) goto drop; if (!xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) { - IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS); + IP6_INC_STATS_BH(net, ip6_dst_idev(dst), + IPSTATS_MIB_INDISCARDS); goto drop; } @@ -370,8 +371,8 @@ int ip6_forward(struct sk_buff *skb) /* Force OUTPUT device used as source address */ skb->dev = dst->dev; icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, 0); - IP6_INC_STATS_BH(net, - ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS); + IP6_INC_STATS_BH(net, ip6_dst_idev(dst), + IPSTATS_MIB_INHDRERRORS); kfree_skb(skb); return -ETIMEDOUT; @@ -384,14 +385,15 @@ int ip6_forward(struct sk_buff *skb) if (proxied > 0) return ip6_input(skb); else if (proxied < 0) { - IP6_INC_STATS(net, ip6_dst_idev(dst), - IPSTATS_MIB_INDISCARDS); + IP6_INC_STATS_BH(net, ip6_dst_idev(dst), + IPSTATS_MIB_INDISCARDS); goto drop; } } if (!xfrm6_route_forward(skb)) { - IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS); + IP6_INC_STATS_BH(net, ip6_dst_idev(dst), + IPSTATS_MIB_INDISCARDS); goto drop; } dst = skb_dst(skb); @@ -448,16 +450,17 @@ int ip6_forward(struct sk_buff *skb) /* Again, force OUTPUT device used as source address */ skb->dev = dst->dev; icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); - IP6_INC_STATS_BH(net, - ip6_dst_idev(dst), IPSTATS_MIB_INTOOBIGERRORS); - IP6_INC_STATS_BH(net, - ip6_dst_idev(dst), IPSTATS_MIB_FRAGFAILS); + IP6_INC_STATS_BH(net, ip6_dst_idev(dst), + IPSTATS_MIB_INTOOBIGERRORS); + IP6_INC_STATS_BH(net, ip6_dst_idev(dst), + IPSTATS_MIB_FRAGFAILS); kfree_skb(skb); return -EMSGSIZE; } if (skb_cow(skb, dst->dev->hard_header_len)) { - IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTDISCARDS); + IP6_INC_STATS_BH(net, ip6_dst_idev(dst), + IPSTATS_MIB_OUTDISCARDS); goto drop; } -- cgit v1.2.3-70-g09d2 From 84b9cd633bc35a028b313178829ee313525f6892 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 5 Dec 2013 21:44:27 -0800 Subject: gro: small napi_get_frags() optim Remove one useless conditional branch : napi->skb is NULL, so nothing bad can happen. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/dev.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index ba3b7ea5ebb..c98052487e9 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3981,8 +3981,7 @@ struct sk_buff *napi_get_frags(struct napi_struct *napi) if (!skb) { skb = netdev_alloc_skb_ip_align(napi->dev, GRO_MAX_HEAD); - if (skb) - napi->skb = skb; + napi->skb = skb; } return skb; } -- cgit v1.2.3-70-g09d2 From 7b7fc97aa390dfe4770e1d19e215fa289d94b477 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 5 Dec 2013 22:31:30 -0800 Subject: tcp: optimize some skb_shinfo(skb) uses Compiler doesn't know skb_shinfo(skb) pointer is usually constant. By using a temporary variable, we help generating smaller code. For example, tcp_init_nondata_skb() is inlined after this patch. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/tcp_output.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 7820f3a7dd7..993da005e08 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -363,15 +363,17 @@ static inline void TCP_ECN_send(struct sock *sk, struct sk_buff *skb, */ static void tcp_init_nondata_skb(struct sk_buff *skb, u32 seq, u8 flags) { + struct skb_shared_info *shinfo = skb_shinfo(skb); + skb->ip_summed = CHECKSUM_PARTIAL; skb->csum = 0; TCP_SKB_CB(skb)->tcp_flags = flags; TCP_SKB_CB(skb)->sacked = 0; - skb_shinfo(skb)->gso_segs = 1; - skb_shinfo(skb)->gso_size = 0; - skb_shinfo(skb)->gso_type = 0; + shinfo->gso_segs = 1; + shinfo->gso_size = 0; + shinfo->gso_type = 0; TCP_SKB_CB(skb)->seq = seq; if (flags & (TCPHDR_SYN | TCPHDR_FIN)) @@ -986,6 +988,8 @@ static void tcp_queue_skb(struct sock *sk, struct sk_buff *skb) static void tcp_set_skb_tso_segs(const struct sock *sk, struct sk_buff *skb, unsigned int mss_now) { + struct skb_shared_info *shinfo = skb_shinfo(skb); + /* Make sure we own this skb before messing gso_size/gso_segs */ WARN_ON_ONCE(skb_cloned(skb)); @@ -993,13 +997,13 @@ static void tcp_set_skb_tso_segs(const struct sock *sk, struct sk_buff *skb, /* Avoid the costly divide in the normal * non-TSO case. */ - skb_shinfo(skb)->gso_segs = 1; - skb_shinfo(skb)->gso_size = 0; - skb_shinfo(skb)->gso_type = 0; + shinfo->gso_segs = 1; + shinfo->gso_size = 0; + shinfo->gso_type = 0; } else { - skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss_now); - skb_shinfo(skb)->gso_size = mss_now; - skb_shinfo(skb)->gso_type = sk->sk_gso_type; + shinfo->gso_segs = DIV_ROUND_UP(skb->len, mss_now); + shinfo->gso_size = mss_now; + shinfo->gso_type = sk->sk_gso_type; } } @@ -1146,6 +1150,7 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, */ static void __pskb_trim_head(struct sk_buff *skb, int len) { + struct skb_shared_info *shinfo; int i, k, eat; eat = min_t(int, len, skb_headlen(skb)); @@ -1157,23 +1162,24 @@ static void __pskb_trim_head(struct sk_buff *skb, int len) } eat = len; k = 0; - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - int size = skb_frag_size(&skb_shinfo(skb)->frags[i]); + shinfo = skb_shinfo(skb); + for (i = 0; i < shinfo->nr_frags; i++) { + int size = skb_frag_size(&shinfo->frags[i]); if (size <= eat) { skb_frag_unref(skb, i); eat -= size; } else { - skb_shinfo(skb)->frags[k] = skb_shinfo(skb)->frags[i]; + shinfo->frags[k] = shinfo->frags[i]; if (eat) { - skb_shinfo(skb)->frags[k].page_offset += eat; - skb_frag_size_sub(&skb_shinfo(skb)->frags[k], eat); + shinfo->frags[k].page_offset += eat; + skb_frag_size_sub(&shinfo->frags[k], eat); eat = 0; } k++; } } - skb_shinfo(skb)->nr_frags = k; + shinfo->nr_frags = k; skb_reset_tail_pointer(skb); skb->data_len -= len; -- cgit v1.2.3-70-g09d2 From 5349d937739a752b3a3c0981543c13654af3bec9 Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Fri, 6 Dec 2013 14:34:19 +0800 Subject: net/fddi: Replace local macro with PCI standard macro Replace local macro DFX_BUS_PCI() with PCI standard macro dev_is_pci(). Acked-by: Maciej W. Rozycki Signed-off-by: Yijing Wang Signed-off-by: David S. Miller --- drivers/net/fddi/defxx.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/drivers/net/fddi/defxx.c b/drivers/net/fddi/defxx.c index 0b40e1c46f0..0344f71bf4a 100644 --- a/drivers/net/fddi/defxx.c +++ b/drivers/net/fddi/defxx.c @@ -241,12 +241,6 @@ static char version[] = */ #define NEW_SKB_SIZE (PI_RCV_DATA_K_SIZE_MAX+128) -#ifdef CONFIG_PCI -#define DFX_BUS_PCI(dev) (dev->bus == &pci_bus_type) -#else -#define DFX_BUS_PCI(dev) 0 -#endif - #ifdef CONFIG_EISA #define DFX_BUS_EISA(dev) (dev->bus == &eisa_bus_type) #else @@ -436,7 +430,7 @@ static void dfx_port_read_long(DFX_board_t *bp, int offset, u32 *data) static void dfx_get_bars(struct device *bdev, resource_size_t *bar_start, resource_size_t *bar_len) { - int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_pci = dev_is_pci(bdev); int dfx_bus_eisa = DFX_BUS_EISA(bdev); int dfx_bus_tc = DFX_BUS_TC(bdev); int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; @@ -518,7 +512,7 @@ static const struct net_device_ops dfx_netdev_ops = { static int dfx_register(struct device *bdev) { static int version_disp; - int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_pci = dev_is_pci(bdev); int dfx_bus_tc = DFX_BUS_TC(bdev); int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; const char *print_name = dev_name(bdev); @@ -667,7 +661,7 @@ static void dfx_bus_init(struct net_device *dev) { DFX_board_t *bp = netdev_priv(dev); struct device *bdev = bp->bus_dev; - int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_pci = dev_is_pci(bdev); int dfx_bus_eisa = DFX_BUS_EISA(bdev); int dfx_bus_tc = DFX_BUS_TC(bdev); int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; @@ -813,7 +807,7 @@ static void dfx_bus_uninit(struct net_device *dev) { DFX_board_t *bp = netdev_priv(dev); struct device *bdev = bp->bus_dev; - int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_pci = dev_is_pci(bdev); int dfx_bus_eisa = DFX_BUS_EISA(bdev); u8 val; @@ -967,7 +961,7 @@ static int dfx_driver_init(struct net_device *dev, const char *print_name, { DFX_board_t *bp = netdev_priv(dev); struct device *bdev = bp->bus_dev; - int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_pci = dev_is_pci(bdev); int dfx_bus_eisa = DFX_BUS_EISA(bdev); int dfx_bus_tc = DFX_BUS_TC(bdev); int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; @@ -1877,7 +1871,7 @@ static irqreturn_t dfx_interrupt(int irq, void *dev_id) struct net_device *dev = dev_id; DFX_board_t *bp = netdev_priv(dev); struct device *bdev = bp->bus_dev; - int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_pci = dev_is_pci(bdev); int dfx_bus_eisa = DFX_BUS_EISA(bdev); int dfx_bus_tc = DFX_BUS_TC(bdev); @@ -3579,7 +3573,7 @@ static void dfx_unregister(struct device *bdev) { struct net_device *dev = dev_get_drvdata(bdev); DFX_board_t *bp = netdev_priv(dev); - int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_pci = dev_is_pci(bdev); int dfx_bus_tc = DFX_BUS_TC(bdev); int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; resource_size_t bar_start = 0; /* pointer to port */ -- cgit v1.2.3-70-g09d2 From d8535a0a02d6e772122339c131151dfaf007866b Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Fri, 6 Dec 2013 14:34:55 +0800 Subject: 3c59x/net: Use dev_is_pci() instead of hardcoding Use PCI standard macro dev_is_pci() instead of hardcoding. Signed-off-by: Yijing Wang Signed-off-by: David S. Miller --- drivers/net/ethernet/3com/3c59x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/3com/3c59x.c b/drivers/net/ethernet/3com/3c59x.c index ad5272b348f..af24c3cf821 100644 --- a/drivers/net/ethernet/3com/3c59x.c +++ b/drivers/net/ethernet/3com/3c59x.c @@ -693,7 +693,7 @@ DEFINE_WINDOW_IO(16) DEFINE_WINDOW_IO(32) #ifdef CONFIG_PCI -#define DEVICE_PCI(dev) (((dev)->bus == &pci_bus_type) ? to_pci_dev((dev)) : NULL) +#define DEVICE_PCI(dev) ((dev_is_pci(dev)) ? to_pci_dev((dev)) : NULL) #else #define DEVICE_PCI(dev) NULL #endif -- cgit v1.2.3-70-g09d2 From f54b311142a92ea2e42598e347b84e1655caf8e3 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 5 Dec 2013 22:36:05 -0800 Subject: tcp: auto corking With the introduction of TCP Small Queues, TSO auto sizing, and TCP pacing, we can implement Automatic Corking in the kernel, to help applications doing small write()/sendmsg() to TCP sockets. Idea is to change tcp_push() to check if the current skb payload is under skb optimal size (a multiple of MSS bytes) If under 'size_goal', and at least one packet is still in Qdisc or NIC TX queues, set the TCP Small Queue Throttled bit, so that the push will be delayed up to TX completion time. This delay might allow the application to coalesce more bytes in the skb in following write()/sendmsg()/sendfile() system calls. The exact duration of the delay is depending on the dynamics of the system, and might be zero if no packet for this flow is actually held in Qdisc or NIC TX ring. Using FQ/pacing is a way to increase the probability of autocorking being triggered. Add a new sysctl (/proc/sys/net/ipv4/tcp_autocorking) to control this feature and default it to 1 (enabled) Add a new SNMP counter : nstat -a | grep TcpExtTCPAutoCorking This counter is incremented every time we detected skb was under used and its flush was deferred. Tested: Interesting effects when using line buffered commands under ssh. Excellent performance results in term of cpu usage and total throughput. lpq83:~# echo 1 >/proc/sys/net/ipv4/tcp_autocorking lpq83:~# perf stat ./super_netperf 4 -t TCP_STREAM -H lpq84 -- -m 128 9410.39 Performance counter stats for './super_netperf 4 -t TCP_STREAM -H lpq84 -- -m 128': 35209.439626 task-clock # 2.901 CPUs utilized 2,294 context-switches # 0.065 K/sec 101 CPU-migrations # 0.003 K/sec 4,079 page-faults # 0.116 K/sec 97,923,241,298 cycles # 2.781 GHz [83.31%] 51,832,908,236 stalled-cycles-frontend # 52.93% frontend cycles idle [83.30%] 25,697,986,603 stalled-cycles-backend # 26.24% backend cycles idle [66.70%] 102,225,978,536 instructions # 1.04 insns per cycle # 0.51 stalled cycles per insn [83.38%] 18,657,696,819 branches # 529.906 M/sec [83.29%] 91,679,646 branch-misses # 0.49% of all branches [83.40%] 12.136204899 seconds time elapsed lpq83:~# echo 0 >/proc/sys/net/ipv4/tcp_autocorking lpq83:~# perf stat ./super_netperf 4 -t TCP_STREAM -H lpq84 -- -m 128 6624.89 Performance counter stats for './super_netperf 4 -t TCP_STREAM -H lpq84 -- -m 128': 40045.864494 task-clock # 3.301 CPUs utilized 171 context-switches # 0.004 K/sec 53 CPU-migrations # 0.001 K/sec 4,080 page-faults # 0.102 K/sec 111,340,458,645 cycles # 2.780 GHz [83.34%] 61,778,039,277 stalled-cycles-frontend # 55.49% frontend cycles idle [83.31%] 29,295,522,759 stalled-cycles-backend # 26.31% backend cycles idle [66.67%] 108,654,349,355 instructions # 0.98 insns per cycle # 0.57 stalled cycles per insn [83.34%] 19,552,170,748 branches # 488.244 M/sec [83.34%] 157,875,417 branch-misses # 0.81% of all branches [83.34%] 12.130267788 seconds time elapsed Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 10 ++++++ include/net/tcp.h | 1 + include/uapi/linux/snmp.h | 1 + net/ipv4/proc.c | 1 + net/ipv4/sysctl_net_ipv4.c | 9 +++++ net/ipv4/tcp.c | 63 +++++++++++++++++++++++++++------- 6 files changed, 72 insertions(+), 13 deletions(-) diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 3c12d9a7ed0..12ba2cd9f03 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -156,6 +156,16 @@ tcp_app_win - INTEGER buffer. Value 0 is special, it means that nothing is reserved. Default: 31 +tcp_autocorking - BOOLEAN + Enable TCP auto corking : + When applications do consecutive small write()/sendmsg() system calls, + we try to coalesce these small writes as much as possible, to lower + total amount of sent packets. This is done if at least one prior + packet for the flow is waiting in Qdisc queues or device transmit + queue. Applications can still use TCP_CORK for optimal behavior + when they know how/when to uncork their sockets. + Default : 1 + tcp_available_congestion_control - STRING Shows the available congestion control choices that are registered. More congestion control algorithms may be available as modules, diff --git a/include/net/tcp.h b/include/net/tcp.h index 70e55d20061..f7e1ab2139e 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -282,6 +282,7 @@ extern int sysctl_tcp_limit_output_bytes; extern int sysctl_tcp_challenge_ack_limit; extern unsigned int sysctl_tcp_notsent_lowat; extern int sysctl_tcp_min_tso_segs; +extern int sysctl_tcp_autocorking; extern atomic_long_t tcp_memory_allocated; extern struct percpu_counter tcp_sockets_allocated; diff --git a/include/uapi/linux/snmp.h b/include/uapi/linux/snmp.h index 1bdb4a39d1e..bbaba22f2d1 100644 --- a/include/uapi/linux/snmp.h +++ b/include/uapi/linux/snmp.h @@ -258,6 +258,7 @@ enum LINUX_MIB_TCPFASTOPENCOOKIEREQD, /* TCPFastOpenCookieReqd */ LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES, /* TCPSpuriousRtxHostQueues */ LINUX_MIB_BUSYPOLLRXPACKETS, /* BusyPollRxPackets */ + LINUX_MIB_TCPAUTOCORKING, /* TCPAutoCorking */ __LINUX_MIB_MAX }; diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index 4a0335854b8..8ecd7ad959b 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -279,6 +279,7 @@ static const struct snmp_mib snmp4_net_list[] = { SNMP_MIB_ITEM("TCPFastOpenCookieReqd", LINUX_MIB_TCPFASTOPENCOOKIEREQD), SNMP_MIB_ITEM("TCPSpuriousRtxHostQueues", LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES), SNMP_MIB_ITEM("BusyPollRxPackets", LINUX_MIB_BUSYPOLLRXPACKETS), + SNMP_MIB_ITEM("TCPAutoCorking", LINUX_MIB_TCPAUTOCORKING), SNMP_MIB_SENTINEL }; diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 3d69ec8dac5..38c8ec90ff6 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -732,6 +732,15 @@ static struct ctl_table ipv4_table[] = { .extra1 = &zero, .extra2 = &gso_max_segs, }, + { + .procname = "tcp_autocorking", + .data = &sysctl_tcp_autocorking, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &one, + }, { .procname = "udp_mem", .data = &sysctl_udp_mem, diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index c4638e6f023..0ca87547bec 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -285,6 +285,8 @@ int sysctl_tcp_fin_timeout __read_mostly = TCP_FIN_TIMEOUT; int sysctl_tcp_min_tso_segs __read_mostly = 2; +int sysctl_tcp_autocorking __read_mostly = 1; + struct percpu_counter tcp_orphan_count; EXPORT_SYMBOL_GPL(tcp_orphan_count); @@ -619,19 +621,52 @@ static inline void tcp_mark_urg(struct tcp_sock *tp, int flags) tp->snd_up = tp->write_seq; } -static inline void tcp_push(struct sock *sk, int flags, int mss_now, - int nonagle) +/* If a not yet filled skb is pushed, do not send it if + * we have packets in Qdisc or NIC queues : + * Because TX completion will happen shortly, it gives a chance + * to coalesce future sendmsg() payload into this skb, without + * need for a timer, and with no latency trade off. + * As packets containing data payload have a bigger truesize + * than pure acks (dataless) packets, the last check prevents + * autocorking if we only have an ACK in Qdisc/NIC queues. + */ +static bool tcp_should_autocork(struct sock *sk, struct sk_buff *skb, + int size_goal) { - if (tcp_send_head(sk)) { - struct tcp_sock *tp = tcp_sk(sk); + return skb->len < size_goal && + sysctl_tcp_autocorking && + atomic_read(&sk->sk_wmem_alloc) > skb->truesize; +} + +static void tcp_push(struct sock *sk, int flags, int mss_now, + int nonagle, int size_goal) +{ + struct tcp_sock *tp = tcp_sk(sk); + struct sk_buff *skb; - if (!(flags & MSG_MORE) || forced_push(tp)) - tcp_mark_push(tp, tcp_write_queue_tail(sk)); + if (!tcp_send_head(sk)) + return; + + skb = tcp_write_queue_tail(sk); + if (!(flags & MSG_MORE) || forced_push(tp)) + tcp_mark_push(tp, skb); + + tcp_mark_urg(tp, flags); + + if (tcp_should_autocork(sk, skb, size_goal)) { - tcp_mark_urg(tp, flags); - __tcp_push_pending_frames(sk, mss_now, - (flags & MSG_MORE) ? TCP_NAGLE_CORK : nonagle); + /* avoid atomic op if TSQ_THROTTLED bit is already set */ + if (!test_bit(TSQ_THROTTLED, &tp->tsq_flags)) { + NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPAUTOCORKING); + set_bit(TSQ_THROTTLED, &tp->tsq_flags); + } + return; } + + if (flags & MSG_MORE) + nonagle = TCP_NAGLE_CORK; + + __tcp_push_pending_frames(sk, mss_now, nonagle); } static int tcp_splice_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, @@ -934,7 +969,8 @@ new_segment: wait_for_sndbuf: set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); wait_for_memory: - tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH); + tcp_push(sk, flags & ~MSG_MORE, mss_now, + TCP_NAGLE_PUSH, size_goal); if ((err = sk_stream_wait_memory(sk, &timeo)) != 0) goto do_error; @@ -944,7 +980,7 @@ wait_for_memory: out: if (copied && !(flags & MSG_SENDPAGE_NOTLAST)) - tcp_push(sk, flags, mss_now, tp->nonagle); + tcp_push(sk, flags, mss_now, tp->nonagle, size_goal); return copied; do_error: @@ -1225,7 +1261,8 @@ wait_for_sndbuf: set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); wait_for_memory: if (copied) - tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH); + tcp_push(sk, flags & ~MSG_MORE, mss_now, + TCP_NAGLE_PUSH, size_goal); if ((err = sk_stream_wait_memory(sk, &timeo)) != 0) goto do_error; @@ -1236,7 +1273,7 @@ wait_for_memory: out: if (copied) - tcp_push(sk, flags, mss_now, tp->nonagle); + tcp_push(sk, flags, mss_now, tp->nonagle, size_goal); release_sock(sk); return copied + copied_syn; -- cgit v1.2.3-70-g09d2 From d1d66186dcec848e89dede4c305f09462e1fbe34 Mon Sep 17 00:00:00 2001 From: wangweidong Date: Fri, 6 Dec 2013 09:36:27 +0800 Subject: sctp: remove the duplicate initialize kzalloc had initialize the allocated memroy. Therefore, remove the initialize with 0 and the memset. Acked-by: Neil Horman Signed-off-by: Wang Weidong Signed-off-by: David S. Miller --- net/sctp/associola.c | 41 ----------------------------------------- 1 file changed, 41 deletions(-) diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 66882a26713..85295208deb 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -89,14 +89,12 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a /* Initialize the object handling fields. */ atomic_set(&asoc->base.refcnt, 1); - asoc->base.dead = false; /* Initialize the bind addr area. */ sctp_bind_addr_init(&asoc->base.bind_addr, ep->base.bind_addr.port); asoc->state = SCTP_STATE_CLOSED; asoc->cookie_life = ms_to_ktime(sp->assocparams.sasoc_cookie_life); - asoc->frag_point = 0; asoc->user_frag = sp->user_frag; /* Set the association max_retrans and RTO values from the @@ -109,8 +107,6 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a asoc->rto_max = msecs_to_jiffies(sp->rtoinfo.srto_max); asoc->rto_min = msecs_to_jiffies(sp->rtoinfo.srto_min); - asoc->overall_error_count = 0; - /* Initialize the association's heartbeat interval based on the * sock configured value. */ @@ -137,12 +133,9 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a asoc->max_burst = sp->max_burst; /* initialize association timers */ - asoc->timeouts[SCTP_EVENT_TIMEOUT_NONE] = 0; asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] = asoc->rto_initial; asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] = asoc->rto_initial; asoc->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = asoc->rto_initial; - asoc->timeouts[SCTP_EVENT_TIMEOUT_T3_RTX] = 0; - asoc->timeouts[SCTP_EVENT_TIMEOUT_T4_RTO] = 0; /* sctpimpguide Section 2.12.2 * If the 'T5-shutdown-guard' timer is used, it SHOULD be set to the @@ -151,7 +144,6 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a asoc->timeouts[SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD] = 5 * asoc->rto_max; - asoc->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] = 0; asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] = asoc->sackdelay; asoc->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] = min_t(unsigned long, sp->autoclose, net->sctp.max_autoclose) * HZ; @@ -172,11 +164,6 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a asoc->max_init_timeo = msecs_to_jiffies(sp->initmsg.sinit_max_init_timeo); - /* Allocate storage for the ssnmap after the inbound and outbound - * streams have been negotiated during Init. - */ - asoc->ssnmap = NULL; - /* Set the local window size for receive. * This is also the rcvbuf space per association. * RFC 6 - A SCTP receiver MUST be able to receive a minimum of @@ -189,25 +176,15 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a asoc->a_rwnd = asoc->rwnd; - asoc->rwnd_over = 0; - asoc->rwnd_press = 0; - /* Use my own max window until I learn something better. */ asoc->peer.rwnd = SCTP_DEFAULT_MAXWINDOW; - /* Set the sndbuf size for transmit. */ - asoc->sndbuf_used = 0; - /* Initialize the receive memory counter */ atomic_set(&asoc->rmem_alloc, 0); init_waitqueue_head(&asoc->wait); asoc->c.my_vtag = sctp_generate_tag(ep); - asoc->peer.i.init_tag = 0; /* INIT needs a vtag of 0. */ - asoc->c.peer_vtag = 0; - asoc->c.my_ttag = 0; - asoc->c.peer_ttag = 0; asoc->c.my_port = ep->base.bind_addr.port; asoc->c.initial_tsn = sctp_generate_tsn(ep); @@ -218,7 +195,6 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a asoc->adv_peer_ack_point = asoc->ctsn_ack_point; asoc->highest_sacked = asoc->ctsn_ack_point; asoc->last_cwr_tsn = asoc->ctsn_ack_point; - asoc->unack_data = 0; /* ADDIP Section 4.1 Asconf Chunk Procedures * @@ -237,7 +213,6 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a /* Make an empty list of remote transport addresses. */ INIT_LIST_HEAD(&asoc->peer.transport_addr_list); - asoc->peer.transport_count = 0; /* RFC 2960 5.1 Normal Establishment of an Association * @@ -251,7 +226,6 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a * already received one packet.] */ asoc->peer.sack_needed = 1; - asoc->peer.sack_cnt = 0; asoc->peer.sack_generation = 1; /* Assume that the peer will tell us if he recognizes ASCONF @@ -259,12 +233,8 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a * The sctp_addip_noauth option is there for backward compatibilty * and will revert old behavior. */ - asoc->peer.asconf_capable = 0; if (net->sctp.addip_noauth) asoc->peer.asconf_capable = 1; - asoc->asconf_addr_del_pending = NULL; - asoc->src_out_of_asoc_ok = 0; - asoc->new_transport = NULL; /* Create an input queue. */ sctp_inq_init(&asoc->base.inqueue); @@ -276,12 +246,6 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a if (!sctp_ulpq_init(&asoc->ulpq, asoc)) goto fail_init; - memset(&asoc->peer.tsn_map, 0, sizeof(struct sctp_tsnmap)); - - asoc->need_ecne = 0; - - asoc->assoc_id = 0; - /* Assume that peer would support both address types unless we are * told otherwise. */ @@ -299,9 +263,6 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a asoc->default_timetolive = sp->default_timetolive; asoc->default_rcv_context = sp->default_rcv_context; - /* SCTP_GET_ASSOC_STATS COUNTERS */ - memset(&asoc->stats, 0, sizeof(struct sctp_priv_assoc_stats)); - /* AUTH related initializations */ INIT_LIST_HEAD(&asoc->endpoint_shared_keys); err = sctp_auth_asoc_copy_shkeys(ep, asoc, gfp); @@ -309,9 +270,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a goto fail_init; asoc->active_key_id = ep->active_key_id; - asoc->asoc_shared_key = NULL; - asoc->default_hmac_id = 0; /* Save the hmacs and chunks list into this association */ if (ep->auth_hmacs_list) memcpy(asoc->c.auth_hmacs, ep->auth_hmacs_list, -- cgit v1.2.3-70-g09d2 From 8b7318d3edb9d961c41c5e7f7e59b563d74d507d Mon Sep 17 00:00:00 2001 From: wangweidong Date: Fri, 6 Dec 2013 09:36:28 +0800 Subject: sctp: remove the else path Make the code more simplification. Acked-by: Neil Horman Suggested-by: Joe Perches Signed-off-by: Wang Weidong Signed-off-by: David S. Miller --- net/sctp/associola.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 85295208deb..c7172f8ebac 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -955,17 +955,13 @@ int sctp_cmp_addr_exact(const union sctp_addr *ss1, */ struct sctp_chunk *sctp_get_ecne_prepend(struct sctp_association *asoc) { - struct sctp_chunk *chunk; + if (!asoc->need_ecne) + return NULL; /* Send ECNE if needed. * Not being able to allocate a chunk here is not deadly. */ - if (asoc->need_ecne) - chunk = sctp_make_ecne(asoc, asoc->last_ecne_tsn); - else - chunk = NULL; - - return chunk; + return sctp_make_ecne(asoc, asoc->last_ecne_tsn); } /* -- cgit v1.2.3-70-g09d2 From ce4a03db9bec5f77fedab9d13ecc0b61925807ad Mon Sep 17 00:00:00 2001 From: wangweidong Date: Fri, 6 Dec 2013 09:36:29 +0800 Subject: sctp: convert sctp_peer_needs_update to boolean sctp_peer_needs_update only return 0 or 1. Acked-by: Neil Horman Signed-off-by: Wang Weidong Signed-off-by: David S. Miller --- net/sctp/associola.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/sctp/associola.c b/net/sctp/associola.c index c7172f8ebac..e803356179b 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -1350,7 +1350,7 @@ void sctp_assoc_sync_pmtu(struct sock *sk, struct sctp_association *asoc) } /* Should we send a SACK to update our peer? */ -static inline int sctp_peer_needs_update(struct sctp_association *asoc) +static inline bool sctp_peer_needs_update(struct sctp_association *asoc) { struct net *net = sock_net(asoc->base.sk); switch (asoc->state) { @@ -1362,12 +1362,12 @@ static inline int sctp_peer_needs_update(struct sctp_association *asoc) ((asoc->rwnd - asoc->a_rwnd) >= max_t(__u32, (asoc->base.sk->sk_rcvbuf >> net->sctp.rwnd_upd_shift), asoc->pathmtu))) - return 1; + return true; break; default: break; } - return 0; + return false; } /* Increase asoc's rwnd by len and send any window update SACK if needed. */ -- cgit v1.2.3-70-g09d2 From 9d2c881afd41c18a67fb04c4386bb6812898cbf3 Mon Sep 17 00:00:00 2001 From: wangweidong Date: Fri, 6 Dec 2013 09:36:30 +0800 Subject: sctp: fix some comments in associola.c fix some typos Acked-by: Neil Horman Signed-off-by: Wang Weidong Signed-off-by: David S. Miller --- net/sctp/associola.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/sctp/associola.c b/net/sctp/associola.c index e803356179b..3d7c6bd4631 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -127,7 +127,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a */ asoc->param_flags = sp->param_flags; - /* Initialize the maximum mumber of new data packets that can be sent + /* Initialize the maximum number of new data packets that can be sent * in a burst. */ asoc->max_burst = sp->max_burst; @@ -230,7 +230,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a /* Assume that the peer will tell us if he recognizes ASCONF * as part of INIT exchange. - * The sctp_addip_noauth option is there for backward compatibilty + * The sctp_addip_noauth option is there for backward compatibility * and will revert old behavior. */ if (net->sctp.addip_noauth) @@ -1222,7 +1222,7 @@ void sctp_assoc_update(struct sctp_association *asoc, } } - /* SCTP-AUTH: Save the peer parameters from the new assocaitions + /* SCTP-AUTH: Save the peer parameters from the new associations * and also move the association shared keys over */ kfree(asoc->peer.peer_random); @@ -1447,7 +1447,7 @@ void sctp_assoc_rwnd_decrease(struct sctp_association *asoc, unsigned int len) /* If we've reached or overflowed our receive buffer, announce * a 0 rwnd if rwnd would still be positive. Store the - * the pottential pressure overflow so that the window can be restored + * the potential pressure overflow so that the window can be restored * back to original value. */ if (rx_count >= asoc->base.sk->sk_rcvbuf) -- cgit v1.2.3-70-g09d2 From 2e79cb303010d5d2b7810c11bc5d1f09a8500405 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 5 Dec 2013 14:52:10 -0800 Subject: net: of_mdio: factor PHY registration from of_mdiobus_register Since commit 779d835e ("net: of_mdio: scan mdiobus for PHYs without reg property") we have two foreach loops which do pretty much the same thing. Factor the PHY device registration in a function helper: of_mdiobus_register_phy() which takes care of the details and allows for future PHY specific extensions. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/of/of_mdio.c | 109 ++++++++++++++++++++++----------------------------- 1 file changed, 46 insertions(+), 63 deletions(-) diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index d5a57a9e329..82485d2dac8 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -22,6 +22,47 @@ MODULE_AUTHOR("Grant Likely "); MODULE_LICENSE("GPL"); +static int of_mdiobus_register_phy(struct mii_bus *mdio, struct device_node *child, + u32 addr) +{ + struct phy_device *phy; + bool is_c45; + int rc; + + is_c45 = of_device_is_compatible(child, + "ethernet-phy-ieee802.3-c45"); + + phy = get_phy_device(mdio, addr, is_c45); + if (!phy || IS_ERR(phy)) + return 1; + + if (mdio->irq) { + mdio->irq[addr] = + irq_of_parse_and_map(child, 0); + if (!mdio->irq[addr]) + mdio->irq[addr] = PHY_POLL; + } + + /* Associate the OF node with the device structure so it + * can be looked up later */ + of_node_get(child); + phy->dev.of_node = child; + + /* All data is now stored in the phy struct; + * register it */ + rc = phy_device_register(phy); + if (rc) { + phy_device_free(phy); + of_node_put(child); + return 1; + } + + dev_dbg(&mdio->dev, "registered phy %s at address %i\n", + child->name, addr); + + return 0; +} + /** * of_mdiobus_register - Register mii_bus and create PHYs from the device tree * @mdio: pointer to mii_bus structure @@ -32,11 +73,10 @@ MODULE_LICENSE("GPL"); */ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) { - struct phy_device *phy; struct device_node *child; const __be32 *paddr; u32 addr; - bool is_c45, scanphys = false; + bool scanphys = false; int rc, i, len; /* Mask out all PHYs from auto probing. Instead the PHYs listed in @@ -73,38 +113,9 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) continue; } - if (mdio->irq) { - mdio->irq[addr] = irq_of_parse_and_map(child, 0); - if (!mdio->irq[addr]) - mdio->irq[addr] = PHY_POLL; - } - - is_c45 = of_device_is_compatible(child, - "ethernet-phy-ieee802.3-c45"); - phy = get_phy_device(mdio, addr, is_c45); - - if (!phy || IS_ERR(phy)) { - dev_err(&mdio->dev, - "cannot get PHY at address %i\n", - addr); - continue; - } - - /* Associate the OF node with the device structure so it - * can be looked up later */ - of_node_get(child); - phy->dev.of_node = child; - - /* All data is now stored in the phy struct; register it */ - rc = phy_device_register(phy); - if (rc) { - phy_device_free(phy); - of_node_put(child); + rc = of_mdiobus_register_phy(mdio, child, addr); + if (rc) continue; - } - - dev_dbg(&mdio->dev, "registered phy %s at address %i\n", - child->name, addr); } if (!scanphys) @@ -117,9 +128,6 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) if (paddr) continue; - is_c45 = of_device_is_compatible(child, - "ethernet-phy-ieee802.3-c45"); - for (addr = 0; addr < PHY_MAX_ADDR; addr++) { /* skip already registered PHYs */ if (mdio->phy_map[addr]) @@ -129,34 +137,9 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) dev_info(&mdio->dev, "scan phy %s at address %i\n", child->name, addr); - phy = get_phy_device(mdio, addr, is_c45); - if (!phy || IS_ERR(phy)) + rc = of_mdiobus_register_phy(mdio, child, addr); + if (rc) continue; - - if (mdio->irq) { - mdio->irq[addr] = - irq_of_parse_and_map(child, 0); - if (!mdio->irq[addr]) - mdio->irq[addr] = PHY_POLL; - } - - /* Associate the OF node with the device structure so it - * can be looked up later */ - of_node_get(child); - phy->dev.of_node = child; - - /* All data is now stored in the phy struct; - * register it */ - rc = phy_device_register(phy); - if (rc) { - phy_device_free(phy); - of_node_put(child); - continue; - } - - dev_info(&mdio->dev, "registered phy %s at address %i\n", - child->name, addr); - break; } } -- cgit v1.2.3-70-g09d2 From bed2f9ed2f3c4debe2e930c44ee95af980db7e20 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 5 Dec 2013 14:52:11 -0800 Subject: net: of_mdio: use PHY_MAX_ADDR constant Use the PHY_MAX_ADDR constant for checking if a MDIO bus address is valid instead of using a plain "32". Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/of/of_mdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index 82485d2dac8..f93ebca0fcb 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -107,7 +107,7 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) } addr = be32_to_cpup(paddr); - if (addr >= 32) { + if (addr >= PHY_MAX_ADDR) { dev_err(&mdio->dev, "%s PHY address %i is too large\n", child->full_name, addr); continue; -- cgit v1.2.3-70-g09d2 From 7d976376560b72e187c96e4b18d059e0a0f9eba5 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 5 Dec 2013 14:52:12 -0800 Subject: net: of_mdio: do not overwrite PHY interrupt configuration If irq_of_parse_and_map fails to find an interrupt line for a given PHY, we will force the PHY interrupt to be PHY_POLL, completely overriding the previous value that the MDIO bus may have set for us (e.g: PHY_IGNORE_INTERRUPT). In case of failure, just restore the previous value. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/of/of_mdio.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index f93ebca0fcb..14feffc3696 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -27,7 +27,7 @@ static int of_mdiobus_register_phy(struct mii_bus *mdio, struct device_node *chi { struct phy_device *phy; bool is_c45; - int rc; + int rc, prev_irq; is_c45 = of_device_is_compatible(child, "ethernet-phy-ieee802.3-c45"); @@ -37,10 +37,11 @@ static int of_mdiobus_register_phy(struct mii_bus *mdio, struct device_node *chi return 1; if (mdio->irq) { + prev_irq = mdio->irq[addr]; mdio->irq[addr] = irq_of_parse_and_map(child, 0); if (!mdio->irq[addr]) - mdio->irq[addr] = PHY_POLL; + mdio->irq[addr] = prev_irq; } /* Associate the OF node with the device structure so it -- cgit v1.2.3-70-g09d2 From e9fbdf176d2a7993b9d4c487b50c68d1c6019b2c Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 5 Dec 2013 14:52:13 -0800 Subject: net: phy: breakdown PHY_*_FEATURES defines Breakdown the PHY_*_FEATURES into per speed defines such that we can easily re-use them individually. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- include/linux/phy.h | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/include/linux/phy.h b/include/linux/phy.h index 48a4dc3cb8c..7ff751ae6f0 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -27,18 +27,27 @@ #include -#define PHY_BASIC_FEATURES (SUPPORTED_10baseT_Half | \ - SUPPORTED_10baseT_Full | \ - SUPPORTED_100baseT_Half | \ - SUPPORTED_100baseT_Full | \ - SUPPORTED_Autoneg | \ +#define PHY_DEFAULT_FEATURES (SUPPORTED_Autoneg | \ SUPPORTED_TP | \ SUPPORTED_MII) -#define PHY_GBIT_FEATURES (PHY_BASIC_FEATURES | \ - SUPPORTED_1000baseT_Half | \ +#define PHY_10BT_FEATURES (SUPPORTED_10baseT_Half | \ + SUPPORTED_10baseT_Full) + +#define PHY_100BT_FEATURES (SUPPORTED_100baseT_Half | \ + SUPPORTED_100baseT_Full) + +#define PHY_1000BT_FEATURES (SUPPORTED_1000baseT_Half | \ SUPPORTED_1000baseT_Full) +#define PHY_BASIC_FEATURES (PHY_10BT_FEATURES | \ + PHY_100BT_FEATURES | \ + PHY_DEFAULT_FEATURES) + +#define PHY_GBIT_FEATURES (PHY_BASIC_FEATURES | \ + PHY_1000BT_FEATURES) + + /* * Set phydev->irq to PHY_POLL if interrupts are not supported, * or not desired for this PHY. Set to PHY_IGNORE_INTERRUPT if -- cgit v1.2.3-70-g09d2 From 8fdade4be755af17a3d205d07f594f939f173504 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 5 Dec 2013 14:52:14 -0800 Subject: net: of_mdio: parse "max-speed" property to set PHY supported features The "max-speed" property is defined per the ePAPR specification to express the maximum speed a PHY supports. Use that property, if present to set the phydev->supported features which properly restricts the PHY within the range of defined speeds. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/of/of_mdio.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index 14feffc3696..a43b8523c61 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -22,12 +22,30 @@ MODULE_AUTHOR("Grant Likely "); MODULE_LICENSE("GPL"); +static void of_set_phy_supported(struct phy_device *phydev, u32 max_speed) +{ + phydev->supported |= PHY_DEFAULT_FEATURES; + + switch (max_speed) { + default: + return; + + case SPEED_1000: + phydev->supported |= PHY_1000BT_FEATURES; + case SPEED_100: + phydev->supported |= PHY_100BT_FEATURES; + case SPEED_10: + phydev->supported |= PHY_10BT_FEATURES; + } +} + static int of_mdiobus_register_phy(struct mii_bus *mdio, struct device_node *child, u32 addr) { struct phy_device *phy; bool is_c45; int rc, prev_irq; + u32 max_speed = 0; is_c45 = of_device_is_compatible(child, "ethernet-phy-ieee802.3-c45"); @@ -58,8 +76,13 @@ static int of_mdiobus_register_phy(struct mii_bus *mdio, struct device_node *chi return 1; } + /* Set phydev->supported based on the "max-speed" property + * if present */ + if (!of_property_read_u32(child, "max-speed", &max_speed)) + of_set_phy_supported(phy, max_speed); + dev_dbg(&mdio->dev, "registered phy %s at address %i\n", - child->name, addr); + child->name, addr); return 0; } -- cgit v1.2.3-70-g09d2 From b0ac9564061265dd14e6f8f777622e3401b82b4b Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 5 Dec 2013 14:52:15 -0800 Subject: arc_emac: remove custom "max-speed" parsing code The ARC emac driver was the only in-tree to parse a PHY device 'max-speed' property but yet failed to do it correctly because 'max-speed' is supposed to set a PHY device supported features, not the advertising features as it was done. Now that of_mdiobus_register() takes care of doing that, remove the custom 'max-speed' parsing code. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/arc/emac.h | 2 -- drivers/net/ethernet/arc/emac_main.c | 20 +------------------- 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/drivers/net/ethernet/arc/emac.h b/drivers/net/ethernet/arc/emac.h index dc08678bf9a..928fac6dd10 100644 --- a/drivers/net/ethernet/arc/emac.h +++ b/drivers/net/ethernet/arc/emac.h @@ -122,7 +122,6 @@ struct buffer_state { * @link: PHY's last seen link state. * @duplex: PHY's last set duplex mode. * @speed: PHY's last set speed. - * @max_speed: Maximum supported by current system network data-rate. */ struct arc_emac_priv { /* Devices */ @@ -152,7 +151,6 @@ struct arc_emac_priv { unsigned int link; unsigned int duplex; unsigned int speed; - unsigned int max_speed; }; /** diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c index b2ffad1304d..eedf2a5fc2b 100644 --- a/drivers/net/ethernet/arc/emac_main.c +++ b/drivers/net/ethernet/arc/emac_main.c @@ -381,17 +381,7 @@ static int arc_emac_open(struct net_device *ndev) phy_dev->autoneg = AUTONEG_ENABLE; phy_dev->speed = 0; phy_dev->duplex = 0; - phy_dev->advertising = phy_dev->supported; - - if (priv->max_speed > 100) { - phy_dev->advertising &= PHY_GBIT_FEATURES; - } else if (priv->max_speed <= 100) { - phy_dev->advertising &= PHY_BASIC_FEATURES; - if (priv->max_speed <= 10) { - phy_dev->advertising &= ~SUPPORTED_100baseT_Half; - phy_dev->advertising &= ~SUPPORTED_100baseT_Full; - } - } + phy_dev->advertising &= phy_dev->supported; priv->last_rx_bd = 0; @@ -704,14 +694,6 @@ static int arc_emac_probe(struct platform_device *pdev) /* Set poll rate so that it polls every 1 ms */ arc_reg_set(priv, R_POLLRATE, clock_frequency / 1000000); - /* Get max speed of operation from device tree */ - if (of_property_read_u32(pdev->dev.of_node, "max-speed", - &priv->max_speed)) { - dev_err(&pdev->dev, "failed to retrieve from device tree\n"); - err = -EINVAL; - goto out; - } - ndev->irq = irq; dev_info(&pdev->dev, "IRQ is %d\n", ndev->irq); -- cgit v1.2.3-70-g09d2 From 9f2b0936b877119280c418258413f6fb9a26acd1 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 5 Dec 2013 14:52:16 -0800 Subject: Documentation: update Ethernet PHY devices binding with 'max-speed' The 'max-speed' property is optional but defined in the ePAPR specification and now supported by the Linux Device Tree parsing infrastructure. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/phy.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/net/phy.txt b/Documentation/devicetree/bindings/net/phy.txt index 7cd18fbfcf7..f648094abc3 100644 --- a/Documentation/devicetree/bindings/net/phy.txt +++ b/Documentation/devicetree/bindings/net/phy.txt @@ -22,6 +22,7 @@ Optional Properties: specifications. If neither of these are specified, the default is to assume clause 22. The compatible list may also contain other elements. +- max-speed: Maximum PHY supported speed (10, 100, 1000...) Example: -- cgit v1.2.3-70-g09d2 From ec99f76d281bae0194c6060417d3465ded94f0ed Mon Sep 17 00:00:00 2001 From: Nithin Sujir Date: Fri, 6 Dec 2013 09:53:16 -0800 Subject: tg3: Don't add rxbds_empty to rx_over_errors rxbds_empty is an informational statistic signifying that a ring full condition was observed. It does not mean an overflow has occurred. Signed-off-by: Nithin Nayak Sujir Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/tg3.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index e35a1c5fc9b..886d50b72cd 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -11746,8 +11746,6 @@ static void tg3_get_nstats(struct tg3 *tp, struct rtnl_link_stats64 *stats) get_stat64(&hw_stats->rx_frame_too_long_errors) + get_stat64(&hw_stats->rx_undersize_packets); - stats->rx_over_errors = old_stats->rx_over_errors + - get_stat64(&hw_stats->rxbds_empty); stats->rx_frame_errors = old_stats->rx_frame_errors + get_stat64(&hw_stats->rx_align_errors); stats->tx_aborted_errors = old_stats->tx_aborted_errors + -- cgit v1.2.3-70-g09d2 From 7c786065b12344ada19e11fa1043555dfeda478a Mon Sep 17 00:00:00 2001 From: Nithin Sujir Date: Fri, 6 Dec 2013 09:53:17 -0800 Subject: tg3: Add flag to disable 1G Half Duplex advertisement Some link partners have issues if the non-standard 1G half duplex is advertised. This patch adds support for an nvram setting to disable the advertisement. Signed-off-by: Nithin Nayak Sujir Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/tg3.c | 28 +++++++++++++++++++++------- drivers/net/ethernet/broadcom/tg3.h | 4 ++++ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 886d50b72cd..e8847ccc639 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -4403,9 +4403,12 @@ static void tg3_phy_copper_begin(struct tg3 *tp) if (tg3_flag(tp, WOL_SPEED_100MB)) adv |= ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full; - if (tp->phy_flags & TG3_PHYFLG_1G_ON_VAUX_OK) - adv |= ADVERTISED_1000baseT_Half | - ADVERTISED_1000baseT_Full; + if (tp->phy_flags & TG3_PHYFLG_1G_ON_VAUX_OK) { + if (!(tp->phy_flags & + TG3_PHYFLG_DISABLE_1G_HD_ADV)) + adv |= ADVERTISED_1000baseT_Half; + adv |= ADVERTISED_1000baseT_Full; + } fc = FLOW_CTRL_TX | FLOW_CTRL_RX; } else { @@ -14917,7 +14920,8 @@ static void tg3_get_eeprom_hw_cfg(struct tg3 *tp) tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val); if (val == NIC_SRAM_DATA_SIG_MAGIC) { u32 nic_cfg, led_cfg; - u32 nic_phy_id, ver, cfg2 = 0, cfg4 = 0, eeprom_phy_id; + u32 cfg2 = 0, cfg4 = 0, cfg5 = 0; + u32 nic_phy_id, ver, eeprom_phy_id; int eeprom_phy_serdes = 0; tg3_read_mem(tp, NIC_SRAM_DATA_CFG, &nic_cfg); @@ -14934,6 +14938,11 @@ static void tg3_get_eeprom_hw_cfg(struct tg3 *tp) if (tg3_asic_rev(tp) == ASIC_REV_5785) tg3_read_mem(tp, NIC_SRAM_DATA_CFG_4, &cfg4); + if (tg3_asic_rev(tp) == ASIC_REV_5717 || + tg3_asic_rev(tp) == ASIC_REV_5719 || + tg3_asic_rev(tp) == ASIC_REV_5720) + tg3_read_mem(tp, NIC_SRAM_DATA_CFG_5, &cfg5); + if ((nic_cfg & NIC_SRAM_DATA_CFG_PHY_TYPE_MASK) == NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER) eeprom_phy_serdes = 1; @@ -15086,6 +15095,9 @@ static void tg3_get_eeprom_hw_cfg(struct tg3 *tp) tg3_flag_set(tp, RGMII_EXT_IBND_RX_EN); if (cfg4 & NIC_SRAM_RGMII_EXT_IBND_TX_EN) tg3_flag_set(tp, RGMII_EXT_IBND_TX_EN); + + if (cfg5 & NIC_SRAM_DISABLE_1G_HALF_ADV) + tp->phy_flags |= TG3_PHYFLG_DISABLE_1G_HD_ADV; } done: if (tg3_flag(tp, WOL_CAP)) @@ -15181,9 +15193,11 @@ static void tg3_phy_init_link_config(struct tg3 *tp) { u32 adv = ADVERTISED_Autoneg; - if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY)) - adv |= ADVERTISED_1000baseT_Half | - ADVERTISED_1000baseT_Full; + if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY)) { + if (!(tp->phy_flags & TG3_PHYFLG_DISABLE_1G_HD_ADV)) + adv |= ADVERTISED_1000baseT_Half; + adv |= ADVERTISED_1000baseT_Full; + } if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES)) adv |= ADVERTISED_100baseT_Half | diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h index 5c3835aa1e1..e128f37282d 100644 --- a/drivers/net/ethernet/broadcom/tg3.h +++ b/drivers/net/ethernet/broadcom/tg3.h @@ -2226,6 +2226,9 @@ #define NIC_SRAM_CPMUSTAT_SIG 0x0000362c #define NIC_SRAM_CPMUSTAT_SIG_MSK 0x0000ffff +#define NIC_SRAM_DATA_CFG_5 0x00000e0c +#define NIC_SRAM_DISABLE_1G_HALF_ADV 0x00000002 + #define NIC_SRAM_RX_MINI_BUFFER_DESC 0x00001000 #define NIC_SRAM_DMA_DESC_POOL_BASE 0x00002000 @@ -3325,6 +3328,7 @@ struct tg3 { #define TG3_PHYFLG_1G_ON_VAUX_OK 0x00080000 #define TG3_PHYFLG_KEEP_LINK_ON_PWRDN 0x00100000 #define TG3_PHYFLG_MDIX_STATE 0x00200000 +#define TG3_PHYFLG_DISABLE_1G_HD_ADV 0x00400000 u32 led_ctrl; u32 phy_otp; -- cgit v1.2.3-70-g09d2 From efe8f0eaaed3c5ebc19cc34ddf012dfdf6f3747d Mon Sep 17 00:00:00 2001 From: Nithin Sujir Date: Fri, 6 Dec 2013 09:53:18 -0800 Subject: tg3: Fix bit definition for the nvram Auto Power Down setting The APD bit is 14 and not bit 10. Signed-off-by: Nithin Nayak Sujir Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/tg3.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h index e128f37282d..e4da9d7834c 100644 --- a/drivers/net/ethernet/broadcom/tg3.h +++ b/drivers/net/ethernet/broadcom/tg3.h @@ -2204,7 +2204,7 @@ #define NIC_SRAM_DATA_CFG_2 0x00000d38 -#define NIC_SRAM_DATA_CFG_2_APD_EN 0x00000400 +#define NIC_SRAM_DATA_CFG_2_APD_EN 0x00004000 #define SHASTA_EXT_LED_MODE_MASK 0x00018000 #define SHASTA_EXT_LED_LEGACY 0x00000000 #define SHASTA_EXT_LED_SHARED 0x00008000 -- cgit v1.2.3-70-g09d2 From 94962f7fddb0fb1373ec284a5b7b9e10ff1859ec Mon Sep 17 00:00:00 2001 From: Nithin Sujir Date: Fri, 6 Dec 2013 09:53:19 -0800 Subject: tg3: Expand multicast drop counter miscounting fix to 5762 commit 4d95847381228639844c7197deb8b2211274ef22 - "tg3: Workaround rx_discards stat bug", added a workaround for miscounted statistics for multicast packets. This fix needs to be applied to the 5762. Signed-off-by: Nithin Nayak Sujir Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/tg3.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index e8847ccc639..7cba1396934 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -9969,6 +9969,7 @@ static int tg3_reset_hw(struct tg3 *tp, bool reset_phy) if (tg3_asic_rev(tp) == ASIC_REV_5719) val |= BUFMGR_MODE_NO_TX_UNDERRUN; if (tg3_asic_rev(tp) == ASIC_REV_5717 || + tg3_asic_rev(tp) == ASIC_REV_5762 || tg3_chip_rev_id(tp) == CHIPREV_ID_5719_A0 || tg3_chip_rev_id(tp) == CHIPREV_ID_5720_A0) val |= BUFMGR_MODE_MBLOW_ATTN_ENAB; @@ -10754,6 +10755,7 @@ static void tg3_periodic_fetch_stats(struct tg3 *tp) TG3_STAT_ADD32(&sp->rxbds_empty, RCVLPC_NO_RCV_BD_CNT); if (tg3_asic_rev(tp) != ASIC_REV_5717 && + tg3_asic_rev(tp) != ASIC_REV_5762 && tg3_chip_rev_id(tp) != CHIPREV_ID_5719_A0 && tg3_chip_rev_id(tp) != CHIPREV_ID_5720_A0) { TG3_STAT_ADD32(&sp->rx_discards, RCVLPC_IN_DISCARDS_CNT); @@ -16545,6 +16547,7 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent) /* Set these bits to enable statistics workaround. */ if (tg3_asic_rev(tp) == ASIC_REV_5717 || + tg3_asic_rev(tp) == ASIC_REV_5762 || tg3_chip_rev_id(tp) == CHIPREV_ID_5719_A0 || tg3_chip_rev_id(tp) == CHIPREV_ID_5720_A0) { tp->coalesce_mode |= HOSTCC_MODE_ATTN; -- cgit v1.2.3-70-g09d2 From 941c22532f40dafa1320adbbc3776e7971bc0764 Mon Sep 17 00:00:00 2001 From: Nithin Sujir Date: Fri, 6 Dec 2013 09:53:20 -0800 Subject: tg3: Update version to 3.135 Signed-off-by: Nithin Nayak Sujir Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/tg3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 7cba1396934..9a4a601ae6c 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -94,10 +94,10 @@ static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits) #define DRV_MODULE_NAME "tg3" #define TG3_MAJ_NUM 3 -#define TG3_MIN_NUM 134 +#define TG3_MIN_NUM 135 #define DRV_MODULE_VERSION \ __stringify(TG3_MAJ_NUM) "." __stringify(TG3_MIN_NUM) -#define DRV_MODULE_RELDATE "Sep 16, 2013" +#define DRV_MODULE_RELDATE "Nov 14, 2013" #define RESET_KIND_SHUTDOWN 0 #define RESET_KIND_INIT 1 -- cgit v1.2.3-70-g09d2 From 59566b6e8cc8f8a05022e0f01a1b90974003f092 Mon Sep 17 00:00:00 2001 From: Zhi Yong Wu Date: Sat, 7 Dec 2013 04:13:03 +0800 Subject: vhost: remove the dead branch Since vhost_dev_init() forever return 0, some branches are never run, therefore need to be removed. Signed-off-by: Zhi Yong Wu Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller --- drivers/vhost/net.c | 9 ++------- drivers/vhost/scsi.c | 7 +------ drivers/vhost/test.c | 8 +------- drivers/vhost/vhost.c | 4 +--- drivers/vhost/vhost.h | 2 +- 5 files changed, 6 insertions(+), 24 deletions(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 831eb4fd197..9a68409580d 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -683,7 +683,7 @@ static int vhost_net_open(struct inode *inode, struct file *f) struct vhost_net *n = kmalloc(sizeof *n, GFP_KERNEL); struct vhost_dev *dev; struct vhost_virtqueue **vqs; - int r, i; + int i; if (!n) return -ENOMEM; @@ -706,12 +706,7 @@ static int vhost_net_open(struct inode *inode, struct file *f) n->vqs[i].vhost_hlen = 0; n->vqs[i].sock_hlen = 0; } - r = vhost_dev_init(dev, vqs, VHOST_NET_VQ_MAX); - if (r < 0) { - kfree(n); - kfree(vqs); - return r; - } + vhost_dev_init(dev, vqs, VHOST_NET_VQ_MAX); vhost_poll_init(n->poll + VHOST_NET_VQ_TX, handle_tx_net, POLLOUT, dev); vhost_poll_init(n->poll + VHOST_NET_VQ_RX, handle_rx_net, POLLIN, dev); diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index f175629513e..1e4c75c5b36 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -1417,18 +1417,13 @@ static int vhost_scsi_open(struct inode *inode, struct file *f) vqs[i] = &vs->vqs[i].vq; vs->vqs[i].vq.handle_kick = vhost_scsi_handle_kick; } - r = vhost_dev_init(&vs->dev, vqs, VHOST_SCSI_MAX_VQ); + vhost_dev_init(&vs->dev, vqs, VHOST_SCSI_MAX_VQ); tcm_vhost_init_inflight(vs, NULL); - if (r < 0) - goto err_init; - f->private_data = vs; return 0; -err_init: - kfree(vqs); err_vqs: vhost_scsi_free(vs); err_vs: diff --git a/drivers/vhost/test.c b/drivers/vhost/test.c index 339eae85859..c2a54fbf7f9 100644 --- a/drivers/vhost/test.c +++ b/drivers/vhost/test.c @@ -104,7 +104,6 @@ static int vhost_test_open(struct inode *inode, struct file *f) struct vhost_test *n = kmalloc(sizeof *n, GFP_KERNEL); struct vhost_dev *dev; struct vhost_virtqueue **vqs; - int r; if (!n) return -ENOMEM; @@ -117,12 +116,7 @@ static int vhost_test_open(struct inode *inode, struct file *f) dev = &n->dev; vqs[VHOST_TEST_VQ] = &n->vqs[VHOST_TEST_VQ]; n->vqs[VHOST_TEST_VQ].handle_kick = handle_vq_kick; - r = vhost_dev_init(dev, vqs, VHOST_TEST_VQ_MAX); - if (r < 0) { - kfree(vqs); - kfree(n); - return r; - } + vhost_dev_init(dev, vqs, VHOST_TEST_VQ_MAX); f->private_data = n; diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 69068e0d8f3..78987e481bc 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -290,7 +290,7 @@ static void vhost_dev_free_iovecs(struct vhost_dev *dev) vhost_vq_free_iovecs(dev->vqs[i]); } -long vhost_dev_init(struct vhost_dev *dev, +void vhost_dev_init(struct vhost_dev *dev, struct vhost_virtqueue **vqs, int nvqs) { struct vhost_virtqueue *vq; @@ -319,8 +319,6 @@ long vhost_dev_init(struct vhost_dev *dev, vhost_poll_init(&vq->poll, vq->handle_kick, POLLIN, dev); } - - return 0; } EXPORT_SYMBOL_GPL(vhost_dev_init); diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index 4465ed5f316..35eeb2a1bad 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -127,7 +127,7 @@ struct vhost_dev { struct task_struct *worker; }; -long vhost_dev_init(struct vhost_dev *, struct vhost_virtqueue **vqs, int nvqs); +void vhost_dev_init(struct vhost_dev *, struct vhost_virtqueue **vqs, int nvqs); long vhost_dev_set_owner(struct vhost_dev *dev); bool vhost_dev_has_owner(struct vhost_dev *dev); long vhost_dev_check_owner(struct vhost_dev *); -- cgit v1.2.3-70-g09d2 From 359d44d764f5e2a8e5bd9aee66f89f240ad7b622 Mon Sep 17 00:00:00 2001 From: Zhi Yong Wu Date: Sat, 7 Dec 2013 04:13:04 +0800 Subject: macvtap: remove the dead branch Signed-off-by: Zhi Yong Wu Signed-off-by: David S. Miller --- drivers/net/macvtap.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 9093004f9b6..f599c47524f 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -588,7 +588,7 @@ static int macvtap_skb_from_vnet_hdr(struct sk_buff *skb, return 0; } -static int macvtap_skb_to_vnet_hdr(const struct sk_buff *skb, +static void macvtap_skb_to_vnet_hdr(const struct sk_buff *skb, struct virtio_net_hdr *vnet_hdr) { memset(vnet_hdr, 0, sizeof(*vnet_hdr)); @@ -619,8 +619,6 @@ static int macvtap_skb_to_vnet_hdr(const struct sk_buff *skb, } else if (skb->ip_summed == CHECKSUM_UNNECESSARY) { vnet_hdr->flags = VIRTIO_NET_HDR_F_DATA_VALID; } /* else everything is zero */ - - return 0; } /* Get packet from user space buffer */ @@ -778,9 +776,7 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q, if ((len -= vnet_hdr_len) < 0) return -EINVAL; - ret = macvtap_skb_to_vnet_hdr(skb, &vnet_hdr); - if (ret) - return ret; + macvtap_skb_to_vnet_hdr(skb, &vnet_hdr); if (memcpy_toiovecend(iv, (void *)&vnet_hdr, 0, sizeof(vnet_hdr))) return -EFAULT; -- cgit v1.2.3-70-g09d2 From 55ec8e25cd9752060c80f926707d0187ea918d73 Mon Sep 17 00:00:00 2001 From: Zhi Yong Wu Date: Sat, 7 Dec 2013 04:13:05 +0800 Subject: macvtap: remove unused parameter in macvtap_do_read() Signed-off-by: Zhi Yong Wu Signed-off-by: David S. Miller --- drivers/net/macvtap.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index f599c47524f..4c6f84c79e9 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -819,7 +819,7 @@ done: return ret ? ret : copied; } -static ssize_t macvtap_do_read(struct macvtap_queue *q, struct kiocb *iocb, +static ssize_t macvtap_do_read(struct macvtap_queue *q, const struct iovec *iv, unsigned long len, int noblock) { @@ -870,7 +870,7 @@ static ssize_t macvtap_aio_read(struct kiocb *iocb, const struct iovec *iv, goto out; } - ret = macvtap_do_read(q, iocb, iv, len, file->f_flags & O_NONBLOCK); + ret = macvtap_do_read(q, iv, len, file->f_flags & O_NONBLOCK); ret = min_t(ssize_t, ret, len); /* XXX copied from tun.c. Why? */ out: return ret; @@ -1102,7 +1102,7 @@ static int macvtap_recvmsg(struct kiocb *iocb, struct socket *sock, int ret; if (flags & ~(MSG_DONTWAIT|MSG_TRUNC)) return -EINVAL; - ret = macvtap_do_read(q, iocb, m->msg_iov, total_len, + ret = macvtap_do_read(q, m->msg_iov, total_len, flags & MSG_DONTWAIT); if (ret > total_len) { m->msg_flags |= MSG_TRUNC; -- cgit v1.2.3-70-g09d2 From f96eb74c84ebb09a03031f7f1e51789a928f9de0 Mon Sep 17 00:00:00 2001 From: Zhi Yong Wu Date: Sat, 7 Dec 2013 04:13:06 +0800 Subject: tun: remove unused parameter in tun_do_read() Signed-off-by: Zhi Yong Wu Signed-off-by: David S. Miller --- drivers/net/tun.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 5ac2877a89c..6b0b2a057a4 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1289,8 +1289,7 @@ done: } static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile, - struct kiocb *iocb, const struct iovec *iv, - ssize_t len, int noblock) + const struct iovec *iv, ssize_t len, int noblock) { DECLARE_WAITQUEUE(wait, current); struct sk_buff *skb; @@ -1353,7 +1352,7 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv, goto out; } - ret = tun_do_read(tun, tfile, iocb, iv, len, + ret = tun_do_read(tun, tfile, iv, len, file->f_flags & O_NONBLOCK); ret = min_t(ssize_t, ret, len); out: @@ -1452,7 +1451,7 @@ static int tun_recvmsg(struct kiocb *iocb, struct socket *sock, SOL_PACKET, TUN_TX_TIMESTAMP); goto out; } - ret = tun_do_read(tun, tfile, iocb, m->msg_iov, total_len, + ret = tun_do_read(tun, tfile, m->msg_iov, total_len, flags & MSG_DONTWAIT); if (ret > total_len) { m->msg_flags |= MSG_TRUNC; -- cgit v1.2.3-70-g09d2 From e6247027e5173c00efb2084d688d06ff835bc3b0 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 5 Dec 2013 04:45:08 -0800 Subject: net: introduce dev_consume_skb_any() Some network drivers use dev_kfree_skb_any() and dev_kfree_skb_irq() helpers to free skbs, both for dropped packets and TX completed ones. We need to separate the two causes to get better diagnostics given by dropwatch or "perf record -e skb:kfree_skb" This patch provides two new helpers, dev_consume_skb_any() and dev_consume_skb_irq() to be used for consumed skbs. __dev_kfree_skb_irq() is slightly optimized to remove one atomic_dec_and_test() in fast path, and use this_cpu_{r|w} accessors. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/netdevice.h | 53 +++++++++++++++++++++++++++++++++++++++-------- net/core/dev.c | 45 ++++++++++++++++++++++++++-------------- 2 files changed, 74 insertions(+), 24 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 7f0ed423a36..9d55e5188b9 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2368,17 +2368,52 @@ static inline int netif_copy_real_num_queues(struct net_device *to_dev, #define DEFAULT_MAX_NUM_RSS_QUEUES (8) int netif_get_num_default_rss_queues(void); -/* Use this variant when it is known for sure that it - * is executing from hardware interrupt context or with hardware interrupts - * disabled. - */ -void dev_kfree_skb_irq(struct sk_buff *skb); +enum skb_free_reason { + SKB_REASON_CONSUMED, + SKB_REASON_DROPPED, +}; + +void __dev_kfree_skb_irq(struct sk_buff *skb, enum skb_free_reason reason); +void __dev_kfree_skb_any(struct sk_buff *skb, enum skb_free_reason reason); -/* Use this variant in places where it could be invoked - * from either hardware interrupt or other context, with hardware interrupts - * either disabled or enabled. +/* + * It is not allowed to call kfree_skb() or consume_skb() from hardware + * interrupt context or with hardware interrupts being disabled. + * (in_irq() || irqs_disabled()) + * + * We provide four helpers that can be used in following contexts : + * + * dev_kfree_skb_irq(skb) when caller drops a packet from irq context, + * replacing kfree_skb(skb) + * + * dev_consume_skb_irq(skb) when caller consumes a packet from irq context. + * Typically used in place of consume_skb(skb) in TX completion path + * + * dev_kfree_skb_any(skb) when caller doesn't know its current irq context, + * replacing kfree_skb(skb) + * + * dev_consume_skb_any(skb) when caller doesn't know its current irq context, + * and consumed a packet. Used in place of consume_skb(skb) */ -void dev_kfree_skb_any(struct sk_buff *skb); +static inline void dev_kfree_skb_irq(struct sk_buff *skb) +{ + __dev_kfree_skb_irq(skb, SKB_REASON_DROPPED); +} + +static inline void dev_consume_skb_irq(struct sk_buff *skb) +{ + __dev_kfree_skb_irq(skb, SKB_REASON_CONSUMED); +} + +static inline void dev_kfree_skb_any(struct sk_buff *skb) +{ + __dev_kfree_skb_any(skb, SKB_REASON_DROPPED); +} + +static inline void dev_consume_skb_any(struct sk_buff *skb) +{ + __dev_kfree_skb_any(skb, SKB_REASON_CONSUMED); +} int netif_rx(struct sk_buff *skb); int netif_rx_ni(struct sk_buff *skb); diff --git a/net/core/dev.c b/net/core/dev.c index c98052487e9..6cc98dd49c7 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2145,30 +2145,42 @@ void __netif_schedule(struct Qdisc *q) } EXPORT_SYMBOL(__netif_schedule); -void dev_kfree_skb_irq(struct sk_buff *skb) +struct dev_kfree_skb_cb { + enum skb_free_reason reason; +}; + +static struct dev_kfree_skb_cb *get_kfree_skb_cb(const struct sk_buff *skb) +{ + return (struct dev_kfree_skb_cb *)skb->cb; +} + +void __dev_kfree_skb_irq(struct sk_buff *skb, enum skb_free_reason reason) { - if (atomic_dec_and_test(&skb->users)) { - struct softnet_data *sd; - unsigned long flags; + unsigned long flags; - local_irq_save(flags); - sd = &__get_cpu_var(softnet_data); - skb->next = sd->completion_queue; - sd->completion_queue = skb; - raise_softirq_irqoff(NET_TX_SOFTIRQ); - local_irq_restore(flags); + if (likely(atomic_read(&skb->users) == 1)) { + smp_rmb(); + atomic_set(&skb->users, 0); + } else if (likely(!atomic_dec_and_test(&skb->users))) { + return; } + get_kfree_skb_cb(skb)->reason = reason; + local_irq_save(flags); + skb->next = __this_cpu_read(softnet_data.completion_queue); + __this_cpu_write(softnet_data.completion_queue, skb); + raise_softirq_irqoff(NET_TX_SOFTIRQ); + local_irq_restore(flags); } -EXPORT_SYMBOL(dev_kfree_skb_irq); +EXPORT_SYMBOL(__dev_kfree_skb_irq); -void dev_kfree_skb_any(struct sk_buff *skb) +void __dev_kfree_skb_any(struct sk_buff *skb, enum skb_free_reason reason) { if (in_irq() || irqs_disabled()) - dev_kfree_skb_irq(skb); + __dev_kfree_skb_irq(skb, reason); else dev_kfree_skb(skb); } -EXPORT_SYMBOL(dev_kfree_skb_any); +EXPORT_SYMBOL(__dev_kfree_skb_any); /** @@ -3306,7 +3318,10 @@ static void net_tx_action(struct softirq_action *h) clist = clist->next; WARN_ON(atomic_read(&skb->users)); - trace_kfree_skb(skb, net_tx_action); + if (likely(get_kfree_skb_cb(skb)->reason == SKB_REASON_CONSUMED)) + trace_consume_skb(skb); + else + trace_kfree_skb(skb, net_tx_action); __kfree_skb(skb); } } -- cgit v1.2.3-70-g09d2 From 479840ffdbe4242e8a25349218c8e0859223aa35 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 6 Dec 2013 09:45:21 +0100 Subject: ipv6 addrconf: extend ifa_flags to u32 There is no more space in u8 ifa_flags. So do what davem suffested and add another netlink attr called IFA_FLAGS for carry more flags. Signed-off-by: Jiri Pirko Signed-off-by: Thomas Haller Signed-off-by: David S. Miller --- include/net/addrconf.h | 4 ++-- include/net/if_inet6.h | 2 +- include/uapi/linux/if_addr.h | 4 ++++ net/ipv6/addrconf.c | 32 ++++++++++++++++++++------------ 4 files changed, 27 insertions(+), 15 deletions(-) diff --git a/include/net/addrconf.h b/include/net/addrconf.h index 86505bfa5d2..e70278eef12 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -81,9 +81,9 @@ int ipv6_dev_get_saddr(struct net *net, const struct net_device *dev, const struct in6_addr *daddr, unsigned int srcprefs, struct in6_addr *saddr); int __ipv6_get_lladdr(struct inet6_dev *idev, struct in6_addr *addr, - unsigned char banned_flags); + u32 banned_flags); int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr, - unsigned char banned_flags); + u32 banned_flags); int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2); void addrconf_join_solict(struct net_device *dev, const struct in6_addr *addr); void addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr); diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h index 76d54270f2e..b58c36c1c3f 100644 --- a/include/net/if_inet6.h +++ b/include/net/if_inet6.h @@ -50,8 +50,8 @@ struct inet6_ifaddr { int state; + __u32 flags; __u8 dad_probes; - __u8 flags; __u16 scope; diff --git a/include/uapi/linux/if_addr.h b/include/uapi/linux/if_addr.h index 23357ab81a7..8ab0c2cc9b7 100644 --- a/include/uapi/linux/if_addr.h +++ b/include/uapi/linux/if_addr.h @@ -18,6 +18,9 @@ struct ifaddrmsg { * It makes no difference for normally configured broadcast interfaces, * but for point-to-point IFA_ADDRESS is DESTINATION address, * local address is supplied in IFA_LOCAL attribute. + * + * IFA_FLAGS is a u32 attribute that extends the u8 field ifa_flags. + * If present, the value from struct ifaddrmsg will be ignored. */ enum { IFA_UNSPEC, @@ -28,6 +31,7 @@ enum { IFA_ANYCAST, IFA_CACHEINFO, IFA_MULTICAST, + IFA_FLAGS, __IFA_MAX, }; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index d5fa5b8c443..334a7e114e1 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1407,7 +1407,7 @@ try_nextdev: EXPORT_SYMBOL(ipv6_dev_get_saddr); int __ipv6_get_lladdr(struct inet6_dev *idev, struct in6_addr *addr, - unsigned char banned_flags) + u32 banned_flags) { struct inet6_ifaddr *ifp; int err = -EADDRNOTAVAIL; @@ -1424,7 +1424,7 @@ int __ipv6_get_lladdr(struct inet6_dev *idev, struct in6_addr *addr, } int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr, - unsigned char banned_flags) + u32 banned_flags) { struct inet6_dev *idev; int err = -EADDRNOTAVAIL; @@ -2178,7 +2178,7 @@ ok: } if (ifp) { - int flags; + u32 flags; unsigned long now; struct inet6_ifaddr *ift; u32 stored_lft; @@ -2363,10 +2363,11 @@ err_exit: /* * Manual configuration of address on an interface */ -static int inet6_addr_add(struct net *net, int ifindex, const struct in6_addr *pfx, +static int inet6_addr_add(struct net *net, int ifindex, + const struct in6_addr *pfx, const struct in6_addr *peer_pfx, - unsigned int plen, __u8 ifa_flags, __u32 prefered_lft, - __u32 valid_lft) + unsigned int plen, __u32 ifa_flags, + __u32 prefered_lft, __u32 valid_lft) { struct inet6_ifaddr *ifp; struct inet6_dev *idev; @@ -3351,7 +3352,7 @@ static void if6_seq_stop(struct seq_file *seq, void *v) static int if6_seq_show(struct seq_file *seq, void *v) { struct inet6_ifaddr *ifp = (struct inet6_ifaddr *)v; - seq_printf(seq, "%pi6 %02x %02x %02x %02x %8s\n", + seq_printf(seq, "%pi6 %02x %02x %02x %03x %8s\n", &ifp->addr, ifp->idev->dev->ifindex, ifp->prefix_len, @@ -3572,6 +3573,7 @@ static const struct nla_policy ifa_ipv6_policy[IFA_MAX+1] = { [IFA_ADDRESS] = { .len = sizeof(struct in6_addr) }, [IFA_LOCAL] = { .len = sizeof(struct in6_addr) }, [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) }, + [IFA_FLAGS] = { .len = sizeof(u32) }, }; static int @@ -3595,7 +3597,7 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh) return inet6_addr_del(net, ifm->ifa_index, pfx, ifm->ifa_prefixlen); } -static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags, +static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 ifa_flags, u32 prefered_lft, u32 valid_lft) { u32 flags; @@ -3650,7 +3652,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh) struct inet6_ifaddr *ifa; struct net_device *dev; u32 valid_lft = INFINITY_LIFE_TIME, preferred_lft = INFINITY_LIFE_TIME; - u8 ifa_flags; + u32 ifa_flags; int err; err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy); @@ -3677,8 +3679,10 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh) if (dev == NULL) return -ENODEV; + ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) : ifm->ifa_flags; + /* We ignore other flags so far. */ - ifa_flags = ifm->ifa_flags & (IFA_F_NODAD | IFA_F_HOMEADDRESS); + ifa_flags &= IFA_F_NODAD | IFA_F_HOMEADDRESS; ifa = ipv6_get_ifaddr(net, pfx, dev, 1); if (ifa == NULL) { @@ -3702,7 +3706,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh) return err; } -static void put_ifaddrmsg(struct nlmsghdr *nlh, u8 prefixlen, u8 flags, +static void put_ifaddrmsg(struct nlmsghdr *nlh, u8 prefixlen, u32 flags, u8 scope, int ifindex) { struct ifaddrmsg *ifm; @@ -3745,7 +3749,8 @@ static inline int inet6_ifaddr_msgsize(void) return NLMSG_ALIGN(sizeof(struct ifaddrmsg)) + nla_total_size(16) /* IFA_LOCAL */ + nla_total_size(16) /* IFA_ADDRESS */ - + nla_total_size(sizeof(struct ifa_cacheinfo)); + + nla_total_size(sizeof(struct ifa_cacheinfo)) + + nla_total_size(4) /* IFA_FLAGS */; } static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa, @@ -3793,6 +3798,9 @@ static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa, if (put_cacheinfo(skb, ifa->cstamp, ifa->tstamp, preferred, valid) < 0) goto error; + if (nla_put_u32(skb, IFA_FLAGS, ifa->flags) < 0) + goto error; + return nlmsg_end(skb, nlh); error: -- cgit v1.2.3-70-g09d2 From 53bd674915379d91e0e505332c89741b34eab05c Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 6 Dec 2013 09:45:22 +0100 Subject: ipv6 addrconf: introduce IFA_F_MANAGETEMPADDR to tell kernel to manage temporary addresses Creating an address with this flag set will result in kernel taking care of temporary addresses in the same way as if the address was created by kernel itself (after RA receive). This allows userspace applications implementing the autoconfiguration (NetworkManager for example) to implement ipv6 addresses privacy. Signed-off-by: Jiri Pirko Signed-off-by: Thomas Haller Signed-off-by: David S. Miller --- include/uapi/linux/if_addr.h | 1 + net/ipv6/addrconf.c | 171 +++++++++++++++++++++++++------------------ 2 files changed, 100 insertions(+), 72 deletions(-) diff --git a/include/uapi/linux/if_addr.h b/include/uapi/linux/if_addr.h index 8ab0c2cc9b7..cfed10be752 100644 --- a/include/uapi/linux/if_addr.h +++ b/include/uapi/linux/if_addr.h @@ -48,6 +48,7 @@ enum { #define IFA_F_DEPRECATED 0x20 #define IFA_F_TENTATIVE 0x40 #define IFA_F_PERMANENT 0x80 +#define IFA_F_MANAGETEMPADDR 0x100 struct ifa_cacheinfo { __u32 ifa_prefered; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 334a7e114e1..5087cc5cb81 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1024,7 +1024,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i u32 addr_flags; unsigned long now = jiffies; - write_lock(&idev->lock); + write_lock_bh(&idev->lock); if (ift) { spin_lock_bh(&ift->lock); memcpy(&addr.s6_addr[8], &ift->addr.s6_addr[8], 8); @@ -1036,7 +1036,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i retry: in6_dev_hold(idev); if (idev->cnf.use_tempaddr <= 0) { - write_unlock(&idev->lock); + write_unlock_bh(&idev->lock); pr_info("%s: use_tempaddr is disabled\n", __func__); in6_dev_put(idev); ret = -1; @@ -1046,7 +1046,7 @@ retry: if (ifp->regen_count++ >= idev->cnf.regen_max_retry) { idev->cnf.use_tempaddr = -1; /*XXX*/ spin_unlock_bh(&ifp->lock); - write_unlock(&idev->lock); + write_unlock_bh(&idev->lock); pr_warn("%s: regeneration time exceeded - disabled temporary address support\n", __func__); in6_dev_put(idev); @@ -1072,7 +1072,7 @@ retry: regen_advance = idev->cnf.regen_max_retry * idev->cnf.dad_transmits * idev->nd_parms->retrans_time / HZ; - write_unlock(&idev->lock); + write_unlock_bh(&idev->lock); /* A temporary address is created only if this calculated Preferred * Lifetime is greater than REGEN_ADVANCE time units. In particular, @@ -1099,7 +1099,7 @@ retry: in6_dev_put(idev); pr_info("%s: retry temporary address regeneration\n", __func__); tmpaddr = &addr; - write_lock(&idev->lock); + write_lock_bh(&idev->lock); goto retry; } @@ -2016,6 +2016,73 @@ static struct inet6_dev *addrconf_add_dev(struct net_device *dev) return idev; } +static void manage_tempaddrs(struct inet6_dev *idev, + struct inet6_ifaddr *ifp, + __u32 valid_lft, __u32 prefered_lft, + bool create, unsigned long now) +{ + u32 flags; + struct inet6_ifaddr *ift; + + read_lock_bh(&idev->lock); + /* update all temporary addresses in the list */ + list_for_each_entry(ift, &idev->tempaddr_list, tmp_list) { + int age, max_valid, max_prefered; + + if (ifp != ift->ifpub) + continue; + + /* RFC 4941 section 3.3: + * If a received option will extend the lifetime of a public + * address, the lifetimes of temporary addresses should + * be extended, subject to the overall constraint that no + * temporary addresses should ever remain "valid" or "preferred" + * for a time longer than (TEMP_VALID_LIFETIME) or + * (TEMP_PREFERRED_LIFETIME - DESYNC_FACTOR), respectively. + */ + age = (now - ift->cstamp) / HZ; + max_valid = idev->cnf.temp_valid_lft - age; + if (max_valid < 0) + max_valid = 0; + + max_prefered = idev->cnf.temp_prefered_lft - + idev->cnf.max_desync_factor - age; + if (max_prefered < 0) + max_prefered = 0; + + if (valid_lft > max_valid) + valid_lft = max_valid; + + if (prefered_lft > max_prefered) + prefered_lft = max_prefered; + + spin_lock(&ift->lock); + flags = ift->flags; + ift->valid_lft = valid_lft; + ift->prefered_lft = prefered_lft; + ift->tstamp = now; + if (prefered_lft > 0) + ift->flags &= ~IFA_F_DEPRECATED; + + spin_unlock(&ift->lock); + if (!(flags&IFA_F_TENTATIVE)) + ipv6_ifa_notify(0, ift); + } + + if ((create || list_empty(&idev->tempaddr_list)) && + idev->cnf.use_tempaddr > 0) { + /* When a new public address is created as described + * in [ADDRCONF], also create a new temporary address. + * Also create a temporary address if it's enabled but + * no temporary address currently exists. + */ + read_unlock_bh(&idev->lock); + ipv6_create_tempaddr(ifp, NULL); + } else { + read_unlock_bh(&idev->lock); + } +} + void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao) { struct prefix_info *pinfo; @@ -2170,6 +2237,7 @@ ok: return; } + ifp->flags |= IFA_F_MANAGETEMPADDR; update_lft = 0; create = 1; ifp->cstamp = jiffies; @@ -2180,7 +2248,6 @@ ok: if (ifp) { u32 flags; unsigned long now; - struct inet6_ifaddr *ift; u32 stored_lft; /* update lifetime (RFC2462 5.5.3 e) */ @@ -2221,70 +2288,8 @@ ok: } else spin_unlock(&ifp->lock); - read_lock_bh(&in6_dev->lock); - /* update all temporary addresses in the list */ - list_for_each_entry(ift, &in6_dev->tempaddr_list, - tmp_list) { - int age, max_valid, max_prefered; - - if (ifp != ift->ifpub) - continue; - - /* - * RFC 4941 section 3.3: - * If a received option will extend the lifetime - * of a public address, the lifetimes of - * temporary addresses should be extended, - * subject to the overall constraint that no - * temporary addresses should ever remain - * "valid" or "preferred" for a time longer than - * (TEMP_VALID_LIFETIME) or - * (TEMP_PREFERRED_LIFETIME - DESYNC_FACTOR), - * respectively. - */ - age = (now - ift->cstamp) / HZ; - max_valid = in6_dev->cnf.temp_valid_lft - age; - if (max_valid < 0) - max_valid = 0; - - max_prefered = in6_dev->cnf.temp_prefered_lft - - in6_dev->cnf.max_desync_factor - - age; - if (max_prefered < 0) - max_prefered = 0; - - if (valid_lft > max_valid) - valid_lft = max_valid; - - if (prefered_lft > max_prefered) - prefered_lft = max_prefered; - - spin_lock(&ift->lock); - flags = ift->flags; - ift->valid_lft = valid_lft; - ift->prefered_lft = prefered_lft; - ift->tstamp = now; - if (prefered_lft > 0) - ift->flags &= ~IFA_F_DEPRECATED; - - spin_unlock(&ift->lock); - if (!(flags&IFA_F_TENTATIVE)) - ipv6_ifa_notify(0, ift); - } - - if ((create || list_empty(&in6_dev->tempaddr_list)) && in6_dev->cnf.use_tempaddr > 0) { - /* - * When a new public address is created as - * described in [ADDRCONF], also create a new - * temporary address. Also create a temporary - * address if it's enabled but no temporary - * address currently exists. - */ - read_unlock_bh(&in6_dev->lock); - ipv6_create_tempaddr(ifp, NULL); - } else { - read_unlock_bh(&in6_dev->lock); - } + manage_tempaddrs(in6_dev, ifp, valid_lft, prefered_lft, + create, now); in6_ifa_put(ifp); addrconf_verify(0); @@ -2386,6 +2391,9 @@ static int inet6_addr_add(struct net *net, int ifindex, if (!valid_lft || prefered_lft > valid_lft) return -EINVAL; + if (ifa_flags & IFA_F_MANAGETEMPADDR && plen != 64) + return -EINVAL; + dev = __dev_get_by_index(net, ifindex); if (!dev) return -ENODEV; @@ -2426,6 +2434,9 @@ static int inet6_addr_add(struct net *net, int ifindex, * manually configured addresses */ addrconf_dad_start(ifp); + if (ifa_flags & IFA_F_MANAGETEMPADDR) + manage_tempaddrs(idev, ifp, valid_lft, prefered_lft, + true, jiffies); in6_ifa_put(ifp); addrconf_verify(0); return 0; @@ -3603,10 +3614,15 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 ifa_flags, u32 flags; clock_t expires; unsigned long timeout; + bool was_managetempaddr; if (!valid_lft || (prefered_lft > valid_lft)) return -EINVAL; + if (ifa_flags & IFA_F_MANAGETEMPADDR && + (ifp->flags & IFA_F_TEMPORARY || ifp->prefix_len != 64)) + return -EINVAL; + timeout = addrconf_timeout_fixup(valid_lft, HZ); if (addrconf_finite_timeout(timeout)) { expires = jiffies_to_clock_t(timeout * HZ); @@ -3626,7 +3642,10 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 ifa_flags, } spin_lock_bh(&ifp->lock); - ifp->flags = (ifp->flags & ~(IFA_F_DEPRECATED | IFA_F_PERMANENT | IFA_F_NODAD | IFA_F_HOMEADDRESS)) | ifa_flags; + was_managetempaddr = ifp->flags & IFA_F_MANAGETEMPADDR; + ifp->flags &= ~(IFA_F_DEPRECATED | IFA_F_PERMANENT | IFA_F_NODAD | + IFA_F_HOMEADDRESS | IFA_F_MANAGETEMPADDR); + ifp->flags |= ifa_flags; ifp->tstamp = jiffies; ifp->valid_lft = valid_lft; ifp->prefered_lft = prefered_lft; @@ -3637,6 +3656,14 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 ifa_flags, addrconf_prefix_route(&ifp->addr, ifp->prefix_len, ifp->idev->dev, expires, flags); + + if (was_managetempaddr || ifp->flags & IFA_F_MANAGETEMPADDR) { + if (was_managetempaddr && !(ifp->flags & IFA_F_MANAGETEMPADDR)) + valid_lft = prefered_lft = 0; + manage_tempaddrs(ifp->idev, ifp, valid_lft, prefered_lft, + !was_managetempaddr, jiffies); + } + addrconf_verify(0); return 0; @@ -3682,7 +3709,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh) ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) : ifm->ifa_flags; /* We ignore other flags so far. */ - ifa_flags &= IFA_F_NODAD | IFA_F_HOMEADDRESS; + ifa_flags &= IFA_F_NODAD | IFA_F_HOMEADDRESS | IFA_F_MANAGETEMPADDR; ifa = ipv6_get_ifaddr(net, pfx, dev, 1); if (ifa == NULL) { -- cgit v1.2.3-70-g09d2 From 5cc208becb10ca271d8a3299a09a5449490c7591 Mon Sep 17 00:00:00 2001 From: wangweidong Date: Fri, 6 Dec 2013 18:03:36 +0800 Subject: unix: convert printks to pr_ use pr_ instead of printk(LEVEL) Signed-off-by: Wang Weidong Signed-off-by: David S. Miller --- net/unix/af_unix.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 01625ccc3ae..81362229631 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -80,6 +80,8 @@ * with BSD names. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -366,7 +368,7 @@ static void unix_sock_destructor(struct sock *sk) WARN_ON(!sk_unhashed(sk)); WARN_ON(sk->sk_socket); if (!sock_flag(sk, SOCK_DEAD)) { - printk(KERN_INFO "Attempt to release alive unix socket: %p\n", sk); + pr_info("Attempt to release alive unix socket: %p\n", sk); return; } @@ -378,7 +380,7 @@ static void unix_sock_destructor(struct sock *sk) sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); local_bh_enable(); #ifdef UNIX_REFCNT_DEBUG - printk(KERN_DEBUG "UNIX %p is destroyed, %ld are still alive.\n", sk, + pr_debug("UNIX %p is destroyed, %ld are still alive.\n", sk, atomic_long_read(&unix_nr_socks)); #endif } @@ -2433,8 +2435,7 @@ static int __init af_unix_init(void) rc = proto_register(&unix_proto, 1); if (rc != 0) { - printk(KERN_CRIT "%s: Cannot create unix_sock SLAB cache!\n", - __func__); + pr_crit("%s: Cannot create unix_sock SLAB cache!\n", __func__); goto out; } -- cgit v1.2.3-70-g09d2 From 0d74c42f788caf3cad727c61c490d9459bc8918b Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 5 Dec 2013 14:54:38 -0800 Subject: ether_addr_equal: Optimize implementation, remove unused compare_ether_addr Add a new check for CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS to reduce the number of or's used in the ether_addr_equal comparison to very slightly improve function performance. Simplify the ether_addr_equal_64bits implementation. Integrate and remove the zap_last_2bytes helper as it's now used only once. Remove the now unused compare_ether_addr function. Update the unaligned-memory-access documentation to remove the compare_ether_addr description and show how unaligned accesses could occur with ether_addr_equal. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- Documentation/unaligned-memory-access.txt | 28 +++++++++++------ include/linux/etherdevice.h | 51 +++++++++++-------------------- 2 files changed, 37 insertions(+), 42 deletions(-) diff --git a/Documentation/unaligned-memory-access.txt b/Documentation/unaligned-memory-access.txt index f866c72291b..a445da098bc 100644 --- a/Documentation/unaligned-memory-access.txt +++ b/Documentation/unaligned-memory-access.txt @@ -137,24 +137,34 @@ Code that causes unaligned access ================================= With the above in mind, let's move onto a real life example of a function -that can cause an unaligned memory access. The following function adapted +that can cause an unaligned memory access. The following function taken from include/linux/etherdevice.h is an optimized routine to compare two ethernet MAC addresses for equality. -unsigned int compare_ether_addr(const u8 *addr1, const u8 *addr2) +bool ether_addr_equal(const u8 *addr1, const u8 *addr2) { - const u16 *a = (const u16 *) addr1; - const u16 *b = (const u16 *) addr2; +#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS + u32 fold = ((*(const u32 *)addr1) ^ (*(const u32 *)addr2)) | + ((*(const u16 *)(addr1 + 4)) ^ (*(const u16 *)(addr2 + 4))); + + return fold == 0; +#else + const u16 *a = (const u16 *)addr1; + const u16 *b = (const u16 *)addr2; return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) != 0; +#endif } -In the above function, the reference to a[0] causes 2 bytes (16 bits) to -be read from memory starting at address addr1. Think about what would happen -if addr1 was an odd address such as 0x10003. (Hint: it'd be an unaligned -access.) +In the above function, when the hardware has efficient unaligned access +capability, there is no issue with this code. But when the hardware isn't +able to access memory on arbitrary boundaries, the reference to a[0] causes +2 bytes (16 bits) to be read from memory starting at address addr1. + +Think about what would happen if addr1 was an odd address such as 0x10003. +(Hint: it'd be an unaligned access.) Despite the potential unaligned access problems with the above function, it -is included in the kernel anyway but is understood to only work on +is included in the kernel anyway but is understood to only work normally on 16-bit-aligned addresses. It is up to the caller to ensure this alignment or not use this function at all. This alignment-unsafe function is still useful as it is a decent optimization for the cases when you can ensure alignment, diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h index fc4a9aa7dd8..3526e819d7a 100644 --- a/include/linux/etherdevice.h +++ b/include/linux/etherdevice.h @@ -26,6 +26,7 @@ #include #include #include +#include #ifdef __KERNEL__ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev); @@ -210,41 +211,27 @@ static inline void eth_hw_addr_inherit(struct net_device *dst, memcpy(dst->dev_addr, src->dev_addr, ETH_ALEN); } -/** - * compare_ether_addr - Compare two Ethernet addresses - * @addr1: Pointer to a six-byte array containing the Ethernet address - * @addr2: Pointer other six-byte array containing the Ethernet address - * - * Compare two Ethernet addresses, returns 0 if equal, non-zero otherwise. - * Unlike memcmp(), it doesn't return a value suitable for sorting. - */ -static inline unsigned compare_ether_addr(const u8 *addr1, const u8 *addr2) -{ - const u16 *a = (const u16 *) addr1; - const u16 *b = (const u16 *) addr2; - - BUILD_BUG_ON(ETH_ALEN != 6); - return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) != 0; -} - /** * ether_addr_equal - Compare two Ethernet addresses * @addr1: Pointer to a six-byte array containing the Ethernet address * @addr2: Pointer other six-byte array containing the Ethernet address * * Compare two Ethernet addresses, returns true if equal + * + * Please note: addr1 & addr2 must both be aligned to u16. */ static inline bool ether_addr_equal(const u8 *addr1, const u8 *addr2) { - return !compare_ether_addr(addr1, addr2); -} +#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) + u32 fold = ((*(const u32 *)addr1) ^ (*(const u32 *)addr2)) | + ((*(const u16 *)(addr1 + 4)) ^ (*(const u16 *)(addr2 + 4))); -static inline unsigned long zap_last_2bytes(unsigned long value) -{ -#ifdef __BIG_ENDIAN - return value >> 16; + return fold == 0; #else - return value << 16; + const u16 *a = (const u16 *)addr1; + const u16 *b = (const u16 *)addr2; + + return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) == 0; #endif } @@ -265,16 +252,14 @@ static inline unsigned long zap_last_2bytes(unsigned long value) static inline bool ether_addr_equal_64bits(const u8 addr1[6+2], const u8 addr2[6+2]) { -#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS - unsigned long fold = ((*(unsigned long *)addr1) ^ - (*(unsigned long *)addr2)); - - if (sizeof(fold) == 8) - return zap_last_2bytes(fold) == 0; +#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 + u64 fold = (*(const u64 *)addr1) ^ (*(const u64 *)addr2); - fold |= zap_last_2bytes((*(unsigned long *)(addr1 + 4)) ^ - (*(unsigned long *)(addr2 + 4))); - return fold == 0; +#ifdef __BIG_ENDIAN + return (fold >> 16) == 0; +#else + return (fold << 16) == 0; +#endif #else return ether_addr_equal(addr1, addr2); #endif -- cgit v1.2.3-70-g09d2 From 2d9955bedb18a403bde1290607d5c02cd86ae5fe Mon Sep 17 00:00:00 2001 From: Robert Stonehouse Date: Mon, 7 Oct 2013 18:44:17 +0100 Subject: sfc: Demote "MC Scheduler error" messages The MC firmware is cooperatively multitasking and its scheduler will send an event when a task yields after running for more than the expected maximum time. This can be useful for firmware development but does not usually indicate a serious error and does not help to detect a lockup (there is a hardware watchdog that does that). Change the message and reduce log level accordingly. Signed-off-by: Ben Hutchings --- drivers/net/ethernet/sfc/mcdi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c index 4b0bd8a1514..25f91c0ca6a 100644 --- a/drivers/net/ethernet/sfc/mcdi.c +++ b/drivers/net/ethernet/sfc/mcdi.c @@ -867,8 +867,8 @@ void efx_mcdi_process_event(struct efx_channel *channel, efx_mcdi_sensor_event(efx, event); break; case MCDI_EVENT_CODE_SCHEDERR: - netif_info(efx, hw, efx->net_dev, - "MC Scheduler error address=0x%x\n", data); + netif_dbg(efx, hw, efx->net_dev, + "MC Scheduler alert (0x%x)\n", data); break; case MCDI_EVENT_CODE_REBOOT: case MCDI_EVENT_CODE_MC_REBOOT: -- cgit v1.2.3-70-g09d2 From 512bb06c65aa25e08d42456e5a28ca6b72306062 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 4 Dec 2013 19:48:07 +0000 Subject: sfc: Update MCDI protocol definitions Signed-off-by: Ben Hutchings --- drivers/net/ethernet/sfc/mcdi_pcol.h | 733 +++++++++++++++++++++++++++++++---- 1 file changed, 663 insertions(+), 70 deletions(-) diff --git a/drivers/net/ethernet/sfc/mcdi_pcol.h b/drivers/net/ethernet/sfc/mcdi_pcol.h index e0a63ddb7a6..a707fb5ef14 100644 --- a/drivers/net/ethernet/sfc/mcdi_pcol.h +++ b/drivers/net/ethernet/sfc/mcdi_pcol.h @@ -224,6 +224,8 @@ #define MC_CMD_ERR_MAC_EXIST 0x1009 /* Slave core not present */ #define MC_CMD_ERR_SLAVE_NOT_PRESENT 0x100a +/* The datapath is disabled. */ +#define MC_CMD_ERR_DATAPATH_DISABLED 0x100b #define MC_CMD_ERR_CODE_OFST 0 @@ -390,6 +392,8 @@ * AOE_ERR_DATA) */ #define MCDI_EVENT_AOE_BYTEBLASTER 0x9 +/* enum: DDR ECC status update */ +#define MCDI_EVENT_AOE_DDR_ECC_STATUS 0xa #define MCDI_EVENT_AOE_ERR_DATA_LBN 8 #define MCDI_EVENT_AOE_ERR_DATA_WIDTH 8 #define MCDI_EVENT_RX_ERR_RXQ_LBN 0 @@ -462,6 +466,10 @@ #define MCDI_EVENT_CODE_ECC_CORR_ERR 0x17 /* enum: the MC has detected an uncorrectable error */ #define MCDI_EVENT_CODE_ECC_FATAL_ERR 0x18 +/* enum: The MC has entered offline BIST mode */ +#define MCDI_EVENT_CODE_MC_BIST 0x19 +/* enum: PTP tick event providing current NIC time */ +#define MCDI_EVENT_CODE_PTP_TIME 0x1a /* enum: Artificial event generated by host and posted via MC for test * purposes. */ @@ -481,15 +489,32 @@ #define MCDI_EVENT_TX_ERR_DATA_OFST 0 #define MCDI_EVENT_TX_ERR_DATA_LBN 0 #define MCDI_EVENT_TX_ERR_DATA_WIDTH 32 -/* Seconds field of timestamp */ +/* For CODE_PTP_RX, CODE_PTP_PPS and CODE_HW_PPS events the seconds field of + * timestamp + */ #define MCDI_EVENT_PTP_SECONDS_OFST 0 #define MCDI_EVENT_PTP_SECONDS_LBN 0 #define MCDI_EVENT_PTP_SECONDS_WIDTH 32 -/* Nanoseconds field of timestamp */ +/* For CODE_PTP_RX, CODE_PTP_PPS and CODE_HW_PPS events the major field of + * timestamp + */ +#define MCDI_EVENT_PTP_MAJOR_OFST 0 +#define MCDI_EVENT_PTP_MAJOR_LBN 0 +#define MCDI_EVENT_PTP_MAJOR_WIDTH 32 +/* For CODE_PTP_RX, CODE_PTP_PPS and CODE_HW_PPS events the nanoseconds field + * of timestamp + */ #define MCDI_EVENT_PTP_NANOSECONDS_OFST 0 #define MCDI_EVENT_PTP_NANOSECONDS_LBN 0 #define MCDI_EVENT_PTP_NANOSECONDS_WIDTH 32 -/* Lowest four bytes of sourceUUID from PTP packet */ +/* For CODE_PTP_RX, CODE_PTP_PPS and CODE_HW_PPS events the minor field of + * timestamp + */ +#define MCDI_EVENT_PTP_MINOR_OFST 0 +#define MCDI_EVENT_PTP_MINOR_LBN 0 +#define MCDI_EVENT_PTP_MINOR_WIDTH 32 +/* For CODE_PTP_RX events, the lowest four bytes of sourceUUID from PTP packet + */ #define MCDI_EVENT_PTP_UUID_OFST 0 #define MCDI_EVENT_PTP_UUID_LBN 0 #define MCDI_EVENT_PTP_UUID_WIDTH 32 @@ -505,6 +530,13 @@ #define MCDI_EVENT_ECC_FATAL_ERR_DATA_OFST 0 #define MCDI_EVENT_ECC_FATAL_ERR_DATA_LBN 0 #define MCDI_EVENT_ECC_FATAL_ERR_DATA_WIDTH 32 +/* For CODE_PTP_TIME events, the major value of the PTP clock */ +#define MCDI_EVENT_PTP_TIME_MAJOR_OFST 0 +#define MCDI_EVENT_PTP_TIME_MAJOR_LBN 0 +#define MCDI_EVENT_PTP_TIME_MAJOR_WIDTH 32 +/* For CODE_PTP_TIME events, bits 19-26 of the minor value of the PTP clock */ +#define MCDI_EVENT_PTP_TIME_MINOR_26_19_LBN 36 +#define MCDI_EVENT_PTP_TIME_MINOR_26_19_WIDTH 8 /* FCDI_EVENT structuredef */ #define FCDI_EVENT_LEN 8 @@ -545,8 +577,10 @@ #define FCDI_EVENT_CODE_TIMED_READ 0x5 /* enum: One or more PPS IN events */ #define FCDI_EVENT_CODE_PPS_IN 0x6 -/* enum: One or more PPS OUT events */ -#define FCDI_EVENT_CODE_PPS_OUT 0x7 +/* enum: Tick event from PTP clock */ +#define FCDI_EVENT_CODE_PTP_TICK 0x7 +/* enum: ECC error counters */ +#define FCDI_EVENT_CODE_DDR_ECC_STATUS 0x8 #define FCDI_EVENT_ASSERT_INSTR_ADDRESS_OFST 0 #define FCDI_EVENT_ASSERT_INSTR_ADDRESS_LBN 0 #define FCDI_EVENT_ASSERT_INSTR_ADDRESS_WIDTH 32 @@ -560,14 +594,21 @@ #define FCDI_EVENT_LINK_STATE_DATA_OFST 0 #define FCDI_EVENT_LINK_STATE_DATA_LBN 0 #define FCDI_EVENT_LINK_STATE_DATA_WIDTH 32 -#define FCDI_EVENT_PPS_COUNT_OFST 0 -#define FCDI_EVENT_PPS_COUNT_LBN 0 -#define FCDI_EVENT_PPS_COUNT_WIDTH 32 - -/* FCDI_EXTENDED_EVENT structuredef */ -#define FCDI_EXTENDED_EVENT_LENMIN 16 -#define FCDI_EXTENDED_EVENT_LENMAX 248 -#define FCDI_EXTENDED_EVENT_LEN(num) (8+8*(num)) +#define FCDI_EVENT_DDR_ECC_STATUS_BANK_ID_LBN 36 +#define FCDI_EVENT_DDR_ECC_STATUS_BANK_ID_WIDTH 8 +#define FCDI_EVENT_DDR_ECC_STATUS_STATUS_OFST 0 +#define FCDI_EVENT_DDR_ECC_STATUS_STATUS_LBN 0 +#define FCDI_EVENT_DDR_ECC_STATUS_STATUS_WIDTH 32 + +/* FCDI_EXTENDED_EVENT_PPS structuredef: Extended FCDI event to send PPS events + * to the MC. Note that this structure | is overlayed over a normal FCDI event + * such that bits 32-63 containing | event code, level, source etc remain the + * same. In this case the data | field of the header is defined to be the + * number of timestamps + */ +#define FCDI_EXTENDED_EVENT_PPS_LENMIN 16 +#define FCDI_EXTENDED_EVENT_PPS_LENMAX 248 +#define FCDI_EXTENDED_EVENT_PPS_LEN(num) (8+8*(num)) /* Number of timestamps following */ #define FCDI_EXTENDED_EVENT_PPS_COUNT_OFST 0 #define FCDI_EXTENDED_EVENT_PPS_COUNT_LBN 0 @@ -581,14 +622,14 @@ #define FCDI_EXTENDED_EVENT_PPS_NANOSECONDS_LBN 96 #define FCDI_EXTENDED_EVENT_PPS_NANOSECONDS_WIDTH 32 /* Timestamp records comprising the event */ -#define FCDI_EXTENDED_EVENT_PPS_TIME_OFST 8 -#define FCDI_EXTENDED_EVENT_PPS_TIME_LEN 8 -#define FCDI_EXTENDED_EVENT_PPS_TIME_LO_OFST 8 -#define FCDI_EXTENDED_EVENT_PPS_TIME_HI_OFST 12 -#define FCDI_EXTENDED_EVENT_PPS_TIME_MINNUM 1 -#define FCDI_EXTENDED_EVENT_PPS_TIME_MAXNUM 30 -#define FCDI_EXTENDED_EVENT_PPS_TIME_LBN 64 -#define FCDI_EXTENDED_EVENT_PPS_TIME_WIDTH 64 +#define FCDI_EXTENDED_EVENT_PPS_TIMESTAMPS_OFST 8 +#define FCDI_EXTENDED_EVENT_PPS_TIMESTAMPS_LEN 8 +#define FCDI_EXTENDED_EVENT_PPS_TIMESTAMPS_LO_OFST 8 +#define FCDI_EXTENDED_EVENT_PPS_TIMESTAMPS_HI_OFST 12 +#define FCDI_EXTENDED_EVENT_PPS_TIMESTAMPS_MINNUM 1 +#define FCDI_EXTENDED_EVENT_PPS_TIMESTAMPS_MAXNUM 30 +#define FCDI_EXTENDED_EVENT_PPS_TIMESTAMPS_LBN 64 +#define FCDI_EXTENDED_EVENT_PPS_TIMESTAMPS_WIDTH 64 /***********************************/ @@ -642,6 +683,10 @@ #define MC_CMD_COPYCODE_IN_LEN 16 /* Source address */ #define MC_CMD_COPYCODE_IN_SRC_ADDR_OFST 0 +/* enum: The main image should be entered via a copy of a single word from and + * to this address when none of the other magic behaviours are required. + */ +#define MC_CMD_COPYCODE_HUNT_NO_MAGIC_ADDR 0x10000 /* enum: Entering the main image via a copy of a single word from and to this * address indicates that it should not attempt to start the datapath CPUs. * This is useful for certain soft rebooting scenarios. (Huntington only) @@ -872,8 +917,28 @@ #define MC_CMD_PTP_OP_RST_CLK 0x14 /* enum: Enable the forwarding of PPS events to the host */ #define MC_CMD_PTP_OP_PPS_ENABLE 0x15 +/* enum: Get the time format used by this NIC for PTP operations */ +#define MC_CMD_PTP_OP_GET_TIME_FORMAT 0x16 +/* enum: Get the clock attributes. NOTE- extended version of + * MC_CMD_PTP_OP_GET_TIME_FORMAT + */ +#define MC_CMD_PTP_OP_GET_ATTRIBUTES 0x16 +/* enum: Get corrections that should be applied to the various different + * timestamps + */ +#define MC_CMD_PTP_OP_GET_TIMESTAMP_CORRECTIONS 0x17 +/* enum: Subscribe to receive periodic time events indicating the current NIC + * time + */ +#define MC_CMD_PTP_OP_TIME_EVENT_SUBSCRIBE 0x18 +/* enum: Unsubscribe to stop receiving time events */ +#define MC_CMD_PTP_OP_TIME_EVENT_UNSUBSCRIBE 0x19 +/* enum: PPS based manfacturing tests. Requires PPS output to be looped to PPS + * input on the same NIC. + */ +#define MC_CMD_PTP_OP_MANFTEST_PPS 0x1a /* enum: Above this for future use. */ -#define MC_CMD_PTP_OP_MAX 0x16 +#define MC_CMD_PTP_OP_MAX 0x1b /* MC_CMD_PTP_IN_ENABLE msgrequest */ #define MC_CMD_PTP_IN_ENABLE_LEN 16 @@ -938,8 +1003,12 @@ #define MC_CMD_PTP_IN_ADJUST_BITS 0x28 /* Time adjustment in seconds */ #define MC_CMD_PTP_IN_ADJUST_SECONDS_OFST 16 +/* Time adjustment major value */ +#define MC_CMD_PTP_IN_ADJUST_MAJOR_OFST 16 /* Time adjustment in nanoseconds */ #define MC_CMD_PTP_IN_ADJUST_NANOSECONDS_OFST 20 +/* Time adjustment minor value */ +#define MC_CMD_PTP_IN_ADJUST_MINOR_OFST 20 /* MC_CMD_PTP_IN_SYNCHRONIZE msgrequest */ #define MC_CMD_PTP_IN_SYNCHRONIZE_LEN 20 @@ -1005,8 +1074,12 @@ /* MC_CMD_PTP_IN_PERIPH_ID_OFST 4 */ /* Time adjustment in seconds */ #define MC_CMD_PTP_IN_CLOCK_OFFSET_ADJUST_SECONDS_OFST 8 +/* Time adjustment major value */ +#define MC_CMD_PTP_IN_CLOCK_OFFSET_ADJUST_MAJOR_OFST 8 /* Time adjustment in nanoseconds */ #define MC_CMD_PTP_IN_CLOCK_OFFSET_ADJUST_NANOSECONDS_OFST 12 +/* Time adjustment minor value */ +#define MC_CMD_PTP_IN_CLOCK_OFFSET_ADJUST_MINOR_OFST 12 /* MC_CMD_PTP_IN_CLOCK_FREQ_ADJUST msgrequest */ #define MC_CMD_PTP_IN_CLOCK_FREQ_ADJUST_LEN 16 @@ -1078,9 +1151,51 @@ #define MC_CMD_PTP_ENABLE_PPS 0x0 /* enum: Disable */ #define MC_CMD_PTP_DISABLE_PPS 0x1 -/* Queueid to send events back */ +/* Queue id to send events back */ #define MC_CMD_PTP_IN_PPS_ENABLE_QUEUE_ID_OFST 8 +/* MC_CMD_PTP_IN_GET_TIME_FORMAT msgrequest */ +#define MC_CMD_PTP_IN_GET_TIME_FORMAT_LEN 8 +/* MC_CMD_PTP_IN_CMD_OFST 0 */ +/* MC_CMD_PTP_IN_PERIPH_ID_OFST 4 */ + +/* MC_CMD_PTP_IN_GET_ATTRIBUTES msgrequest */ +#define MC_CMD_PTP_IN_GET_ATTRIBUTES_LEN 8 +/* MC_CMD_PTP_IN_CMD_OFST 0 */ +/* MC_CMD_PTP_IN_PERIPH_ID_OFST 4 */ + +/* MC_CMD_PTP_IN_GET_TIMESTAMP_CORRECTIONS msgrequest */ +#define MC_CMD_PTP_IN_GET_TIMESTAMP_CORRECTIONS_LEN 8 +/* MC_CMD_PTP_IN_CMD_OFST 0 */ +/* MC_CMD_PTP_IN_PERIPH_ID_OFST 4 */ + +/* MC_CMD_PTP_IN_TIME_EVENT_SUBSCRIBE msgrequest */ +#define MC_CMD_PTP_IN_TIME_EVENT_SUBSCRIBE_LEN 12 +/* MC_CMD_PTP_IN_CMD_OFST 0 */ +/* MC_CMD_PTP_IN_PERIPH_ID_OFST 4 */ +/* Event queue to send PTP time events to */ +#define MC_CMD_PTP_IN_TIME_EVENT_SUBSCRIBE_QUEUE_OFST 8 + +/* MC_CMD_PTP_IN_TIME_EVENT_UNSUBSCRIBE msgrequest */ +#define MC_CMD_PTP_IN_TIME_EVENT_UNSUBSCRIBE_LEN 16 +/* MC_CMD_PTP_IN_CMD_OFST 0 */ +/* MC_CMD_PTP_IN_PERIPH_ID_OFST 4 */ +/* Unsubscribe options */ +#define MC_CMD_PTP_IN_TIME_EVENT_UNSUBSCRIBE_CONTROL_OFST 8 +/* enum: Unsubscribe a single queue */ +#define MC_CMD_PTP_IN_TIME_EVENT_UNSUBSCRIBE_SINGLE 0x0 +/* enum: Unsubscribe all queues */ +#define MC_CMD_PTP_IN_TIME_EVENT_UNSUBSCRIBE_ALL 0x1 +/* Event queue ID */ +#define MC_CMD_PTP_IN_TIME_EVENT_UNSUBSCRIBE_QUEUE_OFST 12 + +/* MC_CMD_PTP_IN_MANFTEST_PPS msgrequest */ +#define MC_CMD_PTP_IN_MANFTEST_PPS_LEN 12 +/* MC_CMD_PTP_IN_CMD_OFST 0 */ +/* MC_CMD_PTP_IN_PERIPH_ID_OFST 4 */ +/* 1 to enable PPS test mode, 0 to disable and return result. */ +#define MC_CMD_PTP_IN_MANFTEST_PPS_TEST_ENABLE_OFST 8 + /* MC_CMD_PTP_OUT msgresponse */ #define MC_CMD_PTP_OUT_LEN 0 @@ -1088,15 +1203,29 @@ #define MC_CMD_PTP_OUT_TRANSMIT_LEN 8 /* Value of seconds timestamp */ #define MC_CMD_PTP_OUT_TRANSMIT_SECONDS_OFST 0 +/* Timestamp major value */ +#define MC_CMD_PTP_OUT_TRANSMIT_MAJOR_OFST 0 /* Value of nanoseconds timestamp */ #define MC_CMD_PTP_OUT_TRANSMIT_NANOSECONDS_OFST 4 +/* Timestamp minor value */ +#define MC_CMD_PTP_OUT_TRANSMIT_MINOR_OFST 4 + +/* MC_CMD_PTP_OUT_TIME_EVENT_SUBSCRIBE msgresponse */ +#define MC_CMD_PTP_OUT_TIME_EVENT_SUBSCRIBE_LEN 0 + +/* MC_CMD_PTP_OUT_TIME_EVENT_UNSUBSCRIBE msgresponse */ +#define MC_CMD_PTP_OUT_TIME_EVENT_UNSUBSCRIBE_LEN 0 /* MC_CMD_PTP_OUT_READ_NIC_TIME msgresponse */ #define MC_CMD_PTP_OUT_READ_NIC_TIME_LEN 8 /* Value of seconds timestamp */ #define MC_CMD_PTP_OUT_READ_NIC_TIME_SECONDS_OFST 0 +/* Timestamp major value */ +#define MC_CMD_PTP_OUT_READ_NIC_TIME_MAJOR_OFST 0 /* Value of nanoseconds timestamp */ #define MC_CMD_PTP_OUT_READ_NIC_TIME_NANOSECONDS_OFST 4 +/* Timestamp minor value */ +#define MC_CMD_PTP_OUT_READ_NIC_TIME_MINOR_OFST 4 /* MC_CMD_PTP_OUT_STATUS msgresponse */ #define MC_CMD_PTP_OUT_STATUS_LEN 64 @@ -1116,21 +1245,21 @@ #define MC_CMD_PTP_OUT_STATUS_STATS_PPS_OFLOW_OFST 24 /* Number of PPS bad periods */ #define MC_CMD_PTP_OUT_STATUS_STATS_PPS_BAD_OFST 28 -/* Minimum period of PPS pulse */ +/* Minimum period of PPS pulse in nanoseconds */ #define MC_CMD_PTP_OUT_STATUS_STATS_PPS_PER_MIN_OFST 32 -/* Maximum period of PPS pulse */ +/* Maximum period of PPS pulse in nanoseconds */ #define MC_CMD_PTP_OUT_STATUS_STATS_PPS_PER_MAX_OFST 36 -/* Last period of PPS pulse */ +/* Last period of PPS pulse in nanoseconds */ #define MC_CMD_PTP_OUT_STATUS_STATS_PPS_PER_LAST_OFST 40 -/* Mean period of PPS pulse */ +/* Mean period of PPS pulse in nanoseconds */ #define MC_CMD_PTP_OUT_STATUS_STATS_PPS_PER_MEAN_OFST 44 -/* Minimum offset of PPS pulse (signed) */ +/* Minimum offset of PPS pulse in nanoseconds (signed) */ #define MC_CMD_PTP_OUT_STATUS_STATS_PPS_OFF_MIN_OFST 48 -/* Maximum offset of PPS pulse (signed) */ +/* Maximum offset of PPS pulse in nanoseconds (signed) */ #define MC_CMD_PTP_OUT_STATUS_STATS_PPS_OFF_MAX_OFST 52 -/* Last offset of PPS pulse (signed) */ +/* Last offset of PPS pulse in nanoseconds (signed) */ #define MC_CMD_PTP_OUT_STATUS_STATS_PPS_OFF_LAST_OFST 56 -/* Mean offset of PPS pulse (signed) */ +/* Mean offset of PPS pulse in nanoseconds (signed) */ #define MC_CMD_PTP_OUT_STATUS_STATS_PPS_OFF_MEAN_OFST 60 /* MC_CMD_PTP_OUT_SYNCHRONIZE msgresponse */ @@ -1146,8 +1275,12 @@ #define MC_CMD_PTP_OUT_SYNCHRONIZE_HOSTSTART_OFST 0 /* Value of seconds timestamp */ #define MC_CMD_PTP_OUT_SYNCHRONIZE_SECONDS_OFST 4 +/* Timestamp major value */ +#define MC_CMD_PTP_OUT_SYNCHRONIZE_MAJOR_OFST 4 /* Value of nanoseconds timestamp */ #define MC_CMD_PTP_OUT_SYNCHRONIZE_NANOSECONDS_OFST 8 +/* Timestamp minor value */ +#define MC_CMD_PTP_OUT_SYNCHRONIZE_MINOR_OFST 8 /* Host time immediately after NIC's hardware clock read */ #define MC_CMD_PTP_OUT_SYNCHRONIZE_HOSTEND_OFST 12 /* Number of nanoseconds waited after reading NIC's hardware clock */ @@ -1177,6 +1310,16 @@ #define MC_CMD_PTP_MANF_PACKET_ENOUGH 0x8 /* enum: Timestamp trigger GPIO not working */ #define MC_CMD_PTP_MANF_GPIO_TRIGGER 0x9 +/* enum: Insufficient PPS events to perform checks */ +#define MC_CMD_PTP_MANF_PPS_ENOUGH 0xa +/* enum: PPS time event period not sufficiently close to 1s. */ +#define MC_CMD_PTP_MANF_PPS_PERIOD 0xb +/* enum: PPS time event nS reading not sufficiently close to zero. */ +#define MC_CMD_PTP_MANF_PPS_NS 0xc +/* enum: PTP peripheral registers incorrect */ +#define MC_CMD_PTP_MANF_REGISTERS 0xd +/* enum: Failed to read time from PTP peripheral */ +#define MC_CMD_PTP_MANF_CLOCK_READ 0xe /* Presence of external oscillator */ #define MC_CMD_PTP_OUT_MANFTEST_BASIC_TEST_EXTOSC_OFST 4 @@ -1198,6 +1341,62 @@ #define MC_CMD_PTP_OUT_FPGAREAD_BUFFER_MINNUM 1 #define MC_CMD_PTP_OUT_FPGAREAD_BUFFER_MAXNUM 252 +/* MC_CMD_PTP_OUT_GET_TIME_FORMAT msgresponse */ +#define MC_CMD_PTP_OUT_GET_TIME_FORMAT_LEN 4 +/* Time format required/used by for this NIC. Applies to all PTP MCDI + * operations that pass times between the host and firmware. If this operation + * is not supported (older firmware) a format of seconds and nanoseconds should + * be assumed. + */ +#define MC_CMD_PTP_OUT_GET_TIME_FORMAT_FORMAT_OFST 0 +/* enum: Times are in seconds and nanoseconds */ +#define MC_CMD_PTP_OUT_GET_TIME_FORMAT_SECONDS_NANOSECONDS 0x0 +/* enum: Major register has units of 16 second per tick, minor 8 ns per tick */ +#define MC_CMD_PTP_OUT_GET_TIME_FORMAT_16SECONDS_8NANOSECONDS 0x1 +/* enum: Major register has units of seconds, minor 2^-27s per tick */ +#define MC_CMD_PTP_OUT_GET_TIME_FORMAT_SECONDS_27FRACTION 0x2 + +/* MC_CMD_PTP_OUT_GET_ATTRIBUTES msgresponse */ +#define MC_CMD_PTP_OUT_GET_ATTRIBUTES_LEN 8 +/* Time format required/used by for this NIC. Applies to all PTP MCDI + * operations that pass times between the host and firmware. If this operation + * is not supported (older firmware) a format of seconds and nanoseconds should + * be assumed. + */ +#define MC_CMD_PTP_OUT_GET_ATTRIBUTES_TIME_FORMAT_OFST 0 +/* enum: Times are in seconds and nanoseconds */ +#define MC_CMD_PTP_OUT_GET_ATTRIBUTES_SECONDS_NANOSECONDS 0x0 +/* enum: Major register has units of 16 second per tick, minor 8 ns per tick */ +#define MC_CMD_PTP_OUT_GET_ATTRIBUTES_16SECONDS_8NANOSECONDS 0x1 +/* enum: Major register has units of seconds, minor 2^-27s per tick */ +#define MC_CMD_PTP_OUT_GET_ATTRIBUTES_SECONDS_27FRACTION 0x2 +/* Minimum acceptable value for a corrected synchronization timeset. When + * comparing host and NIC clock times, the MC returns a set of samples that + * contain the host start and end time, the MC time when the host start was + * detected and the time the MC waited between reading the time and detecting + * the host end. The corrected sync window is the difference between the host + * end and start times minus the time that the MC waited for host end. + */ +#define MC_CMD_PTP_OUT_GET_ATTRIBUTES_SYNC_WINDOW_MIN_OFST 4 + +/* MC_CMD_PTP_OUT_GET_TIMESTAMP_CORRECTIONS msgresponse */ +#define MC_CMD_PTP_OUT_GET_TIMESTAMP_CORRECTIONS_LEN 16 +/* Uncorrected error on transmit timestamps in NIC clock format */ +#define MC_CMD_PTP_OUT_GET_TIMESTAMP_CORRECTIONS_TRANSMIT_OFST 0 +/* Uncorrected error on receive timestamps in NIC clock format */ +#define MC_CMD_PTP_OUT_GET_TIMESTAMP_CORRECTIONS_RECEIVE_OFST 4 +/* Uncorrected error on PPS output in NIC clock format */ +#define MC_CMD_PTP_OUT_GET_TIMESTAMP_CORRECTIONS_PPS_OUT_OFST 8 +/* Uncorrected error on PPS input in NIC clock format */ +#define MC_CMD_PTP_OUT_GET_TIMESTAMP_CORRECTIONS_PPS_IN_OFST 12 + +/* MC_CMD_PTP_OUT_MANFTEST_PPS msgresponse */ +#define MC_CMD_PTP_OUT_MANFTEST_PPS_LEN 4 +/* Results of testing */ +#define MC_CMD_PTP_OUT_MANFTEST_PPS_TEST_RESULT_OFST 0 +/* Enum values, see field(s): */ +/* MC_CMD_PTP_OUT_MANFTEST_BASIC/TEST_RESULT */ + /***********************************/ /* MC_CMD_CSR_READ32 @@ -1923,6 +2122,8 @@ #define MC_CMD_MEDIA_SFP_PLUS 0x5 /* enum: 10GBaseT. */ #define MC_CMD_MEDIA_BASE_T 0x6 +/* enum: QSFP+. */ +#define MC_CMD_MEDIA_QSFP_PLUS 0x7 #define MC_CMD_GET_PHY_CFG_OUT_MMD_MASK_OFST 48 /* enum: Native clause 22 */ #define MC_CMD_MMD_CLAUSE22 0x0 @@ -2223,6 +2424,8 @@ #define MC_CMD_LOOPBACK_SD_FEP_WS 0x21 /* enum: KR Serdes Serial Wireside. */ #define MC_CMD_LOOPBACK_SD_FES_WS 0x22 +/* enum: Near side of AOE Siena side port */ +#define MC_CMD_LOOPBACK_AOE_INT_NEAR 0x23 /* Supported loopbacks. */ #define MC_CMD_GET_LOOPBACK_MODES_OUT_1G_OFST 8 #define MC_CMD_GET_LOOPBACK_MODES_OUT_1G_LEN 8 @@ -2286,6 +2489,10 @@ #define MC_CMD_GET_LINK_OUT_BPX_LINK_WIDTH 1 #define MC_CMD_GET_LINK_OUT_PHY_LINK_LBN 3 #define MC_CMD_GET_LINK_OUT_PHY_LINK_WIDTH 1 +#define MC_CMD_GET_LINK_OUT_LINK_FAULT_RX_LBN 6 +#define MC_CMD_GET_LINK_OUT_LINK_FAULT_RX_WIDTH 1 +#define MC_CMD_GET_LINK_OUT_LINK_FAULT_TX_LBN 7 +#define MC_CMD_GET_LINK_OUT_LINK_FAULT_TX_WIDTH 1 /* This returns the negotiated flow control value. */ #define MC_CMD_GET_LINK_OUT_FCNTL_OFST 20 /* enum: Flow control is off. */ @@ -3175,7 +3382,7 @@ #define MC_CMD_SENSOR_INFO_EXT_IN_PAGE_OFST 0 /* MC_CMD_SENSOR_INFO_OUT msgresponse */ -#define MC_CMD_SENSOR_INFO_OUT_LENMIN 12 +#define MC_CMD_SENSOR_INFO_OUT_LENMIN 4 #define MC_CMD_SENSOR_INFO_OUT_LENMAX 252 #define MC_CMD_SENSOR_INFO_OUT_LEN(num) (4+8*(num)) #define MC_CMD_SENSOR_INFO_OUT_MASK_OFST 0 @@ -3269,16 +3476,18 @@ #define MC_CMD_SENSOR_VDD08D_VSS08D_CSR 0x2b /* enum: voltage between VSS08D and VSS08D at CSR (external ADC): mV */ #define MC_CMD_SENSOR_VDD08D_VSS08D_CSR_EXTADC 0x2c +/* enum: Hotpoint temperature: degC */ +#define MC_CMD_SENSOR_HOTPOINT_TEMP 0x2d /* MC_CMD_SENSOR_INFO_ENTRY_TYPEDEF */ #define MC_CMD_SENSOR_ENTRY_OFST 4 #define MC_CMD_SENSOR_ENTRY_LEN 8 #define MC_CMD_SENSOR_ENTRY_LO_OFST 4 #define MC_CMD_SENSOR_ENTRY_HI_OFST 8 -#define MC_CMD_SENSOR_ENTRY_MINNUM 1 +#define MC_CMD_SENSOR_ENTRY_MINNUM 0 #define MC_CMD_SENSOR_ENTRY_MAXNUM 31 /* MC_CMD_SENSOR_INFO_EXT_OUT msgresponse */ -#define MC_CMD_SENSOR_INFO_EXT_OUT_LENMIN 12 +#define MC_CMD_SENSOR_INFO_EXT_OUT_LENMIN 4 #define MC_CMD_SENSOR_INFO_EXT_OUT_LENMAX 252 #define MC_CMD_SENSOR_INFO_EXT_OUT_LEN(num) (4+8*(num)) #define MC_CMD_SENSOR_INFO_EXT_OUT_MASK_OFST 0 @@ -3291,7 +3500,7 @@ /* MC_CMD_SENSOR_ENTRY_LEN 8 */ /* MC_CMD_SENSOR_ENTRY_LO_OFST 4 */ /* MC_CMD_SENSOR_ENTRY_HI_OFST 8 */ -/* MC_CMD_SENSOR_ENTRY_MINNUM 1 */ +/* MC_CMD_SENSOR_ENTRY_MINNUM 0 */ /* MC_CMD_SENSOR_ENTRY_MAXNUM 31 */ /* MC_CMD_SENSOR_INFO_ENTRY_TYPEDEF structuredef */ @@ -3864,6 +4073,18 @@ #define NVRAM_PARTITION_TYPE_ID_LBN 0 #define NVRAM_PARTITION_TYPE_ID_WIDTH 16 +/* LICENSED_APP_ID structuredef */ +#define LICENSED_APP_ID_LEN 4 +#define LICENSED_APP_ID_ID_OFST 0 +/* enum: OpenOnload */ +#define LICENSED_APP_ID_ONLOAD 0x1 +/* enum: PTP timestamping */ +#define LICENSED_APP_ID_PTP 0x2 +/* enum: SolarCapture Pro */ +#define LICENSED_APP_ID_SOLARCAPTURE_PRO 0x4 +#define LICENSED_APP_ID_ID_LBN 0 +#define LICENSED_APP_ID_ID_WIDTH 32 + /***********************************/ /* MC_CMD_READ_REGS @@ -4021,6 +4242,8 @@ #define MC_CMD_INIT_RXQ_IN_FLAG_CHAIN_WIDTH 1 #define MC_CMD_INIT_RXQ_IN_FLAG_PREFIX_LBN 8 #define MC_CMD_INIT_RXQ_IN_FLAG_PREFIX_WIDTH 1 +#define MC_CMD_INIT_RXQ_IN_FLAG_DISABLE_SCATTER_LBN 9 +#define MC_CMD_INIT_RXQ_IN_FLAG_DISABLE_SCATTER_WIDTH 1 /* Owner ID to use if in buffer mode (zero if physical) */ #define MC_CMD_INIT_RXQ_IN_OWNER_ID_OFST 20 /* The port ID associated with the v-adaptor which should contain this DMAQ. */ @@ -4179,6 +4402,9 @@ #define MC_CMD_PROXY_CMD_IN_TARGET_VF_WIDTH 16 #define MC_CMD_PROXY_CMD_IN_VF_NULL 0xffff /* enum */ +/* MC_CMD_PROXY_CMD_OUT msgresponse */ +#define MC_CMD_PROXY_CMD_OUT_LEN 0 + /***********************************/ /* MC_CMD_ALLOC_BUFTBL_CHUNK @@ -4213,7 +4439,7 @@ /* MC_CMD_PROGRAM_BUFTBL_ENTRIES_IN msgrequest */ #define MC_CMD_PROGRAM_BUFTBL_ENTRIES_IN_LENMIN 20 -#define MC_CMD_PROGRAM_BUFTBL_ENTRIES_IN_LENMAX 252 +#define MC_CMD_PROGRAM_BUFTBL_ENTRIES_IN_LENMAX 268 #define MC_CMD_PROGRAM_BUFTBL_ENTRIES_IN_LEN(num) (12+8*(num)) #define MC_CMD_PROGRAM_BUFTBL_ENTRIES_IN_HANDLE_OFST 0 /* ID */ @@ -4226,7 +4452,7 @@ #define MC_CMD_PROGRAM_BUFTBL_ENTRIES_IN_ENTRY_LO_OFST 12 #define MC_CMD_PROGRAM_BUFTBL_ENTRIES_IN_ENTRY_HI_OFST 16 #define MC_CMD_PROGRAM_BUFTBL_ENTRIES_IN_ENTRY_MINNUM 1 -#define MC_CMD_PROGRAM_BUFTBL_ENTRIES_IN_ENTRY_MAXNUM 30 +#define MC_CMD_PROGRAM_BUFTBL_ENTRIES_IN_ENTRY_MAXNUM 32 /* MC_CMD_PROGRAM_BUFTBL_ENTRIES_OUT msgresponse */ #define MC_CMD_PROGRAM_BUFTBL_ENTRIES_OUT_LEN 0 @@ -6799,6 +7025,30 @@ #define MC_CMD_TRIGGER_INTERRUPT_OUT_LEN 0 +/***********************************/ +/* MC_CMD_CAP_BLK_READ + * Read multiple 64bit words from capture block memory + */ +#define MC_CMD_CAP_BLK_READ 0xe7 + +/* MC_CMD_CAP_BLK_READ_IN msgrequest */ +#define MC_CMD_CAP_BLK_READ_IN_LEN 12 +#define MC_CMD_CAP_BLK_READ_IN_CAP_REG_OFST 0 +#define MC_CMD_CAP_BLK_READ_IN_ADDR_OFST 4 +#define MC_CMD_CAP_BLK_READ_IN_COUNT_OFST 8 + +/* MC_CMD_CAP_BLK_READ_OUT msgresponse */ +#define MC_CMD_CAP_BLK_READ_OUT_LENMIN 8 +#define MC_CMD_CAP_BLK_READ_OUT_LENMAX 248 +#define MC_CMD_CAP_BLK_READ_OUT_LEN(num) (0+8*(num)) +#define MC_CMD_CAP_BLK_READ_OUT_BUFFER_OFST 0 +#define MC_CMD_CAP_BLK_READ_OUT_BUFFER_LEN 8 +#define MC_CMD_CAP_BLK_READ_OUT_BUFFER_LO_OFST 0 +#define MC_CMD_CAP_BLK_READ_OUT_BUFFER_HI_OFST 4 +#define MC_CMD_CAP_BLK_READ_OUT_BUFFER_MINNUM 1 +#define MC_CMD_CAP_BLK_READ_OUT_BUFFER_MAXNUM 31 + + /***********************************/ /* MC_CMD_DUMP_DO * Take a dump of the DUT state @@ -6826,6 +7076,10 @@ #define MC_CMD_DUMP_DO_IN_DUMPSPEC_SRC_CUSTOM_HOST_MEMORY_MLI_DEPTH_OFST 20 #define MC_CMD_DUMP_DO_IN_HOST_MEMORY_MLI_MAX_DEPTH 0x2 /* enum */ #define MC_CMD_DUMP_DO_IN_DUMPSPEC_SRC_CUSTOM_UART_PORT_OFST 12 +/* enum: The uart port this command was received over (if using a uart + * transport) + */ +#define MC_CMD_DUMP_DO_IN_UART_PORT_SRC 0xff #define MC_CMD_DUMP_DO_IN_DUMPSPEC_SRC_CUSTOM_SIZE_OFST 24 #define MC_CMD_DUMP_DO_IN_DUMPFILE_DST_OFST 28 #define MC_CMD_DUMP_DO_IN_DUMPFILE_DST_CUSTOM 0x0 /* enum */ @@ -6942,39 +7196,68 @@ /***********************************/ -/* MC_CMD_START_KR_EYE_PLOT - * Start KR Serdes Eye diagram plot on a given lane. Lane must have valid - * signal. - */ -#define MC_CMD_START_KR_EYE_PLOT 0xee - -/* MC_CMD_START_KR_EYE_PLOT_IN msgrequest */ -#define MC_CMD_START_KR_EYE_PLOT_IN_LEN 4 -#define MC_CMD_START_KR_EYE_PLOT_IN_LANE_OFST 0 - -/* MC_CMD_START_KR_EYE_PLOT_OUT msgresponse */ -#define MC_CMD_START_KR_EYE_PLOT_OUT_LEN 0 - - -/***********************************/ -/* MC_CMD_POLL_KR_EYE_PLOT - * Poll KR Serdes Eye diagram plot. Returns one row of BER data. The caller - * should call this command repeatedly after starting eye plot, until no more - * data is returned. - */ -#define MC_CMD_POLL_KR_EYE_PLOT 0xef - -/* MC_CMD_POLL_KR_EYE_PLOT_IN msgrequest */ -#define MC_CMD_POLL_KR_EYE_PLOT_IN_LEN 0 - -/* MC_CMD_POLL_KR_EYE_PLOT_OUT msgresponse */ -#define MC_CMD_POLL_KR_EYE_PLOT_OUT_LENMIN 0 -#define MC_CMD_POLL_KR_EYE_PLOT_OUT_LENMAX 252 -#define MC_CMD_POLL_KR_EYE_PLOT_OUT_LEN(num) (0+2*(num)) -#define MC_CMD_POLL_KR_EYE_PLOT_OUT_SAMPLES_OFST 0 -#define MC_CMD_POLL_KR_EYE_PLOT_OUT_SAMPLES_LEN 2 -#define MC_CMD_POLL_KR_EYE_PLOT_OUT_SAMPLES_MINNUM 0 -#define MC_CMD_POLL_KR_EYE_PLOT_OUT_SAMPLES_MAXNUM 126 +/* MC_CMD_UART_SEND_DATA + * Send checksummed[sic] block of data over the uart. Response is a placeholder + * should we wish to make this reliable; currently requests are fire-and- + * forget. + */ +#define MC_CMD_UART_SEND_DATA 0xee + +/* MC_CMD_UART_SEND_DATA_OUT msgrequest */ +#define MC_CMD_UART_SEND_DATA_OUT_LENMIN 16 +#define MC_CMD_UART_SEND_DATA_OUT_LENMAX 252 +#define MC_CMD_UART_SEND_DATA_OUT_LEN(num) (16+1*(num)) +/* CRC32 over OFFSET, LENGTH, RESERVED, DATA */ +#define MC_CMD_UART_SEND_DATA_OUT_CHECKSUM_OFST 0 +/* Offset at which to write the data */ +#define MC_CMD_UART_SEND_DATA_OUT_OFFSET_OFST 4 +/* Length of data */ +#define MC_CMD_UART_SEND_DATA_OUT_LENGTH_OFST 8 +/* Reserved for future use */ +#define MC_CMD_UART_SEND_DATA_OUT_RESERVED_OFST 12 +#define MC_CMD_UART_SEND_DATA_OUT_DATA_OFST 16 +#define MC_CMD_UART_SEND_DATA_OUT_DATA_LEN 1 +#define MC_CMD_UART_SEND_DATA_OUT_DATA_MINNUM 0 +#define MC_CMD_UART_SEND_DATA_OUT_DATA_MAXNUM 236 + +/* MC_CMD_UART_SEND_DATA_IN msgresponse */ +#define MC_CMD_UART_SEND_DATA_IN_LEN 0 + + +/***********************************/ +/* MC_CMD_UART_RECV_DATA + * Request checksummed[sic] block of data over the uart. Only a placeholder, + * subject to change and not currently implemented. + */ +#define MC_CMD_UART_RECV_DATA 0xef + +/* MC_CMD_UART_RECV_DATA_OUT msgrequest */ +#define MC_CMD_UART_RECV_DATA_OUT_LEN 16 +/* CRC32 over OFFSET, LENGTH, RESERVED */ +#define MC_CMD_UART_RECV_DATA_OUT_CHECKSUM_OFST 0 +/* Offset from which to read the data */ +#define MC_CMD_UART_RECV_DATA_OUT_OFFSET_OFST 4 +/* Length of data */ +#define MC_CMD_UART_RECV_DATA_OUT_LENGTH_OFST 8 +/* Reserved for future use */ +#define MC_CMD_UART_RECV_DATA_OUT_RESERVED_OFST 12 + +/* MC_CMD_UART_RECV_DATA_IN msgresponse */ +#define MC_CMD_UART_RECV_DATA_IN_LENMIN 16 +#define MC_CMD_UART_RECV_DATA_IN_LENMAX 252 +#define MC_CMD_UART_RECV_DATA_IN_LEN(num) (16+1*(num)) +/* CRC32 over RESERVED1, RESERVED2, RESERVED3, DATA */ +#define MC_CMD_UART_RECV_DATA_IN_CHECKSUM_OFST 0 +/* Offset at which to write the data */ +#define MC_CMD_UART_RECV_DATA_IN_RESERVED1_OFST 4 +/* Length of data */ +#define MC_CMD_UART_RECV_DATA_IN_RESERVED2_OFST 8 +/* Reserved for future use */ +#define MC_CMD_UART_RECV_DATA_IN_RESERVED3_OFST 12 +#define MC_CMD_UART_RECV_DATA_IN_DATA_OFST 16 +#define MC_CMD_UART_RECV_DATA_IN_DATA_LEN 1 +#define MC_CMD_UART_RECV_DATA_IN_DATA_MINNUM 0 +#define MC_CMD_UART_RECV_DATA_IN_DATA_MAXNUM 236 /***********************************/ @@ -7026,6 +7309,15 @@ #define MC_CMD_KR_TUNE_IN_TXEQ_SET 0x3 /* enum: Force KR Serdes reset / recalibration */ #define MC_CMD_KR_TUNE_IN_RECAL 0x4 +/* enum: Start KR Serdes Eye diagram plot on a given lane. Lane must have valid + * signal. + */ +#define MC_CMD_KR_TUNE_IN_START_EYE_PLOT 0x5 +/* enum: Poll KR Serdes Eye diagram plot. Returns one row of BER data. The + * caller should call this command repeatedly after starting eye plot, until no + * more data is returned. + */ +#define MC_CMD_KR_TUNE_IN_POLL_EYE_PLOT 0x6 /* Align the arguments to 32 bits */ #define MC_CMD_KR_TUNE_IN_KR_TUNE_RSVD_OFST 1 #define MC_CMD_KR_TUNE_IN_KR_TUNE_RSVD_LEN 3 @@ -7123,6 +7415,91 @@ /* MC_CMD_KR_TUNE_RXEQ_SET_OUT msgresponse */ #define MC_CMD_KR_TUNE_RXEQ_SET_OUT_LEN 0 +/* MC_CMD_KR_TUNE_TXEQ_GET_IN msgrequest */ +#define MC_CMD_KR_TUNE_TXEQ_GET_IN_LEN 4 +/* Requested operation */ +#define MC_CMD_KR_TUNE_TXEQ_GET_IN_KR_TUNE_OP_OFST 0 +#define MC_CMD_KR_TUNE_TXEQ_GET_IN_KR_TUNE_OP_LEN 1 +/* Align the arguments to 32 bits */ +#define MC_CMD_KR_TUNE_TXEQ_GET_IN_KR_TUNE_RSVD_OFST 1 +#define MC_CMD_KR_TUNE_TXEQ_GET_IN_KR_TUNE_RSVD_LEN 3 + +/* MC_CMD_KR_TUNE_TXEQ_GET_OUT msgresponse */ +#define MC_CMD_KR_TUNE_TXEQ_GET_OUT_LENMIN 4 +#define MC_CMD_KR_TUNE_TXEQ_GET_OUT_LENMAX 252 +#define MC_CMD_KR_TUNE_TXEQ_GET_OUT_LEN(num) (0+4*(num)) +/* TXEQ Parameter */ +#define MC_CMD_KR_TUNE_TXEQ_GET_OUT_PARAM_OFST 0 +#define MC_CMD_KR_TUNE_TXEQ_GET_OUT_PARAM_LEN 4 +#define MC_CMD_KR_TUNE_TXEQ_GET_OUT_PARAM_MINNUM 1 +#define MC_CMD_KR_TUNE_TXEQ_GET_OUT_PARAM_MAXNUM 63 +#define MC_CMD_KR_TUNE_TXEQ_GET_OUT_PARAM_ID_LBN 0 +#define MC_CMD_KR_TUNE_TXEQ_GET_OUT_PARAM_ID_WIDTH 8 +/* enum: TX Amplitude */ +#define MC_CMD_KR_TUNE_TXEQ_GET_OUT_TX_LEV 0x0 +/* enum: De-Emphasis Tap1 Magnitude (0-7) */ +#define MC_CMD_KR_TUNE_TXEQ_GET_OUT_TX_MODE 0x1 +/* enum: De-Emphasis Tap1 Fine */ +#define MC_CMD_KR_TUNE_TXEQ_GET_OUT_TX_DTLEV 0x2 +/* enum: De-Emphasis Tap2 Magnitude (0-6) */ +#define MC_CMD_KR_TUNE_TXEQ_GET_OUT_TX_D2 0x3 +/* enum: De-Emphasis Tap2 Fine */ +#define MC_CMD_KR_TUNE_TXEQ_GET_OUT_TX_D2TLEV 0x4 +/* enum: Pre-Emphasis Magnitude */ +#define MC_CMD_KR_TUNE_TXEQ_GET_OUT_TX_E 0x5 +/* enum: Pre-Emphasis Fine */ +#define MC_CMD_KR_TUNE_TXEQ_GET_OUT_TX_ETLEV 0x6 +/* enum: TX Slew Rate Coarse control */ +#define MC_CMD_KR_TUNE_TXEQ_GET_OUT_TX_PREDRV_DLY 0x7 +/* enum: TX Slew Rate Fine control */ +#define MC_CMD_KR_TUNE_TXEQ_GET_OUT_TX_SR_SET 0x8 +#define MC_CMD_KR_TUNE_TXEQ_GET_OUT_PARAM_LANE_LBN 8 +#define MC_CMD_KR_TUNE_TXEQ_GET_OUT_PARAM_LANE_WIDTH 3 +#define MC_CMD_KR_TUNE_TXEQ_GET_OUT_LANE_0 0x0 /* enum */ +#define MC_CMD_KR_TUNE_TXEQ_GET_OUT_LANE_1 0x1 /* enum */ +#define MC_CMD_KR_TUNE_TXEQ_GET_OUT_LANE_2 0x2 /* enum */ +#define MC_CMD_KR_TUNE_TXEQ_GET_OUT_LANE_3 0x3 /* enum */ +#define MC_CMD_KR_TUNE_TXEQ_GET_OUT_LANE_ALL 0x4 /* enum */ +#define MC_CMD_KR_TUNE_TXEQ_GET_OUT_RESERVED_LBN 11 +#define MC_CMD_KR_TUNE_TXEQ_GET_OUT_RESERVED_WIDTH 5 +#define MC_CMD_KR_TUNE_TXEQ_GET_OUT_PARAM_INITIAL_LBN 16 +#define MC_CMD_KR_TUNE_TXEQ_GET_OUT_PARAM_INITIAL_WIDTH 8 +#define MC_CMD_KR_TUNE_TXEQ_GET_OUT_RESERVED2_LBN 24 +#define MC_CMD_KR_TUNE_TXEQ_GET_OUT_RESERVED2_WIDTH 8 + +/* MC_CMD_KR_TUNE_TXEQ_SET_IN msgrequest */ +#define MC_CMD_KR_TUNE_TXEQ_SET_IN_LENMIN 8 +#define MC_CMD_KR_TUNE_TXEQ_SET_IN_LENMAX 252 +#define MC_CMD_KR_TUNE_TXEQ_SET_IN_LEN(num) (4+4*(num)) +/* Requested operation */ +#define MC_CMD_KR_TUNE_TXEQ_SET_IN_KR_TUNE_OP_OFST 0 +#define MC_CMD_KR_TUNE_TXEQ_SET_IN_KR_TUNE_OP_LEN 1 +/* Align the arguments to 32 bits */ +#define MC_CMD_KR_TUNE_TXEQ_SET_IN_KR_TUNE_RSVD_OFST 1 +#define MC_CMD_KR_TUNE_TXEQ_SET_IN_KR_TUNE_RSVD_LEN 3 +/* TXEQ Parameter */ +#define MC_CMD_KR_TUNE_TXEQ_SET_IN_PARAM_OFST 4 +#define MC_CMD_KR_TUNE_TXEQ_SET_IN_PARAM_LEN 4 +#define MC_CMD_KR_TUNE_TXEQ_SET_IN_PARAM_MINNUM 1 +#define MC_CMD_KR_TUNE_TXEQ_SET_IN_PARAM_MAXNUM 62 +#define MC_CMD_KR_TUNE_TXEQ_SET_IN_PARAM_ID_LBN 0 +#define MC_CMD_KR_TUNE_TXEQ_SET_IN_PARAM_ID_WIDTH 8 +/* Enum values, see field(s): */ +/* MC_CMD_KR_TUNE_TXEQ_GET_OUT/PARAM_ID */ +#define MC_CMD_KR_TUNE_TXEQ_SET_IN_PARAM_LANE_LBN 8 +#define MC_CMD_KR_TUNE_TXEQ_SET_IN_PARAM_LANE_WIDTH 3 +/* Enum values, see field(s): */ +/* MC_CMD_KR_TUNE_TXEQ_GET_OUT/PARAM_LANE */ +#define MC_CMD_KR_TUNE_TXEQ_SET_IN_RESERVED_LBN 11 +#define MC_CMD_KR_TUNE_TXEQ_SET_IN_RESERVED_WIDTH 5 +#define MC_CMD_KR_TUNE_TXEQ_SET_IN_PARAM_INITIAL_LBN 16 +#define MC_CMD_KR_TUNE_TXEQ_SET_IN_PARAM_INITIAL_WIDTH 8 +#define MC_CMD_KR_TUNE_TXEQ_SET_IN_RESERVED2_LBN 24 +#define MC_CMD_KR_TUNE_TXEQ_SET_IN_RESERVED2_WIDTH 8 + +/* MC_CMD_KR_TUNE_TXEQ_SET_OUT msgresponse */ +#define MC_CMD_KR_TUNE_TXEQ_SET_OUT_LEN 0 + /* MC_CMD_KR_TUNE_RECAL_IN msgrequest */ #define MC_CMD_KR_TUNE_RECAL_IN_LEN 4 /* Requested operation */ @@ -7135,6 +7512,37 @@ /* MC_CMD_KR_TUNE_RECAL_OUT msgresponse */ #define MC_CMD_KR_TUNE_RECAL_OUT_LEN 0 +/* MC_CMD_KR_TUNE_START_EYE_PLOT_IN msgrequest */ +#define MC_CMD_KR_TUNE_START_EYE_PLOT_IN_LEN 8 +/* Requested operation */ +#define MC_CMD_KR_TUNE_START_EYE_PLOT_IN_KR_TUNE_OP_OFST 0 +#define MC_CMD_KR_TUNE_START_EYE_PLOT_IN_KR_TUNE_OP_LEN 1 +/* Align the arguments to 32 bits */ +#define MC_CMD_KR_TUNE_START_EYE_PLOT_IN_KR_TUNE_RSVD_OFST 1 +#define MC_CMD_KR_TUNE_START_EYE_PLOT_IN_KR_TUNE_RSVD_LEN 3 +#define MC_CMD_KR_TUNE_START_EYE_PLOT_IN_LANE_OFST 4 + +/* MC_CMD_KR_TUNE_START_EYE_PLOT_OUT msgresponse */ +#define MC_CMD_KR_TUNE_START_EYE_PLOT_OUT_LEN 0 + +/* MC_CMD_KR_TUNE_POLL_EYE_PLOT_IN msgrequest */ +#define MC_CMD_KR_TUNE_POLL_EYE_PLOT_IN_LEN 4 +/* Requested operation */ +#define MC_CMD_KR_TUNE_POLL_EYE_PLOT_IN_KR_TUNE_OP_OFST 0 +#define MC_CMD_KR_TUNE_POLL_EYE_PLOT_IN_KR_TUNE_OP_LEN 1 +/* Align the arguments to 32 bits */ +#define MC_CMD_KR_TUNE_POLL_EYE_PLOT_IN_KR_TUNE_RSVD_OFST 1 +#define MC_CMD_KR_TUNE_POLL_EYE_PLOT_IN_KR_TUNE_RSVD_LEN 3 + +/* MC_CMD_KR_TUNE_POLL_EYE_PLOT_OUT msgresponse */ +#define MC_CMD_KR_TUNE_POLL_EYE_PLOT_OUT_LENMIN 0 +#define MC_CMD_KR_TUNE_POLL_EYE_PLOT_OUT_LENMAX 252 +#define MC_CMD_KR_TUNE_POLL_EYE_PLOT_OUT_LEN(num) (0+2*(num)) +#define MC_CMD_KR_TUNE_POLL_EYE_PLOT_OUT_SAMPLES_OFST 0 +#define MC_CMD_KR_TUNE_POLL_EYE_PLOT_OUT_SAMPLES_LEN 2 +#define MC_CMD_KR_TUNE_POLL_EYE_PLOT_OUT_SAMPLES_MINNUM 0 +#define MC_CMD_KR_TUNE_POLL_EYE_PLOT_OUT_SAMPLES_MAXNUM 126 + /***********************************/ /* MC_CMD_PCIE_TUNE @@ -7157,6 +7565,13 @@ #define MC_CMD_PCIE_TUNE_IN_TXEQ_GET 0x2 /* enum: Override TX Driver settings */ #define MC_CMD_PCIE_TUNE_IN_TXEQ_SET 0x3 +/* enum: Start PCIe Serdes Eye diagram plot on a given lane. */ +#define MC_CMD_PCIE_TUNE_IN_START_EYE_PLOT 0x5 +/* enum: Poll PCIe Serdes Eye diagram plot. Returns one row of BER data. The + * caller should call this command repeatedly after starting eye plot, until no + * more data is returned. + */ +#define MC_CMD_PCIE_TUNE_IN_POLL_EYE_PLOT 0x6 /* Align the arguments to 32 bits */ #define MC_CMD_PCIE_TUNE_IN_PCIE_TUNE_RSVD_OFST 1 #define MC_CMD_PCIE_TUNE_IN_PCIE_TUNE_RSVD_LEN 3 @@ -7258,6 +7673,37 @@ #define MC_CMD_PCIE_TUNE_TXEQ_GET_OUT_PARAM_CURRENT_LBN 24 #define MC_CMD_PCIE_TUNE_TXEQ_GET_OUT_PARAM_CURRENT_WIDTH 8 +/* MC_CMD_PCIE_TUNE_START_EYE_PLOT_IN msgrequest */ +#define MC_CMD_PCIE_TUNE_START_EYE_PLOT_IN_LEN 8 +/* Requested operation */ +#define MC_CMD_PCIE_TUNE_START_EYE_PLOT_IN_PCIE_TUNE_OP_OFST 0 +#define MC_CMD_PCIE_TUNE_START_EYE_PLOT_IN_PCIE_TUNE_OP_LEN 1 +/* Align the arguments to 32 bits */ +#define MC_CMD_PCIE_TUNE_START_EYE_PLOT_IN_PCIE_TUNE_RSVD_OFST 1 +#define MC_CMD_PCIE_TUNE_START_EYE_PLOT_IN_PCIE_TUNE_RSVD_LEN 3 +#define MC_CMD_PCIE_TUNE_START_EYE_PLOT_IN_LANE_OFST 4 + +/* MC_CMD_PCIE_TUNE_START_EYE_PLOT_OUT msgresponse */ +#define MC_CMD_PCIE_TUNE_START_EYE_PLOT_OUT_LEN 0 + +/* MC_CMD_PCIE_TUNE_POLL_EYE_PLOT_IN msgrequest */ +#define MC_CMD_PCIE_TUNE_POLL_EYE_PLOT_IN_LEN 4 +/* Requested operation */ +#define MC_CMD_PCIE_TUNE_POLL_EYE_PLOT_IN_PCIE_TUNE_OP_OFST 0 +#define MC_CMD_PCIE_TUNE_POLL_EYE_PLOT_IN_PCIE_TUNE_OP_LEN 1 +/* Align the arguments to 32 bits */ +#define MC_CMD_PCIE_TUNE_POLL_EYE_PLOT_IN_PCIE_TUNE_RSVD_OFST 1 +#define MC_CMD_PCIE_TUNE_POLL_EYE_PLOT_IN_PCIE_TUNE_RSVD_LEN 3 + +/* MC_CMD_PCIE_TUNE_POLL_EYE_PLOT_OUT msgresponse */ +#define MC_CMD_PCIE_TUNE_POLL_EYE_PLOT_OUT_LENMIN 0 +#define MC_CMD_PCIE_TUNE_POLL_EYE_PLOT_OUT_LENMAX 252 +#define MC_CMD_PCIE_TUNE_POLL_EYE_PLOT_OUT_LEN(num) (0+2*(num)) +#define MC_CMD_PCIE_TUNE_POLL_EYE_PLOT_OUT_SAMPLES_OFST 0 +#define MC_CMD_PCIE_TUNE_POLL_EYE_PLOT_OUT_SAMPLES_LEN 2 +#define MC_CMD_PCIE_TUNE_POLL_EYE_PLOT_OUT_SAMPLES_MINNUM 0 +#define MC_CMD_PCIE_TUNE_POLL_EYE_PLOT_OUT_SAMPLES_MAXNUM 126 + /***********************************/ /* MC_CMD_LICENSING @@ -7310,5 +7756,152 @@ */ #define MC_CMD_MC2MC_PROXY 0xf4 +/* MC_CMD_MC2MC_PROXY_IN msgrequest */ +#define MC_CMD_MC2MC_PROXY_IN_LEN 0 + +/* MC_CMD_MC2MC_PROXY_OUT msgresponse */ +#define MC_CMD_MC2MC_PROXY_OUT_LEN 0 + + +/***********************************/ +/* MC_CMD_GET_LICENSED_APP_STATE + * Query the state of an individual licensed application. (Note that the actual + * state may be invalidated by the MC_CMD_LICENSING OP_UPDATE_LICENSE operation + * or a reboot of the MC.) + */ +#define MC_CMD_GET_LICENSED_APP_STATE 0xf5 + +/* MC_CMD_GET_LICENSED_APP_STATE_IN msgrequest */ +#define MC_CMD_GET_LICENSED_APP_STATE_IN_LEN 4 +/* application ID to query (LICENSED_APP_ID_xxx) */ +#define MC_CMD_GET_LICENSED_APP_STATE_IN_APP_ID_OFST 0 + +/* MC_CMD_GET_LICENSED_APP_STATE_OUT msgresponse */ +#define MC_CMD_GET_LICENSED_APP_STATE_OUT_LEN 4 +/* state of this application */ +#define MC_CMD_GET_LICENSED_APP_STATE_OUT_STATE_OFST 0 +/* enum: no (or invalid) license is present for the application */ +#define MC_CMD_GET_LICENSED_APP_STATE_OUT_NOT_LICENSED 0x0 +/* enum: a valid license is present for the application */ +#define MC_CMD_GET_LICENSED_APP_STATE_OUT_LICENSED 0x1 + + +/***********************************/ +/* MC_CMD_LICENSED_APP_OP + * Perform an action for an individual licensed application. + */ +#define MC_CMD_LICENSED_APP_OP 0xf6 + +/* MC_CMD_LICENSED_APP_OP_IN msgrequest */ +#define MC_CMD_LICENSED_APP_OP_IN_LENMIN 8 +#define MC_CMD_LICENSED_APP_OP_IN_LENMAX 252 +#define MC_CMD_LICENSED_APP_OP_IN_LEN(num) (8+4*(num)) +/* application ID */ +#define MC_CMD_LICENSED_APP_OP_IN_APP_ID_OFST 0 +/* the type of operation requested */ +#define MC_CMD_LICENSED_APP_OP_IN_OP_OFST 4 +/* enum: validate application */ +#define MC_CMD_LICENSED_APP_OP_IN_OP_VALIDATE 0x0 +/* arguments specific to this particular operation */ +#define MC_CMD_LICENSED_APP_OP_IN_ARGS_OFST 8 +#define MC_CMD_LICENSED_APP_OP_IN_ARGS_LEN 4 +#define MC_CMD_LICENSED_APP_OP_IN_ARGS_MINNUM 0 +#define MC_CMD_LICENSED_APP_OP_IN_ARGS_MAXNUM 61 + +/* MC_CMD_LICENSED_APP_OP_OUT msgresponse */ +#define MC_CMD_LICENSED_APP_OP_OUT_LENMIN 0 +#define MC_CMD_LICENSED_APP_OP_OUT_LENMAX 252 +#define MC_CMD_LICENSED_APP_OP_OUT_LEN(num) (0+4*(num)) +/* result specific to this particular operation */ +#define MC_CMD_LICENSED_APP_OP_OUT_RESULT_OFST 0 +#define MC_CMD_LICENSED_APP_OP_OUT_RESULT_LEN 4 +#define MC_CMD_LICENSED_APP_OP_OUT_RESULT_MINNUM 0 +#define MC_CMD_LICENSED_APP_OP_OUT_RESULT_MAXNUM 63 + +/* MC_CMD_LICENSED_APP_OP_VALIDATE_IN msgrequest */ +#define MC_CMD_LICENSED_APP_OP_VALIDATE_IN_LEN 72 +/* application ID */ +#define MC_CMD_LICENSED_APP_OP_VALIDATE_IN_APP_ID_OFST 0 +/* the type of operation requested */ +#define MC_CMD_LICENSED_APP_OP_VALIDATE_IN_OP_OFST 4 +/* validation challenge */ +#define MC_CMD_LICENSED_APP_OP_VALIDATE_IN_CHALLENGE_OFST 8 +#define MC_CMD_LICENSED_APP_OP_VALIDATE_IN_CHALLENGE_LEN 64 + +/* MC_CMD_LICENSED_APP_OP_VALIDATE_OUT msgresponse */ +#define MC_CMD_LICENSED_APP_OP_VALIDATE_OUT_LEN 68 +/* feature expiry (time_t) */ +#define MC_CMD_LICENSED_APP_OP_VALIDATE_OUT_EXPIRY_OFST 0 +/* validation response */ +#define MC_CMD_LICENSED_APP_OP_VALIDATE_OUT_RESPONSE_OFST 4 +#define MC_CMD_LICENSED_APP_OP_VALIDATE_OUT_RESPONSE_LEN 64 + + +/***********************************/ +/* MC_CMD_SET_PORT_SNIFF_CONFIG + * Configure port sniffing for the physical port associated with the calling + * function. Only a privileged function may change the port sniffing + * configuration. A copy of all traffic delivered to the host (non-promiscuous + * mode) or all traffic arriving at the port (promiscuous mode) may be + * delivered to a specific queue, or a set of queues with RSS. + */ +#define MC_CMD_SET_PORT_SNIFF_CONFIG 0xf7 + +/* MC_CMD_SET_PORT_SNIFF_CONFIG_IN msgrequest */ +#define MC_CMD_SET_PORT_SNIFF_CONFIG_IN_LEN 16 +/* configuration flags */ +#define MC_CMD_SET_PORT_SNIFF_CONFIG_IN_FLAGS_OFST 0 +#define MC_CMD_SET_PORT_SNIFF_CONFIG_IN_ENABLE_LBN 0 +#define MC_CMD_SET_PORT_SNIFF_CONFIG_IN_ENABLE_WIDTH 1 +#define MC_CMD_SET_PORT_SNIFF_CONFIG_IN_PROMISCUOUS_LBN 1 +#define MC_CMD_SET_PORT_SNIFF_CONFIG_IN_PROMISCUOUS_WIDTH 1 +/* receive queue handle (for RSS mode, this is the base queue) */ +#define MC_CMD_SET_PORT_SNIFF_CONFIG_IN_RX_QUEUE_OFST 4 +/* receive mode */ +#define MC_CMD_SET_PORT_SNIFF_CONFIG_IN_RX_MODE_OFST 8 +/* enum: receive to just the specified queue */ +#define MC_CMD_SET_PORT_SNIFF_CONFIG_IN_RX_MODE_SIMPLE 0x0 +/* enum: receive to multiple queues using RSS context */ +#define MC_CMD_SET_PORT_SNIFF_CONFIG_IN_RX_MODE_RSS 0x1 +/* RSS context (for RX_MODE_RSS) as returned by MC_CMD_RSS_CONTEXT_ALLOC. Note + * that these handles should be considered opaque to the host, although a value + * of 0xFFFFFFFF is guaranteed never to be a valid handle. + */ +#define MC_CMD_SET_PORT_SNIFF_CONFIG_IN_RX_CONTEXT_OFST 12 + +/* MC_CMD_SET_PORT_SNIFF_CONFIG_OUT msgresponse */ +#define MC_CMD_SET_PORT_SNIFF_CONFIG_OUT_LEN 0 + + +/***********************************/ +/* MC_CMD_GET_PORT_SNIFF_CONFIG + * Obtain the current port sniffing configuration for the physical port + * associated with the calling function. Only a privileged function may read + * the configuration. + */ +#define MC_CMD_GET_PORT_SNIFF_CONFIG 0xf8 + +/* MC_CMD_GET_PORT_SNIFF_CONFIG_IN msgrequest */ +#define MC_CMD_GET_PORT_SNIFF_CONFIG_IN_LEN 0 + +/* MC_CMD_GET_PORT_SNIFF_CONFIG_OUT msgresponse */ +#define MC_CMD_GET_PORT_SNIFF_CONFIG_OUT_LEN 16 +/* configuration flags */ +#define MC_CMD_GET_PORT_SNIFF_CONFIG_OUT_FLAGS_OFST 0 +#define MC_CMD_GET_PORT_SNIFF_CONFIG_OUT_ENABLE_LBN 0 +#define MC_CMD_GET_PORT_SNIFF_CONFIG_OUT_ENABLE_WIDTH 1 +#define MC_CMD_GET_PORT_SNIFF_CONFIG_OUT_PROMISCUOUS_LBN 1 +#define MC_CMD_GET_PORT_SNIFF_CONFIG_OUT_PROMISCUOUS_WIDTH 1 +/* receiving queue handle (for RSS mode, this is the base queue) */ +#define MC_CMD_GET_PORT_SNIFF_CONFIG_OUT_RX_QUEUE_OFST 4 +/* receive mode */ +#define MC_CMD_GET_PORT_SNIFF_CONFIG_OUT_RX_MODE_OFST 8 +/* enum: receiving to just the specified queue */ +#define MC_CMD_GET_PORT_SNIFF_CONFIG_OUT_RX_MODE_SIMPLE 0x0 +/* enum: receiving to multiple queues using RSS context */ +#define MC_CMD_GET_PORT_SNIFF_CONFIG_OUT_RX_MODE_RSS 0x1 +/* RSS context (for RX_MODE_RSS) */ +#define MC_CMD_GET_PORT_SNIFF_CONFIG_OUT_RX_CONTEXT_OFST 12 + #endif /* MCDI_PCOL_H */ -- cgit v1.2.3-70-g09d2 From dcf8f55b15ea290a50091ea86d862c688c2d1188 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 20 Nov 2013 10:02:48 +0000 Subject: i40e: separate TSYNVALID and TSYNINDX fields in Rx descriptor In order to get 1588 to work correctly the defines need a bit of a tweak. Change-Id: Ie50ce2a18e1593441f1560411e5a4f51c6d48aaa Signed-off-by: Jacob Keller Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_type.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 5f81bd52e6f..fdad028f332 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -500,7 +500,8 @@ enum i40e_rx_desc_status_bits { I40E_RX_DESC_STATUS_L2TAG1P_SHIFT = 2, I40E_RX_DESC_STATUS_L3L4P_SHIFT = 3, I40E_RX_DESC_STATUS_CRCP_SHIFT = 4, - I40E_RX_DESC_STATUS_TSYNINDX_SHIFT = 5, /* 3 BITS */ + I40E_RX_DESC_STATUS_TSYNINDX_SHIFT = 5, /* 2 BITS */ + I40E_RX_DESC_STATUS_TSYNVALID_SHIFT = 7, I40E_RX_DESC_STATUS_PIF_SHIFT = 8, I40E_RX_DESC_STATUS_UMBCAST_SHIFT = 9, /* 2 BITS */ I40E_RX_DESC_STATUS_FLM_SHIFT = 11, @@ -509,9 +510,13 @@ enum i40e_rx_desc_status_bits { }; #define I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT I40E_RX_DESC_STATUS_TSYNINDX_SHIFT -#define I40E_RXD_QW1_STATUS_TSYNINDX_MASK (0x7UL << \ +#define I40E_RXD_QW1_STATUS_TSYNINDX_MASK (0x3UL << \ I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT) +#define I40E_RXD_QW1_STATUS_TSYNVALID_SHIFT I40E_RX_DESC_STATUS_TSYNVALID_SHIFT +#define I40E_RXD_QW1_STATUS_TSYNVALID_MASK (0x1UL << \ + I40E_RXD_QW1_STATUS_TSYNVALID_SHIFT) + enum i40e_rx_desc_fltstat_values { I40E_RX_DESC_FLTSTAT_NO_DATA = 0, I40E_RX_DESC_FLTSTAT_RSV_FD_ID = 1, /* 16byte desc? FD_ID : RSV */ -- cgit v1.2.3-70-g09d2 From 8a4949200812b865a8c101958bdde1b7f8cdd020 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Wed, 20 Nov 2013 10:02:49 +0000 Subject: i40e: check multi-bit state correctly The hash is reported correctly in the rss field if and only if the filter status is 3. Other values of filter status mean different things and we shouldn't depend on a bitwise result. The issue was that a & b --> returns true for b={1,2,3} the fix is a & b == b Also refactor this function to use constant operations because we are in fast path. Change-Id: I4e29be87439c1cf8b60bc31bea29dff89596c013 Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index f1f03bc5c72..01d0334fa92 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -891,13 +891,15 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, static inline u32 i40e_rx_hash(struct i40e_ring *ring, union i40e_rx_desc *rx_desc) { - if (ring->netdev->features & NETIF_F_RXHASH) { - if ((le64_to_cpu(rx_desc->wb.qword1.status_error_len) >> - I40E_RX_DESC_STATUS_FLTSTAT_SHIFT) & - I40E_RX_DESC_FLTSTAT_RSS_HASH) - return le32_to_cpu(rx_desc->wb.qword0.hi_dword.rss); - } - return 0; + const __le64 rss_mask = + cpu_to_le64((u64)I40E_RX_DESC_FLTSTAT_RSS_HASH << + I40E_RX_DESC_STATUS_FLTSTAT_SHIFT); + + if ((ring->netdev->features & NETIF_F_RXHASH) && + (rx_desc->wb.qword1.status_error_len & rss_mask) == rss_mask) + return le32_to_cpu(rx_desc->wb.qword0.hi_dword.rss); + else + return 0; } /** -- cgit v1.2.3-70-g09d2 From be405eb0e47f1ee027e9c0e1087129fb29b7bc08 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Wed, 20 Nov 2013 10:02:50 +0000 Subject: i40e: get media type during link info Set the media type in the hardware structure, based on the external connection type. Add Direct Attach to the type of media reported by ethtool. Change-Id: I4ad2f5bf882766d6e737fac4477abf049491b3b3 Signed-off-by: Shannon Nelson Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_common.c | 47 ++++++++++++++++++++++++++ drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 4 +++ drivers/net/ethernet/intel/i40e/i40e_type.h | 1 + 3 files changed, 52 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index 9e868eac8e1..2cc01c21681 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -266,6 +266,52 @@ i40e_status i40e_validate_mac_addr(u8 *mac_addr) return status; } +/** + * i40e_get_media_type - Gets media type + * @hw: pointer to the hardware structure + **/ +static enum i40e_media_type i40e_get_media_type(struct i40e_hw *hw) +{ + enum i40e_media_type media; + + switch (hw->phy.link_info.phy_type) { + case I40E_PHY_TYPE_10GBASE_SR: + case I40E_PHY_TYPE_10GBASE_LR: + case I40E_PHY_TYPE_40GBASE_SR4: + case I40E_PHY_TYPE_40GBASE_LR4: + media = I40E_MEDIA_TYPE_FIBER; + break; + case I40E_PHY_TYPE_100BASE_TX: + case I40E_PHY_TYPE_1000BASE_T: + case I40E_PHY_TYPE_10GBASE_T: + media = I40E_MEDIA_TYPE_BASET; + break; + case I40E_PHY_TYPE_10GBASE_CR1_CU: + case I40E_PHY_TYPE_40GBASE_CR4_CU: + case I40E_PHY_TYPE_10GBASE_CR1: + case I40E_PHY_TYPE_40GBASE_CR4: + case I40E_PHY_TYPE_10GBASE_SFPP_CU: + media = I40E_MEDIA_TYPE_DA; + break; + case I40E_PHY_TYPE_1000BASE_KX: + case I40E_PHY_TYPE_10GBASE_KX4: + case I40E_PHY_TYPE_10GBASE_KR: + case I40E_PHY_TYPE_40GBASE_KR4: + media = I40E_MEDIA_TYPE_BACKPLANE; + break; + case I40E_PHY_TYPE_SGMII: + case I40E_PHY_TYPE_XAUI: + case I40E_PHY_TYPE_XFI: + case I40E_PHY_TYPE_XLAUI: + case I40E_PHY_TYPE_XLPPI: + default: + media = I40E_MEDIA_TYPE_UNKNOWN; + break; + } + + return media; +} + /** * i40e_pf_reset - Reset the PF * @hw: pointer to the hardware structure @@ -499,6 +545,7 @@ i40e_status i40e_aq_get_link_info(struct i40e_hw *hw, /* update link status */ hw_link_info->phy_type = (enum i40e_aq_phy_type)resp->phy_type; + hw->phy.media_type = i40e_get_media_type(hw); hw_link_info->link_speed = (enum i40e_aq_link_speed)resp->link_speed; hw_link_info->link_info = resp->link_info; hw_link_info->an_info = resp->an_info; diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 8f5d538c11c..7fb669bd047 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -211,6 +211,10 @@ static int i40e_get_settings(struct net_device *netdev, ecmd->supported |= SUPPORTED_TP; ecmd->advertising |= ADVERTISED_TP; ecmd->port = PORT_TP; + } else if (hw->phy.media_type == I40E_MEDIA_TYPE_DA) { + ecmd->supported |= SUPPORTED_FIBRE; + ecmd->advertising |= ADVERTISED_FIBRE; + ecmd->port = PORT_DA; } else { ecmd->supported |= SUPPORTED_FIBRE; ecmd->advertising |= ADVERTISED_FIBRE; diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index fdad028f332..88b37e07b25 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -134,6 +134,7 @@ enum i40e_media_type { I40E_MEDIA_TYPE_BASET, I40E_MEDIA_TYPE_BACKPLANE, I40E_MEDIA_TYPE_CX4, + I40E_MEDIA_TYPE_DA, I40E_MEDIA_TYPE_VIRTUAL }; -- cgit v1.2.3-70-g09d2 From e1c51b9586759d2ceaa0cdcddbe648d765accf04 Mon Sep 17 00:00:00 2001 From: Kevin Scott Date: Wed, 20 Nov 2013 10:02:51 +0000 Subject: i40e: Add flag for L2 VEB filtering Add a new flag to the add VEB command which allows the driver to request the hardware to filter on L2 parameters. This is an implementation of the driver access to a new firmware feature. Change-Id: Id61d3cad4125bdc68b8fd9d555c448a10c344b6b Signed-off-by: Kevin Scott Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_common.c | 8 +++++++- drivers/net/ethernet/intel/i40e/i40e_main.c | 4 +++- drivers/net/ethernet/intel/i40e/i40e_prototype.h | 3 ++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index 2cc01c21681..1300d3d0aac 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -924,6 +924,7 @@ i40e_get_link_status_exit: * @downlink_seid: the VSI SEID * @enabled_tc: bitmap of TCs to be enabled * @default_port: true for default port VSI, false for control port + * @enable_l2_filtering: true to add L2 filter table rules to regular forwarding rules for cloud support * @veb_seid: pointer to where to put the resulting VEB SEID * @cmd_details: pointer to command details structure or NULL * @@ -932,7 +933,8 @@ i40e_get_link_status_exit: **/ i40e_status i40e_aq_add_veb(struct i40e_hw *hw, u16 uplink_seid, u16 downlink_seid, u8 enabled_tc, - bool default_port, u16 *veb_seid, + bool default_port, bool enable_l2_filtering, + u16 *veb_seid, struct i40e_asq_cmd_details *cmd_details) { struct i40e_aq_desc desc; @@ -958,6 +960,10 @@ i40e_status i40e_aq_add_veb(struct i40e_hw *hw, u16 uplink_seid, veb_flags |= I40E_AQC_ADD_VEB_PORT_TYPE_DEFAULT; else veb_flags |= I40E_AQC_ADD_VEB_PORT_TYPE_DATA; + + if (enable_l2_filtering) + veb_flags |= I40E_AQC_ADD_VEB_ENABLE_L2_FILTER; + cmd->veb_flags = cpu_to_le16(veb_flags); status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details); diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 5d234a13abc..b6d6494a84a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -6525,11 +6525,13 @@ void i40e_veb_release(struct i40e_veb *veb) static int i40e_add_veb(struct i40e_veb *veb, struct i40e_vsi *vsi) { bool is_default = (vsi->idx == vsi->back->lan_vsi); + bool is_cloud = false; int ret; /* get a VEB from the hardware */ ret = i40e_aq_add_veb(&veb->pf->hw, veb->uplink_seid, vsi->seid, - veb->enabled_tc, is_default, &veb->seid, NULL); + veb->enabled_tc, is_default, + is_cloud, &veb->seid, NULL); if (ret) { dev_info(&veb->pf->pdev->dev, "couldn't add VEB, err %d, aq_err %d\n", diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h index f75bb9ccc90..930f53a2f50 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h @@ -106,7 +106,8 @@ i40e_status i40e_aq_update_vsi_params(struct i40e_hw *hw, struct i40e_asq_cmd_details *cmd_details); i40e_status i40e_aq_add_veb(struct i40e_hw *hw, u16 uplink_seid, u16 downlink_seid, u8 enabled_tc, - bool default_port, u16 *pveb_seid, + bool default_port, bool enable_l2_filtering, + u16 *pveb_seid, struct i40e_asq_cmd_details *cmd_details); i40e_status i40e_aq_get_veb_parameters(struct i40e_hw *hw, u16 veb_seid, u16 *switch_id, bool *floating, -- cgit v1.2.3-70-g09d2 From 7134f9cee04142715c586dd686537c9626f4e03f Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Tue, 26 Nov 2013 08:56:05 +0000 Subject: i40e: enable early hardware support Enable a couple of workarounds based on revision ID that allow the driver to work more fully on early hardware. Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 1 + drivers/net/ethernet/intel/i40e/i40e_common.c | 22 ++++++++--- drivers/net/ethernet/intel/i40e/i40e_main.c | 49 ++++++++++++++++++++++--- drivers/net/ethernet/intel/i40e/i40e_register.h | 6 +++ 4 files changed, 68 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index df685bc72ec..5aa2ea21aaa 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -61,6 +61,7 @@ #define I40E_BASE_VSI_SEID 512 #define I40E_BASE_VEB_SEID 288 #define I40E_MAX_VEB 16 +#define I40E_MAX_NPAR_QPS 32 #define I40E_MAX_NUM_DESCRIPTORS 4096 #define I40E_MAX_REGISTER 0x0038FFFF diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index 1300d3d0aac..0b52fbc7d56 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -312,6 +312,8 @@ static enum i40e_media_type i40e_get_media_type(struct i40e_hw *hw) return media; } +#define I40E_PF_RESET_WAIT_COUNT_A0 200 +#define I40E_PF_RESET_WAIT_COUNT 10 /** * i40e_pf_reset - Reset the PF * @hw: pointer to the hardware structure @@ -321,7 +323,7 @@ static enum i40e_media_type i40e_get_media_type(struct i40e_hw *hw) **/ i40e_status i40e_pf_reset(struct i40e_hw *hw) { - u32 wait_cnt = 0; + u32 cnt = 0; u32 reg = 0; u32 grst_del; @@ -331,7 +333,7 @@ i40e_status i40e_pf_reset(struct i40e_hw *hw) */ grst_del = rd32(hw, I40E_GLGEN_RSTCTL) & I40E_GLGEN_RSTCTL_GRSTDEL_MASK >> I40E_GLGEN_RSTCTL_GRSTDEL_SHIFT; - for (wait_cnt = 0; wait_cnt < grst_del + 2; wait_cnt++) { + for (cnt = 0; cnt < grst_del + 2; cnt++) { reg = rd32(hw, I40E_GLGEN_RSTAT); if (!(reg & I40E_GLGEN_RSTAT_DEVSTATE_MASK)) break; @@ -352,11 +354,15 @@ i40e_status i40e_pf_reset(struct i40e_hw *hw) /* If there was a Global Reset in progress when we got here, * we don't need to do the PF Reset */ - if (!wait_cnt) { + if (!cnt) { + if (hw->revision_id == 0) + cnt = I40E_PF_RESET_WAIT_COUNT_A0; + else + cnt = I40E_PF_RESET_WAIT_COUNT; reg = rd32(hw, I40E_PFGEN_CTRL); wr32(hw, I40E_PFGEN_CTRL, (reg | I40E_PFGEN_CTRL_PFSWR_MASK)); - for (wait_cnt = 0; wait_cnt < 10; wait_cnt++) { + for (; cnt; cnt--) { reg = rd32(hw, I40E_PFGEN_CTRL); if (!(reg & I40E_PFGEN_CTRL_PFSWR_MASK)) break; @@ -385,7 +391,13 @@ void i40e_clear_pxe_mode(struct i40e_hw *hw) /* Clear single descriptor fetch/write-back mode */ reg = rd32(hw, I40E_GLLAN_RCTL_0); - wr32(hw, I40E_GLLAN_RCTL_0, (reg | I40E_GLLAN_RCTL_0_PXE_MODE_MASK)); + + if (hw->revision_id == 0) { + /* As a work around clear PXE_MODE instead of setting it */ + wr32(hw, I40E_GLLAN_RCTL_0, (reg & (~I40E_GLLAN_RCTL_0_PXE_MODE_MASK))); + } else { + wr32(hw, I40E_GLLAN_RCTL_0, (reg | I40E_GLLAN_RCTL_0_PXE_MODE_MASK)); + } } /** diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index b6d6494a84a..ee8152be86b 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -574,10 +574,11 @@ static void i40e_update_veb_stats(struct i40e_veb *veb) i40e_stat_update32(hw, I40E_GLSW_TDPC(idx), veb->stat_offsets_loaded, &oes->tx_discards, &es->tx_discards); - i40e_stat_update32(hw, I40E_GLSW_RUPP(idx), - veb->stat_offsets_loaded, - &oes->rx_unknown_protocol, &es->rx_unknown_protocol); - + if (hw->revision_id > 0) + i40e_stat_update32(hw, I40E_GLSW_RUPP(idx), + veb->stat_offsets_loaded, + &oes->rx_unknown_protocol, + &es->rx_unknown_protocol); i40e_stat_update48(hw, I40E_GLSW_GORCH(idx), I40E_GLSW_GORCL(idx), veb->stat_offsets_loaded, &oes->rx_bytes, &es->rx_bytes); @@ -2240,7 +2241,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring) rx_ctx.tphwdesc_ena = 1; rx_ctx.tphdata_ena = 1; rx_ctx.tphhead_ena = 1; - rx_ctx.lrxqthresh = 2; + if (hw->revision_id == 0) + rx_ctx.lrxqthresh = 0; + else + rx_ctx.lrxqthresh = 2; rx_ctx.crcstrip = 1; rx_ctx.l2tsel = 1; rx_ctx.showiv = 1; @@ -3021,6 +3025,9 @@ static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable) } } + if (hw->revision_id == 0) + mdelay(50); + return 0; } @@ -4612,6 +4619,13 @@ static int i40e_get_capabilities(struct i40e_pf *pf) } } while (err); + if (pf->hw.revision_id == 0 && pf->hw.func_caps.npar_enable) { + pf->hw.func_caps.num_msix_vectors += 1; + pf->hw.func_caps.num_tx_qp = + min_t(int, pf->hw.func_caps.num_tx_qp, + I40E_MAX_NPAR_QPS); + } + if (pf->hw.debug_mask & I40E_DEBUG_USER) dev_info(&pf->pdev->dev, "pf=%d, num_vfs=%d, msix_pf=%d, msix_vf=%d, fd_g=%d, fd_b=%d, pf_max_q=%d num_vsi=%d\n", @@ -4623,6 +4637,15 @@ static int i40e_get_capabilities(struct i40e_pf *pf) pf->hw.func_caps.num_tx_qp, pf->hw.func_caps.num_vsis); +#define DEF_NUM_VSI (1 + (pf->hw.func_caps.fcoe ? 1 : 0) \ + + pf->hw.func_caps.num_vfs) + if (pf->hw.revision_id == 0 && (DEF_NUM_VSI > pf->hw.func_caps.num_vsis)) { + dev_info(&pf->pdev->dev, + "got num_vsis %d, setting num_vsis to %d\n", + pf->hw.func_caps.num_vsis, DEF_NUM_VSI); + pf->hw.func_caps.num_vsis = DEF_NUM_VSI; + } + return 0; } @@ -5618,7 +5641,12 @@ static int i40e_sw_init(struct i40e_pf *pf) I40E_FLAG_MQ_ENABLED | I40E_FLAG_RX_1BUF_ENABLED; + /* Depending on PF configurations, it is possible that the RSS + * maximum might end up larger than the available queues + */ pf->rss_size_max = 0x1 << pf->hw.func_caps.rss_table_entry_width; + pf->rss_size_max = min_t(int, pf->rss_size_max, + pf->hw.func_caps.num_tx_qp); if (pf->hw.func_caps.rss) { pf->flags |= I40E_FLAG_RSS_ENABLED; pf->rss_size = min_t(int, pf->rss_size_max, @@ -7142,6 +7170,17 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) hw->bus.device = PCI_SLOT(pdev->devfn); hw->bus.func = PCI_FUNC(pdev->devfn); + /* do a special CORER for clearing PXE mode once at init */ + if (hw->revision_id == 0 && + (rd32(hw, I40E_GLLAN_RCTL_0) & I40E_GLLAN_RCTL_0_PXE_MODE_MASK)) { + wr32(hw, I40E_GLGEN_RTRIG, I40E_GLGEN_RTRIG_CORER_MASK); + i40e_flush(hw); + msleep(200); + pf->corer_count++; + + i40e_clear_pxe_mode(hw); + } + /* Reset here to make sure all is clean and to define PF 'n' */ err = i40e_pf_reset(hw); if (err) { diff --git a/drivers/net/ethernet/intel/i40e/i40e_register.h b/drivers/net/ethernet/intel/i40e/i40e_register.h index db4958bea58..46a2f40944e 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_register.h +++ b/drivers/net/ethernet/intel/i40e/i40e_register.h @@ -2187,6 +2187,12 @@ #define I40E_GLPCI_PCIERR 0x000BE4FC #define I40E_GLPCI_PCIERR_PCIE_ERR_REP_SHIFT 0 #define I40E_GLPCI_PCIERR_PCIE_ERR_REP_MASK (0xFFFFFFFF << I40E_GLPCI_PCIERR_PCIE_ERR_REP_SHIFT) +#define I40E_GLPCI_PCITEST2 0x000BE4BC +#define I40E_GLPCI_PCITEST2_IOV_TEST_MODE_SHIFT 0 +#define I40E_GLPCI_PCITEST2_IOV_TEST_MODE_MASK (0x1 << I40E_GLPCI_PCITEST2_IOV_TEST_MODE_SHIFT) +#define I40E_GLPCI_PCITEST2_TAG_ALLOC_SHIFT 1 +#define I40E_GLPCI_PCITEST2_TAG_ALLOC_MASK (0x1 << I40E_GLPCI_PCITEST2_TAG_ALLOC_SHIFT) + #define I40E_GLPCI_PKTCT 0x0009C4BC #define I40E_GLPCI_PKTCT_PCI_COUNT_BW_PCT_SHIFT 0 #define I40E_GLPCI_PKTCT_PCI_COUNT_BW_PCT_MASK (0xFFFFFFFF << I40E_GLPCI_PKTCT_PCI_COUNT_BW_PCT_SHIFT) -- cgit v1.2.3-70-g09d2 From a19a41e0fa2f482804443224a5e3e2d390f8f970 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Wed, 20 Nov 2013 10:02:53 +0000 Subject: i40e: whitespace Whitespace fixes Change-Id: I95f4d02e4a2a92d6b6fca3ae2b7865c4b916a9bb Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala --- drivers/net/ethernet/intel/i40e/i40e_register.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_register.h b/drivers/net/ethernet/intel/i40e/i40e_register.h index 46a2f40944e..2394c66870f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_register.h +++ b/drivers/net/ethernet/intel/i40e/i40e_register.h @@ -66,6 +66,7 @@ #define I40E_PFPCI_VM_FLUSH_DONE 0x0009C880 #define I40E_PFPCI_VM_FLUSH_DONE_FLUSH_DONE_SHIFT 0 #define I40E_PFPCI_VM_FLUSH_DONE_FLUSH_DONE_MASK (0x1 << I40E_PFPCI_VM_FLUSH_DONE_FLUSH_DONE_SHIFT) + #define I40E_PF_ARQBAH 0x00080180 #define I40E_PF_ARQBAH_ARQBAH_SHIFT 0 #define I40E_PF_ARQBAH_ARQBAH_MASK (0xFFFFFFFF << I40E_PF_ARQBAH_ARQBAH_SHIFT) -- cgit v1.2.3-70-g09d2 From 217ffd411702e6cd1f0d4c00f72333ae1c4731dc Mon Sep 17 00:00:00 2001 From: Catherine Sullivan Date: Wed, 20 Nov 2013 10:02:54 +0000 Subject: i40e: Bump version Update the driver version to 0.3.12-k Signed-off-by: Catherine Sullivan Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index ee8152be86b..969a6871e3c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -36,7 +36,7 @@ static const char i40e_driver_string[] = #define DRV_VERSION_MAJOR 0 #define DRV_VERSION_MINOR 3 -#define DRV_VERSION_BUILD 11 +#define DRV_VERSION_BUILD 12 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \ __stringify(DRV_VERSION_MINOR) "." \ __stringify(DRV_VERSION_BUILD) DRV_KERN -- cgit v1.2.3-70-g09d2 From f650a38b4d3a3b5a14d0bc093f0ae7773faf7f41 Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Wed, 20 Nov 2013 10:02:55 +0000 Subject: i40e: refactor reset code In order to re-size queues and vectors while the interface is still up, we need to be able to call functions to free and re-allocate without bringing down the VSI. We also need to reset the existing setup, update the configuration and then rebuild again. This requires us to have the reset flow broken down into two parts. Change-Id: I374dd25aabf769decda69b676491c7b7730a4635 Signed-off-by: Anjali Singhai Jain Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 131 ++++++++++++++++++++-------- 1 file changed, 95 insertions(+), 36 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 969a6871e3c..273db9940ff 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -4716,22 +4716,20 @@ static void i40e_fdir_teardown(struct i40e_pf *pf) } /** - * i40e_handle_reset_warning - prep for the core to reset + * i40e_prep_for_reset - prep for the core to reset * @pf: board private structure * - * Close up the VFs and other things in prep for a Core Reset, - * then get ready to rebuild the world. - **/ -static void i40e_handle_reset_warning(struct i40e_pf *pf) + * Close up the VFs and other things in prep for pf Reset. + **/ +static int i40e_prep_for_reset(struct i40e_pf *pf) { - struct i40e_driver_version dv; struct i40e_hw *hw = &pf->hw; i40e_status ret; u32 v; clear_bit(__I40E_RESET_INTR_RECEIVED, &pf->state); if (test_and_set_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state)) - return; + return 0; dev_info(&pf->pdev->dev, "Tearing down internal switch for reset\n"); @@ -4747,6 +4745,26 @@ static void i40e_handle_reset_warning(struct i40e_pf *pf) i40e_shutdown_adminq(&pf->hw); + /* call shutdown HMC */ + ret = i40e_shutdown_lan_hmc(hw); + if (ret) { + dev_info(&pf->pdev->dev, "shutdown_lan_hmc failed: %d\n", ret); + clear_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state); + } + return ret; +} + +/** + * i40e_reset_and_rebuild - reset and rebuid using a saved config + * @pf: board private structure + **/ +static void i40e_reset_and_rebuild(struct i40e_pf *pf) +{ + struct i40e_driver_version dv; + struct i40e_hw *hw = &pf->hw; + i40e_status ret; + u32 v; + /* Now we wait for GRST to settle out. * We don't have to delete the VEBs or VSIs from the hw switch * because the reset will make them disappear. @@ -4774,13 +4792,6 @@ static void i40e_handle_reset_warning(struct i40e_pf *pf) goto end_core_reset; } - /* call shutdown HMC */ - ret = i40e_shutdown_lan_hmc(hw); - if (ret) { - dev_info(&pf->pdev->dev, "shutdown_lan_hmc failed: %d\n", ret); - goto end_core_reset; - } - ret = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp, hw->func_caps.num_rx_qp, pf->fcoe_hmc_cntx_num, pf->fcoe_hmc_filt_num); @@ -4873,6 +4884,22 @@ end_core_reset: clear_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state); } +/** + * i40e_handle_reset_warning - prep for the pf to reset, reset and rebuild + * @pf: board private structure + * + * Close up the VFs and other things in prep for a Core Reset, + * then get ready to rebuild the world. + **/ +static void i40e_handle_reset_warning(struct i40e_pf *pf) +{ + i40e_status ret; + + ret = i40e_prep_for_reset(pf); + if (!ret) + i40e_reset_and_rebuild(pf); +} + /** * i40e_handle_mdd_event * @pf: pointer to the pf structure @@ -5048,6 +5075,40 @@ static int i40e_set_num_rings_in_vsi(struct i40e_vsi *vsi) return 0; } +/** + * i40e_vsi_alloc_arrays - Allocate queue and vector pointer arrays for the vsi + * @type: VSI pointer + * + * On error: returns error code (negative) + * On success: returns 0 + **/ +static int i40e_vsi_alloc_arrays(struct i40e_vsi *vsi) +{ + int size; + int ret = 0; + + /* allocate memory for ring pointers */ + size = sizeof(struct i40e_ring *) * vsi->alloc_queue_pairs * 2; + vsi->tx_rings = kzalloc(size, GFP_KERNEL); + if (!vsi->tx_rings) + return -ENOMEM; + + vsi->rx_rings = &vsi->tx_rings[vsi->alloc_queue_pairs]; + + /* allocate memory for q_vector pointers */ + size = sizeof(struct i40e_q_vectors *) * vsi->num_q_vectors; + vsi->q_vectors = kzalloc(size, GFP_KERNEL); + if (!vsi->q_vectors) { + ret = -ENOMEM; + goto err_vectors; + } + return ret; + +err_vectors: + kfree(vsi->tx_rings); + return ret; +} + /** * i40e_vsi_mem_alloc - Allocates the next available struct vsi in the PF * @pf: board private structure @@ -5060,8 +5121,6 @@ static int i40e_vsi_mem_alloc(struct i40e_pf *pf, enum i40e_vsi_type type) { int ret = -ENODEV; struct i40e_vsi *vsi; - int sz_vectors; - int sz_rings; int vsi_idx; int i; @@ -5111,22 +5170,9 @@ static int i40e_vsi_mem_alloc(struct i40e_pf *pf, enum i40e_vsi_type type) if (ret) goto err_rings; - /* allocate memory for ring pointers */ - sz_rings = sizeof(struct i40e_ring *) * vsi->alloc_queue_pairs * 2; - vsi->tx_rings = kzalloc(sz_rings, GFP_KERNEL); - if (!vsi->tx_rings) { - ret = -ENOMEM; + ret = i40e_vsi_alloc_arrays(vsi); + if (ret) goto err_rings; - } - vsi->rx_rings = &vsi->tx_rings[vsi->alloc_queue_pairs]; - - /* allocate memory for q_vector pointers */ - sz_vectors = sizeof(struct i40e_q_vectors *) * vsi->num_q_vectors; - vsi->q_vectors = kzalloc(sz_vectors, GFP_KERNEL); - if (!vsi->q_vectors) { - ret = -ENOMEM; - goto err_vectors; - } /* Setup default MSIX irq handler for VSI */ i40e_vsi_setup_irqhandler(vsi, i40e_msix_clean_rings); @@ -5135,8 +5181,6 @@ static int i40e_vsi_mem_alloc(struct i40e_pf *pf, enum i40e_vsi_type type) ret = vsi_idx; goto unlock_pf; -err_vectors: - kfree(vsi->tx_rings); err_rings: pf->next_vsi = i - 1; kfree(vsi); @@ -5145,6 +5189,23 @@ unlock_pf: return ret; } +/** + * i40e_vsi_free_arrays - Free queue and vector pointer arrays for the VSI + * @type: VSI pointer + * + * On error: returns error code (negative) + * On success: returns 0 + **/ +static void i40e_vsi_free_arrays(struct i40e_vsi *vsi) +{ + /* free the ring and vector containers */ + kfree(vsi->q_vectors); + vsi->q_vectors = NULL; + kfree(vsi->tx_rings); + vsi->tx_rings = NULL; + vsi->rx_rings = NULL; +} + /** * i40e_vsi_clear - Deallocate the VSI provided * @vsi: the VSI being un-configured @@ -5181,9 +5242,7 @@ static int i40e_vsi_clear(struct i40e_vsi *vsi) i40e_put_lump(pf->qp_pile, vsi->base_queue, vsi->idx); i40e_put_lump(pf->irq_pile, vsi->base_vector, vsi->idx); - /* free the ring and vector containers */ - kfree(vsi->q_vectors); - kfree(vsi->tx_rings); + i40e_vsi_free_arrays(vsi); pf->vsi[vsi->idx] = NULL; if (vsi->idx < pf->next_vsi) -- cgit v1.2.3-70-g09d2 From 4617e8c081382baf11377b999e9eed22ffa1bdf6 Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Wed, 20 Nov 2013 10:02:56 +0000 Subject: i40e: Enable all PCTYPEs except FCOE for RSS. RSS can steer packets based on recognition of all sorts of different headers. Enable some more of them. Change-Id: I2264dedae66fb0bceca6fb6e772e050e3ca8efc8 Signed-off-by: Anjali Singhai Jain Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 38 ++++++++++++++++++----------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 273db9940ff..40c64c4d988 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -5615,15 +5615,34 @@ static int i40e_setup_misc_vector(struct i40e_pf *pf) **/ static int i40e_config_rss(struct i40e_pf *pf) { - struct i40e_hw *hw = &pf->hw; - u32 lut = 0; - int i, j; - u64 hena; + const u64 default_hena = + ((u64)1 << I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP) | + ((u64)1 << I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP) | + ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | + ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) | + ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN) | + ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP) | + ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | + ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4) | + ((u64)1 << I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP) | + ((u64)1 << I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP) | + ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | + ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN) | + ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) | + ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) | + ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | + ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6) | + ((u64)1 << I40E_FILTER_PCTYPE_L2_PAYLOAD); + /* Set of random keys generated using kernel random number generator */ static const u32 seed[I40E_PFQF_HKEY_MAX_INDEX + 1] = {0x41b01687, 0x183cfd8c, 0xce880440, 0x580cbc3c, 0x35897377, 0x328b25e1, 0x4fa98922, 0xb7d90c14, 0xd5bad70d, 0xcd15a2c1, 0xe8580225, 0x4a1e9d11, 0xfe5731be}; + struct i40e_hw *hw = &pf->hw; + u32 lut = 0; + int i, j; + u64 hena; /* Fill out hash function seed */ for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++) @@ -5632,16 +5651,7 @@ static int i40e_config_rss(struct i40e_pf *pf) /* By default we enable TCP/UDP with IPv4/IPv6 ptypes */ hena = (u64)rd32(hw, I40E_PFQF_HENA(0)) | ((u64)rd32(hw, I40E_PFQF_HENA(1)) << 32); - hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | - ((u64)1 << I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP) | - ((u64)1 << I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP) | - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP) | - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) | - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | - ((u64)1 << I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP) | - ((u64)1 << I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP) | - ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4)| - ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6); + hena |= default_hena; wr32(hw, I40E_PFQF_HENA(0), (u32)hena); wr32(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32)); -- cgit v1.2.3-70-g09d2 From ac6c5e3d0e9e784ef8b015085c83dee0253324b0 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 20 Nov 2013 10:02:57 +0000 Subject: i40e: only set up the rings to be used The VSI may be allocated more queues (alloc_queue_pairs) than actually are to be used (num_queue_pairs), so only allocate rings for the queues to be used. The numbers will likely be the same for most VSIs, but can be different based on how TCs are assigned and enabled. Change-Id: Ie40f7ad0affbc4b45d6f049bcf02ee2fa24edc74 Signed-off-by: Shannon Nelson Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 40c64c4d988..aae2f04ab0a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -5087,12 +5087,11 @@ static int i40e_vsi_alloc_arrays(struct i40e_vsi *vsi) int size; int ret = 0; - /* allocate memory for ring pointers */ + /* allocate memory for both Tx and Rx ring pointers */ size = sizeof(struct i40e_ring *) * vsi->alloc_queue_pairs * 2; vsi->tx_rings = kzalloc(size, GFP_KERNEL); if (!vsi->tx_rings) return -ENOMEM; - vsi->rx_rings = &vsi->tx_rings[vsi->alloc_queue_pairs]; /* allocate memory for q_vector pointers */ @@ -5265,7 +5264,7 @@ static s32 i40e_vsi_clear_rings(struct i40e_vsi *vsi) int i; if (vsi->tx_rings[0]) - for (i = 0; i < vsi->alloc_queue_pairs; i++) { + for (i = 0; i < vsi->num_queue_pairs; i++) { kfree_rcu(vsi->tx_rings[i], rcu); vsi->tx_rings[i] = NULL; vsi->rx_rings[i] = NULL; @@ -5284,10 +5283,11 @@ static int i40e_alloc_rings(struct i40e_vsi *vsi) int i; /* Set basic values in the rings to be used later during open() */ - for (i = 0; i < vsi->alloc_queue_pairs; i++) { + for (i = 0; i < vsi->num_queue_pairs; i++) { struct i40e_ring *tx_ring; struct i40e_ring *rx_ring; + /* allocate space for both Tx and Rx in one shot */ tx_ring = kzalloc(sizeof(struct i40e_ring) * 2, GFP_KERNEL); if (!tx_ring) goto err_out; @@ -5858,7 +5858,7 @@ static int i40e_config_netdev(struct i40e_vsi *vsi) int etherdev_size; etherdev_size = sizeof(struct i40e_netdev_priv); - netdev = alloc_etherdev_mq(etherdev_size, vsi->alloc_queue_pairs); + netdev = alloc_etherdev_mq(etherdev_size, vsi->num_queue_pairs); if (!netdev) return -ENOMEM; @@ -6939,8 +6939,8 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf) * into the pf, since this newer code pushes the pf queue * info down a level into a VSI */ - pf->num_rx_queues = vsi->alloc_queue_pairs; - pf->num_tx_queues = vsi->alloc_queue_pairs; + pf->num_rx_queues = vsi->num_queue_pairs; + pf->num_tx_queues = vsi->num_queue_pairs; } else { /* force a reset of TC and queue layout configurations */ u8 enabled_tc = pf->vsi[pf->lan_vsi]->tc_config.enabled_tc; -- cgit v1.2.3-70-g09d2 From c140c17b98f246d736e20757e39ec597fae7bc9e Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 20 Nov 2013 10:02:58 +0000 Subject: i40e: clear test state bit after all ethtool tests Fix a bug where the TESTING state was still set when exiting the ethtool diagnostics. Change-Id: Ic47950d2e86a67167d1d282256d477cecd86d820 Signed-off-by: Shannon Nelson Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 7fb669bd047..44d4a7f8478 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -805,9 +805,10 @@ static void i40e_diag_test(struct net_device *netdev, data[I40E_ETH_TEST_EEPROM] = 0; data[I40E_ETH_TEST_INTR] = 0; data[I40E_ETH_TEST_LOOPBACK] = 0; - - clear_bit(__I40E_TESTING, &pf->state); } + clear_bit(__I40E_TESTING, &pf->state); + + netdev_info(netdev, "testing finished\n"); } static void i40e_get_wol(struct net_device *netdev, -- cgit v1.2.3-70-g09d2 From 7b0863977f097190fc91d949fea16741d92c30ce Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 20 Nov 2013 10:02:59 +0000 Subject: i40e: refactor ethtool tests Put the print and reset statements in the actual test functions to make them more self-contained, and only run the reset for tests that need it. Change-Id: Ic70f49b11bf8bae82e59d8fd25b46215c90c4510 Signed-off-by: Shannon Nelson Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 57 ++++++++++++++------------ 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 44d4a7f8478..f0bab1704dd 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -706,8 +706,12 @@ static int i40e_get_ts_info(struct net_device *dev, return ethtool_op_get_ts_info(dev, info); } -static int i40e_link_test(struct i40e_pf *pf, u64 *data) +static int i40e_link_test(struct net_device *netdev, u64 *data) { + struct i40e_netdev_priv *np = netdev_priv(netdev); + struct i40e_pf *pf = np->vsi->back; + + netdev_info(netdev, "link test\n"); if (i40e_get_link_status(&pf->hw)) *data = 0; else @@ -716,30 +720,36 @@ static int i40e_link_test(struct i40e_pf *pf, u64 *data) return *data; } -static int i40e_reg_test(struct i40e_pf *pf, u64 *data) +static int i40e_reg_test(struct net_device *netdev, u64 *data) { - i40e_status ret; + struct i40e_netdev_priv *np = netdev_priv(netdev); + struct i40e_pf *pf = np->vsi->back; - ret = i40e_diag_reg_test(&pf->hw); - *data = ret; + netdev_info(netdev, "register test\n"); + *data = i40e_diag_reg_test(&pf->hw); - return ret; + i40e_do_reset(pf, (1 << __I40E_PF_RESET_REQUESTED)); + return *data; } -static int i40e_eeprom_test(struct i40e_pf *pf, u64 *data) +static int i40e_eeprom_test(struct net_device *netdev, u64 *data) { - i40e_status ret; + struct i40e_netdev_priv *np = netdev_priv(netdev); + struct i40e_pf *pf = np->vsi->back; - ret = i40e_diag_eeprom_test(&pf->hw); - *data = ret; + netdev_info(netdev, "eeprom test\n"); + *data = i40e_diag_eeprom_test(&pf->hw); - return ret; + return *data; } -static int i40e_intr_test(struct i40e_pf *pf, u64 *data) +static int i40e_intr_test(struct net_device *netdev, u64 *data) { + struct i40e_netdev_priv *np = netdev_priv(netdev); + struct i40e_pf *pf = np->vsi->back; u16 swc_old = pf->sw_int_count; + netdev_info(netdev, "interrupt test\n"); wr32(&pf->hw, I40E_PFINT_DYN_CTL0, (I40E_PFINT_DYN_CTL0_INTENA_MASK | I40E_PFINT_DYN_CTL0_SWINT_TRIG_MASK)); @@ -749,8 +759,9 @@ static int i40e_intr_test(struct i40e_pf *pf, u64 *data) return *data; } -static int i40e_loopback_test(struct i40e_pf *pf, u64 *data) +static int i40e_loopback_test(struct net_device *netdev, u64 *data) { + netdev_info(netdev, "loopback test not implemented\n"); *data = 0; return *data; @@ -771,33 +782,25 @@ static void i40e_diag_test(struct net_device *netdev, /* Link test performed before hardware reset * so autoneg doesn't interfere with test result */ - netdev_info(netdev, "link test starting\n"); - if (i40e_link_test(pf, &data[I40E_ETH_TEST_LINK])) + if (i40e_link_test(netdev, &data[I40E_ETH_TEST_LINK])) eth_test->flags |= ETH_TEST_FL_FAILED; - netdev_info(netdev, "register test starting\n"); - if (i40e_reg_test(pf, &data[I40E_ETH_TEST_REG])) + if (i40e_reg_test(netdev, &data[I40E_ETH_TEST_REG])) eth_test->flags |= ETH_TEST_FL_FAILED; - i40e_do_reset(pf, (1 << __I40E_PF_RESET_REQUESTED)); - netdev_info(netdev, "eeprom test starting\n"); - if (i40e_eeprom_test(pf, &data[I40E_ETH_TEST_EEPROM])) + if (i40e_eeprom_test(netdev, &data[I40E_ETH_TEST_EEPROM])) eth_test->flags |= ETH_TEST_FL_FAILED; - i40e_do_reset(pf, (1 << __I40E_PF_RESET_REQUESTED)); - netdev_info(netdev, "interrupt test starting\n"); - if (i40e_intr_test(pf, &data[I40E_ETH_TEST_INTR])) + if (i40e_intr_test(netdev, &data[I40E_ETH_TEST_INTR])) eth_test->flags |= ETH_TEST_FL_FAILED; - i40e_do_reset(pf, (1 << __I40E_PF_RESET_REQUESTED)); - netdev_info(netdev, "loopback test starting\n"); - if (i40e_loopback_test(pf, &data[I40E_ETH_TEST_LOOPBACK])) + if (i40e_loopback_test(netdev, &data[I40E_ETH_TEST_LOOPBACK])) eth_test->flags |= ETH_TEST_FL_FAILED; } else { netdev_info(netdev, "online test starting\n"); /* Online tests */ - if (i40e_link_test(pf, &data[I40E_ETH_TEST_LINK])) + if (i40e_link_test(netdev, &data[I40E_ETH_TEST_LINK])) eth_test->flags |= ETH_TEST_FL_FAILED; /* Offline only tests, not run in online; pass by default */ -- cgit v1.2.3-70-g09d2 From 4a38d09cd9e27d81aaa04891dc1f7d7c81677c5a Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Wed, 20 Nov 2013 10:03:00 +0000 Subject: i40e: add num_VFs message Print a message to notify the user of how many VFs are initialized on each port. Change-Id: I29ac2acc478ee4e588fd6ffcc35133d4c6607ca9 Signed-off-by: Anjali Singhai Jain Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index aae2f04ab0a..08ac9604ec6 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -5765,6 +5765,9 @@ static int i40e_sw_init(struct i40e_pf *pf) pf->num_req_vfs = min_t(int, pf->hw.func_caps.num_vfs, I40E_MAX_VF_COUNT); + dev_info(&pf->pdev->dev, + "Number of VFs being requested for PF[%d] = %d\n", + pf->hw.pf_id, pf->num_req_vfs); } #endif /* CONFIG_PCI_IOV */ pf->eeprom_version = 0xDEAD; -- cgit v1.2.3-70-g09d2 From 93cd765bb27365e7be92c510c73b017426eb490d Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Wed, 20 Nov 2013 10:03:01 +0000 Subject: i40e: Add a new variable to track number of pf instances Track the number of physical functions (PFs) found, this is a global counter on purpose so that each pf loaded has a unique ID. Change-Id: I74d618520afbce4a774d0235449e3b5f97ff6d4a Signed-off-by: Anjali Singhai Jain Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 2 ++ drivers/net/ethernet/intel/i40e/i40e_main.c | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 5aa2ea21aaa..001d7cfc912 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -276,6 +276,8 @@ struct i40e_pf { struct dentry *i40e_dbg_pf; #endif /* CONFIG_DEBUG_FS */ + u16 instance; /* A unique number per i40e_pf instance in the system */ + /* sr-iov config info */ struct i40e_vf *vf; int num_alloc_vfs; /* actual number of VFs allocated */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 08ac9604ec6..d2b48bb237f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -7176,6 +7176,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct i40e_driver_version dv; struct i40e_pf *pf; struct i40e_hw *hw; + static u16 pfs_found; int err = 0; u32 len; @@ -7241,6 +7242,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) hw->subsystem_device_id = pdev->subsystem_device; hw->bus.device = PCI_SLOT(pdev->devfn); hw->bus.func = PCI_FUNC(pdev->devfn); + pf->instance = pfs_found; /* do a special CORER for clearing PXE mode once at init */ if (hw->revision_id == 0 && @@ -7391,6 +7393,8 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) i40e_flush(hw); } + pfs_found++; + i40e_dbg_pf_init(pf); /* tell the firmware that we're starting */ -- cgit v1.2.3-70-g09d2 From c6d1649050aa7da42f9c0901dc7fa3971254648f Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 7 Dec 2013 09:06:24 -0800 Subject: Bluetooth: Increase minor version of core module With the addition of L2CAP Connection Oriented Channels for Bluetooth Low Energy connections, it makes sense to increase the minor version of the Bluetooth core module. The module version is not used anywhere, but it gives a nice extra hint for debugging purposes. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/af_bluetooth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 56ca494621c..0c5866bb49b 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -31,7 +31,7 @@ #include #include -#define VERSION "2.17" +#define VERSION "2.18" /* Bluetooth sockets */ #define BT_MAX_PROTO 8 -- cgit v1.2.3-70-g09d2 From e569bdab35fd0d31cecb6b072e95af1834991f9d Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Sat, 30 Nov 2013 11:56:17 +0100 Subject: netfilter: nf_tables: fix issue with verdict support The test on verdict was simply done on the value of the verdict which is not correct as far as queue is concern. In fact, the test of verdict test must be done with respect to the verdict mask for verdicts which are not internal to nftables. Signed-off-by: Eric Leblond Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_tables_core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c index cb9e685caae..e8fcc343c2b 100644 --- a/net/netfilter/nf_tables_core.c +++ b/net/netfilter/nf_tables_core.c @@ -164,7 +164,7 @@ next_rule: break; } - switch (data[NFT_REG_VERDICT].verdict) { + switch (data[NFT_REG_VERDICT].verdict & NF_VERDICT_MASK) { case NF_ACCEPT: case NF_DROP: case NF_QUEUE: @@ -172,6 +172,9 @@ next_rule: nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE); return data[NFT_REG_VERDICT].verdict; + } + + switch (data[NFT_REG_VERDICT].verdict) { case NFT_JUMP: if (unlikely(pkt->skb->nf_trace)) nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE); -- cgit v1.2.3-70-g09d2 From 97a2d41c47a2246c3387a937c62126c9faefe875 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 6 Dec 2013 00:24:12 +0100 Subject: netfilter: xt_NFQUEUE: separate reusable code This patch prepares the addition of nft_queue module by moving reusable code into a header file. This patch also converts NFQUEUE to use prandom_u32 to initialize the random jhash seed as suggested by Florian Westphal. Signed-off-by: Eric Leblond Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_queue.h | 62 +++++++++++++++++++++++++++++++ net/netfilter/xt_NFQUEUE.c | 80 ++++++---------------------------------- 2 files changed, 74 insertions(+), 68 deletions(-) diff --git a/include/net/netfilter/nf_queue.h b/include/net/netfilter/nf_queue.h index c1d5b3e34a2..84a53d78030 100644 --- a/include/net/netfilter/nf_queue.h +++ b/include/net/netfilter/nf_queue.h @@ -1,6 +1,10 @@ #ifndef _NF_QUEUE_H #define _NF_QUEUE_H +#include +#include +#include + /* Each queued (to userspace) skbuff has one of these. */ struct nf_queue_entry { struct list_head list; @@ -33,4 +37,62 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict); bool nf_queue_entry_get_refs(struct nf_queue_entry *entry); void nf_queue_entry_release_refs(struct nf_queue_entry *entry); +static inline void init_hashrandom(u32 *jhash_initval) +{ + while (*jhash_initval == 0) + *jhash_initval = prandom_u32(); +} + +static inline u32 hash_v4(const struct sk_buff *skb, u32 jhash_initval) +{ + const struct iphdr *iph = ip_hdr(skb); + + /* packets in either direction go into same queue */ + if ((__force u32)iph->saddr < (__force u32)iph->daddr) + return jhash_3words((__force u32)iph->saddr, + (__force u32)iph->daddr, iph->protocol, jhash_initval); + + return jhash_3words((__force u32)iph->daddr, + (__force u32)iph->saddr, iph->protocol, jhash_initval); +} + +#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) +static inline u32 hash_v6(const struct sk_buff *skb, u32 jhash_initval) +{ + const struct ipv6hdr *ip6h = ipv6_hdr(skb); + u32 a, b, c; + + if ((__force u32)ip6h->saddr.s6_addr32[3] < + (__force u32)ip6h->daddr.s6_addr32[3]) { + a = (__force u32) ip6h->saddr.s6_addr32[3]; + b = (__force u32) ip6h->daddr.s6_addr32[3]; + } else { + b = (__force u32) ip6h->saddr.s6_addr32[3]; + a = (__force u32) ip6h->daddr.s6_addr32[3]; + } + + if ((__force u32)ip6h->saddr.s6_addr32[1] < + (__force u32)ip6h->daddr.s6_addr32[1]) + c = (__force u32) ip6h->saddr.s6_addr32[1]; + else + c = (__force u32) ip6h->daddr.s6_addr32[1]; + + return jhash_3words(a, b, c, jhash_initval); +} +#endif + +static inline u32 +nfqueue_hash(const struct sk_buff *skb, u16 queue, u16 queues_total, u8 family, + u32 jhash_initval) +{ + if (family == NFPROTO_IPV4) + queue += ((u64) hash_v4(skb, jhash_initval) * queues_total) >> 32; +#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) + else if (family == NFPROTO_IPV6) + queue += ((u64) hash_v6(skb, jhash_initval) * queues_total) >> 32; +#endif + + return queue; +} + #endif /* _NF_QUEUE_H */ diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c index ed00fef5899..8f1779ff7e3 100644 --- a/net/netfilter/xt_NFQUEUE.c +++ b/net/netfilter/xt_NFQUEUE.c @@ -11,15 +11,13 @@ #include #include -#include -#include -#include - #include #include #include #include +#include + MODULE_AUTHOR("Harald Welte "); MODULE_DESCRIPTION("Xtables: packet forwarding to netlink"); MODULE_LICENSE("GPL"); @@ -28,7 +26,6 @@ MODULE_ALIAS("ip6t_NFQUEUE"); MODULE_ALIAS("arpt_NFQUEUE"); static u32 jhash_initval __read_mostly; -static bool rnd_inited __read_mostly; static unsigned int nfqueue_tg(struct sk_buff *skb, const struct xt_action_param *par) @@ -38,69 +35,16 @@ nfqueue_tg(struct sk_buff *skb, const struct xt_action_param *par) return NF_QUEUE_NR(tinfo->queuenum); } -static u32 hash_v4(const struct sk_buff *skb) -{ - const struct iphdr *iph = ip_hdr(skb); - - /* packets in either direction go into same queue */ - if ((__force u32)iph->saddr < (__force u32)iph->daddr) - return jhash_3words((__force u32)iph->saddr, - (__force u32)iph->daddr, iph->protocol, jhash_initval); - - return jhash_3words((__force u32)iph->daddr, - (__force u32)iph->saddr, iph->protocol, jhash_initval); -} - -#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) -static u32 hash_v6(const struct sk_buff *skb) -{ - const struct ipv6hdr *ip6h = ipv6_hdr(skb); - u32 a, b, c; - - if ((__force u32)ip6h->saddr.s6_addr32[3] < - (__force u32)ip6h->daddr.s6_addr32[3]) { - a = (__force u32) ip6h->saddr.s6_addr32[3]; - b = (__force u32) ip6h->daddr.s6_addr32[3]; - } else { - b = (__force u32) ip6h->saddr.s6_addr32[3]; - a = (__force u32) ip6h->daddr.s6_addr32[3]; - } - - if ((__force u32)ip6h->saddr.s6_addr32[1] < - (__force u32)ip6h->daddr.s6_addr32[1]) - c = (__force u32) ip6h->saddr.s6_addr32[1]; - else - c = (__force u32) ip6h->daddr.s6_addr32[1]; - - return jhash_3words(a, b, c, jhash_initval); -} -#endif - -static u32 -nfqueue_hash(const struct sk_buff *skb, const struct xt_action_param *par) -{ - const struct xt_NFQ_info_v1 *info = par->targinfo; - u32 queue = info->queuenum; - - if (par->family == NFPROTO_IPV4) - queue += ((u64) hash_v4(skb) * info->queues_total) >> 32; -#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) - else if (par->family == NFPROTO_IPV6) - queue += ((u64) hash_v6(skb) * info->queues_total) >> 32; -#endif - - return queue; -} - static unsigned int nfqueue_tg_v1(struct sk_buff *skb, const struct xt_action_param *par) { const struct xt_NFQ_info_v1 *info = par->targinfo; u32 queue = info->queuenum; - if (info->queues_total > 1) - queue = nfqueue_hash(skb, par); - + if (info->queues_total > 1) { + queue = nfqueue_hash(skb, queue, info->queues_total, + par->family, jhash_initval); + } return NF_QUEUE_NR(queue); } @@ -120,10 +64,8 @@ static int nfqueue_tg_check(const struct xt_tgchk_param *par) const struct xt_NFQ_info_v3 *info = par->targinfo; u32 maxid; - if (unlikely(!rnd_inited)) { - get_random_bytes(&jhash_initval, sizeof(jhash_initval)); - rnd_inited = true; - } + init_hashrandom(&jhash_initval); + if (info->queues_total == 0) { pr_err("NFQUEUE: number of total queues is 0\n"); return -EINVAL; @@ -154,8 +96,10 @@ nfqueue_tg_v3(struct sk_buff *skb, const struct xt_action_param *par) int cpu = smp_processor_id(); queue = info->queuenum + cpu % info->queues_total; - } else - queue = nfqueue_hash(skb, par); + } else { + queue = nfqueue_hash(skb, queue, info->queues_total, + par->family, jhash_initval); + } } ret = NF_QUEUE_NR(queue); -- cgit v1.2.3-70-g09d2 From 0aff078d58e1c69139189e45ba5e929c030e8056 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 6 Dec 2013 00:24:13 +0100 Subject: netfilter: nft: add queue module This patch adds a new nft module named "nft_queue" which provides a new nftables expression that allows you to enqueue packets to userspace via the nfnetlink_queue subsystem. It provides the same level of functionality as NFQUEUE and it shares some code with it. Signed-off-by: Eric Leblond Signed-off-by: Pablo Neira Ayuso --- include/uapi/linux/netfilter/nf_tables.h | 20 +++++ net/netfilter/Kconfig | 9 +++ net/netfilter/Makefile | 1 + net/netfilter/nft_queue.c | 134 +++++++++++++++++++++++++++++++ 4 files changed, 164 insertions(+) create mode 100644 net/netfilter/nft_queue.c diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h index fbfd229a8e9..256d36b1b94 100644 --- a/include/uapi/linux/netfilter/nf_tables.h +++ b/include/uapi/linux/netfilter/nf_tables.h @@ -657,6 +657,26 @@ enum nft_log_attributes { }; #define NFTA_LOG_MAX (__NFTA_LOG_MAX - 1) +/** + * enum nft_queue_attributes - nf_tables queue expression netlink attributes + * + * @NFTA_QUEUE_NUM: netlink queue to send messages to (NLA_U16) + * @NFTA_QUEUE_TOTAL: number of queues to load balance packets on (NLA_U16) + * @NFTA_QUEUE_FLAGS: various flags (NLA_U16) + */ +enum nft_queue_attributes { + NFTA_QUEUE_UNSPEC, + NFTA_QUEUE_NUM, + NFTA_QUEUE_TOTAL, + NFTA_QUEUE_FLAGS, + __NFTA_QUEUE_MAX +}; +#define NFTA_QUEUE_MAX (__NFTA_QUEUE_MAX - 1) + +#define NFT_QUEUE_FLAG_BYPASS 0x01 /* for compatibility with v2 */ +#define NFT_QUEUE_FLAG_CPU_FANOUT 0x02 /* use current CPU (no hashing) */ +#define NFT_QUEUE_FLAG_MASK 0x03 + /** * enum nft_reject_types - nf_tables reject expression reject types * diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 48acec17e27..4371c9819d9 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -456,6 +456,15 @@ config NFT_NAT depends on NF_NAT tristate "Netfilter nf_tables nat module" +config NFT_QUEUE + depends on NF_TABLES + depends on NETFILTER_XTABLES + depends on NETFILTER_NETLINK_QUEUE + tristate "Netfilter nf_tables queue module" + help + This is required if you intend to use the userspace queueing + infrastructure (also known as NFQUEUE) from nftables. + config NFT_COMPAT depends on NF_TABLES depends on NETFILTER_XTABLES diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 394483b2c19..e7637463226 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -76,6 +76,7 @@ obj-$(CONFIG_NFT_META) += nft_meta.o obj-$(CONFIG_NFT_CT) += nft_ct.o obj-$(CONFIG_NFT_LIMIT) += nft_limit.o obj-$(CONFIG_NFT_NAT) += nft_nat.o +obj-$(CONFIG_NFT_QUEUE) += nft_queue.o #nf_tables-objs += nft_meta_target.o obj-$(CONFIG_NFT_RBTREE) += nft_rbtree.o obj-$(CONFIG_NFT_HASH) += nft_hash.o diff --git a/net/netfilter/nft_queue.c b/net/netfilter/nft_queue.c new file mode 100644 index 00000000000..cbea473d69e --- /dev/null +++ b/net/netfilter/nft_queue.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2013 Eric Leblond + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Development of this code partly funded by OISF + * (http://www.openinfosecfoundation.org/) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static u32 jhash_initval __read_mostly; + +struct nft_queue { + u16 queuenum; + u16 queues_total; + u16 flags; + u8 family; +}; + +static void nft_queue_eval(const struct nft_expr *expr, + struct nft_data data[NFT_REG_MAX + 1], + const struct nft_pktinfo *pkt) +{ + struct nft_queue *priv = nft_expr_priv(expr); + u32 queue = priv->queuenum; + u32 ret; + + if (priv->queues_total > 1) { + if (priv->flags & NFT_QUEUE_FLAG_CPU_FANOUT) { + int cpu = smp_processor_id(); + + queue = priv->queuenum + cpu % priv->queues_total; + } else { + queue = nfqueue_hash(pkt->skb, queue, + priv->queues_total, priv->family, + jhash_initval); + } + } + + ret = NF_QUEUE_NR(queue); + if (priv->flags & NFT_QUEUE_FLAG_BYPASS) + ret |= NF_VERDICT_FLAG_QUEUE_BYPASS; + + data[NFT_REG_VERDICT].verdict = ret; +} + +static const struct nla_policy nft_queue_policy[NFTA_QUEUE_MAX + 1] = { + [NFTA_QUEUE_NUM] = { .type = NLA_U16 }, + [NFTA_QUEUE_TOTAL] = { .type = NLA_U16 }, + [NFTA_QUEUE_FLAGS] = { .type = NLA_U16 }, +}; + +static int nft_queue_init(const struct nft_ctx *ctx, + const struct nft_expr *expr, + const struct nlattr * const tb[]) +{ + struct nft_queue *priv = nft_expr_priv(expr); + + if (tb[NFTA_QUEUE_NUM] == NULL) + return -EINVAL; + + init_hashrandom(&jhash_initval); + priv->family = ctx->afi->family; + priv->queuenum = ntohs(nla_get_be16(tb[NFTA_QUEUE_NUM])); + + if (tb[NFTA_QUEUE_TOTAL] != NULL) + priv->queues_total = ntohs(nla_get_be16(tb[NFTA_QUEUE_TOTAL])); + if (tb[NFTA_QUEUE_FLAGS] != NULL) { + priv->flags = ntohs(nla_get_be16(tb[NFTA_QUEUE_FLAGS])); + if (priv->flags & ~NFT_QUEUE_FLAG_MASK) + return -EINVAL; + } + return 0; +} + +static int nft_queue_dump(struct sk_buff *skb, const struct nft_expr *expr) +{ + const struct nft_queue *priv = nft_expr_priv(expr); + + if (nla_put_be16(skb, NFTA_QUEUE_NUM, htons(priv->queuenum)) || + nla_put_be16(skb, NFTA_QUEUE_TOTAL, htons(priv->queues_total)) || + nla_put_be16(skb, NFTA_QUEUE_FLAGS, htons(priv->flags))) + goto nla_put_failure; + + return 0; + +nla_put_failure: + return -1; +} + +static struct nft_expr_type nft_queue_type; +static const struct nft_expr_ops nft_queue_ops = { + .type = &nft_queue_type, + .size = NFT_EXPR_SIZE(sizeof(struct nft_queue)), + .eval = nft_queue_eval, + .init = nft_queue_init, + .dump = nft_queue_dump, +}; + +static struct nft_expr_type nft_queue_type __read_mostly = { + .name = "queue", + .ops = &nft_queue_ops, + .policy = nft_queue_policy, + .maxattr = NFTA_QUEUE_MAX, + .owner = THIS_MODULE, +}; + +static int __init nft_queue_module_init(void) +{ + return nft_register_expr(&nft_queue_type); +} + +static void __exit nft_queue_module_exit(void) +{ + nft_unregister_expr(&nft_queue_type); +} + +module_init(nft_queue_module_init); +module_exit(nft_queue_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Eric Leblond "); +MODULE_ALIAS_NFT_EXPR("queue"); -- cgit v1.2.3-70-g09d2 From 53b834d2333aec1e60fcbfadfddd4ad472329570 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 8 Dec 2013 11:55:33 -0800 Subject: Bluetooth: Use macros for connectionless slave broadcast features Add the LMP feature constants for connectionless slave broadcast and use them for capability testing. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 6 ++++++ include/net/bluetooth/hci_core.h | 6 ++++++ net/bluetooth/hci_core.c | 6 +++--- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 1784c48699f..cc2da73055f 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -275,6 +275,12 @@ enum { #define LMP_EXTFEATURES 0x80 /* Extended LMP features */ +#define LMP_CSB_MASTER 0x01 +#define LMP_CSB_SLAVE 0x02 +#define LMP_SYNC_TRAIN 0x04 +#define LMP_SYNC_SCAN 0x08 + +/* Host features */ #define LMP_HOST_SSP 0x01 #define LMP_HOST_LE 0x02 #define LMP_HOST_LE_BREDR 0x04 diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index f8555ad7b10..b796161fb04 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -798,6 +798,12 @@ void hci_conn_del_sysfs(struct hci_conn *conn); #define lmp_transp_capable(dev) ((dev)->features[0][2] & LMP_TRANSPARENT) /* ----- Extended LMP capabilities ----- */ +#define lmp_csb_master_capable(dev) ((dev)->features[2][0] & LMP_CSB_MASTER) +#define lmp_csb_slave_capable(dev) ((dev)->features[2][0] & LMP_CSB_SLAVE) +#define lmp_sync_train_capable(dev) ((dev)->features[2][0] & LMP_SYNC_TRAIN) +#define lmp_sync_scan_capable(dev) ((dev)->features[2][0] & LMP_SYNC_SCAN) + +/* ----- Host capabilities ----- */ #define lmp_host_ssp_capable(dev) ((dev)->features[1][0] & LMP_HOST_SSP) #define lmp_host_le_capable(dev) (!!((dev)->features[1][0] & LMP_HOST_LE)) #define lmp_host_le_br_capable(dev) (!!((dev)->features[1][0] & LMP_HOST_LE_BREDR)) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 03e83558a41..8b8b5f80dd8 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1228,7 +1228,7 @@ static void hci_set_event_mask_page_2(struct hci_request *req) /* If Connectionless Slave Broadcast master role is supported * enable all necessary events for it. */ - if (hdev->features[2][0] & 0x01) { + if (lmp_csb_master_capable(hdev)) { events[1] |= 0x40; /* Triggered Clock Capture */ events[1] |= 0x80; /* Synchronization Train Complete */ events[2] |= 0x10; /* Slave Page Response Timeout */ @@ -1238,7 +1238,7 @@ static void hci_set_event_mask_page_2(struct hci_request *req) /* If Connectionless Slave Broadcast slave role is supported * enable all necessary events for it. */ - if (hdev->features[2][0] & 0x02) { + if (lmp_csb_slave_capable(hdev)) { events[2] |= 0x01; /* Synchronization Train Received */ events[2] |= 0x02; /* CSB Receive */ events[2] |= 0x04; /* CSB Timeout */ @@ -1309,7 +1309,7 @@ static void hci_init4_req(struct hci_request *req, unsigned long opt) hci_set_event_mask_page_2(req); /* Check for Synchronization Train support */ - if (hdev->features[2][0] & 0x04) + if (lmp_sync_train_capable(hdev)) hci_req_add(req, HCI_OP_READ_SYNC_TRAIN_PARAMS, 0, NULL); } -- cgit v1.2.3-70-g09d2 From 3961a61aad9b711bcd74aa7ea2c3655046df7b43 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 22 Oct 2013 11:27:55 +0300 Subject: iwlwifi: remove TX_CMD id from transport layer The transport layer doesn't need to know the TX_CMD id. It can be set by the op_mode. The transport layer still needs to know the layout of the Tx command because of alignment issues and because of the scratch pointer. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/tx.c | 1 + drivers/net/wireless/iwlwifi/mvm/tx.c | 1 + drivers/net/wireless/iwlwifi/pcie/tx.c | 1 - 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c index 1fef5240e6a..e12b1a63c48 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/iwlwifi/dvm/tx.c @@ -368,6 +368,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, goto drop_unlock_priv; memset(dev_cmd, 0, sizeof(*dev_cmd)); + dev_cmd->hdr.cmd = REPLY_TX; tx_cmd = (struct iwl_tx_cmd *) dev_cmd->payload; /* Total # bytes to be transmitted */ diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 43d97c33a75..1f194580642 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -276,6 +276,7 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb, return NULL; memset(dev_cmd, 0, sizeof(*dev_cmd)); + dev_cmd->hdr.cmd = TX_CMD; tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload; if (info->control.hw_key) diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 0adde919a25..ff977b08341 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -1674,7 +1674,6 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, txq->entries[q->write_ptr].skb = skb; txq->entries[q->write_ptr].cmd = dev_cmd; - dev_cmd->hdr.cmd = REPLY_TX; dev_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) | INDEX_TO_SEQ(q->write_ptr))); -- cgit v1.2.3-70-g09d2 From 119663c3603412962f2986c1318950aef7421b1f Mon Sep 17 00:00:00 2001 From: Alexander Bondar Date: Thu, 17 Oct 2013 14:26:50 +0200 Subject: iwlwifi: mvm: Add debugfs entry to generate NMI to NIC Writting to fw_nmi entry will set DEVICE_SET_NMI_REG (0x00a01c30) generating NMI that halts NIC CPU. Reviewed-by: Johannes Berg Signed-off-by: Alexander Bondar Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-prph.h | 3 +++ drivers/net/wireless/iwlwifi/mvm/debugfs.c | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index a70c7b9d9ba..f6412dae265 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -102,6 +102,9 @@ /* Device system time */ #define DEVICE_SYSTEM_TIME_REG 0xA0206C +/* Device NMI register */ +#define DEVICE_SET_NMI_REG 0x00a01c30 + /***************************************************************************** * 7000/3000 series SHR DTS addresses * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index a8fe6b41f9a..342bd1a07ab 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -63,6 +63,7 @@ #include "mvm.h" #include "sta.h" #include "iwl-io.h" +#include "iwl-prph.h" struct iwl_dbgfs_mvm_ctx { struct iwl_mvm *mvm; @@ -804,6 +805,17 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct file *file, return count; } +static ssize_t iwl_dbgfs_fw_nmi_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_mvm *mvm = file->private_data; + + iwl_write_prph(mvm->trans, DEVICE_SET_NMI_REG, 1); + + return count; +} + static ssize_t iwl_dbgfs_scan_ant_rxchain_read(struct file *file, char __user *user_buf, @@ -1168,6 +1180,7 @@ MVM_DEBUGFS_READ_FILE_OPS(bt_cmd); MVM_DEBUGFS_READ_WRITE_FILE_OPS(disable_power_off); MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats); MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart); +MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi); MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain); #ifdef CONFIG_PM_SLEEP @@ -1196,6 +1209,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) S_IRUSR | S_IWUSR); MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, S_IRUSR); MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR); + MVM_DEBUGFS_ADD_FILE(fw_nmi, mvm->debugfs_dir, S_IWUSR); MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir, S_IWUSR | S_IRUSR); #ifdef CONFIG_PM_SLEEP -- cgit v1.2.3-70-g09d2 From 6dde8c4837128aa840851bb0b547708868494198 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 31 Oct 2013 18:30:38 +0100 Subject: iwlwifi: pcie: remove useless condition test After wait_event_timeout(), the condition must still be true if it returns >0, in fact almost the last thing in it is checking the condition again. It's therefore not useful to check yet again in our code, clean it up. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/tx.c | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index ff977b08341..a4ef5cc1110 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -1542,30 +1542,24 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans, } if (!ret) { - if (test_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status)) { - struct iwl_txq *txq = - &trans_pcie->txq[trans_pcie->cmd_queue]; - struct iwl_queue *q = &txq->q; + struct iwl_txq *txq = &trans_pcie->txq[trans_pcie->cmd_queue]; + struct iwl_queue *q = &txq->q; - IWL_ERR(trans, - "Error sending %s: time out after %dms.\n", - get_cmd_string(trans_pcie, cmd->id), - jiffies_to_msecs(HOST_COMPLETE_TIMEOUT)); + IWL_ERR(trans, "Error sending %s: time out after %dms.\n", + get_cmd_string(trans_pcie, cmd->id), + jiffies_to_msecs(HOST_COMPLETE_TIMEOUT)); - IWL_ERR(trans, - "Current CMD queue read_ptr %d write_ptr %d\n", - q->read_ptr, q->write_ptr); + IWL_ERR(trans, "Current CMD queue read_ptr %d write_ptr %d\n", + q->read_ptr, q->write_ptr); - clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status); - IWL_DEBUG_INFO(trans, - "Clearing HCMD_ACTIVE for command %s\n", - get_cmd_string(trans_pcie, cmd->id)); - ret = -ETIMEDOUT; + clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status); + IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command %s\n", + get_cmd_string(trans_pcie, cmd->id)); + ret = -ETIMEDOUT; - iwl_nic_error(trans); + iwl_nic_error(trans); - goto cancel; - } + goto cancel; } if (test_bit(STATUS_FW_ERROR, &trans_pcie->status)) { -- cgit v1.2.3-70-g09d2 From 1a61b3477817e1a1473644b87c9c377dc08f74c4 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Sat, 9 Nov 2013 02:11:46 +0200 Subject: iwlwifi: mvm: fix and improve printing of rate scale table Info about VHT/HT rates wasn't printed properly when dumping the rate scale table. Fix that and print more info. While at it fix some other minor issues in the printing and prevent overflowing the print buffer. Signed-off-by: Eyal Shapira Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 91 ++++++++++++++++++++++++++++------- 1 file changed, 73 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index a0b4cc8d9c3..f7ac485f85e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -2566,13 +2566,75 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file, return count; } +static int rs_pretty_print_rate(char *buf, const u32 rate) +{ + static const char * const ant_name[] = { + [ANT_NONE] = "None", + [ANT_A] = "A", + [ANT_B] = "B", + [ANT_AB] = "AB", + [ANT_C] = "C", + [ANT_AC] = "AC", + [ANT_BC] = "BC", + [ANT_ABC] = "ABC", + }; + + char *type, *bw; + u8 mcs = 0, nss = 0; + u8 ant = (rate & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS; + + if (!(rate & RATE_MCS_HT_MSK) && + !(rate & RATE_MCS_VHT_MSK)) { + int index = iwl_hwrate_to_plcp_idx(rate); + + return sprintf(buf, "Legacy | ANT: %s Rate: %s Mbps\n", + ant_name[ant], iwl_rate_mcs[index].mbps); + } + + if (rate & RATE_MCS_VHT_MSK) { + type = "VHT"; + mcs = rate & RATE_VHT_MCS_RATE_CODE_MSK; + nss = ((rate & RATE_VHT_MCS_NSS_MSK) + >> RATE_VHT_MCS_NSS_POS) + 1; + } else if (rate & RATE_MCS_HT_MSK) { + type = "HT"; + mcs = rate & RATE_HT_MCS_INDEX_MSK; + } else { + type = "Unknown"; /* shouldn't happen */ + } + + switch (rate & RATE_MCS_CHAN_WIDTH_MSK) { + case RATE_MCS_CHAN_WIDTH_20: + bw = "20Mhz"; + break; + case RATE_MCS_CHAN_WIDTH_40: + bw = "40Mhz"; + break; + case RATE_MCS_CHAN_WIDTH_80: + bw = "80Mhz"; + break; + case RATE_MCS_CHAN_WIDTH_160: + bw = "160Mhz"; + break; + default: + bw = "BAD BW"; + } + + return sprintf(buf, "%s | ANT: %s BW: %s MCS: %d NSS: %d %s%s%s%s%s\n", + type, ant_name[ant], bw, mcs, nss, + (rate & RATE_MCS_SGI_MSK) ? "SGI " : "NGI ", + (rate & RATE_MCS_STBC_MSK) ? "STBC " : "", + (rate & RATE_MCS_LDPC_MSK) ? "LDPC " : "", + (rate & RATE_MCS_BF_MSK) ? "BF " : "", + (rate & RATE_MCS_ZLF_MSK) ? "ZLF " : ""); +} + static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { char *buff; int desc = 0; int i = 0; - int index = 0; ssize_t ret; struct iwl_lq_sta *lq_sta = file->private_data; @@ -2580,7 +2642,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); mvm = lq_sta->drv; - buff = kmalloc(1024, GFP_KERNEL); + buff = kmalloc(2048, GFP_KERNEL); if (!buff) return -ENOMEM; @@ -2597,7 +2659,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, desc += sprintf(buff+desc, "lq type %s\n", (is_legacy(tbl->lq_type)) ? "legacy" : is_vht(tbl->lq_type) ? "VHT" : "HT"); - if (is_ht(tbl->lq_type)) { + if (!is_legacy(tbl->lq_type)) { desc += sprintf(buff+desc, " %s", (is_siso(tbl->lq_type)) ? "SISO" : "MIMO2"); desc += sprintf(buff+desc, " %s", @@ -2605,13 +2667,13 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, (is_ht40(tbl)) ? "40MHz" : (is_ht80(tbl)) ? "80Mhz" : "BAD BW"); desc += sprintf(buff+desc, " %s %s\n", - (tbl->is_SGI) ? "SGI" : "", + (tbl->is_SGI) ? "SGI" : "NGI", (lq_sta->is_agg) ? "AGG on" : ""); } desc += sprintf(buff+desc, "last tx rate=0x%X\n", lq_sta->last_rate_n_flags); desc += sprintf(buff+desc, - "general: flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x\n", + "general: flags=0x%X mimo-d=%d s-ant=0x%x d-ant=0x%x\n", lq_sta->lq.flags, lq_sta->lq.mimo_delim, lq_sta->lq.single_stream_ant_msk, @@ -2631,19 +2693,12 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, lq_sta->lq.initial_rate_index[3]); for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { - index = iwl_hwrate_to_plcp_idx( - le32_to_cpu(lq_sta->lq.rs_table[i])); - if (is_legacy(tbl->lq_type)) { - desc += sprintf(buff+desc, " rate[%d] 0x%X %smbps\n", - i, le32_to_cpu(lq_sta->lq.rs_table[i]), - iwl_rate_mcs[index].mbps); - } else { - desc += sprintf(buff+desc, - " rate[%d] 0x%X %smbps (%s)\n", - i, le32_to_cpu(lq_sta->lq.rs_table[i]), - iwl_rate_mcs[index].mbps, - iwl_rate_mcs[index].mcs); - } + u32 rate = le32_to_cpu(lq_sta->lq.rs_table[i]); + desc += sprintf(buff+desc, + " rate[%d] 0x%X ", + i, rate); + + desc += rs_pretty_print_rate(buff+desc, rate); } ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc); -- cgit v1.2.3-70-g09d2 From 9e680946a48be7f7c074a60d8583b21815526d61 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Sat, 9 Nov 2013 00:16:16 +0200 Subject: iwlwifi: mvm: simplify iwl_mvm_send_lq_cmd Remove the flags parameter which should be set to sync or async according to whether this is called during sta init or not. Signed-off-by: Eyal Shapira Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mvm.h | 3 +-- drivers/net/wireless/iwlwifi/mvm/rs.c | 12 ++++++------ drivers/net/wireless/iwlwifi/mvm/sta.c | 2 +- drivers/net/wireless/iwlwifi/mvm/utils.c | 8 ++------ 4 files changed, 10 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index fed21ef4162..7992baabb88 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -750,8 +750,7 @@ iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif) #endif /* CONFIG_IWLWIFI_DEBUGFS */ /* rate scaling */ -int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, - u8 flags, bool init); +int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool init); /* power managment */ static inline int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index f7ac485f85e..0a640891b46 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -298,7 +298,7 @@ static void rs_program_fix_rate(struct iwl_mvm *mvm, if (lq_sta->dbg_fixed_rate) { rs_fill_link_cmd(NULL, NULL, lq_sta, lq_sta->dbg_fixed_rate); - iwl_mvm_send_lq_cmd(lq_sta->drv, &lq_sta->lq, CMD_ASYNC, false); + iwl_mvm_send_lq_cmd(lq_sta->drv, &lq_sta->lq, false); } } #endif @@ -855,7 +855,7 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, lq_sta->missed_rate_counter++; if (lq_sta->missed_rate_counter > IWL_MISSED_RATE_MAX) { lq_sta->missed_rate_counter = 0; - iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_ASYNC, false); + iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false); } /* Regardless, ignore this status info for outdated rate */ return; @@ -1667,7 +1667,7 @@ static void rs_update_rate_tbl(struct iwl_mvm *mvm, /* Update uCode's rate table. */ rate = rate_n_flags_from_tbl(mvm, tbl, index); rs_fill_link_cmd(mvm, sta, lq_sta, rate); - iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_ASYNC, false); + iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false); } static u8 rs_get_tid(struct iwl_lq_sta *lq_data, @@ -2064,7 +2064,7 @@ lq_update: "Switch current mcs: %X index: %d\n", tbl->current_rate, index); rs_fill_link_cmd(mvm, sta, lq_sta, tbl->current_rate); - iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_ASYNC, false); + iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false); } else { done_search = 1; } @@ -2168,7 +2168,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, rs_set_expected_tpt_table(lq_sta, tbl); rs_fill_link_cmd(NULL, NULL, lq_sta, rate); /* TODO restore station should remember the lq cmd */ - iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_SYNC, true); + iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, true); } static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta, @@ -2841,5 +2841,5 @@ int iwl_mvm_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, lq->flags &= ~LQ_FLAG_SET_STA_TLC_RTS_MSK; } - return iwl_mvm_send_lq_cmd(mvm, lq, CMD_ASYNC, false); + return iwl_mvm_send_lq_cmd(mvm, lq, false); } diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 329952363a5..c89232c8aa7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -945,7 +945,7 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, */ } - return iwl_mvm_send_lq_cmd(mvm, &mvmsta->lq_sta.lq, CMD_ASYNC, false); + return iwl_mvm_send_lq_cmd(mvm, &mvmsta->lq_sta.lq, false); } int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index ed69e9b78e8..56cf819bc0c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -486,22 +486,18 @@ void iwl_mvm_dump_sram(struct iwl_mvm *mvm) * this case to clear the state indicating that station creation is in * progress. */ -int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, - u8 flags, bool init) +int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool init) { struct iwl_host_cmd cmd = { .id = LQ_CMD, .len = { sizeof(struct iwl_lq_cmd), }, - .flags = flags, + .flags = init ? CMD_SYNC : CMD_ASYNC, .data = { lq, }, }; if (WARN_ON(lq->sta_id == IWL_MVM_STATION_COUNT)) return -EINVAL; - if (WARN_ON(init && (cmd.flags & CMD_ASYNC))) - return -EINVAL; - return iwl_mvm_send_cmd(mvm, &cmd); } -- cgit v1.2.3-70-g09d2 From 750a1b456fb655614bdf20c9e3b7c0b523822ab2 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Sat, 9 Nov 2013 22:48:56 +0200 Subject: iwlwifi: mvm: refactor iwl_mvm_rs_rate_init Refactor setting of VHT enabled rates in preparation of adding some more logic there. Signed-off-by: Eyal Shapira Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 49 ++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 0a640891b46..e49bf445fa7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -2242,6 +2242,33 @@ static int rs_vht_highest_rx_mcs_index(struct ieee80211_sta_vht_cap *vht_cap, return -1; } +static void rs_vht_set_enabled_rates(struct ieee80211_sta *sta, + struct ieee80211_sta_vht_cap *vht_cap, + struct iwl_lq_sta *lq_sta) +{ + int i; + int highest_mcs = rs_vht_highest_rx_mcs_index(vht_cap, 1); + + if (highest_mcs >= IWL_RATE_MCS_0_INDEX) { + for (i = IWL_RATE_MCS_0_INDEX; i <= highest_mcs; i++) { + if (i == IWL_RATE_9M_INDEX) + continue; + + lq_sta->active_siso_rate |= BIT(i); + } + } + + highest_mcs = rs_vht_highest_rx_mcs_index(vht_cap, 2); + if (highest_mcs >= IWL_RATE_MCS_0_INDEX) { + for (i = IWL_RATE_MCS_0_INDEX; i <= highest_mcs; i++) { + if (i == IWL_RATE_9M_INDEX) + continue; + + lq_sta->active_mimo2_rate |= BIT(i); + } + } +} + /* * Called after adding a new station to initialize rate scaling */ @@ -2308,27 +2335,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, lq_sta->is_vht = false; } else { - int highest_mcs = rs_vht_highest_rx_mcs_index(vht_cap, 1); - if (highest_mcs >= IWL_RATE_MCS_0_INDEX) { - for (i = IWL_RATE_MCS_0_INDEX; i <= highest_mcs; i++) { - if (i == IWL_RATE_9M_INDEX) - continue; - - lq_sta->active_siso_rate |= BIT(i); - } - } - - highest_mcs = rs_vht_highest_rx_mcs_index(vht_cap, 2); - if (highest_mcs >= IWL_RATE_MCS_0_INDEX) { - for (i = IWL_RATE_MCS_0_INDEX; i <= highest_mcs; i++) { - if (i == IWL_RATE_9M_INDEX) - continue; - - lq_sta->active_mimo2_rate |= BIT(i); - } - } - - /* TODO: avoid MCS9 in 20Mhz which isn't valid for 11ac */ + rs_vht_set_enabled_rates(sta, vht_cap, lq_sta); lq_sta->is_vht = true; } -- cgit v1.2.3-70-g09d2 From 4ed80a86da93241c18d0e6c676134c7b9440d4b9 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 7 Nov 2013 13:23:21 +0200 Subject: iwlwifi: mvm: enable d3_test even if d3_test_pme_ptr is not available Even if d3_test_pme_ptr is not available, d3_test can still be useful, e.g. by manually triggering resume (with ctrl-c), and reading the wakeup reasons. Signed-off-by: Eliad Peller Reviewed-by: Luciano Coelho Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/d3.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index b9b81e881dd..12354f84425 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -1216,10 +1216,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, if (len >= sizeof(u32) * 2) { mvm->d3_test_pme_ptr = le32_to_cpup((__le32 *)d3_cfg_cmd.resp_pkt->data); - } else if (test) { - /* in test mode we require the pointer */ - ret = -EIO; - goto out; } #endif iwl_free_resp(&d3_cfg_cmd); @@ -1871,10 +1867,14 @@ static ssize_t iwl_mvm_d3_test_read(struct file *file, char __user *user_buf, u32 pme_asserted; while (true) { - pme_asserted = iwl_trans_read_mem32(mvm->trans, - mvm->d3_test_pme_ptr); - if (pme_asserted) - break; + /* read pme_ptr if available */ + if (mvm->d3_test_pme_ptr) { + pme_asserted = iwl_trans_read_mem32(mvm->trans, + mvm->d3_test_pme_ptr); + if (pme_asserted) + break; + } + if (msleep_interruptible(100)) break; } -- cgit v1.2.3-70-g09d2 From 431591ccb3d744851bca76b10de24cfababf639d Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 7 Nov 2013 14:12:09 +0200 Subject: iwlwifi: mvm: disconnect on disconnection wakeup event When waking up from d3 due to disconnection event (e.g. because of beacon loss), we should disconnect immediately. Signed-off-by: Eliad Peller Reviewed-by: Luciano Coelho Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/d3.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 12354f84425..96b09d9d706 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -1533,10 +1533,16 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, struct iwl_mvm_d3_gtk_iter_data gtkdata = { .status = status, }; + u32 disconnection_reasons = + IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON | + IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH; if (!status || !vif->bss_conf.bssid) return false; + if (le32_to_cpu(status->wakeup_reasons) & disconnection_reasons) + return false; + /* find last GTK that we used initially, if any */ gtkdata.find_phase = true; ieee80211_iter_keys(mvm->hw, vif, -- cgit v1.2.3-70-g09d2 From b87c2179a7d4f0d7d476df289c69cf9ebf8b7163 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Sat, 9 Nov 2013 23:37:55 +0200 Subject: iwlwifi: mvm: implement rate_update hook in rs Re-initialize rs when we get a rate_update hook called which happens when remote STA changes bandwidth or sends a VHT opmode notification. Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 3 ++- drivers/net/wireless/iwlwifi/mvm/rs.c | 30 +++++++++++++++++++++++++---- drivers/net/wireless/iwlwifi/mvm/rs.h | 2 +- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index b56c989ad78..eea2f162e90 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1149,7 +1149,8 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, ret = iwl_mvm_update_sta(mvm, vif, sta); if (ret == 0) iwl_mvm_rs_rate_init(mvm, sta, - mvmvif->phy_ctxt->channel->band); + mvmvif->phy_ctxt->channel->band, + true); } else if (old_state == IEEE80211_STA_ASSOC && new_state == IEEE80211_STA_AUTHORIZED) { /* enable beacon filtering */ diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index e49bf445fa7..a85938cb3ab 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -2126,7 +2126,8 @@ out: static void rs_initialize_lq(struct iwl_mvm *mvm, struct ieee80211_sta *sta, struct iwl_lq_sta *lq_sta, - enum ieee80211_band band) + enum ieee80211_band band, + bool init) { struct iwl_scale_tbl_info *tbl; int rate_idx; @@ -2168,7 +2169,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, rs_set_expected_tpt_table(lq_sta, tbl); rs_fill_link_cmd(NULL, NULL, lq_sta, rate); /* TODO restore station should remember the lq cmd */ - iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, true); + iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, init); } static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta, @@ -2273,7 +2274,7 @@ static void rs_vht_set_enabled_rates(struct ieee80211_sta *sta, * Called after adding a new station to initialize rate scaling */ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, - enum ieee80211_band band) + enum ieee80211_band band, bool init) { int i, j; struct ieee80211_hw *hw = mvm->hw; @@ -2286,6 +2287,8 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, sta_priv = (struct iwl_mvm_sta *)sta->drv_priv; lq_sta = &sta_priv->lq_sta; + memset(lq_sta, 0, sizeof(*lq_sta)); + sband = hw->wiphy->bands[band]; lq_sta->lq.sta_id = sta_priv->sta_id; @@ -2371,7 +2374,25 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, lq_sta->dbg_fixed_rate = 0; #endif - rs_initialize_lq(mvm, sta, lq_sta, band); + rs_initialize_lq(mvm, sta, lq_sta, band, init); +} + +static void rs_rate_update(void *mvm_r, + struct ieee80211_supported_band *sband, + struct cfg80211_chan_def *chandef, + struct ieee80211_sta *sta, void *priv_sta, + u32 changed) +{ + u8 tid; + struct iwl_op_mode *op_mode = + (struct iwl_op_mode *)mvm_r; + struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); + + /* Stop any ongoing aggregations as rs starts off assuming no agg */ + for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) + ieee80211_stop_tx_ba_session(sta, tid); + + iwl_mvm_rs_rate_init(mvm, sta, sband->band, false); } static void rs_fill_link_cmd(struct iwl_mvm *mvm, @@ -2808,6 +2829,7 @@ static struct rate_control_ops rs_mvm_ops = { .free = rs_free, .alloc_sta = rs_alloc_sta, .free_sta = rs_free_sta, + .rate_update = rs_rate_update, #ifdef CONFIG_MAC80211_DEBUGFS .add_sta_debugfs = rs_add_debugfs, .remove_sta_debugfs = rs_remove_debugfs, diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index 5d5344f7070..8d5dc78086e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -353,7 +353,7 @@ static inline u8 num_of_ant(u8 mask) /* Initialize station's rate scaling information after adding station */ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, - enum ieee80211_band band); + enum ieee80211_band band, bool init); /** * iwl_rate_control_register - Register the rate control algorithm callbacks -- cgit v1.2.3-70-g09d2 From 78c9df66c8f1af8577df802f57ce4dbb877fee4b Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 7 Nov 2013 14:13:30 +0200 Subject: iwlwifi: mvm: allow keeping connections in d3_test Keeping connection can be useful also when testing d3 using the debugfs file (d3_test). Save the vif to keep connection on, and consider it when iterating over the interfaces. Signed-off-by: Eliad Peller Reviewed-by: Luciano Coelho Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/d3.c | 11 ++++++++++- drivers/net/wireless/iwlwifi/mvm/mvm.h | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 96b09d9d706..b9e1f30e33d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -1807,6 +1807,10 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) iwl_mvm_read_d3_sram(mvm); keep = iwl_mvm_query_wakeup_reasons(mvm, vif); +#ifdef CONFIG_IWLWIFI_DEBUGFS + if (keep) + mvm->keep_vif = vif; +#endif /* has unlocked the mutex, so skip that */ goto out; @@ -1863,6 +1867,7 @@ static int iwl_mvm_d3_test_open(struct inode *inode, struct file *file) return err; } mvm->d3_test_active = true; + mvm->keep_vif = NULL; return 0; } @@ -1891,6 +1896,10 @@ static ssize_t iwl_mvm_d3_test_read(struct file *file, char __user *user_buf, static void iwl_mvm_d3_test_disconn_work_iter(void *_data, u8 *mac, struct ieee80211_vif *vif) { + /* skip the one we keep connection on */ + if (_data == vif) + return; + if (vif->type == NL80211_IFTYPE_STATION) ieee80211_connection_loss(vif); } @@ -1917,7 +1926,7 @@ static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file) ieee80211_iterate_active_interfaces_atomic( mvm->hw, IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_d3_test_disconn_work_iter, NULL); + iwl_mvm_d3_test_disconn_work_iter, mvm->keep_vif); ieee80211_wake_queues(mvm->hw); diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 7992baabb88..c002b45e03c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -531,6 +531,7 @@ struct iwl_mvm { bool store_d3_resume_sram; void *d3_resume_sram; u32 d3_test_pme_ptr; + struct ieee80211_vif *keep_vif; #endif #endif -- cgit v1.2.3-70-g09d2 From 8a5e3660c645200ca5d965903c73b97fb86c9518 Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Tue, 12 Nov 2013 19:16:03 +0200 Subject: iwlwifi: mvm: fix ht protection flags The HT protection flags have been a mess for a long time, this patch fixes all this. The proper source of information for this is the protection in the HT operation mode IE which is propagated to bss_conf by mac80211. 1) No need to set the HT protection flags when the link doesn't support HT. 2) We need to set the TGG protection when ERP is active. Signed-off-by: Avri Altman Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | 51 ++++++++++++++++++++++++----- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 11 +++++++ 2 files changed, 53 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index f41f9b07983..fb93961da75 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c @@ -488,6 +488,40 @@ static void iwl_mvm_ack_rates(struct iwl_mvm *mvm, *ofdm_rates = ofdm; } +static void iwl_mvm_mac_ctxt_set_ht_flags(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct iwl_mac_ctx_cmd *cmd) +{ + /* for both sta and ap, ht_operation_mode hold the protection_mode */ + u8 protection_mode = vif->bss_conf.ht_operation_mode & + IEEE80211_HT_OP_MODE_PROTECTION; + /* The fw does not distinguish between ht and fat */ + u32 ht_flag = MAC_PROT_FLG_HT_PROT | MAC_PROT_FLG_FAT_PROT; + + IWL_DEBUG_RATE(mvm, "protection mode set to %d\n", protection_mode); + /* + * See section 9.23.3.1 of IEEE 80211-2012. + * Nongreenfield HT STAs Present is not supported. + */ + switch (protection_mode) { + case IEEE80211_HT_OP_MODE_PROTECTION_NONE: + break; + case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER: + case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: + cmd->protection_flags |= cpu_to_le32(ht_flag); + break; + case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: + /* Protect when channel wider than 20MHz */ + if (vif->bss_conf.chandef.width > NL80211_CHAN_WIDTH_20) + cmd->protection_flags |= cpu_to_le32(ht_flag); + break; + default: + IWL_ERR(mvm, "Illegal protection mode %d\n", + protection_mode); + break; + } +} + static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mac_ctx_cmd *cmd, @@ -495,6 +529,8 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct ieee80211_chanctx_conf *chanctx; + bool ht_enabled = !!(vif->bss_conf.ht_operation_mode & + IEEE80211_HT_OP_MODE_PROTECTION); u8 cck_ack_rates, ofdm_ack_rates; int i; @@ -573,16 +609,13 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, cmd->protection_flags |= cpu_to_le32(MAC_PROT_FLG_SELF_CTS_EN); } - - /* - * I think that we should enable these 2 flags regardless the HT PROT - * fields in the HT IE, but I am not sure. Someone knows whom to ask?... - */ - if (vif->bss_conf.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) { + IWL_DEBUG_RATE(mvm, "use_cts_prot %d, ht_operation_mode %d\n", + vif->bss_conf.use_cts_prot, + vif->bss_conf.ht_operation_mode); + if (vif->bss_conf.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_TGN); - cmd->protection_flags |= cpu_to_le32(MAC_PROT_FLG_HT_PROT | - MAC_PROT_FLG_FAT_PROT); - } + if (ht_enabled) + iwl_mvm_mac_ctxt_set_ht_flags(mvm, vif, cmd); cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP); } diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index eea2f162e90..f8bf15c2b2d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -990,6 +990,17 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm, struct ieee80211_bss_conf *bss_conf, u32 changes) { + enum ieee80211_bss_change ht_change = BSS_CHANGED_ERP_CTS_PROT | + BSS_CHANGED_HT | + BSS_CHANGED_BANDWIDTH; + int ret; + + if (changes & ht_change) { + ret = iwl_mvm_mac_ctxt_changed(mvm, vif); + if (ret) + IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr); + } + /* Need to send a new beacon template to the FW */ if (changes & BSS_CHANGED_BEACON) { if (iwl_mvm_mac_ctxt_beacon_changed(mvm, vif)) -- cgit v1.2.3-70-g09d2 From 8a0bd168fa750d7c57d3494b331e9fb2b0bbd928 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 Nov 2013 16:48:03 +0100 Subject: iwlwifi: mvm: small debugfs cleanups Just clean up the code a bit, in particular * make all the debugfs writes follow the same pattern with respect to buf/buf_size variables * get rid of useless comments * check return values of all file creations * drop unnecessary parentheses * remove an unused struct definition * fix some whitespace Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 77 +++++++++++------------------- 1 file changed, 27 insertions(+), 50 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 342bd1a07ab..a34fb80422c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -65,26 +65,19 @@ #include "iwl-io.h" #include "iwl-prph.h" -struct iwl_dbgfs_mvm_ctx { - struct iwl_mvm *mvm; - struct ieee80211_vif *vif; -}; - static ssize_t iwl_dbgfs_tx_flush_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct iwl_mvm *mvm = file->private_data; - - char buf[16]; - int buf_size, ret; + char buf[16] = {}; + size_t buf_size = min(count, sizeof(buf) - 1); + int ret; u32 scd_q_msk; if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR) return -EIO; - memset(buf, 0, sizeof(buf)); - buf_size = min(count, sizeof(buf) - 1); if (copy_from_user(buf, user_buf, buf_size)) return -EFAULT; @@ -106,15 +99,13 @@ static ssize_t iwl_dbgfs_sta_drain_write(struct file *file, { struct iwl_mvm *mvm = file->private_data; struct ieee80211_sta *sta; - - char buf[8]; - int buf_size, sta_id, drain, ret; + char buf[8] = {}; + size_t buf_size = min(count, sizeof(buf) - 1); + int sta_id, drain, ret; if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR) return -EIO; - memset(buf, 0, sizeof(buf)); - buf_size = min(count, sizeof(buf) - 1); if (copy_from_user(buf, user_buf, buf_size)) return -EFAULT; @@ -200,12 +191,10 @@ static ssize_t iwl_dbgfs_sram_write(struct file *file, loff_t *ppos) { struct iwl_mvm *mvm = file->private_data; - char buf[64]; - int buf_size; + char buf[64] = {}; + size_t buf_size = min(count, sizeof(buf) - 1); u32 offset, len; - memset(buf, 0, sizeof(buf)); - buf_size = min(count, sizeof(buf) - 1); if (copy_from_user(buf, user_buf, buf_size)) return -EFAULT; @@ -274,14 +263,14 @@ static ssize_t iwl_dbgfs_disable_power_off_write(struct file *file, { struct iwl_mvm *mvm = file->private_data; char buf[64] = {}; + size_t buf_size = min(count, sizeof(buf) - 1); int ret; int val; if (!mvm->ucode_loaded) return -EIO; - count = min_t(size_t, count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, count)) + if (copy_from_user(buf, user_buf, buf_size)) return -EFAULT; if (!strncmp("disable_power_off_d0=", buf, 21)) { @@ -319,11 +308,10 @@ static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm, int dtimper_msec = dtimper * vif->bss_conf.beacon_int; IWL_DEBUG_POWER(mvm, "debugfs: set keep_alive= %d sec\n", val); - if (val * MSEC_PER_SEC < 3 * dtimper_msec) { + if (val * MSEC_PER_SEC < 3 * dtimper_msec) IWL_WARN(mvm, "debugfs: keep alive period (%ld msec) is less than minimum required (%d msec)\n", val * MSEC_PER_SEC, 3 * dtimper_msec); - } dbgfs_pm->keep_alive_seconds = val; break; } @@ -372,11 +360,11 @@ static ssize_t iwl_dbgfs_pm_params_write(struct file *file, struct iwl_mvm *mvm = mvmvif->dbgfs_data; enum iwl_dbgfs_pm_mask param; char buf[32] = {}; + size_t buf_size = min(count, sizeof(buf) - 1); int val; int ret; - count = min_t(size_t, count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, count)) + if (copy_from_user(buf, user_buf, buf_size)) return -EFAULT; if (!strncmp("keep_alive=", buf, 11)) { @@ -471,7 +459,7 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file, pos += scnprintf(buf+pos, bufsz-pos, "bssid: %pM\n", vif->bss_conf.bssid); pos += scnprintf(buf+pos, bufsz-pos, "QoS:\n"); - for (i = 0; i < ARRAY_SIZE(mvmvif->queue_params); i++) { + for (i = 0; i < ARRAY_SIZE(mvmvif->queue_params); i++) pos += scnprintf(buf+pos, bufsz-pos, "\t%d: txop:%d - cw_min:%d - cw_max = %d - aifs = %d upasd = %d\n", i, mvmvif->queue_params[i].txop, @@ -479,7 +467,6 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file, mvmvif->queue_params[i].cw_max, mvmvif->queue_params[i].aifs, mvmvif->queue_params[i].uapsd); - } if (vif->type == NL80211_IFTYPE_STATION && ap_sta_id != IWL_MVM_STATION_COUNT) { @@ -496,12 +483,11 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file, rcu_read_lock(); chanctx_conf = rcu_dereference(vif->chanctx_conf); - if (chanctx_conf) { + if (chanctx_conf) pos += scnprintf(buf+pos, bufsz-pos, "idle rx chains %d, active rx chains: %d\n", chanctx_conf->rx_chains_static, chanctx_conf->rx_chains_dynamic); - } rcu_read_unlock(); mutex_unlock(&mvm->mutex); @@ -845,14 +831,10 @@ iwl_dbgfs_scan_ant_rxchain_write(struct file *file, size_t count, loff_t *ppos) { struct iwl_mvm *mvm = file->private_data; - char buf[8]; - int buf_size; + char buf[8] = {}; + size_t buf_size = min(count, sizeof(buf) - 1); u8 scan_rx_ant; - memset(buf, 0, sizeof(buf)); - buf_size = min(count, sizeof(buf) - 1); - - /* get the argument from the user and check if it is valid */ if (copy_from_user(buf, user_buf, buf_size)) return -EFAULT; if (sscanf(buf, "%hhx", &scan_rx_ant) != 1) @@ -862,7 +844,6 @@ iwl_dbgfs_scan_ant_rxchain_write(struct file *file, if (scan_rx_ant & ~iwl_fw_valid_rx_ant(mvm->fw)) return -EINVAL; - /* change the rx antennas for scan command */ mvm->scan_rx_ant = scan_rx_ant; return count; @@ -922,13 +903,10 @@ static ssize_t iwl_dbgfs_bf_params_write(struct file *file, struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm *mvm = mvmvif->dbgfs_data; enum iwl_dbgfs_bf_mask param; - char buf[256]; - int buf_size; - int value; - int ret = 0; + char buf[256] = {}; + size_t buf_size = min(count, sizeof(buf) - 1); + int value, ret = 0; - memset(buf, 0, sizeof(buf)); - buf_size = min(count, sizeof(buf) - 1); if (copy_from_user(buf, user_buf, buf_size)) return -EFAULT; @@ -1012,11 +990,10 @@ static ssize_t iwl_dbgfs_bf_params_write(struct file *file, mutex_lock(&mvm->mutex); iwl_dbgfs_update_bf(vif, param, value); - if (param == MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER && !value) { + if (param == MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER && !value) ret = iwl_mvm_disable_beacon_filter(mvm, vif); - } else { + else ret = iwl_mvm_enable_beacon_filter(mvm, vif); - } mutex_unlock(&mvm->mutex); return ret ?: count; @@ -1078,10 +1055,10 @@ static ssize_t iwl_dbgfs_d3_sram_write(struct file *file, { struct iwl_mvm *mvm = file->private_data; char buf[8] = {}; + size_t buf_size = min(count, sizeof(buf) - 1); int store; - count = min_t(size_t, count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, count)) + if (copy_from_user(buf, user_buf, buf_size)) return -EFAULT; if (sscanf(buf, "%d", &store) != 1) @@ -1137,14 +1114,14 @@ static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf, #endif #define MVM_DEBUGFS_READ_FILE_OPS(name) \ -static const struct file_operations iwl_dbgfs_##name##_ops = { \ +static const struct file_operations iwl_dbgfs_##name##_ops = { \ .read = iwl_dbgfs_##name##_read, \ .open = simple_open, \ .llseek = generic_file_llseek, \ } #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name) \ -static const struct file_operations iwl_dbgfs_##name##_ops = { \ +static const struct file_operations iwl_dbgfs_##name##_ops = { \ .write = iwl_dbgfs_##name##_write, \ .read = iwl_dbgfs_##name##_read, \ .open = simple_open, \ @@ -1152,7 +1129,7 @@ static const struct file_operations iwl_dbgfs_##name##_ops = { \ }; #define MVM_DEBUGFS_WRITE_FILE_OPS(name) \ -static const struct file_operations iwl_dbgfs_##name##_ops = { \ +static const struct file_operations iwl_dbgfs_##name##_ops = { \ .write = iwl_dbgfs_##name##_write, \ .open = simple_open, \ .llseek = generic_file_llseek, \ -- cgit v1.2.3-70-g09d2 From 820a1a50025550061b0d0ea15a760ecd183886f7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 Nov 2013 16:58:41 +0100 Subject: iwlwifi: mvm: move interface-specific debugfs to a new file The debugfs file is getting pretty large and mixed up between code for the hardware and code for each interface (the two aren't even clearly separated in the code). Make it easier to handle by splitting the per-interface code into a separate file called debugfs-vif.c. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/Makefile | 1 + drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c | 190 ++++++++++ drivers/net/wireless/iwlwifi/mvm/debugfs.c | 505 +------------------------ drivers/net/wireless/iwlwifi/mvm/debugfs.h | 84 ++++ 4 files changed, 276 insertions(+), 504 deletions(-) create mode 100644 drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c create mode 100644 drivers/net/wireless/iwlwifi/mvm/debugfs.h diff --git a/drivers/net/wireless/iwlwifi/mvm/Makefile b/drivers/net/wireless/iwlwifi/mvm/Makefile index 6d73817850c..285d8c7486f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/Makefile +++ b/drivers/net/wireless/iwlwifi/mvm/Makefile @@ -5,6 +5,7 @@ iwlmvm-y += scan.o time-event.o rs.o iwlmvm-y += power.o power_legacy.o bt-coex.o iwlmvm-y += led.o tt.o iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o +iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o iwlmvm-$(CONFIG_PM_SLEEP) += d3.o ccflags-y += -D__CHECK_ENDIAN__ -I$(src)/../ diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c new file mode 100644 index 00000000000..a90dde0f8d6 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c @@ -0,0 +1,190 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +#include "mvm.h" +#include "debugfs.h" + +static ssize_t iwl_dbgfs_mac_params_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_vif *vif = file->private_data; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm *mvm = mvmvif->dbgfs_data; + u8 ap_sta_id; + struct ieee80211_chanctx_conf *chanctx_conf; + char buf[512]; + int bufsz = sizeof(buf); + int pos = 0; + int i; + + mutex_lock(&mvm->mutex); + + ap_sta_id = mvmvif->ap_sta_id; + + pos += scnprintf(buf+pos, bufsz-pos, "mac id/color: %d / %d\n", + mvmvif->id, mvmvif->color); + pos += scnprintf(buf+pos, bufsz-pos, "bssid: %pM\n", + vif->bss_conf.bssid); + pos += scnprintf(buf+pos, bufsz-pos, "QoS:\n"); + for (i = 0; i < ARRAY_SIZE(mvmvif->queue_params); i++) + pos += scnprintf(buf+pos, bufsz-pos, + "\t%d: txop:%d - cw_min:%d - cw_max = %d - aifs = %d upasd = %d\n", + i, mvmvif->queue_params[i].txop, + mvmvif->queue_params[i].cw_min, + mvmvif->queue_params[i].cw_max, + mvmvif->queue_params[i].aifs, + mvmvif->queue_params[i].uapsd); + + if (vif->type == NL80211_IFTYPE_STATION && + ap_sta_id != IWL_MVM_STATION_COUNT) { + struct ieee80211_sta *sta; + struct iwl_mvm_sta *mvm_sta; + + sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[ap_sta_id], + lockdep_is_held(&mvm->mutex)); + mvm_sta = (void *)sta->drv_priv; + pos += scnprintf(buf+pos, bufsz-pos, + "ap_sta_id %d - reduced Tx power %d\n", + ap_sta_id, mvm_sta->bt_reduced_txpower); + } + + rcu_read_lock(); + chanctx_conf = rcu_dereference(vif->chanctx_conf); + if (chanctx_conf) + pos += scnprintf(buf+pos, bufsz-pos, + "idle rx chains %d, active rx chains: %d\n", + chanctx_conf->rx_chains_static, + chanctx_conf->rx_chains_dynamic); + rcu_read_unlock(); + + mutex_unlock(&mvm->mutex); + + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +#define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do { \ + if (!debugfs_create_file(#name, mode, parent, vif, \ + &iwl_dbgfs_##name##_ops)) \ + goto err; \ + } while (0) + +MVM_DEBUGFS_READ_FILE_OPS(mac_params); + +void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) +{ + struct dentry *dbgfs_dir = vif->debugfs_dir; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + char buf[100]; + + /* + * Check if debugfs directory already exist before creating it. + * This may happen when, for example, resetting hw or suspend-resume + */ + if (!dbgfs_dir || mvmvif->dbgfs_dir) + return; + + mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir); + mvmvif->dbgfs_data = mvm; + + if (!mvmvif->dbgfs_dir) { + IWL_ERR(mvm, "Failed to create debugfs directory under %s\n", + dbgfs_dir->d_name.name); + return; + } + + MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, + S_IRUSR); + + /* + * Create symlink for convenience pointing to interface specific + * debugfs entries for the driver. For example, under + * /sys/kernel/debug/iwlwifi/0000\:02\:00.0/iwlmvm/ + * find + * netdev:wlan0 -> ../../../ieee80211/phy0/netdev:wlan0/iwlmvm/ + */ + snprintf(buf, 100, "../../../%s/%s/%s/%s", + dbgfs_dir->d_parent->d_parent->d_name.name, + dbgfs_dir->d_parent->d_name.name, + dbgfs_dir->d_name.name, + mvmvif->dbgfs_dir->d_name.name); + + mvmvif->dbgfs_slink = debugfs_create_symlink(dbgfs_dir->d_name.name, + mvm->debugfs_dir, buf); + if (!mvmvif->dbgfs_slink) + IWL_ERR(mvm, "Can't create debugfs symbolic link under %s\n", + dbgfs_dir->d_name.name); + return; +err: + IWL_ERR(mvm, "Can't create debugfs entity\n"); +} + +void iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + + debugfs_remove(mvmvif->dbgfs_slink); + mvmvif->dbgfs_slink = NULL; + + debugfs_remove_recursive(mvmvif->dbgfs_dir); + mvmvif->dbgfs_dir = NULL; +} diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index a34fb80422c..6850a2d94bc 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -64,6 +64,7 @@ #include "sta.h" #include "iwl-io.h" #include "iwl-prph.h" +#include "debugfs.h" static ssize_t iwl_dbgfs_tx_flush_write(struct file *file, const char __user *user_buf, @@ -292,209 +293,6 @@ static ssize_t iwl_dbgfs_disable_power_off_write(struct file *file, return ret ?: count; } -static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - enum iwl_dbgfs_pm_mask param, int val) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_dbgfs_pm *dbgfs_pm = &mvmvif->dbgfs_pm; - - dbgfs_pm->mask |= param; - - switch (param) { - case MVM_DEBUGFS_PM_KEEP_ALIVE: { - struct ieee80211_hw *hw = mvm->hw; - int dtimper = hw->conf.ps_dtim_period ?: 1; - int dtimper_msec = dtimper * vif->bss_conf.beacon_int; - - IWL_DEBUG_POWER(mvm, "debugfs: set keep_alive= %d sec\n", val); - if (val * MSEC_PER_SEC < 3 * dtimper_msec) - IWL_WARN(mvm, - "debugfs: keep alive period (%ld msec) is less than minimum required (%d msec)\n", - val * MSEC_PER_SEC, 3 * dtimper_msec); - dbgfs_pm->keep_alive_seconds = val; - break; - } - case MVM_DEBUGFS_PM_SKIP_OVER_DTIM: - IWL_DEBUG_POWER(mvm, "skip_over_dtim %s\n", - val ? "enabled" : "disabled"); - dbgfs_pm->skip_over_dtim = val; - break; - case MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS: - IWL_DEBUG_POWER(mvm, "skip_dtim_periods=%d\n", val); - dbgfs_pm->skip_dtim_periods = val; - break; - case MVM_DEBUGFS_PM_RX_DATA_TIMEOUT: - IWL_DEBUG_POWER(mvm, "rx_data_timeout=%d\n", val); - dbgfs_pm->rx_data_timeout = val; - break; - case MVM_DEBUGFS_PM_TX_DATA_TIMEOUT: - IWL_DEBUG_POWER(mvm, "tx_data_timeout=%d\n", val); - dbgfs_pm->tx_data_timeout = val; - break; - case MVM_DEBUGFS_PM_DISABLE_POWER_OFF: - IWL_DEBUG_POWER(mvm, "disable_power_off=%d\n", val); - dbgfs_pm->disable_power_off = val; - break; - case MVM_DEBUGFS_PM_LPRX_ENA: - IWL_DEBUG_POWER(mvm, "lprx %s\n", val ? "enabled" : "disabled"); - dbgfs_pm->lprx_ena = val; - break; - case MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD: - IWL_DEBUG_POWER(mvm, "lprx_rssi_threshold=%d\n", val); - dbgfs_pm->lprx_rssi_threshold = val; - break; - case MVM_DEBUGFS_PM_SNOOZE_ENABLE: - IWL_DEBUG_POWER(mvm, "snooze_enable=%d\n", val); - dbgfs_pm->snooze_ena = val; - break; - } -} - -static ssize_t iwl_dbgfs_pm_params_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ieee80211_vif *vif = file->private_data; - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm *mvm = mvmvif->dbgfs_data; - enum iwl_dbgfs_pm_mask param; - char buf[32] = {}; - size_t buf_size = min(count, sizeof(buf) - 1); - int val; - int ret; - - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - - if (!strncmp("keep_alive=", buf, 11)) { - if (sscanf(buf + 11, "%d", &val) != 1) - return -EINVAL; - param = MVM_DEBUGFS_PM_KEEP_ALIVE; - } else if (!strncmp("skip_over_dtim=", buf, 15)) { - if (sscanf(buf + 15, "%d", &val) != 1) - return -EINVAL; - param = MVM_DEBUGFS_PM_SKIP_OVER_DTIM; - } else if (!strncmp("skip_dtim_periods=", buf, 18)) { - if (sscanf(buf + 18, "%d", &val) != 1) - return -EINVAL; - param = MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS; - } else if (!strncmp("rx_data_timeout=", buf, 16)) { - if (sscanf(buf + 16, "%d", &val) != 1) - return -EINVAL; - param = MVM_DEBUGFS_PM_RX_DATA_TIMEOUT; - } else if (!strncmp("tx_data_timeout=", buf, 16)) { - if (sscanf(buf + 16, "%d", &val) != 1) - return -EINVAL; - param = MVM_DEBUGFS_PM_TX_DATA_TIMEOUT; - } else if (!strncmp("disable_power_off=", buf, 18) && - !(mvm->fw->ucode_capa.flags & - IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD)) { - if (sscanf(buf + 18, "%d", &val) != 1) - return -EINVAL; - param = MVM_DEBUGFS_PM_DISABLE_POWER_OFF; - } else if (!strncmp("lprx=", buf, 5)) { - if (sscanf(buf + 5, "%d", &val) != 1) - return -EINVAL; - param = MVM_DEBUGFS_PM_LPRX_ENA; - } else if (!strncmp("lprx_rssi_threshold=", buf, 20)) { - if (sscanf(buf + 20, "%d", &val) != 1) - return -EINVAL; - if (val > POWER_LPRX_RSSI_THRESHOLD_MAX || val < - POWER_LPRX_RSSI_THRESHOLD_MIN) - return -EINVAL; - param = MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD; - } else if (!strncmp("snooze_enable=", buf, 14)) { - if (sscanf(buf + 14, "%d", &val) != 1) - return -EINVAL; - param = MVM_DEBUGFS_PM_SNOOZE_ENABLE; - } else { - return -EINVAL; - } - - mutex_lock(&mvm->mutex); - iwl_dbgfs_update_pm(mvm, vif, param, val); - ret = iwl_mvm_power_update_mode(mvm, vif); - mutex_unlock(&mvm->mutex); - - return ret ?: count; -} - -static ssize_t iwl_dbgfs_pm_params_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ieee80211_vif *vif = file->private_data; - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm *mvm = mvmvif->dbgfs_data; - char buf[512]; - int bufsz = sizeof(buf); - int pos; - - pos = iwl_mvm_power_dbgfs_read(mvm, vif, buf, bufsz); - - return simple_read_from_buffer(user_buf, count, ppos, buf, pos); -} - -static ssize_t iwl_dbgfs_mac_params_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ieee80211_vif *vif = file->private_data; - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm *mvm = mvmvif->dbgfs_data; - u8 ap_sta_id; - struct ieee80211_chanctx_conf *chanctx_conf; - char buf[512]; - int bufsz = sizeof(buf); - int pos = 0; - int i; - - mutex_lock(&mvm->mutex); - - ap_sta_id = mvmvif->ap_sta_id; - - pos += scnprintf(buf+pos, bufsz-pos, "mac id/color: %d / %d\n", - mvmvif->id, mvmvif->color); - pos += scnprintf(buf+pos, bufsz-pos, "bssid: %pM\n", - vif->bss_conf.bssid); - pos += scnprintf(buf+pos, bufsz-pos, "QoS:\n"); - for (i = 0; i < ARRAY_SIZE(mvmvif->queue_params); i++) - pos += scnprintf(buf+pos, bufsz-pos, - "\t%d: txop:%d - cw_min:%d - cw_max = %d - aifs = %d upasd = %d\n", - i, mvmvif->queue_params[i].txop, - mvmvif->queue_params[i].cw_min, - mvmvif->queue_params[i].cw_max, - mvmvif->queue_params[i].aifs, - mvmvif->queue_params[i].uapsd); - - if (vif->type == NL80211_IFTYPE_STATION && - ap_sta_id != IWL_MVM_STATION_COUNT) { - struct ieee80211_sta *sta; - struct iwl_mvm_sta *mvm_sta; - - sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[ap_sta_id], - lockdep_is_held(&mvm->mutex)); - mvm_sta = (void *)sta->drv_priv; - pos += scnprintf(buf+pos, bufsz-pos, - "ap_sta_id %d - reduced Tx power %d\n", - ap_sta_id, mvm_sta->bt_reduced_txpower); - } - - rcu_read_lock(); - chanctx_conf = rcu_dereference(vif->chanctx_conf); - if (chanctx_conf) - pos += scnprintf(buf+pos, bufsz-pos, - "idle rx chains %d, active rx chains: %d\n", - chanctx_conf->rx_chains_static, - chanctx_conf->rx_chains_dynamic); - rcu_read_unlock(); - - mutex_unlock(&mvm->mutex); - - return simple_read_from_buffer(user_buf, count, ppos, buf, pos); -} - #define BT_MBOX_MSG(_notif, _num, _field) \ ((le32_to_cpu((_notif)->mbox_msg[(_num)]) & BT_MBOX##_num##_##_field)\ >> BT_MBOX##_num##_##_field##_POS) @@ -849,205 +647,6 @@ iwl_dbgfs_scan_ant_rxchain_write(struct file *file, return count; } - -static void iwl_dbgfs_update_bf(struct ieee80211_vif *vif, - enum iwl_dbgfs_bf_mask param, int value) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_dbgfs_bf *dbgfs_bf = &mvmvif->dbgfs_bf; - - dbgfs_bf->mask |= param; - - switch (param) { - case MVM_DEBUGFS_BF_ENERGY_DELTA: - dbgfs_bf->bf_energy_delta = value; - break; - case MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA: - dbgfs_bf->bf_roaming_energy_delta = value; - break; - case MVM_DEBUGFS_BF_ROAMING_STATE: - dbgfs_bf->bf_roaming_state = value; - break; - case MVM_DEBUGFS_BF_TEMP_THRESHOLD: - dbgfs_bf->bf_temp_threshold = value; - break; - case MVM_DEBUGFS_BF_TEMP_FAST_FILTER: - dbgfs_bf->bf_temp_fast_filter = value; - break; - case MVM_DEBUGFS_BF_TEMP_SLOW_FILTER: - dbgfs_bf->bf_temp_slow_filter = value; - break; - case MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER: - dbgfs_bf->bf_enable_beacon_filter = value; - break; - case MVM_DEBUGFS_BF_DEBUG_FLAG: - dbgfs_bf->bf_debug_flag = value; - break; - case MVM_DEBUGFS_BF_ESCAPE_TIMER: - dbgfs_bf->bf_escape_timer = value; - break; - case MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT: - dbgfs_bf->ba_enable_beacon_abort = value; - break; - case MVM_DEBUGFS_BA_ESCAPE_TIMER: - dbgfs_bf->ba_escape_timer = value; - break; - } -} - -static ssize_t iwl_dbgfs_bf_params_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ieee80211_vif *vif = file->private_data; - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm *mvm = mvmvif->dbgfs_data; - enum iwl_dbgfs_bf_mask param; - char buf[256] = {}; - size_t buf_size = min(count, sizeof(buf) - 1); - int value, ret = 0; - - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - - if (!strncmp("bf_energy_delta=", buf, 16)) { - if (sscanf(buf+16, "%d", &value) != 1) - return -EINVAL; - if (value < IWL_BF_ENERGY_DELTA_MIN || - value > IWL_BF_ENERGY_DELTA_MAX) - return -EINVAL; - param = MVM_DEBUGFS_BF_ENERGY_DELTA; - } else if (!strncmp("bf_roaming_energy_delta=", buf, 24)) { - if (sscanf(buf+24, "%d", &value) != 1) - return -EINVAL; - if (value < IWL_BF_ROAMING_ENERGY_DELTA_MIN || - value > IWL_BF_ROAMING_ENERGY_DELTA_MAX) - return -EINVAL; - param = MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA; - } else if (!strncmp("bf_roaming_state=", buf, 17)) { - if (sscanf(buf+17, "%d", &value) != 1) - return -EINVAL; - if (value < IWL_BF_ROAMING_STATE_MIN || - value > IWL_BF_ROAMING_STATE_MAX) - return -EINVAL; - param = MVM_DEBUGFS_BF_ROAMING_STATE; - } else if (!strncmp("bf_temp_threshold=", buf, 18)) { - if (sscanf(buf+18, "%d", &value) != 1) - return -EINVAL; - if (value < IWL_BF_TEMP_THRESHOLD_MIN || - value > IWL_BF_TEMP_THRESHOLD_MAX) - return -EINVAL; - param = MVM_DEBUGFS_BF_TEMP_THRESHOLD; - } else if (!strncmp("bf_temp_fast_filter=", buf, 20)) { - if (sscanf(buf+20, "%d", &value) != 1) - return -EINVAL; - if (value < IWL_BF_TEMP_FAST_FILTER_MIN || - value > IWL_BF_TEMP_FAST_FILTER_MAX) - return -EINVAL; - param = MVM_DEBUGFS_BF_TEMP_FAST_FILTER; - } else if (!strncmp("bf_temp_slow_filter=", buf, 20)) { - if (sscanf(buf+20, "%d", &value) != 1) - return -EINVAL; - if (value < IWL_BF_TEMP_SLOW_FILTER_MIN || - value > IWL_BF_TEMP_SLOW_FILTER_MAX) - return -EINVAL; - param = MVM_DEBUGFS_BF_TEMP_SLOW_FILTER; - } else if (!strncmp("bf_enable_beacon_filter=", buf, 24)) { - if (sscanf(buf+24, "%d", &value) != 1) - return -EINVAL; - if (value < 0 || value > 1) - return -EINVAL; - param = MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER; - } else if (!strncmp("bf_debug_flag=", buf, 14)) { - if (sscanf(buf+14, "%d", &value) != 1) - return -EINVAL; - if (value < 0 || value > 1) - return -EINVAL; - param = MVM_DEBUGFS_BF_DEBUG_FLAG; - } else if (!strncmp("bf_escape_timer=", buf, 16)) { - if (sscanf(buf+16, "%d", &value) != 1) - return -EINVAL; - if (value < IWL_BF_ESCAPE_TIMER_MIN || - value > IWL_BF_ESCAPE_TIMER_MAX) - return -EINVAL; - param = MVM_DEBUGFS_BF_ESCAPE_TIMER; - } else if (!strncmp("ba_escape_timer=", buf, 16)) { - if (sscanf(buf+16, "%d", &value) != 1) - return -EINVAL; - if (value < IWL_BA_ESCAPE_TIMER_MIN || - value > IWL_BA_ESCAPE_TIMER_MAX) - return -EINVAL; - param = MVM_DEBUGFS_BA_ESCAPE_TIMER; - } else if (!strncmp("ba_enable_beacon_abort=", buf, 23)) { - if (sscanf(buf+23, "%d", &value) != 1) - return -EINVAL; - if (value < 0 || value > 1) - return -EINVAL; - param = MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT; - } else { - return -EINVAL; - } - - mutex_lock(&mvm->mutex); - iwl_dbgfs_update_bf(vif, param, value); - if (param == MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER && !value) - ret = iwl_mvm_disable_beacon_filter(mvm, vif); - else - ret = iwl_mvm_enable_beacon_filter(mvm, vif); - mutex_unlock(&mvm->mutex); - - return ret ?: count; -} - -static ssize_t iwl_dbgfs_bf_params_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ieee80211_vif *vif = file->private_data; - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - char buf[256]; - int pos = 0; - const size_t bufsz = sizeof(buf); - struct iwl_beacon_filter_cmd cmd = { - IWL_BF_CMD_CONFIG_DEFAULTS, - .bf_enable_beacon_filter = - cpu_to_le32(IWL_BF_ENABLE_BEACON_FILTER_DEFAULT), - .ba_enable_beacon_abort = - cpu_to_le32(IWL_BA_ENABLE_BEACON_ABORT_DEFAULT), - }; - - iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd); - if (mvmvif->bf_data.bf_enabled) - cmd.bf_enable_beacon_filter = cpu_to_le32(1); - else - cmd.bf_enable_beacon_filter = 0; - - pos += scnprintf(buf+pos, bufsz-pos, "bf_energy_delta = %d\n", - le32_to_cpu(cmd.bf_energy_delta)); - pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_energy_delta = %d\n", - le32_to_cpu(cmd.bf_roaming_energy_delta)); - pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_state = %d\n", - le32_to_cpu(cmd.bf_roaming_state)); - pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_threshold = %d\n", - le32_to_cpu(cmd.bf_temp_threshold)); - pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_fast_filter = %d\n", - le32_to_cpu(cmd.bf_temp_fast_filter)); - pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_slow_filter = %d\n", - le32_to_cpu(cmd.bf_temp_slow_filter)); - pos += scnprintf(buf+pos, bufsz-pos, "bf_enable_beacon_filter = %d\n", - le32_to_cpu(cmd.bf_enable_beacon_filter)); - pos += scnprintf(buf+pos, bufsz-pos, "bf_debug_flag = %d\n", - le32_to_cpu(cmd.bf_debug_flag)); - pos += scnprintf(buf+pos, bufsz-pos, "bf_escape_timer = %d\n", - le32_to_cpu(cmd.bf_escape_timer)); - pos += scnprintf(buf+pos, bufsz-pos, "ba_escape_timer = %d\n", - le32_to_cpu(cmd.ba_escape_timer)); - pos += scnprintf(buf+pos, bufsz-pos, "ba_enable_beacon_abort = %d\n", - le32_to_cpu(cmd.ba_enable_beacon_abort)); - - return simple_read_from_buffer(user_buf, count, ppos, buf, pos); -} - #ifdef CONFIG_PM_SLEEP static ssize_t iwl_dbgfs_d3_sram_write(struct file *file, const char __user *user_buf, @@ -1113,40 +712,12 @@ static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf, } #endif -#define MVM_DEBUGFS_READ_FILE_OPS(name) \ -static const struct file_operations iwl_dbgfs_##name##_ops = { \ - .read = iwl_dbgfs_##name##_read, \ - .open = simple_open, \ - .llseek = generic_file_llseek, \ -} - -#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name) \ -static const struct file_operations iwl_dbgfs_##name##_ops = { \ - .write = iwl_dbgfs_##name##_write, \ - .read = iwl_dbgfs_##name##_read, \ - .open = simple_open, \ - .llseek = generic_file_llseek, \ -}; - -#define MVM_DEBUGFS_WRITE_FILE_OPS(name) \ -static const struct file_operations iwl_dbgfs_##name##_ops = { \ - .write = iwl_dbgfs_##name##_write, \ - .open = simple_open, \ - .llseek = generic_file_llseek, \ -}; - #define MVM_DEBUGFS_ADD_FILE(name, parent, mode) do { \ if (!debugfs_create_file(#name, mode, parent, mvm, \ &iwl_dbgfs_##name##_ops)) \ goto err; \ } while (0) -#define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do { \ - if (!debugfs_create_file(#name, mode, parent, vif, \ - &iwl_dbgfs_##name##_ops)) \ - goto err; \ - } while (0) - /* Device wide debugfs entries */ MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush); MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain); @@ -1164,11 +735,6 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain); MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram); #endif -/* Interface specific debugfs entries */ -MVM_DEBUGFS_READ_FILE_OPS(mac_params); -MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params); -MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params); - int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) { char buf[100]; @@ -1212,72 +778,3 @@ err: IWL_ERR(mvm, "Can't create the mvm debugfs directory\n"); return -ENOMEM; } - -void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) -{ - struct dentry *dbgfs_dir = vif->debugfs_dir; - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - char buf[100]; - - /* - * Check if debugfs directory already exist before creating it. - * This may happen when, for example, resetting hw or suspend-resume - */ - if (!dbgfs_dir || mvmvif->dbgfs_dir) - return; - - mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir); - mvmvif->dbgfs_data = mvm; - - if (!mvmvif->dbgfs_dir) { - IWL_ERR(mvm, "Failed to create debugfs directory under %s\n", - dbgfs_dir->d_name.name); - return; - } - - if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM && - vif->type == NL80211_IFTYPE_STATION && !vif->p2p) - MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, S_IWUSR | - S_IRUSR); - - MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, - S_IRUSR); - - if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p && - mvmvif == mvm->bf_allowed_vif) - MVM_DEBUGFS_ADD_FILE_VIF(bf_params, mvmvif->dbgfs_dir, - S_IRUSR | S_IWUSR); - - /* - * Create symlink for convenience pointing to interface specific - * debugfs entries for the driver. For example, under - * /sys/kernel/debug/iwlwifi/0000\:02\:00.0/iwlmvm/ - * find - * netdev:wlan0 -> ../../../ieee80211/phy0/netdev:wlan0/iwlmvm/ - */ - snprintf(buf, 100, "../../../%s/%s/%s/%s", - dbgfs_dir->d_parent->d_parent->d_name.name, - dbgfs_dir->d_parent->d_name.name, - dbgfs_dir->d_name.name, - mvmvif->dbgfs_dir->d_name.name); - - mvmvif->dbgfs_slink = debugfs_create_symlink(dbgfs_dir->d_name.name, - mvm->debugfs_dir, buf); - if (!mvmvif->dbgfs_slink) - IWL_ERR(mvm, "Can't create debugfs symbolic link under %s\n", - dbgfs_dir->d_name.name); - return; -err: - IWL_ERR(mvm, "Can't create debugfs entity\n"); -} - -void iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - - debugfs_remove(mvmvif->dbgfs_slink); - mvmvif->dbgfs_slink = NULL; - - debugfs_remove_recursive(mvmvif->dbgfs_dir); - mvmvif->dbgfs_dir = NULL; -} diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.h b/drivers/net/wireless/iwlwifi/mvm/debugfs.h new file mode 100644 index 00000000000..faa73b80b62 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.h @@ -0,0 +1,84 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#define MVM_DEBUGFS_READ_FILE_OPS(name) \ +static const struct file_operations iwl_dbgfs_##name##_ops = { \ + .read = iwl_dbgfs_##name##_read, \ + .open = simple_open, \ + .llseek = generic_file_llseek, \ +} + +#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name) \ +static const struct file_operations iwl_dbgfs_##name##_ops = { \ + .write = iwl_dbgfs_##name##_write, \ + .read = iwl_dbgfs_##name##_read, \ + .open = simple_open, \ + .llseek = generic_file_llseek, \ +}; + +#define MVM_DEBUGFS_WRITE_FILE_OPS(name) \ +static const struct file_operations iwl_dbgfs_##name##_ops = { \ + .write = iwl_dbgfs_##name##_write, \ + .open = simple_open, \ + .llseek = generic_file_llseek, \ +}; -- cgit v1.2.3-70-g09d2 From 7f09d70436729dee9dfa7ab11fda9d384c4bdf9f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 Nov 2013 17:16:38 +0100 Subject: iwlwifi: mvm: don't use void pointers in debugfs There's really no reason to use void *dbgfs_data rather than a struct iwl_mvm *mvm, so do that. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c | 4 ++-- drivers/net/wireless/iwlwifi/mvm/mvm.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c index a90dde0f8d6..67f6a207165 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c @@ -69,7 +69,7 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file, { struct ieee80211_vif *vif = file->private_data; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm *mvm = mvmvif->dbgfs_data; + struct iwl_mvm *mvm = mvmvif->mvm; u8 ap_sta_id; struct ieee80211_chanctx_conf *chanctx_conf; char buf[512]; @@ -144,7 +144,7 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) return; mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir); - mvmvif->dbgfs_data = mvm; + mvmvif->mvm = mvm; if (!mvmvif->dbgfs_dir) { IWL_ERR(mvm, "Failed to create debugfs directory under %s\n", diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index c002b45e03c..e7c97ccec5e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -323,9 +323,9 @@ struct iwl_mvm_vif { #endif #ifdef CONFIG_IWLWIFI_DEBUGFS + struct iwl_mvm *mvm; struct dentry *dbgfs_dir; struct dentry *dbgfs_slink; - void *dbgfs_data; struct iwl_dbgfs_pm dbgfs_pm; struct iwl_dbgfs_bf dbgfs_bf; #endif -- cgit v1.2.3-70-g09d2 From 1fa3f57a1ca19ad45ff5fa248d509fc442e82a63 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 13 Nov 2013 09:10:21 +0100 Subject: iwlwifi: mvm: refactor debugfs copy_from_user() Abstract the copy_from_user() pattern into the macros defining debugfs files, reducing the code and making adding new files safer by avoiding having deal with copy_from_user() directly. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 87 ++++++++---------------------- drivers/net/wireless/iwlwifi/mvm/debugfs.h | 25 +++++++-- 2 files changed, 43 insertions(+), 69 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 6850a2d94bc..931723a03a4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -66,22 +66,15 @@ #include "iwl-prph.h" #include "debugfs.h" -static ssize_t iwl_dbgfs_tx_flush_write(struct file *file, - const char __user *user_buf, +static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf, size_t count, loff_t *ppos) { - struct iwl_mvm *mvm = file->private_data; - char buf[16] = {}; - size_t buf_size = min(count, sizeof(buf) - 1); int ret; u32 scd_q_msk; if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR) return -EIO; - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - if (sscanf(buf, "%x", &scd_q_msk) != 1) return -EINVAL; @@ -94,22 +87,15 @@ static ssize_t iwl_dbgfs_tx_flush_write(struct file *file, return ret; } -static ssize_t iwl_dbgfs_sta_drain_write(struct file *file, - const char __user *user_buf, +static ssize_t iwl_dbgfs_sta_drain_write(struct iwl_mvm *mvm, char *buf, size_t count, loff_t *ppos) { - struct iwl_mvm *mvm = file->private_data; struct ieee80211_sta *sta; - char buf[8] = {}; - size_t buf_size = min(count, sizeof(buf) - 1); int sta_id, drain, ret; if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR) return -EIO; - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - if (sscanf(buf, "%d %d", &sta_id, &drain) != 2) return -EINVAL; if (sta_id < 0 || sta_id >= IWL_MVM_STATION_COUNT) @@ -187,18 +173,11 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf, return ret; } -static ssize_t iwl_dbgfs_sram_write(struct file *file, - const char __user *user_buf, size_t count, - loff_t *ppos) +static ssize_t iwl_dbgfs_sram_write(struct iwl_mvm *mvm, char *buf, + size_t count, loff_t *ppos) { - struct iwl_mvm *mvm = file->private_data; - char buf[64] = {}; - size_t buf_size = min(count, sizeof(buf) - 1); u32 offset, len; - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - if (sscanf(buf, "%x,%x", &offset, &len) == 2) { if ((offset & 0x3) || (len & 0x3)) return -EINVAL; @@ -258,22 +237,14 @@ static ssize_t iwl_dbgfs_disable_power_off_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } -static ssize_t iwl_dbgfs_disable_power_off_write(struct file *file, - const char __user *user_buf, +static ssize_t iwl_dbgfs_disable_power_off_write(struct iwl_mvm *mvm, char *buf, size_t count, loff_t *ppos) { - struct iwl_mvm *mvm = file->private_data; - char buf[64] = {}; - size_t buf_size = min(count, sizeof(buf) - 1); - int ret; - int val; + int ret, val; if (!mvm->ucode_loaded) return -EIO; - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - if (!strncmp("disable_power_off_d0=", buf, 21)) { if (sscanf(buf + 21, "%d", &val) != 1) return -EINVAL; @@ -568,11 +539,9 @@ static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file, } #undef PRINT_STAT_LE32 -static ssize_t iwl_dbgfs_fw_restart_write(struct file *file, - const char __user *user_buf, +static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf, size_t count, loff_t *ppos) { - struct iwl_mvm *mvm = file->private_data; int ret; mutex_lock(&mvm->mutex); @@ -589,12 +558,9 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct file *file, return count; } -static ssize_t iwl_dbgfs_fw_nmi_write(struct file *file, - const char __user *user_buf, +static ssize_t iwl_dbgfs_fw_nmi_write(struct iwl_mvm *mvm, char *buf, size_t count, loff_t *ppos) { - struct iwl_mvm *mvm = file->private_data; - iwl_write_prph(mvm->trans, DEVICE_SET_NMI_REG, 1); return count; @@ -624,17 +590,11 @@ iwl_dbgfs_scan_ant_rxchain_read(struct file *file, } static ssize_t -iwl_dbgfs_scan_ant_rxchain_write(struct file *file, - const char __user *user_buf, +iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf, size_t count, loff_t *ppos) { - struct iwl_mvm *mvm = file->private_data; - char buf[8] = {}; - size_t buf_size = min(count, sizeof(buf) - 1); u8 scan_rx_ant; - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; if (sscanf(buf, "%hhx", &scan_rx_ant) != 1) return -EINVAL; if (scan_rx_ant > ANT_ABC) @@ -648,18 +608,11 @@ iwl_dbgfs_scan_ant_rxchain_write(struct file *file, } #ifdef CONFIG_PM_SLEEP -static ssize_t iwl_dbgfs_d3_sram_write(struct file *file, - const char __user *user_buf, +static ssize_t iwl_dbgfs_d3_sram_write(struct iwl_mvm *mvm, char *buf, size_t count, loff_t *ppos) { - struct iwl_mvm *mvm = file->private_data; - char buf[8] = {}; - size_t buf_size = min(count, sizeof(buf) - 1); int store; - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - if (sscanf(buf, "%d", &store) != 1) return -EINVAL; @@ -712,6 +665,10 @@ static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf, } #endif +#define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \ + _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm) +#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \ + _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm) #define MVM_DEBUGFS_ADD_FILE(name, parent, mode) do { \ if (!debugfs_create_file(#name, mode, parent, mvm, \ &iwl_dbgfs_##name##_ops)) \ @@ -719,20 +676,20 @@ static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf, } while (0) /* Device wide debugfs entries */ -MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush); -MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain); -MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram); +MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush, 16); +MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain, 8); +MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram, 64); MVM_DEBUGFS_READ_FILE_OPS(stations); MVM_DEBUGFS_READ_FILE_OPS(bt_notif); MVM_DEBUGFS_READ_FILE_OPS(bt_cmd); -MVM_DEBUGFS_READ_WRITE_FILE_OPS(disable_power_off); +MVM_DEBUGFS_READ_WRITE_FILE_OPS(disable_power_off, 64); MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats); -MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart); -MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi); -MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain); +MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart, 10); +MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi, 10); +MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8); #ifdef CONFIG_PM_SLEEP -MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram); +MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8); #endif int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.h b/drivers/net/wireless/iwlwifi/mvm/debugfs.h index faa73b80b62..85f9f958bfd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.h +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.h @@ -68,17 +68,34 @@ static const struct file_operations iwl_dbgfs_##name##_ops = { \ .llseek = generic_file_llseek, \ } -#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name) \ +#define MVM_DEBUGFS_WRITE_WRAPPER(name, buflen, argtype) \ +static ssize_t _iwl_dbgfs_##name##_write(struct file *file, \ + const char __user *user_buf, \ + size_t count, loff_t *ppos) \ +{ \ + argtype *arg = file->private_data; \ + char buf[buflen] = {}; \ + size_t buf_size = min(count, sizeof(buf) - 1); \ + \ + if (copy_from_user(buf, user_buf, buf_size)) \ + return -EFAULT; \ + \ + return iwl_dbgfs_##name##_write(arg, buf, buf_size, ppos); \ +} \ + +#define _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, buflen, argtype) \ +MVM_DEBUGFS_WRITE_WRAPPER(name, buflen, argtype) \ static const struct file_operations iwl_dbgfs_##name##_ops = { \ - .write = iwl_dbgfs_##name##_write, \ + .write = _iwl_dbgfs_##name##_write, \ .read = iwl_dbgfs_##name##_read, \ .open = simple_open, \ .llseek = generic_file_llseek, \ }; -#define MVM_DEBUGFS_WRITE_FILE_OPS(name) \ +#define _MVM_DEBUGFS_WRITE_FILE_OPS(name, buflen, argtype) \ +MVM_DEBUGFS_WRITE_WRAPPER(name, buflen, argtype) \ static const struct file_operations iwl_dbgfs_##name##_ops = { \ - .write = iwl_dbgfs_##name##_write, \ + .write = _iwl_dbgfs_##name##_write, \ .open = simple_open, \ .llseek = generic_file_llseek, \ }; -- cgit v1.2.3-70-g09d2 From d307ec8d112abdc9f2792540b9e364c510461c44 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Mon, 11 Nov 2013 19:56:21 +0200 Subject: iwlwifi: mvm: add LQ flags definitions Add more bit field definitions used in LQ flags. Also rename the first bit to a shorter name. Signed-off-by: Eyal Shapira Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h | 27 +++++++++++++++++++++++++-- drivers/net/wireless/iwlwifi/mvm/rs.c | 4 ++-- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h index 538f1c7a596..532312c7b93 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h @@ -281,8 +281,31 @@ enum { /* # entries in rate scale table to support Tx retries */ #define LQ_MAX_RETRY_NUM 16 -/* Link quality command flags, only this one is available */ -#define LQ_FLAG_SET_STA_TLC_RTS_MSK BIT(0) +/* Link quality command flags bit fields */ + +/* Bit 0: (0) Don't use RTS (1) Use RTS */ +#define LQ_FLAG_USE_RTS_POS 0 +#define LQ_FLAG_USE_RTS_MSK (1 << LQ_FLAG_USE_RTS_POS) + +/* Bit 1-3: LQ command color. Used to match responses to LQ commands */ +#define LQ_FLAG_COLOR_POS 1 +#define LQ_FLAG_COLOR_MSK (7 << LQ_FLAG_COLOR_POS) + +/* Bit 4-5: Tx RTS BW Signalling + * (0) No RTS BW signalling + * (1) Static BW signalling + * (2) Dynamic BW signalling + */ +#define LQ_FLAG_RTS_BW_SIG_POS 4 +#define LQ_FLAG_RTS_BW_SIG_NONE (0 << LQ_FLAG_RTS_BW_SIG_POS) +#define LQ_FLAG_RTS_BW_SIG_STATIC (1 << LQ_FLAG_RTS_BW_SIG_POS) +#define LQ_FLAG_RTS_BW_SIG_DYNAMIC (2 << LQ_FLAG_RTS_BW_SIG_POS) + +/* Bit 6: (0) No dynamic BW selection (1) Allow dynamic BW selection + * Dyanmic BW selection allows Tx with narrower BW then requested in rates + */ +#define LQ_FLAG_DYNAMIC_BW_POS 6 +#define LQ_FLAG_DYNAMIC_BW_MSK (1 << LQ_FLAG_DYNAMIC_BW_POS) /** * struct iwl_lq_cmd - link quality command diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index a85938cb3ab..482b91b80c3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -2862,12 +2862,12 @@ int iwl_mvm_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, if (enable) { if (mvmsta->tx_protection == 0) - lq->flags |= LQ_FLAG_SET_STA_TLC_RTS_MSK; + lq->flags |= LQ_FLAG_USE_RTS_MSK; mvmsta->tx_protection++; } else { mvmsta->tx_protection--; if (mvmsta->tx_protection == 0) - lq->flags &= ~LQ_FLAG_SET_STA_TLC_RTS_MSK; + lq->flags &= ~LQ_FLAG_USE_RTS_MSK; } return iwl_mvm_send_lq_cmd(mvm, lq, false); -- cgit v1.2.3-70-g09d2 From c21193516209705c59aa8d9f01021944cf42a0e9 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 13 Nov 2013 22:00:30 +0200 Subject: iwlwifi: mvm: BT Coex - fine tune the aggregation size Latest tests have shown that when BT is active and has connections but the traffic is low, the WiFi aggregation can be large up to 4000us without noticeable impact on BT. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/bt-coex.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c index 75b72a95655..75c3e0b6e07 100644 --- a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c @@ -921,7 +921,7 @@ u16 iwl_mvm_bt_coex_agg_time_limit(struct iwl_mvm *mvm, enum iwl_bt_coex_lut_type lut_type; if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < - BT_LOW_TRAFFIC) + BT_HIGH_TRAFFIC) return LINK_QUAL_AGG_TIME_LIMIT_DEF; lut_type = iwl_get_coex_type(mvm, mvmsta->vif); -- cgit v1.2.3-70-g09d2 From 8c21c5386d6e9404b347acf5b13db61ca7b5e037 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 23 Oct 2013 15:44:25 +0300 Subject: iwlwifi: mvm: a few more SKUs for 7260 and 3160 These devices are not sold as discrete modules but are rather soldered down to the board. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/drv.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 86605027c41..2e97a399533 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -297,6 +297,9 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { {IWL_PCI_DEVICE(0x08B2, 0x4370, iwl7260_2ac_cfg)}, {IWL_PCI_DEVICE(0x08B2, 0x4360, iwl7260_2n_cfg)}, {IWL_PCI_DEVICE(0x08B1, 0x5070, iwl7260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x08B1, 0x5072, iwl7260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x08B1, 0x5170, iwl7260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x08B1, 0x5770, iwl7260_2ac_cfg)}, {IWL_PCI_DEVICE(0x08B1, 0x4020, iwl7260_2n_cfg)}, {IWL_PCI_DEVICE(0x08B1, 0x402A, iwl7260_2n_cfg)}, {IWL_PCI_DEVICE(0x08B2, 0x4220, iwl7260_2n_cfg)}, @@ -350,6 +353,8 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { {IWL_PCI_DEVICE(0x08B4, 0x8270, iwl3160_2ac_cfg)}, {IWL_PCI_DEVICE(0x08B3, 0x8470, iwl3160_2ac_cfg)}, {IWL_PCI_DEVICE(0x08B3, 0x8570, iwl3160_2ac_cfg)}, + {IWL_PCI_DEVICE(0x08B3, 0x1070, iwl3160_2ac_cfg)}, + {IWL_PCI_DEVICE(0x08B3, 0x1170, iwl3160_2ac_cfg)}, /* 7265 Series */ {IWL_PCI_DEVICE(0x095A, 0x5010, iwl7265_2ac_cfg)}, -- cgit v1.2.3-70-g09d2 From 84c317c9b09f757b4c4a4fb38549ac54d1559419 Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Sun, 10 Nov 2013 20:06:37 +0100 Subject: iwlwifi: pcie: remove minor dead code inta is checked to be zero in a IRQ_NONE branch so afterwards it cannot be zero as it is never modified. Signed-off-by: Michal Nazarewicz [reword the patch title and fix comment] Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/rx.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index be3995afa9d..1d6bf7b98e2 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -1126,7 +1126,6 @@ static irqreturn_t iwl_pcie_isr(int irq, void *data) struct iwl_trans *trans = data; struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); u32 inta, inta_mask; - irqreturn_t ret = IRQ_NONE; lockdep_assert_held(&trans_pcie->irq_lock); @@ -1155,7 +1154,16 @@ static irqreturn_t iwl_pcie_isr(int irq, void *data) * or due to sporadic interrupts thrown from our NIC. */ if (!inta) { IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n"); - goto none; + /* + * Re-enable interrupts here since we don't have anything to + * service, but only in case the handler won't run. Note that + * the handler can be scheduled because of a previous + * interrupt. + */ + if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) && + !trans_pcie->inta) + iwl_enable_interrupts(trans); + return IRQ_NONE; } if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { @@ -1173,19 +1181,7 @@ static irqreturn_t iwl_pcie_isr(int irq, void *data) trans_pcie->inta |= inta; /* the thread will service interrupts and re-enable them */ - if (likely(inta)) - return IRQ_WAKE_THREAD; - - ret = IRQ_HANDLED; - -none: - /* re-enable interrupts here since we don't have anything to service. */ - /* only Re-enable if disabled by irq and no schedules tasklet. */ - if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) && - !trans_pcie->inta) - iwl_enable_interrupts(trans); - - return ret; + return IRQ_WAKE_THREAD; } /* interrupt handler using ict table, with this interrupt driver will -- cgit v1.2.3-70-g09d2 From a7b8b2ca916ca4ecf248fa12275eeceff510ad22 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Thu, 7 Nov 2013 19:38:04 +0200 Subject: iwlwifi: fix check for a single rx antenna valid_rx_ant is a bitmask of available antennas and not the number of Rx antennas. Use num_of_ant and remove duplicate definitions in both dvm and mvm. Signed-off-by: Eyal Shapira Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/rs.h | 7 ------- drivers/net/wireless/iwlwifi/iwl-config.h | 6 ++++++ drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 3 ++- drivers/net/wireless/iwlwifi/mvm/rs.h | 8 -------- 4 files changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/dvm/rs.h b/drivers/net/wireless/iwlwifi/dvm/rs.h index 26fc550cd68..41988f4b8a5 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rs.h +++ b/drivers/net/wireless/iwlwifi/dvm/rs.h @@ -389,13 +389,6 @@ struct iwl_lq_sta { u8 last_bt_traffic; }; -static inline u8 num_of_ant(u8 mask) -{ - return !!((mask) & ANT_A) + - !!((mask) & ANT_B) + - !!((mask) & ANT_C); -} - static inline u8 first_antenna(u8 mask) { if (mask & ANT_A) diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 03fd9aa8bfd..0b916249669 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -129,6 +129,12 @@ enum iwl_led_mode { #define ANT_BC (ANT_B | ANT_C) #define ANT_ABC (ANT_A | ANT_B | ANT_C) +static inline u8 num_of_ant(u8 mask) +{ + return !!((mask) & ANT_A) + + !!((mask) & ANT_B) + + !!((mask) & ANT_C); +} /* * @max_ll_items: max number of OTP blocks diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index 2fab203d302..94aef22df73 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -283,7 +283,8 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 | IEEE80211_VHT_MCS_NOT_SUPPORTED << 14); - if (data->valid_rx_ant == 1 || cfg->rx_with_siso_diversity) { + if (num_of_ant(data->valid_rx_ant) == 1 || + cfg->rx_with_siso_diversity) { vht_cap->cap |= IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN | IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN; /* this works because NOT_SUPPORTED == 3 */ diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index 8d5dc78086e..b41686b7672 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -343,14 +343,6 @@ enum iwl_bt_coex_profile_traffic_load { */ }; - -static inline u8 num_of_ant(u8 mask) -{ - return !!((mask) & ANT_A) + - !!((mask) & ANT_B) + - !!((mask) & ANT_C); -} - /* Initialize station's rate scaling information after adding station */ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, enum ieee80211_band band, bool init); -- cgit v1.2.3-70-g09d2 From 5b577a90fb3d86447ee86f8e0c6ddbd5da2ef8c9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 14 Nov 2013 18:20:04 +0100 Subject: iwlwifi: mvm: add iwl_mvm_sta_from_mac80211 This is just a helper function to go from the mac80211 station struct to our internal one, to later allow us to avoid temporary 'mvmsta' variables. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/bt-coex.c | 8 ++++---- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 2 +- drivers/net/wireless/iwlwifi/mvm/sta.c | 12 ++++++------ drivers/net/wireless/iwlwifi/mvm/sta.h | 6 ++++++ drivers/net/wireless/iwlwifi/mvm/tt.c | 2 +- drivers/net/wireless/iwlwifi/mvm/tx.c | 10 +++++----- 6 files changed, 23 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c index 75c3e0b6e07..468a4ba49a0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c @@ -514,7 +514,7 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, if (IS_ERR_OR_NULL(sta)) return 0; - mvmsta = (void *)sta->drv_priv; + mvmsta = iwl_mvm_sta_from_mac80211(sta); /* nothing to do */ if (mvmsta->bt_reduced_txpower == enable) @@ -846,7 +846,7 @@ static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac, if (IS_ERR_OR_NULL(sta)) return; - mvmsta = (void *)sta->drv_priv; + mvmsta = iwl_mvm_sta_from_mac80211(sta); data->num_bss_ifaces++; @@ -917,7 +917,7 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, u16 iwl_mvm_bt_coex_agg_time_limit(struct iwl_mvm *mvm, struct ieee80211_sta *sta) { - struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); enum iwl_bt_coex_lut_type lut_type; if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < @@ -936,7 +936,7 @@ u16 iwl_mvm_bt_coex_agg_time_limit(struct iwl_mvm *mvm, bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, struct ieee80211_sta *sta) { - struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < BT_HIGH_TRAFFIC) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index f8bf15c2b2d..6b3273d8215 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1091,7 +1091,7 @@ static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, struct ieee80211_sta *sta) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); switch (cmd) { case STA_NOTIFY_SLEEP: diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index c89232c8aa7..7a5b7473eaf 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -840,7 +840,7 @@ static const u8 tid_to_ac[] = { int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid, u16 *ssn) { - struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct iwl_mvm_tid_data *tid_data; int txq_id; @@ -895,7 +895,7 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid, u8 buf_size) { - struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; int queue, fifo, ret; u16 ssn; @@ -951,7 +951,7 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid) { - struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; u16 txq_id; int err; @@ -1023,7 +1023,7 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid) { - struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; u16 txq_id; enum iwl_mvm_agg_state old_state; @@ -1416,7 +1416,7 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm, void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, struct ieee80211_sta *sta) { - struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct iwl_mvm_add_sta_cmd_v6 cmd = { .add_modify = STA_MODE_MODIFY, .sta_id = mvmsta->sta_id, @@ -1438,7 +1438,7 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, u16 sleep_state_flags = (reason == IEEE80211_FRAME_RELEASE_UAPSD) ? STA_SLEEP_STATE_UAPSD : STA_SLEEP_STATE_PS_POLL; - struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct iwl_mvm_add_sta_cmd_v6 cmd = { .add_modify = STA_MODE_MODIFY, .sta_id = mvmsta->sta_id, diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h index 4dfc359a4bd..b34941148a9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/sta.h @@ -298,6 +298,12 @@ struct iwl_mvm_sta { bool tt_tx_protection; }; +static inline struct iwl_mvm_sta * +iwl_mvm_sta_from_mac80211(struct ieee80211_sta *sta) +{ + return (void *)sta->drv_priv; +} + /** * struct iwl_mvm_int_sta - representation of an internal station (auxiliary or * broadcast) diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c index 1f3282dff51..18be04da8e3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/iwlwifi/mvm/tt.c @@ -388,7 +388,7 @@ static void iwl_mvm_tt_tx_protection(struct iwl_mvm *mvm, bool enable) lockdep_is_held(&mvm->mutex)); if (IS_ERR_OR_NULL(sta)) continue; - mvmsta = (void *)sta->drv_priv; + mvmsta = iwl_mvm_sta_from_mac80211(sta); if (enable == mvmsta->tt_tx_protection) continue; err = iwl_mvm_tx_protection(mvm, mvmsta, enable); diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 1f194580642..d87649ac88e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -362,7 +362,7 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, u8 txq_id = info->hw_queue; bool is_data_qos = false, is_ampdu = false; - mvmsta = (void *)sta->drv_priv; + mvmsta = iwl_mvm_sta_from_mac80211(sta); fc = hdr->frame_control; if (WARN_ON_ONCE(!mvmsta)) @@ -433,7 +433,7 @@ drop: static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm, struct ieee80211_sta *sta, u8 tid) { - struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; struct ieee80211_vif *vif = mvmsta->vif; @@ -663,7 +663,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); if (!IS_ERR_OR_NULL(sta)) { - mvmsta = (void *)sta->drv_priv; + mvmsta = iwl_mvm_sta_from_mac80211(sta); if (tid != IWL_TID_NON_QOS) { struct iwl_mvm_tid_data *tid_data = @@ -794,7 +794,7 @@ static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm, sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); if (!WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) { - struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); mvmsta->tid_data[tid].rate_n_flags = le32_to_cpu(tx_resp->initial_rate); } @@ -850,7 +850,7 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, return 0; } - mvmsta = (void *)sta->drv_priv; + mvmsta = iwl_mvm_sta_from_mac80211(sta); tid_data = &mvmsta->tid_data[tid]; if (WARN_ONCE(tid_data->txq_id != scd_flow, "Q %d, tid %d, flow %d", -- cgit v1.2.3-70-g09d2 From b70ab7278f5e872dec600a6f16c6a8dba4601794 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Tue, 19 Nov 2013 22:53:41 +0200 Subject: iwlwifi: mvm: don't restart HW if suspending fails before D3 image is loaded If we haven't loaded the D3 image yet and a failure in the suspend process occurs, we shouldn't restart the HW, because we're still running the D0 image. Signed-off-by: Luciano Coelho Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/d3.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index b9e1f30e33d..665f87e788d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -1227,10 +1227,11 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, mvm->aux_sta.sta_id = old_aux_sta_id; mvm_ap_sta->sta_id = old_ap_sta_id; mvmvif->ap_sta_id = old_ap_sta_id; - out_noreset: - kfree(key_data.rsc_tsc); + if (ret < 0) ieee80211_restart_hw(mvm->hw); + out_noreset: + kfree(key_data.rsc_tsc); mutex_unlock(&mvm->mutex); -- cgit v1.2.3-70-g09d2 From 086f7368d4120ff0de376af9b7f9beaec8bf4b4d Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 18 Nov 2013 17:00:03 +0200 Subject: iwlwifi: mvm: dump NVM from debugfs This allows to see the content of the NVM the driver reads. Note that the output is in binary, and requires some external user space tool to display the data properly. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 13 +++++++++++++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 5 +++++ drivers/net/wireless/iwlwifi/mvm/nvm.c | 23 +++++++++++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 931723a03a4..e8f62a6a1b5 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -720,6 +720,19 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) goto err; #endif + if (!debugfs_create_blob("nvm_hw", S_IRUSR, + mvm->debugfs_dir, &mvm->nvm_hw_blob)) + goto err; + if (!debugfs_create_blob("nvm_sw", S_IRUSR, + mvm->debugfs_dir, &mvm->nvm_sw_blob)) + goto err; + if (!debugfs_create_blob("nvm_calib", S_IRUSR, + mvm->debugfs_dir, &mvm->nvm_calib_blob)) + goto err; + if (!debugfs_create_blob("nvm_prod", S_IRUSR, + mvm->debugfs_dir, &mvm->nvm_prod_blob)) + goto err; + /* * Create a symlink with mac80211. It will be removed when mac80211 * exists (before the opmode exists which removes the target.) diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index e7c97ccec5e..7dc57cfe580 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -494,6 +494,11 @@ struct iwl_mvm { u32 dbgfs_sram_offset, dbgfs_sram_len; bool disable_power_off; bool disable_power_off_d3; + + struct debugfs_blob_wrapper nvm_hw_blob; + struct debugfs_blob_wrapper nvm_sw_blob; + struct debugfs_blob_wrapper nvm_calib_blob; + struct debugfs_blob_wrapper nvm_prod_blob; #endif struct iwl_mvm_phy_ctxt phy_ctxts[NUM_PHY_CTX]; diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index 2beffd028b6..48089b1625f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c @@ -443,6 +443,29 @@ int iwl_nvm_init(struct iwl_mvm *mvm) } mvm->nvm_sections[section].data = temp; mvm->nvm_sections[section].length = ret; + +#ifdef CONFIG_IWLWIFI_DEBUGFS + switch (section) { + case NVM_SECTION_TYPE_HW: + mvm->nvm_hw_blob.data = temp; + mvm->nvm_hw_blob.size = ret; + break; + case NVM_SECTION_TYPE_SW: + mvm->nvm_sw_blob.data = temp; + mvm->nvm_sw_blob.size = ret; + break; + case NVM_SECTION_TYPE_CALIBRATION: + mvm->nvm_calib_blob.data = temp; + mvm->nvm_calib_blob.size = ret; + break; + case NVM_SECTION_TYPE_PRODUCTION: + mvm->nvm_prod_blob.data = temp; + mvm->nvm_prod_blob.size = ret; + break; + default: + WARN(1, "section: %d", section); + } +#endif } kfree(nvm_buffer); if (ret < 0) -- cgit v1.2.3-70-g09d2 From de33fb5e80a62a3dfb50ab4d498db9b978c6c07f Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 10 Nov 2013 12:59:46 +0200 Subject: iwlwifi: mvm: fix scan offloading flag definition Bit 0 in the scan offloading flags asks the filter to pass all the results (instead of filtering them, by default), rather than the other way around (like it is defined and used today). Fix the flag name appropriately, and fix its user. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h | 5 ++--- drivers/net/wireless/iwlwifi/mvm/scan.c | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h index c3782b48ded..b3ed59237cb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h @@ -530,14 +530,13 @@ struct iwl_scan_offload_schedule { /* * iwl_scan_offload_flags * - * IWL_SCAN_OFFLOAD_FLAG_FILTER_SSID: filter mode - upload every beacon or match - * ssid list. + * IWL_SCAN_OFFLOAD_FLAG_PASS_ALL: pass all results - no filtering. * IWL_SCAN_OFFLOAD_FLAG_CACHED_CHANNEL: add cached channels to partial scan. * IWL_SCAN_OFFLOAD_FLAG_ENERGY_SCAN: use energy based scan before partial scan * on A band. */ enum iwl_scan_offload_flags { - IWL_SCAN_OFFLOAD_FLAG_FILTER_SSID = BIT(0), + IWL_SCAN_OFFLOAD_FLAG_PASS_ALL = BIT(0), IWL_SCAN_OFFLOAD_FLAG_CACHED_CHANNEL = BIT(2), IWL_SCAN_OFFLOAD_FLAG_ENERGY_SCAN = BIT(3), }; diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index e0cd100b40c..67d7b8defa0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -817,11 +817,10 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, IWL_DEBUG_SCAN(mvm, "Sending scheduled scan with filtering, filter len %d\n", req->n_match_sets); - scan_req.flags |= - cpu_to_le16(IWL_SCAN_OFFLOAD_FLAG_FILTER_SSID); } else { IWL_DEBUG_SCAN(mvm, "Sending Scheduled scan without filtering\n"); + scan_req.flags |= cpu_to_le16(IWL_SCAN_OFFLOAD_FLAG_PASS_ALL); } return iwl_mvm_send_cmd_pdu(mvm, SCAN_OFFLOAD_REQUEST_CMD, CMD_SYNC, -- cgit v1.2.3-70-g09d2 From 61f6325d3e453fc3523d5891f9641d0af5e3ceaf Mon Sep 17 00:00:00 2001 From: Haim Dreyfuss Date: Sun, 3 Nov 2013 23:02:59 +0200 Subject: iwlwifi: mvm: Implement low-priority scan Advertise driver's support for low priority scan. Notice that this overwrites current setting by mac80211 which depends only on hw scan support. This scan priority can be configured by user space application and it affects scan continuity, low priority scan will be more fragmented scan. Signed-off-by: Haim Dreyfuss Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 3 +- drivers/net/wireless/iwlwifi/mvm/scan.c | 52 +++++++++++++++++++++-------- 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 6b3273d8215..afc4419be46 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -256,7 +256,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) } hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN | - NL80211_FEATURE_P2P_GO_OPPPS; + NL80211_FEATURE_P2P_GO_OPPPS | + NL80211_FEATURE_LOW_PRIORITY_SCAN; mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 67d7b8defa0..4ce9bb58114 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -70,6 +70,9 @@ #define IWL_PLCP_QUIET_THRESH 1 #define IWL_ACTIVE_QUIET_TIME 10 +#define LONG_OUT_TIME_PERIOD 600 +#define SHORT_OUT_TIME_PERIOD 200 +#define SUSPEND_TIME_PERIOD 100 static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm) { @@ -87,20 +90,22 @@ static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm) return cpu_to_le16(rx_chain); } -static inline __le32 iwl_mvm_scan_max_out_time(struct ieee80211_vif *vif) +static inline __le32 iwl_mvm_scan_max_out_time(struct ieee80211_vif *vif, + u32 flags, bool is_assoc) { - if (vif->bss_conf.assoc) - return cpu_to_le32(200 * 1024); - else + if (!is_assoc) return 0; + if (flags & NL80211_SCAN_FLAG_LOW_PRIORITY) + return cpu_to_le32(ieee80211_tu_to_usec(SHORT_OUT_TIME_PERIOD)); + return cpu_to_le32(ieee80211_tu_to_usec(LONG_OUT_TIME_PERIOD)); } -static inline __le32 iwl_mvm_scan_suspend_time(struct ieee80211_vif *vif) +static inline __le32 iwl_mvm_scan_suspend_time(struct ieee80211_vif *vif, + bool is_assoc) { - if (!vif->bss_conf.assoc) + if (!is_assoc) return 0; - - return cpu_to_le32(ieee80211_tu_to_usec(vif->bss_conf.beacon_int)); + return cpu_to_le32(ieee80211_tu_to_usec(SUSPEND_TIME_PERIOD)); } static inline __le32 @@ -262,6 +267,15 @@ static u16 iwl_mvm_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta, return (u16)len; } +static void iwl_mvm_vif_assoc_iterator(void *data, u8 *mac, + struct ieee80211_vif *vif) +{ + bool *is_assoc = data; + + if (vif->bss_conf.assoc) + *is_assoc = true; +} + int iwl_mvm_scan_request(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct cfg80211_scan_request *req) @@ -274,6 +288,7 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm, .dataflags = { IWL_HCMD_DFL_NOCOPY, }, }; struct iwl_scan_cmd *cmd = mvm->scan_cmd; + bool is_assoc = false; int ret; u32 status; int ssid_len = 0; @@ -289,13 +304,17 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm, memset(cmd, 0, sizeof(struct iwl_scan_cmd) + mvm->fw->ucode_capa.max_probe_length + (MAX_NUM_SCAN_CHANNELS * sizeof(struct iwl_scan_channel))); - + ieee80211_iterate_active_interfaces_atomic(mvm->hw, + IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_vif_assoc_iterator, + &is_assoc); cmd->channel_count = (u8)req->n_channels; cmd->quiet_time = cpu_to_le16(IWL_ACTIVE_QUIET_TIME); cmd->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH); cmd->rxchain_sel_flags = iwl_mvm_scan_rx_chain(mvm); - cmd->max_out_time = iwl_mvm_scan_max_out_time(vif); - cmd->suspend_time = iwl_mvm_scan_suspend_time(vif); + cmd->max_out_time = iwl_mvm_scan_max_out_time(vif, req->flags, + is_assoc); + cmd->suspend_time = iwl_mvm_scan_suspend_time(vif, is_assoc); cmd->rxon_flags = iwl_mvm_scan_rxon_flags(req); cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP | MAC_FILTER_IN_BEACON); @@ -522,6 +541,12 @@ static void iwl_build_scan_cmd(struct iwl_mvm *mvm, struct cfg80211_sched_scan_request *req, struct iwl_scan_offload_cmd *scan) { + bool is_assoc = false; + + ieee80211_iterate_active_interfaces_atomic(mvm->hw, + IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_vif_assoc_iterator, + &is_assoc); scan->channel_count = mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels + mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels; @@ -529,8 +554,9 @@ static void iwl_build_scan_cmd(struct iwl_mvm *mvm, scan->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH); scan->good_CRC_th = IWL_GOOD_CRC_TH_DEFAULT; scan->rx_chain = iwl_mvm_scan_rx_chain(mvm); - scan->max_out_time = cpu_to_le32(200 * 1024); - scan->suspend_time = iwl_mvm_scan_suspend_time(vif); + scan->max_out_time = iwl_mvm_scan_max_out_time(vif, req->flags, + is_assoc); + scan->suspend_time = iwl_mvm_scan_suspend_time(vif, is_assoc); scan->filter_flags |= cpu_to_le32(MAC_FILTER_ACCEPT_GRP | MAC_FILTER_IN_BEACON); scan->scan_type = cpu_to_le32(SCAN_TYPE_BACKGROUND); -- cgit v1.2.3-70-g09d2 From 9470c3700bc4d6071af9091e8a9de17afa7e3115 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 19 Nov 2013 20:36:25 +0100 Subject: iwlwifi: mvm: quota command max_duration should be zero For now, the firmware doesn't really use the field, but it should be set to zero if there's no specific request. Setting it to the max quota doesn't make sense. Signed-off-by: Johannes Berg Reviewed-by: Ilan Peer Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/quota.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c index 17e2bc827f9..38165eba2a1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/iwlwifi/mvm/quota.c @@ -217,8 +217,7 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) } else { cmd.quotas[idx].quota = cpu_to_le32(quota * data.n_interfaces[i]); - cmd.quotas[idx].max_duration = - cpu_to_le32(IWL_MVM_MAX_QUOTA); + cmd.quotas[idx].max_duration = cpu_to_le32(0); } idx++; } -- cgit v1.2.3-70-g09d2 From 393b9e5b821f4a27cd6decb55c866b6b9294c198 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Wed, 13 Nov 2013 16:46:19 +0200 Subject: iwlwifi: mvm: stop using MIMO in case BT doesn't allow it Switch to using the new btcoex decision api regarding MIMO and stop accessing the internal btcoex structs. In case MIMO should be disabled it would detect this upon the next Tx and force a search. The search will switch to SISO on a antenna A which isn't used by BT. Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 26 ++++++-------------------- drivers/net/wireless/iwlwifi/mvm/rs.h | 13 ------------- 2 files changed, 6 insertions(+), 33 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 482b91b80c3..95652601cd5 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -1499,6 +1499,9 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm, u8 update_search_tbl_counter = 0; int ret; + if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) + tbl->action = IWL_MIMO2_SWITCH_SISO_A; + start_action = tbl->action; while (1) { lq_sta->action_counter++; @@ -1970,26 +1973,9 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, (current_tpt > (100 * tbl->expected_tpt[low])))) scale_action = 0; - if ((le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) >= - IWL_BT_COEX_TRAFFIC_LOAD_HIGH) && (is_mimo(tbl->lq_type))) { - if (lq_sta->last_bt_traffic > - le32_to_cpu(mvm->last_bt_notif.bt_activity_grading)) { - /* - * don't set scale_action, don't want to scale up if - * the rate scale doesn't otherwise think that is a - * good idea. - */ - } else if (lq_sta->last_bt_traffic <= - le32_to_cpu(mvm->last_bt_notif.bt_activity_grading)) { - scale_action = -1; - } - } - lq_sta->last_bt_traffic = - le32_to_cpu(mvm->last_bt_notif.bt_activity_grading); - - if ((le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) >= - IWL_BT_COEX_TRAFFIC_LOAD_HIGH) && is_mimo(tbl->lq_type)) { - /* search for a new modulation */ + /* Force a search in case BT doesn't like us being in MIMO */ + if (is_mimo(tbl->lq_type) && + !iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) { rs_stay_in_table(lq_sta, true); goto lq_update; } diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index b41686b7672..5dd30eace42 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -328,19 +328,6 @@ struct iwl_lq_sta { u32 last_rate_n_flags; /* packets destined for this STA are aggregated */ u8 is_agg; - /* BT traffic this sta was last updated in */ - u8 last_bt_traffic; -}; - -enum iwl_bt_coex_profile_traffic_load { - IWL_BT_COEX_TRAFFIC_LOAD_NONE = 0, - IWL_BT_COEX_TRAFFIC_LOAD_LOW = 1, - IWL_BT_COEX_TRAFFIC_LOAD_HIGH = 2, - IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS = 3, -/* - * There are no more even though below is a u8, the - * indication from the BT device only has two bits. - */ }; /* Initialize station's rate scaling information after adding station */ -- cgit v1.2.3-70-g09d2 From 271518adff21b48c88caeb7d8847cb94af197994 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Sat, 9 Nov 2013 23:25:06 +0200 Subject: iwlwifi: mvm: don't enable VHT MCS9 in 20Mhz MCS9 in NSS=1 or NSS=2 isn't valid for 20Mhz so don't enable it in case we're dealing with a 20Mhz sta. Trying to configure an MCS9 rate with 20Mhz in the LQ rate table would lead to a FW assert. Signed-off-by: Eyal Shapira Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 95652601cd5..f1364b7f58e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -2241,6 +2241,11 @@ static void rs_vht_set_enabled_rates(struct ieee80211_sta *sta, if (i == IWL_RATE_9M_INDEX) continue; + /* VHT MCS9 isn't valid for 20Mhz for NSS=1,2 */ + if (i == IWL_RATE_MCS_9_INDEX && + sta->bandwidth == IEEE80211_STA_RX_BW_20) + continue; + lq_sta->active_siso_rate |= BIT(i); } } @@ -2251,6 +2256,11 @@ static void rs_vht_set_enabled_rates(struct ieee80211_sta *sta, if (i == IWL_RATE_9M_INDEX) continue; + /* VHT MCS9 isn't valid for 20Mhz for NSS=1,2 */ + if (i == IWL_RATE_MCS_9_INDEX && + sta->bandwidth == IEEE80211_STA_RX_BW_20) + continue; + lq_sta->active_mimo2_rate |= BIT(i); } } -- cgit v1.2.3-70-g09d2 From ecc90e79e5add903de9f1bb599bdb2384cc762fb Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Sat, 9 Nov 2013 23:31:38 +0200 Subject: iwlwifi: mvm: don't configure mimo rates if nss is limited to 1 Remote peer can publish a different number of supported nss via the operating mode notification IE or action frame. If it limits to 1 then we don't want mimo rates configured in the rate table. Signed-off-by: Eyal Shapira Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index f1364b7f58e..a7efeb31c25 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -2250,6 +2250,9 @@ static void rs_vht_set_enabled_rates(struct ieee80211_sta *sta, } } + if (sta->rx_nss < 2) + return; + highest_mcs = rs_vht_highest_rx_mcs_index(vht_cap, 2); if (highest_mcs >= IWL_RATE_MCS_0_INDEX) { for (i = IWL_RATE_MCS_0_INDEX; i <= highest_mcs; i++) { -- cgit v1.2.3-70-g09d2 From 4d30ee8247872b7eb7f38342d603963045ed8cba Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Wed, 20 Nov 2013 01:45:38 +0200 Subject: iwlwifi: mvm: rs: improve debug prints Enable better tracking of different decisions made by the rate scale algorithm. Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 116 ++++++++++++++++++++++++---------- 1 file changed, 83 insertions(+), 33 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index a7efeb31c25..065520968d2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -174,7 +174,7 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm, struct ieee80211_sta *sta, struct iwl_lq_sta *lq_sta, u32 rate_n_flags); static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search); - +static const char *rs_pretty_lq_type(enum iwl_table_type type); #ifdef CONFIG_MAC80211_DEBUGFS static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, @@ -778,9 +778,6 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, struct iwl_scale_tbl_info tbl_type; struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl; - IWL_DEBUG_RATE_LIMIT(mvm, - "get frame ack response, update rate scale window\n"); - /* Treat uninitialized rate scaling data same as non-existing. */ if (!lq_sta) { IWL_DEBUG_RATE(mvm, "Station rate scaling not created yet.\n"); @@ -1499,8 +1496,10 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm, u8 update_search_tbl_counter = 0; int ret; - if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) + if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) { + IWL_DEBUG_RATE(mvm, "BT COEX force switch to SISO A\n"); tbl->action = IWL_MIMO2_SWITCH_SISO_A; + } start_action = tbl->action; while (1) { @@ -1721,8 +1720,6 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, struct iwl_mvm_sta *sta_priv = (void *)sta->drv_priv; struct iwl_mvm_tid_data *tid_data; - IWL_DEBUG_RATE(mvm, "rate scale calculate new rate for skb\n"); - /* Send management frames and NO_ACK data using lowest rate. */ /* TODO: this could probably be improved.. */ if (!ieee80211_is_data(hdr->frame_control) || @@ -1758,14 +1755,9 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, /* current tx rate */ index = lq_sta->last_txrate_idx; - IWL_DEBUG_RATE(mvm, "Rate scale index %d for type %d\n", index, - tbl->lq_type); - /* rates available for this association, and for modulation mode */ rate_mask = rs_get_supported_rates(lq_sta, hdr, tbl->lq_type); - IWL_DEBUG_RATE(mvm, "mask 0x%04X\n", rate_mask); - /* mask with station rate restriction */ if (is_legacy(tbl->lq_type)) { if (lq_sta->band == IEEE80211_BAND_5GHZ) @@ -1809,6 +1801,9 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, index = lq_sta->max_rate_idx; update_lq = 1; window = &(tbl->win[index]); + IWL_DEBUG_RATE(mvm, + "Forcing user max rate %d\n", + index); goto lq_update; } @@ -1825,8 +1820,9 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, if ((fail_count < IWL_RATE_MIN_FAILURE_TH) && (window->success_counter < IWL_RATE_MIN_SUCCESS_TH)) { IWL_DEBUG_RATE(mvm, - "LQ: still below TH. succ=%d total=%d for index %d\n", - window->success_counter, window->counter, index); + "(%s: %d): Test Window: succ %d total %d\n", + rs_pretty_lq_type(tbl->lq_type), + index, window->success_counter, window->counter); /* Can't calculate this yet; not enough history */ window->average_tpt = IWL_INVALID_VALUE; @@ -1854,7 +1850,8 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, * continuing to use the setup that we've been trying. */ if (window->average_tpt > lq_sta->last_tpt) { IWL_DEBUG_RATE(mvm, - "LQ: SWITCHING TO NEW TABLE suc=%d cur-tpt=%d old-tpt=%d\n", + "SWITCHING TO NEW TABLE SR: %d " + "cur-tpt %d old-tpt %d\n", window->success_ratio, window->average_tpt, lq_sta->last_tpt); @@ -1868,7 +1865,8 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, /* Else poor success; go back to mode in "active" table */ } else { IWL_DEBUG_RATE(mvm, - "LQ: GOING BACK TO THE OLD TABLE suc=%d cur-tpt=%d old-tpt=%d\n", + "GOING BACK TO THE OLD TABLE: SR %d " + "cur-tpt %d old-tpt %d\n", window->success_ratio, window->average_tpt, lq_sta->last_tpt); @@ -1916,20 +1914,31 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, if (high != IWL_RATE_INVALID) high_tpt = tbl->win[high].average_tpt; + IWL_DEBUG_RATE(mvm, + "(%s: %d): cur_tpt %d SR %d low %d high %d low_tpt %d high_tpt %d\n", + rs_pretty_lq_type(tbl->lq_type), index, current_tpt, + sr, low, high, low_tpt, high_tpt); + scale_action = 0; /* Too many failures, decrease rate */ if ((sr <= IWL_RATE_DECREASE_TH) || (current_tpt == 0)) { IWL_DEBUG_RATE(mvm, - "decrease rate because of low success_ratio\n"); + "decrease rate because of low SR\n"); scale_action = -1; /* No throughput measured yet for adjacent rates; try increase. */ } else if ((low_tpt == IWL_INVALID_VALUE) && (high_tpt == IWL_INVALID_VALUE)) { - if (high != IWL_RATE_INVALID && sr >= IWL_RATE_INCREASE_TH) + if (high != IWL_RATE_INVALID && sr >= IWL_RATE_INCREASE_TH) { + IWL_DEBUG_RATE(mvm, + "Good SR and no high rate measurement. " + "Increase rate\n"); scale_action = 1; - else if (low != IWL_RATE_INVALID) + } else if (low != IWL_RATE_INVALID) { + IWL_DEBUG_RATE(mvm, + "Remain in current rate\n"); scale_action = 0; + } } /* Both adjacent throughputs are measured, but neither one has better @@ -1937,8 +1946,12 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, else if ((low_tpt != IWL_INVALID_VALUE) && (high_tpt != IWL_INVALID_VALUE) && (low_tpt < current_tpt) && - (high_tpt < current_tpt)) + (high_tpt < current_tpt)) { + IWL_DEBUG_RATE(mvm, + "Both high and low are worse. " + "Maintain rate\n"); scale_action = 0; + } /* At least one adjacent rate's throughput is measured, * and may have better performance. */ @@ -1948,8 +1961,14 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, /* Higher rate has better throughput */ if (high_tpt > current_tpt && sr >= IWL_RATE_INCREASE_TH) { + IWL_DEBUG_RATE(mvm, + "Higher rate is better and good " + "SR. Increate rate\n"); scale_action = 1; } else { + IWL_DEBUG_RATE(mvm, + "Higher rate isn't better OR " + "no good SR. Maintain rate\n"); scale_action = 0; } @@ -1958,9 +1977,13 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, /* Lower rate has better throughput */ if (low_tpt > current_tpt) { IWL_DEBUG_RATE(mvm, - "decrease rate because of low tpt\n"); + "Lower rate is better. " + "Decrease rate\n"); scale_action = -1; } else if (sr >= IWL_RATE_INCREASE_TH) { + IWL_DEBUG_RATE(mvm, + "Lower rate isn't better and " + "good SR. Increase rate\n"); scale_action = 1; } } @@ -1970,12 +1993,17 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, * has been good at old rate. Don't change it. */ if ((scale_action == -1) && (low != IWL_RATE_INVALID) && ((sr > IWL_RATE_HIGH_TH) || - (current_tpt > (100 * tbl->expected_tpt[low])))) + (current_tpt > (100 * tbl->expected_tpt[low])))) { + IWL_DEBUG_RATE(mvm, + "Sanity check failed. Maintain rate\n"); scale_action = 0; + } /* Force a search in case BT doesn't like us being in MIMO */ if (is_mimo(tbl->lq_type) && !iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) { + IWL_DEBUG_RATE(mvm, + "BT Coex forbids MIMO. Search for new config\n"); rs_stay_in_table(lq_sta, true); goto lq_update; } @@ -1986,6 +2014,9 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, if (low != IWL_RATE_INVALID) { update_lq = 1; index = low; + } else { + IWL_DEBUG_RATE(mvm, + "At the bottom rate. Can't decrease\n"); } break; @@ -1994,6 +2025,9 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, if (high != IWL_RATE_INVALID) { update_lq = 1; index = high; + } else { + IWL_DEBUG_RATE(mvm, + "At the top rate. Can't increase\n"); } break; @@ -2003,10 +2037,6 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, break; } - IWL_DEBUG_RATE(mvm, - "choose rate scale index %d action %d low %d high %d type %d\n", - index, scale_action, low, high, tbl->lq_type); - lq_update: /* Replace uCode's rate table for the destination station. */ if (update_lq) @@ -2025,6 +2055,10 @@ lq_update: /* Save current throughput to compare with "search" throughput*/ lq_sta->last_tpt = current_tpt; + IWL_DEBUG_RATE(mvm, + "Start Search: update_lq %d done_search %d stay_in_tbl %d win->counter %d\n", + update_lq, done_search, lq_sta->stay_in_tbl, + window->counter); /* Select a new "search" modulation mode to try. * If one is found, set up the new "search" table. */ if (is_legacy(tbl->lq_type)) @@ -2047,8 +2081,11 @@ lq_update: index = iwl_hwrate_to_plcp_idx(tbl->current_rate); IWL_DEBUG_RATE(mvm, - "Switch current mcs: %X index: %d\n", - tbl->current_rate, index); + "Switch to SEARCH TABLE: " + "mcs %X (%s: %d)\n", + tbl->current_rate, + rs_pretty_lq_type(tbl->lq_type), + index); rs_fill_link_cmd(mvm, sta, lq_sta, tbl->current_rate); iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false); } else { @@ -2169,8 +2206,6 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_lq_sta *lq_sta = mvm_sta; - IWL_DEBUG_RATE_LIMIT(mvm, "rate scale calculate new rate for skb\n"); - /* Get max rate if user set max rate */ if (lq_sta) { lq_sta->max_rate_idx = txrc->max_rate_idx; @@ -2554,7 +2589,6 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, >> RATE_MCS_ANT_POS); if ((valid_tx_ant & ant_sel_tx) == ant_sel_tx) { *rate_n_flags = lq_sta->dbg_fixed_rate; - IWL_DEBUG_RATE(mvm, "Fixed rate ON\n"); } else { lq_sta->dbg_fixed_rate = 0; IWL_ERR(mvm, @@ -2562,8 +2596,6 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, ant_sel_tx, valid_tx_ant); IWL_DEBUG_RATE(mvm, "Fixed rate OFF\n"); } - } else { - IWL_DEBUG_RATE(mvm, "Fixed rate OFF\n"); } } @@ -2593,6 +2625,24 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file, return count; } +static const char *rs_pretty_lq_type(enum iwl_table_type type) +{ + static const char * const lq_type[] = { + [LQ_NONE] = "NONE", + [LQ_LEGACY_A] = "LEGACY_A", + [LQ_LEGACY_G] = "LEGACY_G", + [LQ_HT_SISO] = "HT SISO", + [LQ_HT_MIMO2] = "HT MIMO", + [LQ_VHT_SISO] = "VHT SISO", + [LQ_VHT_MIMO2] = "VHT MIMO", + }; + + if (type < LQ_NONE || type >= LQ_MAX) + return "UNKNOWN"; + + return lq_type[type]; +} + static int rs_pretty_print_rate(char *buf, const u32 rate) { static const char * const ant_name[] = { -- cgit v1.2.3-70-g09d2 From d17334c4405951e326d6c393a357d3cb937a090e Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Wed, 20 Nov 2013 02:08:12 +0200 Subject: iwlwifi: mvm: rs: reduce min failures to end test window This terminates a test window of a new rate quicker in case we've hit a bad rate and should recover better. Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 065520968d2..ecf24cb6ebf 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -47,7 +47,7 @@ #define IWL_HT_NUMBER_TRY 3 #define IWL_RATE_MAX_WINDOW 62 /* # tx in history window */ -#define IWL_RATE_MIN_FAILURE_TH 6 /* min failures to calc tpt */ +#define IWL_RATE_MIN_FAILURE_TH 3 /* min failures to calc tpt */ #define IWL_RATE_MIN_SUCCESS_TH 8 /* min successes to calc tpt */ /* max allowed rate miss before sync LQ cmd */ -- cgit v1.2.3-70-g09d2 From 9d015a03345d54d8de0339b2137deb96524766e0 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Thu, 21 Nov 2013 01:12:11 +0200 Subject: iwlwifi: mvm: rs: update expected TPT tables if aggregation changed Expected TPT table was updated only when switching to a new modulation. This is wrong as toggling aggregation changes the expected TPT signficantly. This leads to scenarios where turning aggregation on after being in MIMO sends us back to SISO despite a perfect success ratio. This occurred because the TPT of the SISO mode was being estimated based on aggregation while the MIMO one wasn't. Also remove an error print which isn't an error anymore since we might be updating the expected TPT table due to aggregation changes. Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index ecf24cb6ebf..882ecd30cf5 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -1717,6 +1717,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, u16 high_low; s32 sr; u8 tid = IWL_MAX_TID_COUNT; + u8 prev_agg = lq_sta->is_agg; struct iwl_mvm_sta *sta_priv = (void *)sta->drv_priv; struct iwl_mvm_tid_data *tid_data; @@ -1752,6 +1753,13 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, tbl = &(lq_sta->lq_info[active_tbl]); + if (prev_agg != lq_sta->is_agg) { + IWL_DEBUG_RATE(mvm, + "Aggregation changed: prev %d current %d. Update expected TPT table\n", + prev_agg, lq_sta->is_agg); + rs_set_expected_tpt_table(lq_sta, tbl); + } + /* current tx rate */ index = lq_sta->last_txrate_idx; @@ -1837,8 +1845,6 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, * actual average throughput */ if (window->average_tpt != ((window->success_ratio * tbl->expected_tpt[index] + 64) / 128)) { - IWL_ERR(mvm, - "expected_tpt should have been calculated by now\n"); window->average_tpt = ((window->success_ratio * tbl->expected_tpt[index] + 64) / 128); } -- cgit v1.2.3-70-g09d2 From c48075d27db571ff1deeb6a0fda7bf1f0abeee4c Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Thu, 21 Nov 2013 01:18:47 +0200 Subject: iwlwifi: mvm: rs: rename thresholds defines Rename for clearer names. Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 4 ++-- drivers/net/wireless/iwlwifi/mvm/rs.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 882ecd30cf5..a289b774ba6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -1107,7 +1107,7 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm, * "active" throughput (under perfect conditions). */ if ((((100 * tpt_tbl[rate]) > lq_sta->last_tpt) && - ((active_sr > IWL_RATE_DECREASE_TH) && + ((active_sr > RS_SR_FORCE_DECREASE) && (active_sr <= IWL_RATE_HIGH_TH) && (tpt_tbl[rate] <= active_tpt))) || ((active_sr >= IWL_RATE_SCALE_SWITCH) && @@ -1928,7 +1928,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, scale_action = 0; /* Too many failures, decrease rate */ - if ((sr <= IWL_RATE_DECREASE_TH) || (current_tpt == 0)) { + if ((sr <= RS_SR_FORCE_DECREASE) || (current_tpt == 0)) { IWL_DEBUG_RATE(mvm, "decrease rate because of low SR\n"); scale_action = -1; diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index 5dd30eace42..e5d448c0d1a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -155,7 +155,7 @@ enum { #define IWL_RATE_SCALE_SWITCH 10880 /* 85% */ #define IWL_RATE_HIGH_TH 10880 /* 85% */ #define IWL_RATE_INCREASE_TH 6400 /* 50% */ -#define IWL_RATE_DECREASE_TH 1920 /* 15% */ +#define RS_SR_FORCE_DECREASE 1920 /* 15% */ /* possible actions when in legacy mode */ enum { -- cgit v1.2.3-70-g09d2 From 32b01726b944ea21e9c9dacfb34753a8e63ba877 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Fri, 22 Nov 2013 09:41:38 +0200 Subject: iwlwifi: mvm: rs: increase stay in column timeout Remain in the same Tx modulation (i.e. column) for a longer time before starting a search cycle for a better modulation. This has been shown to give better results. Also change the name of the timeout define to better match its description. Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index a289b774ba6..9249e52dafc 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -52,8 +52,8 @@ /* max allowed rate miss before sync LQ cmd */ #define IWL_MISSED_RATE_MAX 15 -/* max time to accum history 2 seconds */ -#define IWL_RATE_SCALE_FLUSH_INTVL (3*HZ) +#define RS_STAY_IN_COLUMN_TIMEOUT (5*HZ) + static u8 rs_ht_to_legacy[] = { [IWL_RATE_1M_INDEX] = IWL_RATE_6M_INDEX, @@ -1599,7 +1599,7 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search) flush_interval_passed = time_after(jiffies, (unsigned long)(lq_sta->flush_timer + - IWL_RATE_SCALE_FLUSH_INTVL)); + RS_STAY_IN_COLUMN_TIMEOUT)); /* * Check if we should allow search for new modulation mode. -- cgit v1.2.3-70-g09d2 From 0c308e97d40f0e8f43336b6076f4b26e71ba59c6 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Fri, 22 Nov 2013 14:27:20 +0200 Subject: iwlwifi: mvm: rs: remove unused timestamp field Remove this as it's unused. Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 4 ---- drivers/net/wireless/iwlwifi/mvm/rs.h | 1 - 2 files changed, 5 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 9249e52dafc..0598f26b5da 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -271,7 +271,6 @@ static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window) window->success_ratio = IWL_INVALID_VALUE; window->counter = 0; window->average_tpt = IWL_INVALID_VALUE; - window->stamp = 0; } static inline u8 rs_is_valid_ant(u8 valid_antenna, u8 ant_type) @@ -428,9 +427,6 @@ static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl, else window->average_tpt = IWL_INVALID_VALUE; - /* Tag this window as having been updated */ - window->stamp = jiffies; - return 0; } diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index e5d448c0d1a..ae983bce217 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -257,7 +257,6 @@ struct iwl_rate_scale_data { s32 success_ratio; /* per-cent * 128 */ s32 counter; /* number of frames attempted */ s32 average_tpt; /* success ratio * expected throughput */ - unsigned long stamp; }; /** -- cgit v1.2.3-70-g09d2 From 5aa335537aa27e0d169e98d90d23342434a1cef0 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Sat, 23 Nov 2013 01:06:36 +0200 Subject: iwlwifi: mvm: rs: refactor to use rs_rate Introduce rs_rate which represents a rate. Use this structure instead of iwl_scale_tbl_info where we're dealing with a single rate. This avoids allocating the big iwl_scale_tbl_info structure on the stack in several cases like converting to ucode rate format or from ucode rate format. Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 568 +++++++++++++++++----------------- drivers/net/wireless/iwlwifi/mvm/rs.h | 60 ++-- 2 files changed, 331 insertions(+), 297 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 0598f26b5da..3af90620b3d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -175,6 +175,7 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm, struct iwl_lq_sta *lq_sta, u32 rate_n_flags); static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search); static const char *rs_pretty_lq_type(enum iwl_table_type type); +static const char *rs_pretty_ant(u8 ant); #ifdef CONFIG_MAC80211_DEBUGFS static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, @@ -264,6 +265,15 @@ static const struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = { #define MCS_INDEX_PER_STREAM (8) +static inline void rs_dump_rate(struct iwl_mvm *mvm, const struct rs_rate *rate, + const char *prefix) +{ + IWL_DEBUG_RATE(mvm, "%s: (%s: %d) ANT: %s BW: %d SGI: %d\n", + prefix, rs_pretty_lq_type(rate->type), + rate->index, rs_pretty_ant(rate->ant), + rate->bw, rate->sgi); +} + static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window) { window->data = 0; @@ -430,167 +440,160 @@ static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl, return 0; } -/* - * Fill uCode API rate_n_flags field, based on "search" or "active" table. - */ -/* FIXME:RS:remove this function and put the flags statically in the table */ -static u32 rate_n_flags_from_tbl(struct iwl_mvm *mvm, - struct iwl_scale_tbl_info *tbl, int index) +/* Convert rs_rate object into ucode rate bitmask */ +static u32 ucode_rate_from_rs_rate(struct iwl_mvm *mvm, + struct rs_rate *rate) { - u32 rate_n_flags = 0; + u32 ucode_rate = 0; + int index = rate->index; - rate_n_flags |= ((tbl->ant_type << RATE_MCS_ANT_POS) & + ucode_rate |= ((rate->ant << RATE_MCS_ANT_POS) & RATE_MCS_ANT_ABC_MSK); - if (is_legacy(tbl->lq_type)) { - rate_n_flags |= iwl_rates[index].plcp; + if (is_legacy(rate)) { + ucode_rate |= iwl_rates[index].plcp; if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE) - rate_n_flags |= RATE_MCS_CCK_MSK; - return rate_n_flags; + ucode_rate |= RATE_MCS_CCK_MSK; + return ucode_rate; } - if (is_ht(tbl->lq_type)) { + if (is_ht(rate)) { if (index < IWL_FIRST_HT_RATE || index > IWL_LAST_HT_RATE) { IWL_ERR(mvm, "Invalid HT rate index %d\n", index); index = IWL_LAST_HT_RATE; } - rate_n_flags |= RATE_MCS_HT_MSK; + ucode_rate |= RATE_MCS_HT_MSK; - if (is_ht_siso(tbl->lq_type)) - rate_n_flags |= iwl_rates[index].plcp_ht_siso; - else if (is_ht_mimo2(tbl->lq_type)) - rate_n_flags |= iwl_rates[index].plcp_ht_mimo2; + if (is_ht_siso(rate)) + ucode_rate |= iwl_rates[index].plcp_ht_siso; + else if (is_ht_mimo2(rate)) + ucode_rate |= iwl_rates[index].plcp_ht_mimo2; else WARN_ON_ONCE(1); - } else if (is_vht(tbl->lq_type)) { + } else if (is_vht(rate)) { if (index < IWL_FIRST_VHT_RATE || index > IWL_LAST_VHT_RATE) { IWL_ERR(mvm, "Invalid VHT rate index %d\n", index); index = IWL_LAST_VHT_RATE; } - rate_n_flags |= RATE_MCS_VHT_MSK; - if (is_vht_siso(tbl->lq_type)) - rate_n_flags |= iwl_rates[index].plcp_vht_siso; - else if (is_vht_mimo2(tbl->lq_type)) - rate_n_flags |= iwl_rates[index].plcp_vht_mimo2; + ucode_rate |= RATE_MCS_VHT_MSK; + if (is_vht_siso(rate)) + ucode_rate |= iwl_rates[index].plcp_vht_siso; + else if (is_vht_mimo2(rate)) + ucode_rate |= iwl_rates[index].plcp_vht_mimo2; else WARN_ON_ONCE(1); } else { - IWL_ERR(mvm, "Invalid tbl->lq_type %d\n", tbl->lq_type); + IWL_ERR(mvm, "Invalid rate->type %d\n", rate->type); } - rate_n_flags |= tbl->bw; - if (tbl->is_SGI) - rate_n_flags |= RATE_MCS_SGI_MSK; + ucode_rate |= rate->bw; + if (rate->sgi) + ucode_rate |= RATE_MCS_SGI_MSK; - return rate_n_flags; + return ucode_rate; } -/* - * Interpret uCode API's rate_n_flags format, - * fill "search" or "active" tx mode table. - */ -static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags, - enum ieee80211_band band, - struct iwl_scale_tbl_info *tbl, - int *rate_idx) +/* Convert a ucode rate into an rs_rate object */ +static int rs_rate_from_ucode_rate(const u32 ucode_rate, + enum ieee80211_band band, + struct rs_rate *rate) { - u32 ant_msk = (rate_n_flags & RATE_MCS_ANT_ABC_MSK); - u8 num_of_ant = get_num_of_ant_from_rate(rate_n_flags); + u32 ant_msk = ucode_rate & RATE_MCS_ANT_ABC_MSK; + u8 num_of_ant = get_num_of_ant_from_rate(ucode_rate); u8 nss; - memset(tbl, 0, offsetof(struct iwl_scale_tbl_info, win)); - *rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags); + memset(rate, 0, sizeof(struct rs_rate)); + rate->index = iwl_hwrate_to_plcp_idx(ucode_rate); - if (*rate_idx == IWL_RATE_INVALID) { - *rate_idx = -1; + if (rate->index == IWL_RATE_INVALID) { + rate->index = -1; return -EINVAL; } - tbl->is_SGI = 0; /* default legacy setup */ - tbl->bw = 0; - tbl->ant_type = (ant_msk >> RATE_MCS_ANT_POS); - tbl->lq_type = LQ_NONE; - tbl->max_search = IWL_MAX_SEARCH; + + rate->ant = (ant_msk >> RATE_MCS_ANT_POS); /* Legacy */ - if (!(rate_n_flags & RATE_MCS_HT_MSK) && - !(rate_n_flags & RATE_MCS_VHT_MSK)) { + if (!(ucode_rate & RATE_MCS_HT_MSK) && + !(ucode_rate & RATE_MCS_VHT_MSK)) { if (num_of_ant == 1) { if (band == IEEE80211_BAND_5GHZ) - tbl->lq_type = LQ_LEGACY_A; + rate->type = LQ_LEGACY_A; else - tbl->lq_type = LQ_LEGACY_G; + rate->type = LQ_LEGACY_G; } return 0; } /* HT or VHT */ - if (rate_n_flags & RATE_MCS_SGI_MSK) - tbl->is_SGI = 1; + if (ucode_rate & RATE_MCS_SGI_MSK) + rate->sgi = true; - tbl->bw = rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK; + rate->bw = ucode_rate & RATE_MCS_CHAN_WIDTH_MSK; - if (rate_n_flags & RATE_MCS_HT_MSK) { - nss = ((rate_n_flags & RATE_HT_MCS_NSS_MSK) >> + if (ucode_rate & RATE_MCS_HT_MSK) { + nss = ((ucode_rate & RATE_HT_MCS_NSS_MSK) >> RATE_HT_MCS_NSS_POS) + 1; if (nss == 1) { - tbl->lq_type = LQ_HT_SISO; + rate->type = LQ_HT_SISO; WARN_ON_ONCE(num_of_ant != 1); } else if (nss == 2) { - tbl->lq_type = LQ_HT_MIMO2; + rate->type = LQ_HT_MIMO2; WARN_ON_ONCE(num_of_ant != 2); } else { WARN_ON_ONCE(1); } - } else if (rate_n_flags & RATE_MCS_VHT_MSK) { - nss = ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >> + } else if (ucode_rate & RATE_MCS_VHT_MSK) { + nss = ((ucode_rate & RATE_VHT_MCS_NSS_MSK) >> RATE_VHT_MCS_NSS_POS) + 1; if (nss == 1) { - tbl->lq_type = LQ_VHT_SISO; + rate->type = LQ_VHT_SISO; WARN_ON_ONCE(num_of_ant != 1); } else if (nss == 2) { - tbl->lq_type = LQ_VHT_MIMO2; + rate->type = LQ_VHT_MIMO2; WARN_ON_ONCE(num_of_ant != 2); } else { WARN_ON_ONCE(1); } } - WARN_ON_ONCE(tbl->bw == RATE_MCS_CHAN_WIDTH_160); - WARN_ON_ONCE(tbl->bw == RATE_MCS_CHAN_WIDTH_80 && - !is_vht(tbl->lq_type)); + WARN_ON_ONCE(rate->bw == RATE_MCS_CHAN_WIDTH_160); + WARN_ON_ONCE(rate->bw == RATE_MCS_CHAN_WIDTH_80 && + !is_vht(rate)); return 0; } /* switch to another antenna/antennas and return 1 */ /* if no other valid antenna found, return 0 */ -static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags, - struct iwl_scale_tbl_info *tbl) +static int rs_toggle_antenna(u32 valid_ant, u32 *ucode_rate, + struct rs_rate *rate) { u8 new_ant_type; - if (!tbl->ant_type || tbl->ant_type > ANT_ABC) + if (!rate->ant || rate->ant > ANT_ABC) return 0; - if (!rs_is_valid_ant(valid_ant, tbl->ant_type)) + if (!rs_is_valid_ant(valid_ant, rate->ant)) return 0; - new_ant_type = ant_toggle_lookup[tbl->ant_type]; + new_ant_type = ant_toggle_lookup[rate->ant]; - while ((new_ant_type != tbl->ant_type) && + while ((new_ant_type != rate->ant) && !rs_is_valid_ant(valid_ant, new_ant_type)) new_ant_type = ant_toggle_lookup[new_ant_type]; - if (new_ant_type == tbl->ant_type) + if (new_ant_type == rate->ant) return 0; - tbl->ant_type = new_ant_type; - *rate_n_flags &= ~RATE_MCS_ANT_ABC_MSK; - *rate_n_flags |= new_ant_type << RATE_MCS_ANT_POS; + rate->ant = new_ant_type; + + /* TODO: get rid of ucode_rate here. This should handle only rs_rate */ + *ucode_rate &= ~RATE_MCS_ANT_ABC_MSK; + *ucode_rate |= new_ant_type << RATE_MCS_ANT_POS; return 1; } @@ -603,13 +606,13 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags, */ static u16 rs_get_supported_rates(struct iwl_lq_sta *lq_sta, struct ieee80211_hdr *hdr, - enum iwl_table_type rate_type) + struct rs_rate *rate) { - if (is_legacy(rate_type)) + if (is_legacy(rate)) return lq_sta->active_legacy_rate; - else if (is_siso(rate_type)) + else if (is_siso(rate)) return lq_sta->active_siso_rate; - else if (is_mimo2(rate_type)) + else if (is_mimo2(rate)) return lq_sta->active_mimo2_rate; WARN_ON_ONCE(1); @@ -624,7 +627,7 @@ static u16 rs_get_adjacent_rate(struct iwl_mvm *mvm, u8 index, u16 rate_mask, /* 802.11A or ht walks to the next literal adjacent rate in * the rate table */ - if (is_a_band(rate_type) || !is_legacy(rate_type)) { + if (is_type_a_band(rate_type) || !is_type_legacy(rate_type)) { int i; u32 mask; @@ -673,7 +676,7 @@ static u16 rs_get_adjacent_rate(struct iwl_mvm *mvm, u8 index, u16 rate_mask, } static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta, - struct iwl_scale_tbl_info *tbl, + struct rs_rate *rate, u8 scale_index, u8 ht_possible) { s32 low; @@ -685,30 +688,29 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta, /* check if we need to switch from HT to legacy rates. * assumption is that mandatory rates (1Mbps or 6Mbps) * are always supported (spec demand) */ - if (!is_legacy(tbl->lq_type) && (!ht_possible || !scale_index)) { + if (!is_legacy(rate) && (!ht_possible || !scale_index)) { switch_to_legacy = 1; scale_index = rs_ht_to_legacy[scale_index]; if (lq_sta->band == IEEE80211_BAND_5GHZ) - tbl->lq_type = LQ_LEGACY_A; + rate->type = LQ_LEGACY_A; else - tbl->lq_type = LQ_LEGACY_G; + rate->type = LQ_LEGACY_G; - if (num_of_ant(tbl->ant_type) > 1) - tbl->ant_type = + if (num_of_ant(rate->ant) > 1) + rate->ant = first_antenna(iwl_fw_valid_tx_ant(mvm->fw)); - tbl->bw = 0; - tbl->is_SGI = 0; - tbl->max_search = IWL_MAX_SEARCH; + rate->bw = 0; + rate->sgi = false; } - rate_mask = rs_get_supported_rates(lq_sta, NULL, tbl->lq_type); + rate_mask = rs_get_supported_rates(lq_sta, NULL, rate); /* Mask with station rate restriction */ - if (is_legacy(tbl->lq_type)) { + if (is_legacy(rate)) { /* supp_rates has no CCK bits in A mode */ if (lq_sta->band == IEEE80211_BAND_5GHZ) - rate_mask = (u16)(rate_mask & + rate_mask = (u16)(rate_mask & (lq_sta->supp_rates << IWL_FIRST_OFDM_RATE)); else rate_mask = (u16)(rate_mask & lq_sta->supp_rates); @@ -721,24 +723,22 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta, } high_low = rs_get_adjacent_rate(lq_sta->drv, scale_index, rate_mask, - tbl->lq_type); + rate->type); low = high_low & 0xff; if (low == IWL_RATE_INVALID) low = scale_index; out: - return rate_n_flags_from_tbl(lq_sta->drv, tbl, low); + rate->index = low; + return ucode_rate_from_rs_rate(lq_sta->drv, rate); } -/* - * Simple function to compare two rate scale table types - */ -static bool table_type_matches(struct iwl_scale_tbl_info *a, - struct iwl_scale_tbl_info *b) +/* Simple function to compare two rate scale table types */ +static inline bool rs_rate_match(struct rs_rate *a, + struct rs_rate *b) { - return (a->lq_type == b->lq_type) && (a->ant_type == b->ant_type) && - (a->is_SGI == b->is_SGI); + return (a->type == b->type) && (a->ant == b->ant) && (a->sgi == b->sgi); } static u32 rs_ch_width_from_mac_flags(enum mac80211_rate_control_flags flags) @@ -762,7 +762,7 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, { int legacy_success; int retries; - int rs_index, mac_index, i; + int mac_index, i; struct iwl_lq_sta *lq_sta = priv_sta; struct iwl_lq_cmd *table; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; @@ -770,8 +770,8 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); enum mac80211_rate_control_flags mac_flags; - u32 tx_rate; - struct iwl_scale_tbl_info tbl_type; + u32 ucode_rate; + struct rs_rate rate; struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl; /* Treat uninitialized rate scaling data same as non-existing. */ @@ -801,10 +801,10 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, * to a new "search" mode (which might become the new "active" mode). */ table = &lq_sta->lq; - tx_rate = le32_to_cpu(table->rs_table[0]); - rs_get_tbl_info_from_mcs(tx_rate, info->band, &tbl_type, &rs_index); + ucode_rate = le32_to_cpu(table->rs_table[0]); + rs_rate_from_ucode_rate(ucode_rate, info->band, &rate); if (info->band == IEEE80211_BAND_5GHZ) - rs_index -= IWL_FIRST_OFDM_RATE; + rate.index -= IWL_FIRST_OFDM_RATE; mac_flags = info->status.rates[0].flags; mac_index = info->status.rates[0].idx; /* For HT packets, map MCS to PLCP */ @@ -827,19 +827,19 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, /* Here we actually compare this rate to the latest LQ command */ if ((mac_index < 0) || - (tbl_type.is_SGI != !!(mac_flags & IEEE80211_TX_RC_SHORT_GI)) || - (tbl_type.bw != rs_ch_width_from_mac_flags(mac_flags)) || - (tbl_type.ant_type != info->status.antenna) || - (!!(tx_rate & RATE_MCS_HT_MSK) != + (rate.sgi != !!(mac_flags & IEEE80211_TX_RC_SHORT_GI)) || + (rate.bw != rs_ch_width_from_mac_flags(mac_flags)) || + (rate.ant != info->status.antenna) || + (!!(ucode_rate & RATE_MCS_HT_MSK) != !!(mac_flags & IEEE80211_TX_RC_MCS)) || - (!!(tx_rate & RATE_MCS_VHT_MSK) != + (!!(ucode_rate & RATE_MCS_VHT_MSK) != !!(mac_flags & IEEE80211_TX_RC_VHT_MCS)) || - (!!(tx_rate & RATE_HT_MCS_GF_MSK) != + (!!(ucode_rate & RATE_HT_MCS_GF_MSK) != !!(mac_flags & IEEE80211_TX_RC_GREEN_FIELD)) || - (rs_index != mac_index)) { + (rate.index != mac_index)) { IWL_DEBUG_RATE(mvm, "initial rate %d does not match %d (0x%x)\n", - mac_index, rs_index, tx_rate); + mac_index, rate.index, ucode_rate); /* * Since rates mis-match, the last LQ command may have failed. * After IWL_MISSED_RATE_MAX mis-matches, resync the uCode with @@ -857,28 +857,23 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, lq_sta->missed_rate_counter = 0; /* Figure out if rate scale algorithm is in active or search table */ - if (table_type_matches(&tbl_type, - &(lq_sta->lq_info[lq_sta->active_tbl]))) { + if (rs_rate_match(&rate, + &(lq_sta->lq_info[lq_sta->active_tbl].rate))) { curr_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); other_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); - } else if (table_type_matches( - &tbl_type, &lq_sta->lq_info[1 - lq_sta->active_tbl])) { + } else if (rs_rate_match(&rate, + &lq_sta->lq_info[1 - lq_sta->active_tbl].rate)) { curr_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); other_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); } else { IWL_DEBUG_RATE(mvm, "Neither active nor search matches tx rate\n"); tmp_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); - IWL_DEBUG_RATE(mvm, "active- lq:%x, ant:%x, SGI:%d\n", - tmp_tbl->lq_type, tmp_tbl->ant_type, - tmp_tbl->is_SGI); + rs_dump_rate(mvm, &tmp_tbl->rate, "ACTIVE"); tmp_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); - IWL_DEBUG_RATE(mvm, "search- lq:%x, ant:%x, SGI:%d\n", - tmp_tbl->lq_type, tmp_tbl->ant_type, - tmp_tbl->is_SGI); - IWL_DEBUG_RATE(mvm, "actual- lq:%x, ant:%x, SGI:%d\n", - tbl_type.lq_type, tbl_type.ant_type, - tbl_type.is_SGI); + rs_dump_rate(mvm, &tmp_tbl->rate, "SEARCH"); + rs_dump_rate(mvm, &rate, "ACTUAL"); + /* * no matching table found, let's by-pass the data collection * and continue to perform rate scale to find the rate table @@ -895,10 +890,9 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, * first index into rate scale table. */ if (info->flags & IEEE80211_TX_STAT_AMPDU) { - tx_rate = le32_to_cpu(table->rs_table[0]); - rs_get_tbl_info_from_mcs(tx_rate, info->band, &tbl_type, - &rs_index); - rs_collect_tx_data(curr_tbl, rs_index, + ucode_rate = le32_to_cpu(table->rs_table[0]); + rs_rate_from_ucode_rate(ucode_rate, info->band, &rate); + rs_collect_tx_data(curr_tbl, rate.index, info->status.ampdu_len, info->status.ampdu_ack_len); @@ -920,20 +914,19 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, legacy_success = !!(info->flags & IEEE80211_TX_STAT_ACK); /* Collect data for each rate used during failed TX attempts */ for (i = 0; i <= retries; ++i) { - tx_rate = le32_to_cpu(table->rs_table[i]); - rs_get_tbl_info_from_mcs(tx_rate, info->band, - &tbl_type, &rs_index); + ucode_rate = le32_to_cpu(table->rs_table[i]); + rs_rate_from_ucode_rate(ucode_rate, info->band, &rate); /* * Only collect stats if retried rate is in the same RS * table as active/search. */ - if (table_type_matches(&tbl_type, curr_tbl)) + if (rs_rate_match(&rate, &curr_tbl->rate)) tmp_tbl = curr_tbl; - else if (table_type_matches(&tbl_type, other_tbl)) + else if (rs_rate_match(&rate, &other_tbl->rate)) tmp_tbl = other_tbl; else continue; - rs_collect_tx_data(tmp_tbl, rs_index, 1, + rs_collect_tx_data(tmp_tbl, rate.index, 1, i < retries ? 0 : legacy_success); } @@ -944,7 +937,7 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, } } /* The last TX rate is cached in lq_sta; it's set in if/else above */ - lq_sta->last_rate_n_flags = tx_rate; + lq_sta->last_rate_n_flags = ucode_rate; done: /* See if there's a better rate or modulation mode to try. */ if (sta && sta->supp_rates[sband->band]) @@ -988,16 +981,17 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, { /* Used to choose among HT tables */ s32 (*ht_tbl_pointer)[IWL_RATE_COUNT]; + struct rs_rate *rate = &tbl->rate; /* Check for invalid LQ type */ - if (WARN_ON_ONCE(!is_legacy(tbl->lq_type) && !is_ht(tbl->lq_type) && - !(is_vht(tbl->lq_type)))) { + if (WARN_ON_ONCE(!is_legacy(rate) && !is_ht(rate) && + !(is_vht(rate)))) { tbl->expected_tpt = expected_tpt_legacy; return; } /* Legacy rates have only one table */ - if (is_legacy(tbl->lq_type)) { + if (is_legacy(rate)) { tbl->expected_tpt = expected_tpt_legacy; return; } @@ -1006,8 +1000,8 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, /* Choose among many HT tables depending on number of streams * (SISO/MIMO2), channel width (20/40/80), SGI, and aggregation * status */ - if (is_siso(tbl->lq_type)) { - switch (tbl->bw) { + if (is_siso(rate)) { + switch (rate->bw) { case RATE_MCS_CHAN_WIDTH_20: ht_tbl_pointer = expected_tpt_siso_20MHz; break; @@ -1020,8 +1014,8 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, default: WARN_ON_ONCE(1); } - } else if (is_mimo2(tbl->lq_type)) { - switch (tbl->bw) { + } else if (is_mimo2(rate)) { + switch (rate->bw) { case RATE_MCS_CHAN_WIDTH_20: ht_tbl_pointer = expected_tpt_mimo2_20MHz; break; @@ -1038,11 +1032,11 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, WARN_ON_ONCE(1); } - if (!tbl->is_SGI && !lq_sta->is_agg) /* Normal */ + if (!rate->sgi && !lq_sta->is_agg) /* Normal */ tbl->expected_tpt = ht_tbl_pointer[0]; - else if (tbl->is_SGI && !lq_sta->is_agg) /* SGI */ + else if (rate->sgi && !lq_sta->is_agg) /* SGI */ tbl->expected_tpt = ht_tbl_pointer[1]; - else if (!tbl->is_SGI && lq_sta->is_agg) /* AGG */ + else if (!rate->sgi && lq_sta->is_agg) /* AGG */ tbl->expected_tpt = ht_tbl_pointer[2]; else /* AGG+SGI */ tbl->expected_tpt = ht_tbl_pointer[3]; @@ -1082,7 +1076,7 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm, while (1) { high_low = rs_get_adjacent_rate(mvm, rate, rate_mask, - tbl->lq_type); + tbl->rate.type); low = high_low & 0xff; high = (high_low >> 8) & 0xff; @@ -1163,30 +1157,29 @@ static inline void rs_move_next_action(struct iwl_scale_tbl_info *tbl, tbl->action = (tbl->action + 1) % (last_action + 1); } -static void rs_set_bw_from_sta(struct iwl_scale_tbl_info *tbl, - struct ieee80211_sta *sta) +static u32 rs_bw_from_sta_bw(struct ieee80211_sta *sta) { if (sta->bandwidth >= IEEE80211_STA_RX_BW_80) - tbl->bw = RATE_MCS_CHAN_WIDTH_80; + return RATE_MCS_CHAN_WIDTH_80; else if (sta->bandwidth >= IEEE80211_STA_RX_BW_40) - tbl->bw = RATE_MCS_CHAN_WIDTH_40; - else - tbl->bw = RATE_MCS_CHAN_WIDTH_20; + return RATE_MCS_CHAN_WIDTH_40; + + return RATE_MCS_CHAN_WIDTH_20; } -static bool rs_sgi_allowed(struct iwl_scale_tbl_info *tbl, +static bool rs_sgi_allowed(struct rs_rate *rate, struct ieee80211_sta *sta) { struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap; - if (is_ht20(tbl) && (ht_cap->cap & + if (is_ht20(rate) && (ht_cap->cap & IEEE80211_HT_CAP_SGI_20)) return true; - if (is_ht40(tbl) && (ht_cap->cap & + if (is_ht40(rate) && (ht_cap->cap & IEEE80211_HT_CAP_SGI_40)) return true; - if (is_ht80(tbl) && (vht_cap->cap & + if (is_ht80(rate) && (vht_cap->cap & IEEE80211_VHT_CAP_SHORT_GI_80)) return true; @@ -1202,7 +1195,7 @@ static int rs_switch_to_mimo2(struct iwl_mvm *mvm, struct iwl_scale_tbl_info *tbl, int index) { u16 rate_mask; - s32 rate; + s32 rate_idx; if (!sta->ht_cap.ht_supported) return -1; @@ -1216,24 +1209,26 @@ static int rs_switch_to_mimo2(struct iwl_mvm *mvm, IWL_DEBUG_RATE(mvm, "LQ: try to switch to MIMO2\n"); - tbl->lq_type = lq_sta->is_vht ? LQ_VHT_MIMO2 : LQ_HT_MIMO2; + tbl->rate.type = lq_sta->is_vht ? LQ_VHT_MIMO2 : LQ_HT_MIMO2; tbl->action = 0; tbl->max_search = IWL_MAX_SEARCH; rate_mask = lq_sta->active_mimo2_rate; - rs_set_bw_from_sta(tbl, sta); + tbl->rate.bw = rs_bw_from_sta_bw(sta); rs_set_expected_tpt_table(lq_sta, tbl); - rate = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index); + rate_idx = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index); IWL_DEBUG_RATE(mvm, "LQ: MIMO2 best rate %d mask %X\n", - rate, rate_mask); - if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) { + rate_idx, rate_mask); + if ((rate_idx == IWL_RATE_INVALID) || !((1 << rate_idx) & rate_mask)) { IWL_DEBUG_RATE(mvm, "Can't switch with index %d rate mask %x\n", - rate, rate_mask); + rate_idx, rate_mask); return -1; } - tbl->current_rate = rate_n_flags_from_tbl(mvm, tbl, rate); + + tbl->rate.index = rate_idx; + tbl->current_rate = ucode_rate_from_rs_rate(mvm, &tbl->rate); IWL_DEBUG_RATE(mvm, "LQ: Switch to new mcs %X index\n", tbl->current_rate); @@ -1249,30 +1244,34 @@ static int rs_switch_to_siso(struct iwl_mvm *mvm, struct iwl_scale_tbl_info *tbl, int index) { u16 rate_mask; - s32 rate; + s32 rate_idx; if (!sta->ht_cap.ht_supported) return -1; IWL_DEBUG_RATE(mvm, "LQ: try to switch to SISO\n"); - tbl->lq_type = lq_sta->is_vht ? LQ_VHT_SISO : LQ_HT_SISO; + tbl->rate.type = lq_sta->is_vht ? LQ_VHT_SISO : LQ_HT_SISO; tbl->action = 0; tbl->max_search = IWL_MAX_SEARCH; rate_mask = lq_sta->active_siso_rate; - rs_set_bw_from_sta(tbl, sta); + tbl->rate.bw = rs_bw_from_sta_bw(sta); rs_set_expected_tpt_table(lq_sta, tbl); - rate = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index); + rate_idx = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index); - IWL_DEBUG_RATE(mvm, "LQ: get best rate %d mask %X\n", rate, rate_mask); - if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) { + IWL_DEBUG_RATE(mvm, "LQ: get best rate %d mask %X\n", + rate_idx, rate_mask); + if ((rate_idx == IWL_RATE_INVALID) || !((1 << rate_idx) & rate_mask)) { IWL_DEBUG_RATE(mvm, "can not switch with index %d rate mask %x\n", - rate, rate_mask); + rate_idx, rate_mask); return -1; } - tbl->current_rate = rate_n_flags_from_tbl(mvm, tbl, rate); + + tbl->rate.index = rate_idx; + tbl->current_rate = ucode_rate_from_rs_rate(mvm, &tbl->rate); + IWL_DEBUG_RATE(mvm, "LQ: Switch to new mcs %X index\n", tbl->current_rate); return 0; @@ -1289,6 +1288,7 @@ static int rs_move_legacy_other(struct iwl_mvm *mvm, struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); struct iwl_scale_tbl_info *search_tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); + struct rs_rate *rate = &search_tbl->rate; struct iwl_rate_scale_data *window = &(tbl->win[index]); u32 sz = (sizeof(struct iwl_scale_tbl_info) - (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); @@ -1317,7 +1317,7 @@ static int rs_move_legacy_other(struct iwl_mvm *mvm, if (rs_toggle_antenna(valid_tx_ant, &search_tbl->current_rate, - search_tbl)) { + &search_tbl->rate)) { update_search_tbl_counter = 1; rs_set_expected_tpt_table(lq_sta, search_tbl); goto out; @@ -1328,7 +1328,7 @@ static int rs_move_legacy_other(struct iwl_mvm *mvm, /* Set up search table to try SISO */ memcpy(search_tbl, tbl, sz); - search_tbl->is_SGI = 0; + rate->sgi = false; ret = rs_switch_to_siso(mvm, lq_sta, sta, search_tbl, index); if (!ret) { @@ -1342,12 +1342,11 @@ static int rs_move_legacy_other(struct iwl_mvm *mvm, /* Set up search table to try MIMO */ memcpy(search_tbl, tbl, sz); - search_tbl->is_SGI = 0; - - search_tbl->ant_type = ANT_AB; + rate->sgi = false; + rate->ant = ANT_AB; if (!rs_is_valid_ant(valid_tx_ant, - search_tbl->ant_type)) + rate->ant)) break; ret = rs_switch_to_mimo2(mvm, lq_sta, sta, @@ -1365,7 +1364,7 @@ static int rs_move_legacy_other(struct iwl_mvm *mvm, if (tbl->action == start_action) break; } - search_tbl->lq_type = LQ_NONE; + rate->type = LQ_NONE; return 0; out: @@ -1386,6 +1385,7 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm, struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); struct iwl_scale_tbl_info *search_tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); + struct rs_rate *rate = &search_tbl->rate; struct iwl_rate_scale_data *window = &(tbl->win[index]); u32 sz = (sizeof(struct iwl_scale_tbl_info) - (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); @@ -1416,7 +1416,7 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm, memcpy(search_tbl, tbl, sz); if (rs_toggle_antenna(valid_tx_ant, &search_tbl->current_rate, - search_tbl)) { + rate)) { update_search_tbl_counter = 1; goto out; } @@ -1424,12 +1424,11 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm, case IWL_SISO_SWITCH_MIMO2: IWL_DEBUG_RATE(mvm, "LQ: SISO switch to MIMO2\n"); memcpy(search_tbl, tbl, sz); - search_tbl->is_SGI = 0; - - search_tbl->ant_type = ANT_AB; + rate->sgi = false; + rate->ant = ANT_AB; if (!rs_is_valid_ant(valid_tx_ant, - search_tbl->ant_type)) + rate->ant)) break; ret = rs_switch_to_mimo2(mvm, lq_sta, sta, @@ -1438,21 +1437,22 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm, goto out; break; case IWL_SISO_SWITCH_GI: - if (!rs_sgi_allowed(tbl, sta)) + if (!rs_sgi_allowed(rate, sta)) break; IWL_DEBUG_RATE(mvm, "LQ: SISO toggle SGI/NGI\n"); memcpy(search_tbl, tbl, sz); - search_tbl->is_SGI = !tbl->is_SGI; + rate->sgi = !tbl->rate.sgi; rs_set_expected_tpt_table(lq_sta, search_tbl); - if (tbl->is_SGI) { + if (tbl->rate.sgi) { s32 tpt = lq_sta->last_tpt / 100; if (tpt >= search_tbl->expected_tpt[index]) break; } + rate->index = index; search_tbl->current_rate = - rate_n_flags_from_tbl(mvm, search_tbl, index); + ucode_rate_from_rs_rate(mvm, rate); update_search_tbl_counter = 1; goto out; default: @@ -1463,7 +1463,7 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm, if (tbl->action == start_action) break; } - search_tbl->lq_type = LQ_NONE; + rate->type = LQ_NONE; return 0; out: @@ -1485,6 +1485,7 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm, struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); struct iwl_scale_tbl_info *search_tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); + struct rs_rate *rate = &search_tbl->rate; u32 sz = (sizeof(struct iwl_scale_tbl_info) - (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); u8 start_action; @@ -1509,12 +1510,12 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm, memcpy(search_tbl, tbl, sz); if (tbl->action == IWL_MIMO2_SWITCH_SISO_A) - search_tbl->ant_type = ANT_A; + rate->ant = ANT_A; else /* tbl->action == IWL_MIMO2_SWITCH_SISO_B */ - search_tbl->ant_type = ANT_B; + rate->ant = ANT_B; if (!rs_is_valid_ant(valid_tx_ant, - search_tbl->ant_type)) + rate->ant)) break; ret = rs_switch_to_siso(mvm, lq_sta, sta, @@ -1525,14 +1526,14 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm, break; case IWL_MIMO2_SWITCH_GI: - if (!rs_sgi_allowed(tbl, sta)) + if (!rs_sgi_allowed(rate, sta)) break; IWL_DEBUG_RATE(mvm, "LQ: MIMO2 toggle SGI/NGI\n"); /* Set up new search table for MIMO2 */ memcpy(search_tbl, tbl, sz); - search_tbl->is_SGI = !tbl->is_SGI; + rate->sgi = !tbl->rate.sgi; rs_set_expected_tpt_table(lq_sta, search_tbl); /* * If active table already uses the fastest possible @@ -1540,13 +1541,14 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm, * and it's working well, there's no need to look * for a better type of modulation! */ - if (tbl->is_SGI) { + if (tbl->rate.sgi) { s32 tpt = lq_sta->last_tpt / 100; if (tpt >= search_tbl->expected_tpt[index]) break; } + rate->index = index; search_tbl->current_rate = - rate_n_flags_from_tbl(mvm, search_tbl, index); + ucode_rate_from_rs_rate(mvm, rate); update_search_tbl_counter = 1; goto out; default: @@ -1557,7 +1559,7 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm, if (tbl->action == start_action) break; } - search_tbl->lq_type = LQ_NONE; + rate->type = LQ_NONE; return 0; out: lq_sta->search_better_tbl = 1; @@ -1657,14 +1659,12 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search) static void rs_update_rate_tbl(struct iwl_mvm *mvm, struct ieee80211_sta *sta, struct iwl_lq_sta *lq_sta, - struct iwl_scale_tbl_info *tbl, - int index) + struct rs_rate *rate) { - u32 rate; + u32 ucode_rate; - /* Update uCode's rate table. */ - rate = rate_n_flags_from_tbl(mvm, tbl, index); - rs_fill_link_cmd(mvm, sta, lq_sta, rate); + ucode_rate = ucode_rate_from_rs_rate(mvm, rate); + rs_fill_link_cmd(mvm, sta, lq_sta, ucode_rate); iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false); } @@ -1716,6 +1716,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, u8 prev_agg = lq_sta->is_agg; struct iwl_mvm_sta *sta_priv = (void *)sta->drv_priv; struct iwl_mvm_tid_data *tid_data; + struct rs_rate *rate; /* Send management frames and NO_ACK data using lowest rate. */ /* TODO: this could probably be improved.. */ @@ -1748,6 +1749,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, active_tbl = 1 - lq_sta->active_tbl; tbl = &(lq_sta->lq_info[active_tbl]); + rate = &tbl->rate; if (prev_agg != lq_sta->is_agg) { IWL_DEBUG_RATE(mvm, @@ -1760,10 +1762,10 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, index = lq_sta->last_txrate_idx; /* rates available for this association, and for modulation mode */ - rate_mask = rs_get_supported_rates(lq_sta, hdr, tbl->lq_type); + rate_mask = rs_get_supported_rates(lq_sta, hdr, rate); /* mask with station rate restriction */ - if (is_legacy(tbl->lq_type)) { + if (is_legacy(rate)) { if (lq_sta->band == IEEE80211_BAND_5GHZ) /* supp_rates has no CCK bits in A mode */ rate_scale_index_msk = (u16) (rate_mask & @@ -1783,12 +1785,13 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, IWL_ERR(mvm, "Current Rate is not valid\n"); if (lq_sta->search_better_tbl) { /* revert to active table if search table is not valid*/ - tbl->lq_type = LQ_NONE; + rate->type = LQ_NONE; lq_sta->search_better_tbl = 0; tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); /* get "active" rate info */ index = iwl_hwrate_to_plcp_idx(tbl->current_rate); - rs_update_rate_tbl(mvm, sta, lq_sta, tbl, index); + tbl->rate.index = index; + rs_update_rate_tbl(mvm, sta, lq_sta, &tbl->rate); } return; } @@ -1825,7 +1828,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, (window->success_counter < IWL_RATE_MIN_SUCCESS_TH)) { IWL_DEBUG_RATE(mvm, "(%s: %d): Test Window: succ %d total %d\n", - rs_pretty_lq_type(tbl->lq_type), + rs_pretty_lq_type(rate->type), index, window->success_counter, window->counter); /* Can't calculate this yet; not enough history */ @@ -1858,7 +1861,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, window->average_tpt, lq_sta->last_tpt); - if (!is_legacy(tbl->lq_type)) + if (!is_legacy(rate)) lq_sta->enable_counter = 1; /* Swap tables; "search" becomes "active" */ @@ -1874,7 +1877,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, lq_sta->last_tpt); /* Nullify "search" table */ - tbl->lq_type = LQ_NONE; + rate->type = LQ_NONE; /* Revert to "active" table */ active_tbl = lq_sta->active_tbl; @@ -1898,7 +1901,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, /* (Else) not in search of better modulation mode, try for better * starting rate, while staying in this mode. */ high_low = rs_get_adjacent_rate(mvm, index, rate_scale_index_msk, - tbl->lq_type); + rate->type); low = high_low & 0xff; high = (high_low >> 8) & 0xff; @@ -1918,8 +1921,8 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, IWL_DEBUG_RATE(mvm, "(%s: %d): cur_tpt %d SR %d low %d high %d low_tpt %d high_tpt %d\n", - rs_pretty_lq_type(tbl->lq_type), index, current_tpt, - sr, low, high, low_tpt, high_tpt); + rs_pretty_lq_type(rate->type), index, current_tpt, sr, + low, high, low_tpt, high_tpt); scale_action = 0; @@ -2002,7 +2005,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, } /* Force a search in case BT doesn't like us being in MIMO */ - if (is_mimo(tbl->lq_type) && + if (is_mimo(rate) && !iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) { IWL_DEBUG_RATE(mvm, "BT Coex forbids MIMO. Search for new config\n"); @@ -2041,8 +2044,10 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, lq_update: /* Replace uCode's rate table for the destination station. */ - if (update_lq) - rs_update_rate_tbl(mvm, sta, lq_sta, tbl, index); + if (update_lq) { + tbl->rate.index = index; + rs_update_rate_tbl(mvm, sta, lq_sta, &tbl->rate); + } rs_stay_in_table(lq_sta, false); @@ -2063,11 +2068,11 @@ lq_update: window->counter); /* Select a new "search" modulation mode to try. * If one is found, set up the new "search" table. */ - if (is_legacy(tbl->lq_type)) + if (is_legacy(&tbl->rate)) rs_move_legacy_other(mvm, lq_sta, sta, index); - else if (is_siso(tbl->lq_type)) + else if (is_siso(&tbl->rate)) rs_move_siso_to_other(mvm, lq_sta, sta, index); - else if (is_mimo2(tbl->lq_type)) + else if (is_mimo2(&tbl->rate)) rs_move_mimo2_to_other(mvm, lq_sta, sta, index); else WARN_ON_ONCE(1); @@ -2086,7 +2091,7 @@ lq_update: "Switch to SEARCH TABLE: " "mcs %X (%s: %d)\n", tbl->current_rate, - rs_pretty_lq_type(tbl->lq_type), + rs_pretty_lq_type(tbl->rate.type), index); rs_fill_link_cmd(mvm, sta, lq_sta, tbl->current_rate); iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false); @@ -2102,7 +2107,7 @@ lq_update: * stay with best antenna legacy modulation for a while * before next round of mode comparisons. */ tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]); - if (is_legacy(tbl1->lq_type) && !sta->ht_cap.ht_supported && + if (is_legacy(&tbl1->rate) && !sta->ht_cap.ht_supported && lq_sta->action_counter > tbl1->max_search) { IWL_DEBUG_RATE(mvm, "LQ: STAY in legacy table\n"); rs_set_stay_in_table(mvm, 1, lq_sta); @@ -2130,7 +2135,8 @@ lq_update: } out: - tbl->current_rate = rate_n_flags_from_tbl(mvm, tbl, index); + tbl->rate.index = index; + tbl->current_rate = ucode_rate_from_rs_rate(mvm, &tbl->rate); lq_sta->last_txrate_idx = index; } @@ -2155,9 +2161,9 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, bool init) { struct iwl_scale_tbl_info *tbl; - int rate_idx; + struct rs_rate *rate; int i; - u32 rate; + u32 ucode_rate; u8 active_tbl = 0; u8 valid_tx_ant; @@ -2174,25 +2180,26 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, active_tbl = 1 - lq_sta->active_tbl; tbl = &(lq_sta->lq_info[active_tbl]); + rate = &tbl->rate; if ((i < 0) || (i >= IWL_RATE_COUNT)) i = 0; - rate = iwl_rates[i].plcp; - tbl->ant_type = first_antenna(valid_tx_ant); - rate |= tbl->ant_type << RATE_MCS_ANT_POS; + ucode_rate = iwl_rates[i].plcp; + rate->ant = first_antenna(valid_tx_ant); + ucode_rate |= rate->ant << RATE_MCS_ANT_POS; if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE) - rate |= RATE_MCS_CCK_MSK; + ucode_rate |= RATE_MCS_CCK_MSK; - rs_get_tbl_info_from_mcs(rate, band, tbl, &rate_idx); - if (!rs_is_valid_ant(valid_tx_ant, tbl->ant_type)) - rs_toggle_antenna(valid_tx_ant, &rate, tbl); + rs_rate_from_ucode_rate(ucode_rate, band, rate); + if (!rs_is_valid_ant(valid_tx_ant, rate->ant)) + rs_toggle_antenna(valid_tx_ant, &ucode_rate, rate); - rate = rate_n_flags_from_tbl(mvm, tbl, rate_idx); - tbl->current_rate = rate; + ucode_rate = ucode_rate_from_rs_rate(mvm, rate); + tbl->current_rate = ucode_rate; rs_set_expected_tpt_table(lq_sta, tbl); - rs_fill_link_cmd(NULL, NULL, lq_sta, rate); + rs_fill_link_cmd(NULL, NULL, lq_sta, ucode_rate); /* TODO restore station should remember the lq cmd */ iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, init); } @@ -2435,9 +2442,8 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm, struct ieee80211_sta *sta, struct iwl_lq_sta *lq_sta, u32 new_rate) { - struct iwl_scale_tbl_info tbl_type; + struct rs_rate rate; int index = 0; - int rate_idx; int repeat_rate = 0; u8 ant_toggle_cnt = 0; u8 use_ht_possible = 1; @@ -2447,12 +2453,10 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm, /* Override starting rate (index 0) if needed for debug purposes */ rs_dbgfs_set_mcs(lq_sta, &new_rate); - /* Interpret new_rate (rate_n_flags) */ - rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, - &tbl_type, &rate_idx); + rs_rate_from_ucode_rate(new_rate, lq_sta->band, &rate); /* How many times should we repeat the initial rate? */ - if (is_legacy(tbl_type.lq_type)) { + if (is_legacy(&rate)) { ant_toggle_cnt = 1; repeat_rate = IWL_NUMBER_TRY; } else { @@ -2460,15 +2464,15 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm, LINK_QUAL_AGG_DISABLE_START_DEF - 1); } - lq_cmd->mimo_delim = is_mimo(tbl_type.lq_type) ? 1 : 0; + lq_cmd->mimo_delim = is_mimo(&rate) ? 1 : 0; /* Fill 1st table entry (index 0) */ lq_cmd->rs_table[index] = cpu_to_le32(new_rate); - if (num_of_ant(tbl_type.ant_type) == 1) - lq_cmd->single_stream_ant_msk = tbl_type.ant_type; - else if (num_of_ant(tbl_type.ant_type) == 2) - lq_cmd->dual_stream_ant_msk = tbl_type.ant_type; + if (num_of_ant(rate.ant) == 1) + lq_cmd->single_stream_ant_msk = rate.ant; + else if (num_of_ant(rate.ant) == 2) + lq_cmd->dual_stream_ant_msk = rate.ant; /* otherwise we don't modify the existing value */ index++; @@ -2482,12 +2486,12 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm, * For legacy IWL_NUMBER_TRY == 1, this loop will not execute. * For HT IWL_HT_NUMBER_TRY == 3, this executes twice. */ while (repeat_rate > 0 && (index < LINK_QUAL_MAX_RETRY_NUM)) { - if (is_legacy(tbl_type.lq_type)) { + if (is_legacy(&rate)) { if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE) ant_toggle_cnt++; else if (mvm && rs_toggle_antenna(valid_tx_ant, - &new_rate, &tbl_type)) + &new_rate, &rate)) ant_toggle_cnt = 1; } @@ -2501,26 +2505,25 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm, index++; } - rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, &tbl_type, - &rate_idx); + rs_rate_from_ucode_rate(new_rate, lq_sta->band, &rate); /* Indicate to uCode which entries might be MIMO. * If initial rate was MIMO, this will finally end up * as (IWL_HT_NUMBER_TRY * 2), after 2nd pass, otherwise 0. */ - if (is_mimo(tbl_type.lq_type)) + if (is_mimo(&rate)) lq_cmd->mimo_delim = index; /* Get next rate */ - new_rate = rs_get_lower_rate(lq_sta, &tbl_type, rate_idx, + new_rate = rs_get_lower_rate(lq_sta, &rate, rate.index, use_ht_possible); /* How many times should we repeat the next rate? */ - if (is_legacy(tbl_type.lq_type)) { + if (is_legacy(&rate)) { if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE) ant_toggle_cnt++; else if (mvm && rs_toggle_antenna(valid_tx_ant, - &new_rate, &tbl_type)) + &new_rate, &rate)) ant_toggle_cnt = 1; repeat_rate = IWL_NUMBER_TRY; @@ -2629,7 +2632,7 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file, static const char *rs_pretty_lq_type(enum iwl_table_type type) { - static const char * const lq_type[] = { + static const char * const lq_types[] = { [LQ_NONE] = "NONE", [LQ_LEGACY_A] = "LEGACY_A", [LQ_LEGACY_G] = "LEGACY_G", @@ -2642,10 +2645,10 @@ static const char *rs_pretty_lq_type(enum iwl_table_type type) if (type < LQ_NONE || type >= LQ_MAX) return "UNKNOWN"; - return lq_type[type]; + return lq_types[type]; } -static int rs_pretty_print_rate(char *buf, const u32 rate) +static const char *rs_pretty_ant(u8 ant) { static const char * const ant_name[] = { [ANT_NONE] = "None", @@ -2658,6 +2661,15 @@ static int rs_pretty_print_rate(char *buf, const u32 rate) [ANT_ABC] = "ABC", }; + if (ant > ANT_ABC) + return "UNKNOWN"; + + return ant_name[ant]; +} + +static int rs_pretty_print_rate(char *buf, const u32 rate) +{ + char *type, *bw; u8 mcs = 0, nss = 0; u8 ant = (rate & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS; @@ -2667,7 +2679,7 @@ static int rs_pretty_print_rate(char *buf, const u32 rate) int index = iwl_hwrate_to_plcp_idx(rate); return sprintf(buf, "Legacy | ANT: %s Rate: %s Mbps\n", - ant_name[ant], iwl_rate_mcs[index].mbps); + rs_pretty_ant(ant), iwl_rate_mcs[index].mbps); } if (rate & RATE_MCS_VHT_MSK) { @@ -2700,7 +2712,7 @@ static int rs_pretty_print_rate(char *buf, const u32 rate) } return sprintf(buf, "%s | ANT: %s BW: %s MCS: %d NSS: %d %s%s%s%s%s\n", - type, ant_name[ant], bw, mcs, nss, + type, rs_pretty_ant(ant), bw, mcs, nss, (rate & RATE_MCS_SGI_MSK) ? "SGI " : "NGI ", (rate & RATE_MCS_STBC_MSK) ? "STBC " : "", (rate & RATE_MCS_LDPC_MSK) ? "LDPC " : "", @@ -2719,7 +2731,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, struct iwl_lq_sta *lq_sta = file->private_data; struct iwl_mvm *mvm; struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); - + struct rs_rate *rate = &tbl->rate; mvm = lq_sta->drv; buff = kmalloc(2048, GFP_KERNEL); if (!buff) @@ -2736,17 +2748,17 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, (iwl_fw_valid_tx_ant(mvm->fw) & ANT_B) ? "ANT_B," : "", (iwl_fw_valid_tx_ant(mvm->fw) & ANT_C) ? "ANT_C" : ""); desc += sprintf(buff+desc, "lq type %s\n", - (is_legacy(tbl->lq_type)) ? "legacy" : - is_vht(tbl->lq_type) ? "VHT" : "HT"); - if (!is_legacy(tbl->lq_type)) { + (is_legacy(rate)) ? "legacy" : + is_vht(rate) ? "VHT" : "HT"); + if (!is_legacy(rate)) { desc += sprintf(buff+desc, " %s", - (is_siso(tbl->lq_type)) ? "SISO" : "MIMO2"); + (is_siso(rate)) ? "SISO" : "MIMO2"); desc += sprintf(buff+desc, " %s", - (is_ht20(tbl)) ? "20MHz" : - (is_ht40(tbl)) ? "40MHz" : - (is_ht80(tbl)) ? "80Mhz" : "BAD BW"); + (is_ht20(rate)) ? "20MHz" : + (is_ht40(rate)) ? "40MHz" : + (is_ht80(rate)) ? "80Mhz" : "BAD BW"); desc += sprintf(buff+desc, " %s %s\n", - (tbl->is_SGI) ? "SGI" : "NGI", + (rate->sgi) ? "SGI" : "NGI", (lq_sta->is_agg) ? "AGG on" : ""); } desc += sprintf(buff+desc, "last tx rate=0x%X\n", @@ -2799,6 +2811,7 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file, int i, j; ssize_t ret; struct iwl_scale_tbl_info *tbl; + struct rs_rate *rate; struct iwl_lq_sta *lq_sta = file->private_data; buff = kmalloc(1024, GFP_KERNEL); @@ -2807,15 +2820,16 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file, for (i = 0; i < LQ_SIZE; i++) { tbl = &(lq_sta->lq_info[i]); + rate = &tbl->rate; desc += sprintf(buff+desc, "%s type=%d SGI=%d BW=%s DUP=0\n" "rate=0x%X\n", lq_sta->active_tbl == i ? "*" : "x", - tbl->lq_type, - tbl->is_SGI, - is_ht20(tbl) ? "20Mhz" : - is_ht40(tbl) ? "40Mhz" : - is_ht80(tbl) ? "80Mhz" : "ERR", + rate->type, + rate->sgi, + is_ht20(rate) ? "20Mhz" : + is_ht40(rate) ? "40Mhz" : + is_ht80(rate) ? "80Mhz" : "ERR", tbl->current_rate); for (j = 0; j < IWL_RATE_COUNT; j++) { desc += sprintf(buff+desc, diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index ae983bce217..8fa26aff133 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -224,22 +224,45 @@ enum iwl_table_type { LQ_MAX, }; -#define is_legacy(tbl) (((tbl) == LQ_LEGACY_G) || ((tbl) == LQ_LEGACY_A)) -#define is_ht_siso(tbl) ((tbl) == LQ_HT_SISO) -#define is_ht_mimo2(tbl) ((tbl) == LQ_HT_MIMO2) -#define is_vht_siso(tbl) ((tbl) == LQ_VHT_SISO) -#define is_vht_mimo2(tbl) ((tbl) == LQ_VHT_MIMO2) -#define is_siso(tbl) (is_ht_siso(tbl) || is_vht_siso(tbl)) -#define is_mimo2(tbl) (is_ht_mimo2(tbl) || is_vht_mimo2(tbl)) -#define is_mimo(tbl) (is_mimo2(tbl)) -#define is_ht(tbl) (is_ht_siso(tbl) || is_ht_mimo2(tbl)) -#define is_vht(tbl) (is_vht_siso(tbl) || is_vht_mimo2(tbl)) -#define is_a_band(tbl) ((tbl) == LQ_LEGACY_A) -#define is_g_band(tbl) ((tbl) == LQ_LEGACY_G) - -#define is_ht20(tbl) (tbl->bw == RATE_MCS_CHAN_WIDTH_20) -#define is_ht40(tbl) (tbl->bw == RATE_MCS_CHAN_WIDTH_40) -#define is_ht80(tbl) (tbl->bw == RATE_MCS_CHAN_WIDTH_80) +struct rs_rate { + int index; + enum iwl_table_type type; + u8 ant; + u32 bw; + bool sgi; +}; + + +#define is_type_legacy(type) (((type) == LQ_LEGACY_G) || \ + ((type) == LQ_LEGACY_A)) +#define is_type_ht_siso(type) ((type) == LQ_HT_SISO) +#define is_type_ht_mimo2(type) ((type) == LQ_HT_MIMO2) +#define is_type_vht_siso(type) ((type) == LQ_VHT_SISO) +#define is_type_vht_mimo2(type) ((type) == LQ_VHT_MIMO2) +#define is_type_siso(type) (is_type_ht_siso(type) || is_type_vht_siso(type)) +#define is_type_mimo2(type) (is_type_ht_mimo2(type) || is_type_vht_mimo2(type)) +#define is_type_mimo(type) (is_type_mimo2(type)) +#define is_type_ht(type) (is_type_ht_siso(type) || is_type_ht_mimo2(type)) +#define is_type_vht(type) (is_type_vht_siso(type) || is_type_vht_mimo2(type)) +#define is_type_a_band(type) ((type) == LQ_LEGACY_A) +#define is_type_g_band(type) ((type) == LQ_LEGACY_G) + +#define is_legacy(rate) is_type_legacy((rate)->type) +#define is_ht_siso(rate) is_type_ht_siso((rate)->type) +#define is_ht_mimo2(rate) is_type_ht_mimo2((rate)->type) +#define is_vht_siso(rate) is_type_vht_siso((rate)->type) +#define is_vht_mimo2(rate) is_type_vht_mimo2((rate)->type) +#define is_siso(rate) is_type_siso((rate)->type) +#define is_mimo2(rate) is_type_mimo2((rate)->type) +#define is_mimo(rate) is_type_mimo((rate)->type) +#define is_ht(rate) is_type_ht((rate)->type) +#define is_vht(rate) is_type_vht((rate)->type) +#define is_a_band(rate) is_type_a_band((rate)->type) +#define is_g_band(rate) is_type_g_band((rate)->type) + +#define is_ht20(rate) ((rate)->bw == RATE_MCS_CHAN_WIDTH_20) +#define is_ht40(rate) ((rate)->bw == RATE_MCS_CHAN_WIDTH_40) +#define is_ht80(rate) ((rate)->bw == RATE_MCS_CHAN_WIDTH_80) #define IWL_MAX_MCS_DISPLAY_SIZE 12 @@ -266,10 +289,7 @@ struct iwl_rate_scale_data { * one for "active", and one for "search". */ struct iwl_scale_tbl_info { - enum iwl_table_type lq_type; - u8 ant_type; - u8 is_SGI; /* 1 = short guard interval */ - u32 bw; /* channel bandwidth; RATE_MCS_CHAN_WIDTH_XX */ + struct rs_rate rate; u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */ u8 max_search; /* maximun number of tables we can search */ s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */ -- cgit v1.2.3-70-g09d2 From a8ff14f5964a6988fb883ec63de726de2a3bc19e Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Sat, 23 Nov 2013 01:30:44 +0200 Subject: iwlwifi: mvm: rs: remove unused parameter to rs_get_supported_rates No use of the ieee80211 header. Drop it. Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 3af90620b3d..7beb548fd8d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -597,15 +597,7 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *ucode_rate, return 1; } -/** - * rs_get_supported_rates - get the available rates - * - * if management frame or broadcast frame only return - * basic available rates. - * - */ static u16 rs_get_supported_rates(struct iwl_lq_sta *lq_sta, - struct ieee80211_hdr *hdr, struct rs_rate *rate) { if (is_legacy(rate)) @@ -704,7 +696,7 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta, rate->sgi = false; } - rate_mask = rs_get_supported_rates(lq_sta, NULL, rate); + rate_mask = rs_get_supported_rates(lq_sta, rate); /* Mask with station rate restriction */ if (is_legacy(rate)) { @@ -1762,7 +1754,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, index = lq_sta->last_txrate_idx; /* rates available for this association, and for modulation mode */ - rate_mask = rs_get_supported_rates(lq_sta, hdr, rate); + rate_mask = rs_get_supported_rates(lq_sta, rate); /* mask with station rate restriction */ if (is_legacy(rate)) { -- cgit v1.2.3-70-g09d2 From 809bccfa313e4703b64572986fce6321fb0c039f Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Thu, 28 Nov 2013 02:25:24 +0200 Subject: iwlwifi: mvm: rs: set dual_stream_ant_msk to ANT_AB always Drop code which was relevant when there were chips with 3 antennas. Setting to ANT_AB should be ok with all mvm supported chips. Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 7beb548fd8d..5c98d462b7c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -2386,15 +2386,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, /* These values will be overridden later */ lq_sta->lq.single_stream_ant_msk = first_antenna(iwl_fw_valid_tx_ant(mvm->fw)); - lq_sta->lq.dual_stream_ant_msk = - iwl_fw_valid_tx_ant(mvm->fw) & - ~first_antenna(iwl_fw_valid_tx_ant(mvm->fw)); - if (!lq_sta->lq.dual_stream_ant_msk) { - lq_sta->lq.dual_stream_ant_msk = ANT_AB; - } else if (num_of_ant(iwl_fw_valid_tx_ant(mvm->fw)) == 2) { - lq_sta->lq.dual_stream_ant_msk = - iwl_fw_valid_tx_ant(mvm->fw); - } + lq_sta->lq.dual_stream_ant_msk = ANT_AB; /* as default allow aggregation for all tids */ lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID; @@ -2463,8 +2455,6 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm, if (num_of_ant(rate.ant) == 1) lq_cmd->single_stream_ant_msk = rate.ant; - else if (num_of_ant(rate.ant) == 2) - lq_cmd->dual_stream_ant_msk = rate.ant; /* otherwise we don't modify the existing value */ index++; -- cgit v1.2.3-70-g09d2 From da87d7d5e787d35a85ab821888e2f0e115dc18cc Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Thu, 28 Nov 2013 12:27:03 +0200 Subject: iwlwifi: mvm: rs: fix mapping from HT/VHT rates to legacy The table rs_ht_to_legacy is used to get the next legacy rate following the last HT or VHT rate in the LQ rates table. The mapping wasn't correct as well as didn't include entries for MCS8/9 which led to out of bounds access. This didn't trigger a crash but led to legacy rate entries using 1Mbps rate. In 5Ghz this probably caused the Tx to fail completely given that Tx attempt would have reached the legacy entries and 1Mbps isn't valid. Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 5c98d462b7c..ef7126ad5d8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -56,19 +56,16 @@ static u8 rs_ht_to_legacy[] = { - [IWL_RATE_1M_INDEX] = IWL_RATE_6M_INDEX, - [IWL_RATE_2M_INDEX] = IWL_RATE_6M_INDEX, - [IWL_RATE_5M_INDEX] = IWL_RATE_6M_INDEX, - [IWL_RATE_11M_INDEX] = IWL_RATE_6M_INDEX, - [IWL_RATE_6M_INDEX] = IWL_RATE_6M_INDEX, - [IWL_RATE_9M_INDEX] = IWL_RATE_6M_INDEX, - [IWL_RATE_12M_INDEX] = IWL_RATE_9M_INDEX, - [IWL_RATE_18M_INDEX] = IWL_RATE_12M_INDEX, - [IWL_RATE_24M_INDEX] = IWL_RATE_18M_INDEX, - [IWL_RATE_36M_INDEX] = IWL_RATE_24M_INDEX, - [IWL_RATE_48M_INDEX] = IWL_RATE_36M_INDEX, - [IWL_RATE_54M_INDEX] = IWL_RATE_48M_INDEX, - [IWL_RATE_60M_INDEX] = IWL_RATE_54M_INDEX, + [IWL_RATE_MCS_0_INDEX] = IWL_RATE_6M_INDEX, + [IWL_RATE_MCS_1_INDEX] = IWL_RATE_9M_INDEX, + [IWL_RATE_MCS_2_INDEX] = IWL_RATE_12M_INDEX, + [IWL_RATE_MCS_3_INDEX] = IWL_RATE_18M_INDEX, + [IWL_RATE_MCS_4_INDEX] = IWL_RATE_24M_INDEX, + [IWL_RATE_MCS_5_INDEX] = IWL_RATE_36M_INDEX, + [IWL_RATE_MCS_6_INDEX] = IWL_RATE_48M_INDEX, + [IWL_RATE_MCS_7_INDEX] = IWL_RATE_54M_INDEX, + [IWL_RATE_MCS_8_INDEX] = IWL_RATE_54M_INDEX, + [IWL_RATE_MCS_9_INDEX] = IWL_RATE_54M_INDEX, }; static const u8 ant_toggle_lookup[] = { @@ -682,6 +679,8 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta, * are always supported (spec demand) */ if (!is_legacy(rate) && (!ht_possible || !scale_index)) { switch_to_legacy = 1; + WARN_ON_ONCE(scale_index < IWL_RATE_MCS_0_INDEX && + scale_index > IWL_RATE_MCS_9_INDEX); scale_index = rs_ht_to_legacy[scale_index]; if (lq_sta->band == IEEE80211_BAND_5GHZ) rate->type = LQ_LEGACY_A; -- cgit v1.2.3-70-g09d2 From a56db7d100dc9695dad262e0c7f2ec3d6f6f186b Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Thu, 28 Nov 2013 12:35:42 +0200 Subject: iwlwifi: mvm: rs: use the proper channel width define for legacy rate Use the 20Mhz channel width define instead of just the number zero for legacy rates. Note that the define has the same value so this is just a minor cleanup. Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index ef7126ad5d8..1bfdde52db5 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -691,7 +691,7 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta, rate->ant = first_antenna(iwl_fw_valid_tx_ant(mvm->fw)); - rate->bw = 0; + rate->bw = RATE_MCS_CHAN_WIDTH_20; rate->sgi = false; } -- cgit v1.2.3-70-g09d2 From b3b06a32547fd2b0ba0f3f95ff37fbf94ad997dd Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Sun, 24 Nov 2013 21:30:13 +0200 Subject: iwlwifi: mvm: rs: overhaul search cycle state machine Rewrite the search cycle state machine to use a more data oriented approach where the different Tx columns (configs) limitations and next columns to search are reprsented in tables which are easy to change. This overhaul also includes several major fixes: 1. Prevent going back to a specific Tx column in a search cycle if it was already explored. 2. Avoid switching to a Tx column that doesn't have any chance if it performs perfectly to beat the current throughput we're getting. These issues were degrading throughput as they were causing switching to "bad" Tx columns. Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 921 ++++++++++++++++------------------ drivers/net/wireless/iwlwifi/mvm/rs.h | 64 ++- 2 files changed, 458 insertions(+), 527 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 1bfdde52db5..1bb6581f3b2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -123,6 +123,190 @@ static const struct iwl_rs_rate_info iwl_rates[IWL_RATE_COUNT] = { IWL_DECLARE_MCS_RATE(9), /* MCS 9 */ }; +enum rs_column_mode { + RS_INVALID = 0, + RS_LEGACY, + RS_SISO, + RS_MIMO2, +}; + +#define MAX_NEXT_COLUMNS 5 +#define MAX_COLUMN_CHECKS 3 + +typedef bool (*allow_column_func_t) (struct iwl_mvm *mvm, + struct ieee80211_sta *sta, + struct iwl_scale_tbl_info *tbl); + +struct rs_tx_column { + enum rs_column_mode mode; + u8 ant; + bool sgi; + enum rs_column next_columns[MAX_NEXT_COLUMNS]; + allow_column_func_t checks[MAX_COLUMN_CHECKS]; +}; + +static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta, + struct iwl_scale_tbl_info *tbl) +{ + if (!sta->ht_cap.ht_supported) + return false; + + if (sta->smps_mode == IEEE80211_SMPS_STATIC) + return false; + + if (num_of_ant(iwl_fw_valid_tx_ant(mvm->fw)) < 2) + return false; + + if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) + return false; + + return true; +} + +static bool rs_siso_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta, + struct iwl_scale_tbl_info *tbl) +{ + if (!sta->ht_cap.ht_supported) + return false; + + return true; +} + +static bool rs_sgi_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta, + struct iwl_scale_tbl_info *tbl) +{ + struct rs_rate *rate = &tbl->rate; + struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; + struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap; + + if (is_ht20(rate) && (ht_cap->cap & + IEEE80211_HT_CAP_SGI_20)) + return true; + if (is_ht40(rate) && (ht_cap->cap & + IEEE80211_HT_CAP_SGI_40)) + return true; + if (is_ht80(rate) && (vht_cap->cap & + IEEE80211_VHT_CAP_SHORT_GI_80)) + return true; + + return false; +} + +static const struct rs_tx_column rs_tx_columns[] = { + [RS_COLUMN_LEGACY_ANT_A] = { + .mode = RS_LEGACY, + .ant = ANT_A, + .next_columns = { + RS_COLUMN_LEGACY_ANT_B, + RS_COLUMN_SISO_ANT_A, + RS_COLUMN_MIMO2, + RS_COLUMN_INVALID, + RS_COLUMN_INVALID, + }, + }, + [RS_COLUMN_LEGACY_ANT_B] = { + .mode = RS_LEGACY, + .ant = ANT_B, + .next_columns = { + RS_COLUMN_LEGACY_ANT_A, + RS_COLUMN_SISO_ANT_B, + RS_COLUMN_MIMO2, + RS_COLUMN_INVALID, + RS_COLUMN_INVALID, + }, + }, + [RS_COLUMN_SISO_ANT_A] = { + .mode = RS_SISO, + .ant = ANT_A, + .next_columns = { + RS_COLUMN_SISO_ANT_B, + RS_COLUMN_MIMO2, + RS_COLUMN_SISO_ANT_A_SGI, + RS_COLUMN_INVALID, + RS_COLUMN_INVALID, + }, + .checks = { + rs_siso_allow, + }, + }, + [RS_COLUMN_SISO_ANT_B] = { + .mode = RS_SISO, + .ant = ANT_B, + .next_columns = { + RS_COLUMN_SISO_ANT_A, + RS_COLUMN_MIMO2, + RS_COLUMN_SISO_ANT_B_SGI, + RS_COLUMN_INVALID, + RS_COLUMN_INVALID, + }, + .checks = { + rs_siso_allow, + }, + }, + [RS_COLUMN_SISO_ANT_A_SGI] = { + .mode = RS_SISO, + .ant = ANT_A, + .sgi = true, + .next_columns = { + RS_COLUMN_SISO_ANT_B_SGI, + RS_COLUMN_MIMO2_SGI, + RS_COLUMN_SISO_ANT_A, + RS_COLUMN_INVALID, + RS_COLUMN_INVALID, + }, + .checks = { + rs_siso_allow, + rs_sgi_allow, + }, + }, + [RS_COLUMN_SISO_ANT_B_SGI] = { + .mode = RS_SISO, + .ant = ANT_B, + .sgi = true, + .next_columns = { + RS_COLUMN_SISO_ANT_A_SGI, + RS_COLUMN_MIMO2_SGI, + RS_COLUMN_SISO_ANT_B, + RS_COLUMN_INVALID, + RS_COLUMN_INVALID, + }, + .checks = { + rs_siso_allow, + rs_sgi_allow, + }, + }, + [RS_COLUMN_MIMO2] = { + .mode = RS_MIMO2, + .ant = ANT_AB, + .next_columns = { + RS_COLUMN_SISO_ANT_A, + RS_COLUMN_MIMO2_SGI, + RS_COLUMN_INVALID, + RS_COLUMN_INVALID, + RS_COLUMN_INVALID, + }, + .checks = { + rs_mimo_allow, + }, + }, + [RS_COLUMN_MIMO2_SGI] = { + .mode = RS_MIMO2, + .ant = ANT_AB, + .sgi = true, + .next_columns = { + RS_COLUMN_SISO_ANT_A_SGI, + RS_COLUMN_MIMO2, + RS_COLUMN_INVALID, + RS_COLUMN_INVALID, + RS_COLUMN_INVALID, + }, + .checks = { + rs_mimo_allow, + rs_sgi_allow, + }, + }, +}; + static inline u8 rs_extract_rate(u32 rate_n_flags) { /* also works for HT because bits 7:6 are zero there */ @@ -839,6 +1023,9 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, lq_sta->missed_rate_counter++; if (lq_sta->missed_rate_counter > IWL_MISSED_RATE_MAX) { lq_sta->missed_rate_counter = 0; + IWL_DEBUG_RATE(mvm, + "Too many rates mismatch. Send sync LQ. rs_state %d\n", + lq_sta->rs_state); iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false); } /* Regardless, ignore this status info for outdated rate */ @@ -888,7 +1075,7 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, info->status.ampdu_ack_len); /* Update success/fail counts if not searching for new mode */ - if (lq_sta->stay_in_tbl) { + if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) { lq_sta->total_success += info->status.ampdu_ack_len; lq_sta->total_failed += (info->status.ampdu_len - info->status.ampdu_ack_len); @@ -915,14 +1102,20 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, tmp_tbl = curr_tbl; else if (rs_rate_match(&rate, &other_tbl->rate)) tmp_tbl = other_tbl; - else + else { + IWL_DEBUG_RATE(mvm, + "Tx packet rate doesn't match ACTIVE or SEARCH tables\n"); + rs_dump_rate(mvm, &rate, "Tx PACKET:"); + rs_dump_rate(mvm, &curr_tbl->rate, "CURRENT:"); + rs_dump_rate(mvm, &other_tbl->rate, "OTHER:"); continue; + } rs_collect_tx_data(tmp_tbl, rate.index, 1, i < retries ? 0 : legacy_success); } /* Update success/fail counts if not searching for new mode */ - if (lq_sta->stay_in_tbl) { + if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) { lq_sta->total_success += legacy_success; lq_sta->total_failed += retries + (1 - legacy_success); } @@ -946,8 +1139,8 @@ done: static void rs_set_stay_in_table(struct iwl_mvm *mvm, u8 is_legacy, struct iwl_lq_sta *lq_sta) { - IWL_DEBUG_RATE(mvm, "we are staying in the same table\n"); - lq_sta->stay_in_tbl = 1; /* only place this gets set */ + IWL_DEBUG_RATE(mvm, "Moving to RS_STATE_STAY_IN_COLUMN\n"); + lq_sta->rs_state = RS_STATE_STAY_IN_COLUMN; if (is_legacy) { lq_sta->table_count_limit = IWL_LEGACY_TABLE_COUNT; lq_sta->max_failure_limit = IWL_LEGACY_FAILURE_LIMIT; @@ -961,38 +1154,31 @@ static void rs_set_stay_in_table(struct iwl_mvm *mvm, u8 is_legacy, lq_sta->total_failed = 0; lq_sta->total_success = 0; lq_sta->flush_timer = jiffies; - lq_sta->action_counter = 0; + lq_sta->visited_columns = 0; } -/* - * Find correct throughput table for given mode of modulation - */ -static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, - struct iwl_scale_tbl_info *tbl) +static s32 *rs_get_expected_tpt_table(struct iwl_lq_sta *lq_sta, + const struct rs_tx_column *column, + u32 bw) { /* Used to choose among HT tables */ s32 (*ht_tbl_pointer)[IWL_RATE_COUNT]; - struct rs_rate *rate = &tbl->rate; - /* Check for invalid LQ type */ - if (WARN_ON_ONCE(!is_legacy(rate) && !is_ht(rate) && - !(is_vht(rate)))) { - tbl->expected_tpt = expected_tpt_legacy; - return; - } + if (WARN_ON_ONCE(column->mode != RS_LEGACY && + column->mode != RS_SISO && + column->mode != RS_MIMO2)) + return expected_tpt_legacy; /* Legacy rates have only one table */ - if (is_legacy(rate)) { - tbl->expected_tpt = expected_tpt_legacy; - return; - } + if (column->mode == RS_LEGACY) + return expected_tpt_legacy; ht_tbl_pointer = expected_tpt_mimo2_20MHz; /* Choose among many HT tables depending on number of streams * (SISO/MIMO2), channel width (20/40/80), SGI, and aggregation * status */ - if (is_siso(rate)) { - switch (rate->bw) { + if (column->mode == RS_SISO) { + switch (bw) { case RATE_MCS_CHAN_WIDTH_20: ht_tbl_pointer = expected_tpt_siso_20MHz; break; @@ -1005,8 +1191,8 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, default: WARN_ON_ONCE(1); } - } else if (is_mimo2(rate)) { - switch (rate->bw) { + } else if (column->mode == RS_MIMO2) { + switch (bw) { case RATE_MCS_CHAN_WIDTH_20: ht_tbl_pointer = expected_tpt_mimo2_20MHz; break; @@ -1023,14 +1209,23 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, WARN_ON_ONCE(1); } - if (!rate->sgi && !lq_sta->is_agg) /* Normal */ - tbl->expected_tpt = ht_tbl_pointer[0]; - else if (rate->sgi && !lq_sta->is_agg) /* SGI */ - tbl->expected_tpt = ht_tbl_pointer[1]; - else if (!rate->sgi && lq_sta->is_agg) /* AGG */ - tbl->expected_tpt = ht_tbl_pointer[2]; + if (!column->sgi && !lq_sta->is_agg) /* Normal */ + return ht_tbl_pointer[0]; + else if (column->sgi && !lq_sta->is_agg) /* SGI */ + return ht_tbl_pointer[1]; + else if (!column->sgi && lq_sta->is_agg) /* AGG */ + return ht_tbl_pointer[2]; else /* AGG+SGI */ - tbl->expected_tpt = ht_tbl_pointer[3]; + return ht_tbl_pointer[3]; +} + +static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, + struct iwl_scale_tbl_info *tbl) +{ + struct rs_rate *rate = &tbl->rate; + const struct rs_tx_column *column = &rs_tx_columns[tbl->column]; + + tbl->expected_tpt = rs_get_expected_tpt_table(lq_sta, column, rate->bw); } /* @@ -1135,19 +1330,6 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm, return new_rate; } -/* Move to the next action and wrap around to the first action in case - * we're at the last action. Assumes actions start at 0. - */ -static inline void rs_move_next_action(struct iwl_scale_tbl_info *tbl, - u8 last_action) -{ - BUILD_BUG_ON(IWL_LEGACY_FIRST_ACTION != 0); - BUILD_BUG_ON(IWL_SISO_FIRST_ACTION != 0); - BUILD_BUG_ON(IWL_MIMO2_FIRST_ACTION != 0); - - tbl->action = (tbl->action + 1) % (last_action + 1); -} - static u32 rs_bw_from_sta_bw(struct ieee80211_sta *sta) { if (sta->bandwidth >= IEEE80211_STA_RX_BW_80) @@ -1158,409 +1340,6 @@ static u32 rs_bw_from_sta_bw(struct ieee80211_sta *sta) return RATE_MCS_CHAN_WIDTH_20; } -static bool rs_sgi_allowed(struct rs_rate *rate, - struct ieee80211_sta *sta) -{ - struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; - struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap; - - if (is_ht20(rate) && (ht_cap->cap & - IEEE80211_HT_CAP_SGI_20)) - return true; - if (is_ht40(rate) && (ht_cap->cap & - IEEE80211_HT_CAP_SGI_40)) - return true; - if (is_ht80(rate) && (vht_cap->cap & - IEEE80211_VHT_CAP_SHORT_GI_80)) - return true; - - return false; -} - -/* - * Set up search table for MIMO2 - */ -static int rs_switch_to_mimo2(struct iwl_mvm *mvm, - struct iwl_lq_sta *lq_sta, - struct ieee80211_sta *sta, - struct iwl_scale_tbl_info *tbl, int index) -{ - u16 rate_mask; - s32 rate_idx; - - if (!sta->ht_cap.ht_supported) - return -1; - - if (sta->smps_mode == IEEE80211_SMPS_STATIC) - return -1; - - /* Need both Tx chains/antennas to support MIMO */ - if (num_of_ant(iwl_fw_valid_tx_ant(mvm->fw)) < 2) - return -1; - - IWL_DEBUG_RATE(mvm, "LQ: try to switch to MIMO2\n"); - - tbl->rate.type = lq_sta->is_vht ? LQ_VHT_MIMO2 : LQ_HT_MIMO2; - tbl->action = 0; - tbl->max_search = IWL_MAX_SEARCH; - rate_mask = lq_sta->active_mimo2_rate; - - tbl->rate.bw = rs_bw_from_sta_bw(sta); - rs_set_expected_tpt_table(lq_sta, tbl); - - rate_idx = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index); - - IWL_DEBUG_RATE(mvm, "LQ: MIMO2 best rate %d mask %X\n", - rate_idx, rate_mask); - if ((rate_idx == IWL_RATE_INVALID) || !((1 << rate_idx) & rate_mask)) { - IWL_DEBUG_RATE(mvm, "Can't switch with index %d rate mask %x\n", - rate_idx, rate_mask); - return -1; - } - - tbl->rate.index = rate_idx; - tbl->current_rate = ucode_rate_from_rs_rate(mvm, &tbl->rate); - - IWL_DEBUG_RATE(mvm, "LQ: Switch to new mcs %X index\n", - tbl->current_rate); - return 0; -} - -/* - * Set up search table for SISO - */ -static int rs_switch_to_siso(struct iwl_mvm *mvm, - struct iwl_lq_sta *lq_sta, - struct ieee80211_sta *sta, - struct iwl_scale_tbl_info *tbl, int index) -{ - u16 rate_mask; - s32 rate_idx; - - if (!sta->ht_cap.ht_supported) - return -1; - - IWL_DEBUG_RATE(mvm, "LQ: try to switch to SISO\n"); - - tbl->rate.type = lq_sta->is_vht ? LQ_VHT_SISO : LQ_HT_SISO; - tbl->action = 0; - tbl->max_search = IWL_MAX_SEARCH; - rate_mask = lq_sta->active_siso_rate; - - tbl->rate.bw = rs_bw_from_sta_bw(sta); - rs_set_expected_tpt_table(lq_sta, tbl); - rate_idx = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index); - - IWL_DEBUG_RATE(mvm, "LQ: get best rate %d mask %X\n", - rate_idx, rate_mask); - if ((rate_idx == IWL_RATE_INVALID) || !((1 << rate_idx) & rate_mask)) { - IWL_DEBUG_RATE(mvm, - "can not switch with index %d rate mask %x\n", - rate_idx, rate_mask); - return -1; - } - - tbl->rate.index = rate_idx; - tbl->current_rate = ucode_rate_from_rs_rate(mvm, &tbl->rate); - - IWL_DEBUG_RATE(mvm, "LQ: Switch to new mcs %X index\n", - tbl->current_rate); - return 0; -} - -/* - * Try to switch to new modulation mode from legacy - */ -static int rs_move_legacy_other(struct iwl_mvm *mvm, - struct iwl_lq_sta *lq_sta, - struct ieee80211_sta *sta, - int index) -{ - struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); - struct iwl_scale_tbl_info *search_tbl = - &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); - struct rs_rate *rate = &search_tbl->rate; - struct iwl_rate_scale_data *window = &(tbl->win[index]); - u32 sz = (sizeof(struct iwl_scale_tbl_info) - - (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); - u8 start_action; - u8 valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw); - u8 tx_chains_num = num_of_ant(valid_tx_ant); - int ret; - u8 update_search_tbl_counter = 0; - - start_action = tbl->action; - while (1) { - lq_sta->action_counter++; - switch (tbl->action) { - case IWL_LEGACY_SWITCH_ANTENNA: - IWL_DEBUG_RATE(mvm, "LQ: Legacy toggle Antenna\n"); - - if (tx_chains_num <= 1) - break; - - /* Don't change antenna if success has been great */ - if (window->success_ratio >= IWL_RS_GOOD_RATIO) - break; - - /* Set up search table to try other antenna */ - memcpy(search_tbl, tbl, sz); - - if (rs_toggle_antenna(valid_tx_ant, - &search_tbl->current_rate, - &search_tbl->rate)) { - update_search_tbl_counter = 1; - rs_set_expected_tpt_table(lq_sta, search_tbl); - goto out; - } - break; - case IWL_LEGACY_SWITCH_SISO: - IWL_DEBUG_RATE(mvm, "LQ: Legacy switch to SISO\n"); - - /* Set up search table to try SISO */ - memcpy(search_tbl, tbl, sz); - rate->sgi = false; - ret = rs_switch_to_siso(mvm, lq_sta, sta, - search_tbl, index); - if (!ret) { - lq_sta->action_counter = 0; - goto out; - } - - break; - case IWL_LEGACY_SWITCH_MIMO2: - IWL_DEBUG_RATE(mvm, "LQ: Legacy switch to MIMO2\n"); - - /* Set up search table to try MIMO */ - memcpy(search_tbl, tbl, sz); - rate->sgi = false; - rate->ant = ANT_AB; - - if (!rs_is_valid_ant(valid_tx_ant, - rate->ant)) - break; - - ret = rs_switch_to_mimo2(mvm, lq_sta, sta, - search_tbl, index); - if (!ret) { - lq_sta->action_counter = 0; - goto out; - } - break; - default: - WARN_ON_ONCE(1); - } - rs_move_next_action(tbl, IWL_LEGACY_LAST_ACTION); - - if (tbl->action == start_action) - break; - } - rate->type = LQ_NONE; - return 0; - -out: - lq_sta->search_better_tbl = 1; - rs_move_next_action(tbl, IWL_LEGACY_LAST_ACTION); - if (update_search_tbl_counter) - search_tbl->action = tbl->action; - return 0; -} - -/* - * Try to switch to new modulation mode from SISO - */ -static int rs_move_siso_to_other(struct iwl_mvm *mvm, - struct iwl_lq_sta *lq_sta, - struct ieee80211_sta *sta, int index) -{ - struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); - struct iwl_scale_tbl_info *search_tbl = - &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); - struct rs_rate *rate = &search_tbl->rate; - struct iwl_rate_scale_data *window = &(tbl->win[index]); - u32 sz = (sizeof(struct iwl_scale_tbl_info) - - (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); - u8 start_action; - u8 valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw); - u8 tx_chains_num = num_of_ant(valid_tx_ant); - u8 update_search_tbl_counter = 0; - int ret; - - if (tbl->action == IWL_SISO_SWITCH_MIMO2 && - !iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) - tbl->action = IWL_SISO_SWITCH_ANTENNA; - - start_action = tbl->action; - while (1) { - lq_sta->action_counter++; - switch (tbl->action) { - case IWL_SISO_SWITCH_ANTENNA: - IWL_DEBUG_RATE(mvm, "LQ: SISO toggle Antenna\n"); - if (tx_chains_num <= 1) - break; - - if (window->success_ratio >= IWL_RS_GOOD_RATIO && - BT_MBOX_MSG(&mvm->last_bt_notif, 3, - TRAFFIC_LOAD) == 0) - break; - - memcpy(search_tbl, tbl, sz); - if (rs_toggle_antenna(valid_tx_ant, - &search_tbl->current_rate, - rate)) { - update_search_tbl_counter = 1; - goto out; - } - break; - case IWL_SISO_SWITCH_MIMO2: - IWL_DEBUG_RATE(mvm, "LQ: SISO switch to MIMO2\n"); - memcpy(search_tbl, tbl, sz); - rate->sgi = false; - rate->ant = ANT_AB; - - if (!rs_is_valid_ant(valid_tx_ant, - rate->ant)) - break; - - ret = rs_switch_to_mimo2(mvm, lq_sta, sta, - search_tbl, index); - if (!ret) - goto out; - break; - case IWL_SISO_SWITCH_GI: - if (!rs_sgi_allowed(rate, sta)) - break; - - IWL_DEBUG_RATE(mvm, "LQ: SISO toggle SGI/NGI\n"); - - memcpy(search_tbl, tbl, sz); - rate->sgi = !tbl->rate.sgi; - rs_set_expected_tpt_table(lq_sta, search_tbl); - if (tbl->rate.sgi) { - s32 tpt = lq_sta->last_tpt / 100; - if (tpt >= search_tbl->expected_tpt[index]) - break; - } - rate->index = index; - search_tbl->current_rate = - ucode_rate_from_rs_rate(mvm, rate); - update_search_tbl_counter = 1; - goto out; - default: - WARN_ON_ONCE(1); - } - rs_move_next_action(tbl, IWL_SISO_LAST_ACTION); - - if (tbl->action == start_action) - break; - } - rate->type = LQ_NONE; - return 0; - - out: - lq_sta->search_better_tbl = 1; - rs_move_next_action(tbl, IWL_SISO_LAST_ACTION); - if (update_search_tbl_counter) - search_tbl->action = tbl->action; - - return 0; -} - -/* - * Try to switch to new modulation mode from MIMO2 - */ -static int rs_move_mimo2_to_other(struct iwl_mvm *mvm, - struct iwl_lq_sta *lq_sta, - struct ieee80211_sta *sta, int index) -{ - struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); - struct iwl_scale_tbl_info *search_tbl = - &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); - struct rs_rate *rate = &search_tbl->rate; - u32 sz = (sizeof(struct iwl_scale_tbl_info) - - (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); - u8 start_action; - u8 valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw); - u8 update_search_tbl_counter = 0; - int ret; - - if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) { - IWL_DEBUG_RATE(mvm, "BT COEX force switch to SISO A\n"); - tbl->action = IWL_MIMO2_SWITCH_SISO_A; - } - - start_action = tbl->action; - while (1) { - lq_sta->action_counter++; - switch (tbl->action) { - case IWL_MIMO2_SWITCH_SISO_A: - case IWL_MIMO2_SWITCH_SISO_B: - IWL_DEBUG_RATE(mvm, "LQ: MIMO2 switch to SISO\n"); - - /* Set up new search table for SISO */ - memcpy(search_tbl, tbl, sz); - - if (tbl->action == IWL_MIMO2_SWITCH_SISO_A) - rate->ant = ANT_A; - else /* tbl->action == IWL_MIMO2_SWITCH_SISO_B */ - rate->ant = ANT_B; - - if (!rs_is_valid_ant(valid_tx_ant, - rate->ant)) - break; - - ret = rs_switch_to_siso(mvm, lq_sta, sta, - search_tbl, index); - if (!ret) - goto out; - - break; - - case IWL_MIMO2_SWITCH_GI: - if (!rs_sgi_allowed(rate, sta)) - break; - - IWL_DEBUG_RATE(mvm, "LQ: MIMO2 toggle SGI/NGI\n"); - - /* Set up new search table for MIMO2 */ - memcpy(search_tbl, tbl, sz); - rate->sgi = !tbl->rate.sgi; - rs_set_expected_tpt_table(lq_sta, search_tbl); - /* - * If active table already uses the fastest possible - * modulation (dual stream with short guard interval), - * and it's working well, there's no need to look - * for a better type of modulation! - */ - if (tbl->rate.sgi) { - s32 tpt = lq_sta->last_tpt / 100; - if (tpt >= search_tbl->expected_tpt[index]) - break; - } - rate->index = index; - search_tbl->current_rate = - ucode_rate_from_rs_rate(mvm, rate); - update_search_tbl_counter = 1; - goto out; - default: - WARN_ON_ONCE(1); - } - rs_move_next_action(tbl, IWL_MIMO2_LAST_ACTION); - - if (tbl->action == start_action) - break; - } - rate->type = LQ_NONE; - return 0; - out: - lq_sta->search_better_tbl = 1; - rs_move_next_action(tbl, IWL_MIMO2_LAST_ACTION); - if (update_search_tbl_counter) - search_tbl->action = tbl->action; - - return 0; -} - /* * Check whether we should continue using same modulation mode, or * begin search for a new mode, based on: @@ -1582,7 +1361,7 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search) tbl = &(lq_sta->lq_info[active_tbl]); /* If we've been disallowing search, see if we should now allow it */ - if (lq_sta->stay_in_tbl) { + if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) { /* Elapsed time using current modulation mode */ if (lq_sta->flush_timer) flush_interval_passed = @@ -1610,10 +1389,14 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search) flush_interval_passed); /* Allow search for new mode */ - lq_sta->stay_in_tbl = 0; /* only place reset */ + lq_sta->rs_state = RS_STATE_SEARCH_CYCLE_STARTED; + IWL_DEBUG_RATE(mvm, + "Moving to RS_STATE_SEARCH_CYCLE_STARTED\n"); lq_sta->total_failed = 0; lq_sta->total_success = 0; lq_sta->flush_timer = 0; + /* mark the current column as visited */ + lq_sta->visited_columns = BIT(tbl->column); /* * Else if we've used this modulation mode enough repetitions * (regardless of elapsed time or success/failure), reset @@ -1637,7 +1420,8 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search) /* If transitioning to allow "search", reset all history * bitmaps and stats in active table (this will become the new * "search" table). */ - if (!lq_sta->stay_in_tbl) { + if (lq_sta->rs_state == RS_STATE_SEARCH_CYCLE_STARTED) { + IWL_DEBUG_RATE(mvm, "Clearing up window stats\n"); for (i = 0; i < IWL_RATE_COUNT; i++) rs_rate_scale_clear_window(&(tbl->win[i])); } @@ -1675,6 +1459,162 @@ static u8 rs_get_tid(struct iwl_lq_sta *lq_data, return tid; } +static enum rs_column rs_get_next_column(struct iwl_mvm *mvm, + struct iwl_lq_sta *lq_sta, + struct ieee80211_sta *sta, + struct iwl_scale_tbl_info *tbl) +{ + int i, j, n; + enum rs_column next_col_id; + const struct rs_tx_column *curr_col = &rs_tx_columns[tbl->column]; + const struct rs_tx_column *next_col; + allow_column_func_t allow_func; + u8 valid_ants = iwl_fw_valid_tx_ant(mvm->fw); + s32 *expected_tpt_tbl; + s32 tpt, max_expected_tpt; + + for (i = 0; i < MAX_NEXT_COLUMNS; i++) { + next_col_id = curr_col->next_columns[i]; + + if (next_col_id == RS_COLUMN_INVALID) + continue; + + if (lq_sta->visited_columns & BIT(next_col_id)) { + IWL_DEBUG_RATE(mvm, "Skip already visited column %d\n", + next_col_id); + continue; + } + + next_col = &rs_tx_columns[next_col_id]; + + if (!rs_is_valid_ant(valid_ants, next_col->ant)) { + IWL_DEBUG_RATE(mvm, + "Skip column %d as ANT config isn't supported by chip. valid_ants 0x%x column ant 0x%x\n", + next_col_id, valid_ants, next_col->ant); + continue; + } + + for (j = 0; j < MAX_COLUMN_CHECKS; j++) { + allow_func = next_col->checks[j]; + if (allow_func && !allow_func(mvm, sta, tbl)) + break; + } + + if (j != MAX_COLUMN_CHECKS) { + IWL_DEBUG_RATE(mvm, + "Skip column %d: not allowed (check %d failed)\n", + next_col_id, j); + + continue; + } + + tpt = lq_sta->last_tpt / 100; + expected_tpt_tbl = rs_get_expected_tpt_table(lq_sta, next_col, + tbl->rate.bw); + if (WARN_ON_ONCE(!expected_tpt_tbl)) + continue; + + max_expected_tpt = 0; + for (n = 0; n < IWL_RATE_COUNT; n++) + if (expected_tpt_tbl[n] > max_expected_tpt) + max_expected_tpt = expected_tpt_tbl[n]; + + if (tpt >= max_expected_tpt) { + IWL_DEBUG_RATE(mvm, + "Skip column %d: can't beat current TPT. Max expected %d current %d\n", + next_col_id, max_expected_tpt, tpt); + continue; + } + + break; + } + + if (i == MAX_NEXT_COLUMNS) + return RS_COLUMN_INVALID; + + IWL_DEBUG_RATE(mvm, "Found potential column %d\n", next_col_id); + + return next_col_id; +} + +static int rs_switch_to_column(struct iwl_mvm *mvm, + struct iwl_lq_sta *lq_sta, + struct ieee80211_sta *sta, + enum rs_column col_id) +{ + struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); + struct iwl_scale_tbl_info *search_tbl = + &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); + struct rs_rate *rate = &search_tbl->rate; + const struct rs_tx_column *column = &rs_tx_columns[col_id]; + const struct rs_tx_column *curr_column = &rs_tx_columns[tbl->column]; + u32 sz = (sizeof(struct iwl_scale_tbl_info) - + (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); + u16 rate_mask = 0; + u32 rate_idx = 0; + + memcpy(search_tbl, tbl, sz); + + rate->sgi = column->sgi; + rate->ant = column->ant; + + if (column->mode == RS_LEGACY) { + if (lq_sta->band == IEEE80211_BAND_5GHZ) + rate->type = LQ_LEGACY_A; + else + rate->type = LQ_LEGACY_G; + + rate_mask = lq_sta->active_legacy_rate; + } else if (column->mode == RS_SISO) { + rate->type = lq_sta->is_vht ? LQ_VHT_SISO : LQ_HT_SISO; + rate_mask = lq_sta->active_siso_rate; + } else if (column->mode == RS_MIMO2) { + rate->type = lq_sta->is_vht ? LQ_VHT_MIMO2 : LQ_HT_MIMO2; + rate_mask = lq_sta->active_mimo2_rate; + } else { + WARN_ON_ONCE("Bad column mode"); + } + + rate->bw = rs_bw_from_sta_bw(sta); + search_tbl->column = col_id; + rs_set_expected_tpt_table(lq_sta, search_tbl); + + /* Get the best matching rate if we're changing modes. e.g. + * SISO->MIMO, LEGACY->SISO, MIMO->SISO + */ + if (curr_column->mode != column->mode) { + rate_idx = rs_get_best_rate(mvm, lq_sta, search_tbl, + rate_mask, rate->index); + + if ((rate_idx == IWL_RATE_INVALID) || + !(BIT(rate_idx) & rate_mask)) { + IWL_DEBUG_RATE(mvm, + "can not switch with index %d" + " rate mask %x\n", + rate_idx, rate_mask); + + goto err; + } + + rate->index = rate_idx; + } + + /* TODO: remove current_rate and keep using rs_rate all the way until + * we need to fill in the rs_table in the LQ command + */ + search_tbl->current_rate = ucode_rate_from_rs_rate(mvm, rate); + IWL_DEBUG_RATE(mvm, "Switched to column %d: Index %d\n", + col_id, rate->index); + + lq_sta->visited_columns |= BIT(col_id); + return 0; + +err: + rate->type = LQ_NONE; + return -1; +} + + /* * Do rate scaling and search for new modulation mode. */ @@ -1772,7 +1712,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, if (!rate_scale_index_msk) rate_scale_index_msk = rate_mask; - if (!((1 << index) & rate_scale_index_msk)) { + if (!((BIT(index) & rate_scale_index_msk))) { IWL_ERR(mvm, "Current Rate is not valid\n"); if (lq_sta->search_better_tbl) { /* revert to active table if search table is not valid*/ @@ -1852,9 +1792,6 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, window->average_tpt, lq_sta->last_tpt); - if (!is_legacy(rate)) - lq_sta->enable_counter = 1; - /* Swap tables; "search" becomes "active" */ lq_sta->active_tbl = active_tbl; current_tpt = window->average_tpt; @@ -2049,24 +1986,29 @@ lq_update: * 3) Allowing a new search */ if (!update_lq && !done_search && - !lq_sta->stay_in_tbl && window->counter) { + lq_sta->rs_state == RS_STATE_SEARCH_CYCLE_STARTED + && window->counter) { + enum rs_column next_column; + /* Save current throughput to compare with "search" throughput*/ lq_sta->last_tpt = current_tpt; IWL_DEBUG_RATE(mvm, - "Start Search: update_lq %d done_search %d stay_in_tbl %d win->counter %d\n", - update_lq, done_search, lq_sta->stay_in_tbl, + "Start Search: update_lq %d done_search %d rs_state %d win->counter %d\n", + update_lq, done_search, lq_sta->rs_state, window->counter); - /* Select a new "search" modulation mode to try. - * If one is found, set up the new "search" table. */ - if (is_legacy(&tbl->rate)) - rs_move_legacy_other(mvm, lq_sta, sta, index); - else if (is_siso(&tbl->rate)) - rs_move_siso_to_other(mvm, lq_sta, sta, index); - else if (is_mimo2(&tbl->rate)) - rs_move_mimo2_to_other(mvm, lq_sta, sta, index); - else - WARN_ON_ONCE(1); + + next_column = rs_get_next_column(mvm, lq_sta, sta, tbl); + if (next_column != RS_COLUMN_INVALID) { + int ret = rs_switch_to_column(mvm, lq_sta, sta, + next_column); + if (!ret) + lq_sta->search_better_tbl = 1; + } else { + IWL_DEBUG_RATE(mvm, + "No more columns to explore in search cycle. Go to RS_STATE_SEARCH_CYCLE_ENDED\n"); + lq_sta->rs_state = RS_STATE_SEARCH_CYCLE_ENDED; + } /* If new "search" mode was selected, set up in uCode table */ if (lq_sta->search_better_tbl) { @@ -2078,12 +2020,8 @@ lq_update: /* Use new "search" start rate */ index = iwl_hwrate_to_plcp_idx(tbl->current_rate); - IWL_DEBUG_RATE(mvm, - "Switch to SEARCH TABLE: " - "mcs %X (%s: %d)\n", - tbl->current_rate, - rs_pretty_lq_type(tbl->rate.type), - index); + rs_dump_rate(mvm, &tbl->rate, + "Switch to SEARCH TABLE:"); rs_fill_link_cmd(mvm, sta, lq_sta, tbl->current_rate); iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false); } else { @@ -2091,24 +2029,20 @@ lq_update: } } - if (done_search && !lq_sta->stay_in_tbl) { + if (done_search && lq_sta->rs_state == RS_STATE_SEARCH_CYCLE_ENDED) { /* If the "active" (non-search) mode was legacy, * and we've tried switching antennas, * but we haven't been able to try HT modes (not available), * stay with best antenna legacy modulation for a while * before next round of mode comparisons. */ tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]); - if (is_legacy(&tbl1->rate) && !sta->ht_cap.ht_supported && - lq_sta->action_counter > tbl1->max_search) { + if (is_legacy(&tbl1->rate) && !sta->ht_cap.ht_supported) { IWL_DEBUG_RATE(mvm, "LQ: STAY in legacy table\n"); rs_set_stay_in_table(mvm, 1, lq_sta); - } - + } else { /* If we're in an HT mode, and all 3 mode switch actions * have been tried and compared, stay in this best modulation * mode for a while before next round of mode comparisons. */ - if (lq_sta->enable_counter && - (lq_sta->action_counter >= tbl1->max_search)) { if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) && (lq_sta->tx_agg_tid_en & (1 << tid)) && (tid != IWL_MAX_TID_COUNT)) { @@ -2176,19 +2110,24 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, if ((i < 0) || (i >= IWL_RATE_COUNT)) i = 0; - ucode_rate = iwl_rates[i].plcp; + rate->index = i; rate->ant = first_antenna(valid_tx_ant); - ucode_rate |= rate->ant << RATE_MCS_ANT_POS; - - if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE) - ucode_rate |= RATE_MCS_CCK_MSK; - - rs_rate_from_ucode_rate(ucode_rate, band, rate); - if (!rs_is_valid_ant(valid_tx_ant, rate->ant)) - rs_toggle_antenna(valid_tx_ant, &ucode_rate, rate); + rate->sgi = false; + rate->bw = RATE_MCS_CHAN_WIDTH_20; + if (band == IEEE80211_BAND_5GHZ) + rate->type = LQ_LEGACY_A; + else + rate->type = LQ_LEGACY_G; ucode_rate = ucode_rate_from_rs_rate(mvm, rate); tbl->current_rate = ucode_rate; + + WARN_ON_ONCE(rate->ant != ANT_A && rate->ant != ANT_B); + if (rate->ant == ANT_A) + tbl->column = RS_COLUMN_LEGACY_ANT_A; + else + tbl->column = RS_COLUMN_LEGACY_ANT_B; + rs_set_expected_tpt_table(lq_sta, tbl); rs_fill_link_cmd(NULL, NULL, lq_sta, ucode_rate); /* TODO restore station should remember the lq cmd */ diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index 8fa26aff133..b3296079638 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -157,37 +157,6 @@ enum { #define IWL_RATE_INCREASE_TH 6400 /* 50% */ #define RS_SR_FORCE_DECREASE 1920 /* 15% */ -/* possible actions when in legacy mode */ -enum { - IWL_LEGACY_SWITCH_ANTENNA, - IWL_LEGACY_SWITCH_SISO, - IWL_LEGACY_SWITCH_MIMO2, - IWL_LEGACY_FIRST_ACTION = IWL_LEGACY_SWITCH_ANTENNA, - IWL_LEGACY_LAST_ACTION = IWL_LEGACY_SWITCH_MIMO2, -}; - -/* possible actions when in siso mode */ -enum { - IWL_SISO_SWITCH_ANTENNA, - IWL_SISO_SWITCH_MIMO2, - IWL_SISO_SWITCH_GI, - IWL_SISO_FIRST_ACTION = IWL_SISO_SWITCH_ANTENNA, - IWL_SISO_LAST_ACTION = IWL_SISO_SWITCH_GI, -}; - -/* possible actions when in mimo mode */ -enum { - IWL_MIMO2_SWITCH_SISO_A, - IWL_MIMO2_SWITCH_SISO_B, - IWL_MIMO2_SWITCH_GI, - IWL_MIMO2_FIRST_ACTION = IWL_MIMO2_SWITCH_SISO_A, - IWL_MIMO2_LAST_ACTION = IWL_MIMO2_SWITCH_GI, -}; - -#define IWL_MAX_SEARCH IWL_MIMO2_LAST_ACTION - -#define IWL_ACTION_LIMIT 3 /* # possible actions */ - #define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) /* 4 milliseconds */ #define LINK_QUAL_AGG_TIME_LIMIT_MAX (8000) #define LINK_QUAL_AGG_TIME_LIMIT_MIN (100) @@ -282,6 +251,23 @@ struct iwl_rate_scale_data { s32 average_tpt; /* success ratio * expected throughput */ }; +/* Possible Tx columns + * Tx Column = a combo of legacy/siso/mimo x antenna x SGI + */ +enum rs_column { + RS_COLUMN_LEGACY_ANT_A = 0, + RS_COLUMN_LEGACY_ANT_B, + RS_COLUMN_SISO_ANT_A, + RS_COLUMN_SISO_ANT_B, + RS_COLUMN_SISO_ANT_A_SGI, + RS_COLUMN_SISO_ANT_B_SGI, + RS_COLUMN_MIMO2, + RS_COLUMN_MIMO2_SGI, + + RS_COLUMN_LAST = RS_COLUMN_MIMO2_SGI, + RS_COLUMN_INVALID, +}; + /** * struct iwl_scale_tbl_info -- tx params and success history for all rates * @@ -290,13 +276,18 @@ struct iwl_rate_scale_data { */ struct iwl_scale_tbl_info { struct rs_rate rate; - u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */ - u8 max_search; /* maximun number of tables we can search */ + enum rs_column column; s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */ u32 current_rate; /* rate_n_flags, uCode API format */ struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */ }; +enum { + RS_STATE_SEARCH_CYCLE_STARTED, + RS_STATE_SEARCH_CYCLE_ENDED, + RS_STATE_STAY_IN_COLUMN, +}; + /** * struct iwl_lq_sta -- driver's rate scaling private structure * @@ -304,8 +295,7 @@ struct iwl_scale_tbl_info { */ struct iwl_lq_sta { u8 active_tbl; /* index of active table, range 0-1 */ - u8 enable_counter; /* indicates HT mode */ - u8 stay_in_tbl; /* 1: disallow, 0: allow search for new mode */ + u8 rs_state; /* RS_STATE_* */ u8 search_better_tbl; /* 1: currently trying alternate mode */ s32 last_tpt; @@ -318,7 +308,9 @@ struct iwl_lq_sta { u32 total_success; /* total successful frames, any/all rates */ u64 flush_timer; /* time staying in mode before new search */ - u8 action_counter; /* # mode-switch actions tried */ + u32 visited_columns; /* Bitmask marking which Tx columns were + * explored during a search cycle + */ bool is_vht; enum ieee80211_band band; -- cgit v1.2.3-70-g09d2 From b9c509cc994f11799174a8a94ac5c4c09cf773a6 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 28 Nov 2013 14:58:20 +0200 Subject: iwlwifi: mvm: BT Coex - enable Sync to SCO Sync to SCO is a feature that allows to synchronise the wifi activity with the predictable BT activity in SCO profile. This allows to reduce the collisions and improve overall quality. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/bt-coex.c | 3 ++- drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c index 468a4ba49a0..d126245c48d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c @@ -396,7 +396,8 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) BT_VALID_ANT_ISOLATION | BT_VALID_ANT_ISOLATION_THRS | BT_VALID_TXTX_DELTA_FREQ_THRS | - BT_VALID_TXRX_MAX_FREQ_0); + BT_VALID_TXRX_MAX_FREQ_0 | + BT_VALID_SYNC_TO_SCO); if (mvm->cfg->bt_shared_single_ant) memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant, diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h index 4ea5e24ca92..af500996bbf 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h @@ -127,6 +127,7 @@ enum iwl_bt_coex_valid_bit_msk { BT_VALID_ANT_ISOLATION_THRS = BIT(15), BT_VALID_TXTX_DELTA_FREQ_THRS = BIT(16), BT_VALID_TXRX_MAX_FREQ_0 = BIT(17), + BT_VALID_SYNC_TO_SCO = BIT(18), }; /** -- cgit v1.2.3-70-g09d2 From 9d10849e4ea8bf9d8da80afa73918a9fe45c09ef Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 3 Dec 2013 11:50:30 +0200 Subject: iwlwifi: mvm: rs: fix compilation without CONFIG_MAC80211_DEBUGFS This fixes compilation issues with CONFIG_MAC80211_DEBUGFS not enabled. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 128 +++++++++++++++++----------------- 1 file changed, 63 insertions(+), 65 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 1bb6581f3b2..bf6e29f5b4d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -355,8 +355,6 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm, struct ieee80211_sta *sta, struct iwl_lq_sta *lq_sta, u32 rate_n_flags); static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search); -static const char *rs_pretty_lq_type(enum iwl_table_type type); -static const char *rs_pretty_ant(u8 ant); #ifdef CONFIG_MAC80211_DEBUGFS static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, @@ -446,6 +444,43 @@ static const struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = { #define MCS_INDEX_PER_STREAM (8) +static const char *rs_pretty_ant(u8 ant) +{ + static const char * const ant_name[] = { + [ANT_NONE] = "None", + [ANT_A] = "A", + [ANT_B] = "B", + [ANT_AB] = "AB", + [ANT_C] = "C", + [ANT_AC] = "AC", + [ANT_BC] = "BC", + [ANT_ABC] = "ABC", + }; + + if (ant > ANT_ABC) + return "UNKNOWN"; + + return ant_name[ant]; +} + +static const char *rs_pretty_lq_type(enum iwl_table_type type) +{ + static const char * const lq_types[] = { + [LQ_NONE] = "NONE", + [LQ_LEGACY_A] = "LEGACY_A", + [LQ_LEGACY_G] = "LEGACY_G", + [LQ_HT_SISO] = "HT SISO", + [LQ_HT_MIMO2] = "HT MIMO", + [LQ_VHT_SISO] = "VHT SISO", + [LQ_VHT_MIMO2] = "VHT MIMO", + }; + + if (type < LQ_NONE || type >= LQ_MAX) + return "UNKNOWN"; + + return lq_types[type]; +} + static inline void rs_dump_rate(struct iwl_mvm *mvm, const struct rs_rate *rate, const char *prefix) { @@ -2524,69 +2559,6 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, } } -static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file, - const char __user *user_buf, size_t count, loff_t *ppos) -{ - struct iwl_lq_sta *lq_sta = file->private_data; - struct iwl_mvm *mvm; - char buf[64]; - size_t buf_size; - u32 parsed_rate; - - - mvm = lq_sta->drv; - memset(buf, 0, sizeof(buf)); - buf_size = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - - if (sscanf(buf, "%x", &parsed_rate) == 1) - lq_sta->dbg_fixed_rate = parsed_rate; - else - lq_sta->dbg_fixed_rate = 0; - - rs_program_fix_rate(mvm, lq_sta); - - return count; -} - -static const char *rs_pretty_lq_type(enum iwl_table_type type) -{ - static const char * const lq_types[] = { - [LQ_NONE] = "NONE", - [LQ_LEGACY_A] = "LEGACY_A", - [LQ_LEGACY_G] = "LEGACY_G", - [LQ_HT_SISO] = "HT SISO", - [LQ_HT_MIMO2] = "HT MIMO", - [LQ_VHT_SISO] = "VHT SISO", - [LQ_VHT_MIMO2] = "VHT MIMO", - }; - - if (type < LQ_NONE || type >= LQ_MAX) - return "UNKNOWN"; - - return lq_types[type]; -} - -static const char *rs_pretty_ant(u8 ant) -{ - static const char * const ant_name[] = { - [ANT_NONE] = "None", - [ANT_A] = "A", - [ANT_B] = "B", - [ANT_AB] = "AB", - [ANT_C] = "C", - [ANT_AC] = "AC", - [ANT_BC] = "BC", - [ANT_ABC] = "ABC", - }; - - if (ant > ANT_ABC) - return "UNKNOWN"; - - return ant_name[ant]; -} - static int rs_pretty_print_rate(char *buf, const u32 rate) { @@ -2640,6 +2612,32 @@ static int rs_pretty_print_rate(char *buf, const u32 rate) (rate & RATE_MCS_ZLF_MSK) ? "ZLF " : ""); } +static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + struct iwl_lq_sta *lq_sta = file->private_data; + struct iwl_mvm *mvm; + char buf[64]; + size_t buf_size; + u32 parsed_rate; + + + mvm = lq_sta->drv; + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + + if (sscanf(buf, "%x", &parsed_rate) == 1) + lq_sta->dbg_fixed_rate = parsed_rate; + else + lq_sta->dbg_fixed_rate = 0; + + rs_program_fix_rate(mvm, lq_sta); + + return count; +} + static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { -- cgit v1.2.3-70-g09d2 From 710e4d08f2ab6eed7950884ab30e684704e325ca Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 28 Nov 2013 15:25:21 +0200 Subject: iwlwifi: mvm: don't send SMPS action frame with single RX antenna Products that have only 1 antenna in Rx don't support MIMO in RX. As a consequence, they will be in STATIC always. Don't tell mac80211 to update SMPS in that case. mac80211 would send an action frame to the AP which is clearly bogus. As a matter of fact, we have seen that some APs send a deauth when that happens. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/utils.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index 56cf819bc0c..f4aff56a36d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -518,6 +518,11 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, int i; lockdep_assert_held(&mvm->mutex); + + /* SMPS is irrelevant for NICs that don't have at least 2 RX antenna */ + if (num_of_ant(iwl_fw_valid_rx_ant(mvm->fw)) == 1) + return; + mvmvif = iwl_mvm_vif_from_mac80211(vif); mvmvif->smps_requests[req_type] = smps_request; for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) { -- cgit v1.2.3-70-g09d2 From 342a11e1459bb5a053b60ae248e3b78d4da79395 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 3 Dec 2013 08:00:27 +0900 Subject: bcma: pci: remove DEFINE_PCI_DEVICE_TABLE macro Don't use DEFINE_PCI_DEVICE_TABLE macro, because this macro is not preferred. Signed-off-by: Jingoo Han Signed-off-by: John W. Linville --- drivers/bcma/host_pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c index 12a4ff75135..e333305363a 100644 --- a/drivers/bcma/host_pci.c +++ b/drivers/bcma/host_pci.c @@ -269,7 +269,7 @@ static SIMPLE_DEV_PM_OPS(bcma_pm_ops, bcma_host_pci_suspend, #endif /* CONFIG_PM_SLEEP */ -static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = { +static const struct pci_device_id bcma_pci_bridge_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4313) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43224) }, -- cgit v1.2.3-70-g09d2 From 4348d085b8ef9067e32ccc1a9e90e33c0e4b4e66 Mon Sep 17 00:00:00 2001 From: Ujjal Roy Date: Mon, 2 Dec 2013 23:17:48 -0800 Subject: mwifiex: use little-endian variables in firmware structures The firmware expects the command structure members in little endianness. Signed-off-by: Ujjal Roy Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cmdevt.c | 4 ++-- drivers/net/wireless/mwifiex/fw.h | 28 ++++++++++++++-------------- drivers/net/wireless/mwifiex/sta_cmd.c | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index e47f4e3012b..1ddc8b2e372 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -312,14 +312,14 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter) } if (GET_BSS_ROLE(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY)) == MWIFIEX_BSS_ROLE_STA) { - if (!sleep_cfm_buf->resp_ctrl) + if (!le16_to_cpu(sleep_cfm_buf->resp_ctrl)) /* Response is not needed for sleep confirm command */ adapter->ps_state = PS_STATE_SLEEP; else adapter->ps_state = PS_STATE_SLEEP_CFM; - if (!sleep_cfm_buf->resp_ctrl && + if (!le16_to_cpu(sleep_cfm_buf->resp_ctrl) && (adapter->is_hs_configured && !adapter->sleep_period.period)) { adapter->pm_wakeup_card_req = true; diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index c8385ec77a8..6998413c888 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -610,12 +610,12 @@ struct mwifiex_ie_types_tsf_timestamp { struct mwifiex_cf_param_set { u8 cfp_cnt; u8 cfp_period; - u16 cfp_max_duration; - u16 cfp_duration_remaining; + __le16 cfp_max_duration; + __le16 cfp_duration_remaining; } __packed; struct mwifiex_ibss_param_set { - u16 atim_window; + __le16 atim_window; } __packed; struct mwifiex_ie_types_ss_param_set { @@ -627,7 +627,7 @@ struct mwifiex_ie_types_ss_param_set { } __packed; struct mwifiex_fh_param_set { - u16 dwell_time; + __le16 dwell_time; u8 hop_set; u8 hop_pattern; u8 hop_index; @@ -684,10 +684,10 @@ struct host_cmd_ds_802_11_key_material { } __packed; struct host_cmd_ds_gen { - u16 command; - u16 size; - u16 seq_num; - u16 result; + __le16 command; + __le16 size; + __le16 seq_num; + __le16 result; }; #define S_DS_GEN sizeof(struct host_cmd_ds_gen) @@ -820,8 +820,8 @@ struct ieee_types_cf_param_set { u8 len; u8 cfp_cnt; u8 cfp_period; - u16 cfp_max_duration; - u16 cfp_duration_remaining; + __le16 cfp_max_duration; + __le16 cfp_duration_remaining; } __packed; struct ieee_types_ibss_param_set { @@ -957,7 +957,7 @@ struct mwifiex_hs_config_param { } __packed; struct hs_activate_param { - u16 resp_ctrl; + __le16 resp_ctrl; } __packed; struct host_cmd_ds_802_11_hs_cfg_enh { @@ -1131,7 +1131,7 @@ struct host_cmd_ds_802_11_bg_scan_query { } __packed; struct host_cmd_ds_802_11_bg_scan_query_rsp { - u32 report_condition; + __le32 report_condition; struct host_cmd_ds_802_11_scan_rsp scan_resp; } __packed; @@ -1230,7 +1230,7 @@ struct mwifiex_ie_types_wmm_queue_status { struct mwifiex_ie_types_header header; u8 queue_index; u8 disabled; - u16 medium_time; + __le16 medium_time; u8 flow_required; u8 flow_created; u32 reserved; @@ -1310,7 +1310,7 @@ struct mwifiex_ie_types_vht_oper { u8 chan_center_freq_1; u8 chan_center_freq_2; /* Basic MCS set map, each 2 bits stands for a NSS */ - u16 basic_mcs_map; + __le16 basic_mcs_map; } __packed; struct mwifiex_ie_types_wmmcap { diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 2181ee283d8..1efa43ec1c6 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -354,7 +354,7 @@ mwifiex_cmd_802_11_hs_cfg(struct mwifiex_private *priv, } if (hs_activate) { hs_cfg->action = cpu_to_le16(HS_ACTIVATE); - hs_cfg->params.hs_activate.resp_ctrl = RESP_NEEDED; + hs_cfg->params.hs_activate.resp_ctrl = cpu_to_le16(RESP_NEEDED); } else { hs_cfg->action = cpu_to_le16(HS_CONFIGURE); hs_cfg->params.hs_config.conditions = hscfg_param->conditions; -- cgit v1.2.3-70-g09d2 From a6efc5b7f8e737c8e7c97b3c671ae211c5ece3d8 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Mon, 2 Dec 2013 23:17:49 -0800 Subject: mwifiex: declare snap_type as __be16 variable Actually we are updating snap_type with h_proto (__be16 variable) in ethernet frame header. Hence endianness conversion is not required. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/11n_aggr.c | 6 +++--- drivers/net/wireless/mwifiex/fw.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c index 1214c587fd0..63211707f93 100644 --- a/drivers/net/wireless/mwifiex/11n_aggr.c +++ b/drivers/net/wireless/mwifiex/11n_aggr.c @@ -69,9 +69,9 @@ mwifiex_11n_form_amsdu_pkt(struct sk_buff *skb_aggr, memcpy(&tx_header->eth803_hdr, skb_src->data, dt_offset); /* Copy SNAP header */ - snap.snap_type = - le16_to_cpu(*(__le16 *) ((u8 *)skb_src->data + dt_offset)); - dt_offset += sizeof(u16); + snap.snap_type = ((struct ethhdr *)skb_src->data)->h_proto; + + dt_offset += sizeof(__be16); memcpy(&tx_header->rfc1042_hdr, &snap, sizeof(struct rfc_1042_hdr)); diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 6998413c888..8fcb500fa09 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -30,7 +30,7 @@ struct rfc_1042_hdr { u8 llc_ssap; u8 llc_ctrl; u8 snap_oui[3]; - u16 snap_type; + __be16 snap_type; }; struct rx_packet_hdr { -- cgit v1.2.3-70-g09d2 From 1bf947a79177643f33b875586642b61cb175782a Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Mon, 2 Dec 2013 23:17:50 -0800 Subject: mwifiex: remove rfc1042_eth_hdr variable Use 'rfc1042_header' available in net/wireless/util.c Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/sta_rx.c | 5 ++--- drivers/net/wireless/mwifiex/uap_txrx.c | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mwifiex/sta_rx.c b/drivers/net/wireless/mwifiex/sta_rx.c index bb22664923e..241c0e5fc8f 100644 --- a/drivers/net/wireless/mwifiex/sta_rx.c +++ b/drivers/net/wireless/mwifiex/sta_rx.c @@ -88,15 +88,14 @@ int mwifiex_process_rx_packet(struct mwifiex_private *priv, struct rxpd *local_rx_pd; int hdr_chop; struct ethhdr *eth_hdr; - u8 rfc1042_eth_hdr[ETH_ALEN] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; local_rx_pd = (struct rxpd *) (skb->data); rx_pkt_hdr = (void *)local_rx_pd + le16_to_cpu(local_rx_pd->rx_pkt_offset); - if (!memcmp(&rx_pkt_hdr->rfc1042_hdr, - rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr))) { + if (!memcmp(&rx_pkt_hdr->rfc1042_hdr, rfc1042_header, + sizeof(rfc1042_header))) { /* * Replace the 803 header and rfc1042 header (llc/snap) with an * EthernetII header, keep the src/dst and snap_type diff --git a/drivers/net/wireless/mwifiex/uap_txrx.c b/drivers/net/wireless/mwifiex/uap_txrx.c index 92f76d655e6..0d4b7d62ebc 100644 --- a/drivers/net/wireless/mwifiex/uap_txrx.c +++ b/drivers/net/wireless/mwifiex/uap_txrx.c @@ -98,7 +98,6 @@ static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv, int hdr_chop; struct timeval tv; struct ethhdr *p_ethhdr; - u8 rfc1042_eth_hdr[ETH_ALEN] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; uap_rx_pd = (struct uap_rxpd *)(skb->data); rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset); @@ -112,8 +111,8 @@ static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv, return; } - if (!memcmp(&rx_pkt_hdr->rfc1042_hdr, - rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr))) { + if (!memcmp(&rx_pkt_hdr->rfc1042_hdr, rfc1042_header, + sizeof(rfc1042_header))) { /* Replace the 803 header and rfc1042 header (llc/snap) with * an Ethernet II header, keep the src/dst and snap_type * (ethertype). -- cgit v1.2.3-70-g09d2 From c613d16fa77fb7738a436ba23979ecf60ec82494 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Mon, 2 Dec 2013 23:17:51 -0800 Subject: mwifiex: fix an issue with Appletalk devices SNAP/LLC header in the AARP packet is being stripped off while preparing an EthernetII header. Annex M, Table M.3 in 802.11 spec says that some header (ex. AppleTalk AARP(2)) should pass through untouched. This patch modifies the check to exclude/include EthernetII header translation for special cases. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/sta_rx.c | 8 ++++++-- drivers/net/wireless/mwifiex/uap_txrx.c | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mwifiex/sta_rx.c b/drivers/net/wireless/mwifiex/sta_rx.c index 241c0e5fc8f..45238995952 100644 --- a/drivers/net/wireless/mwifiex/sta_rx.c +++ b/drivers/net/wireless/mwifiex/sta_rx.c @@ -94,8 +94,12 @@ int mwifiex_process_rx_packet(struct mwifiex_private *priv, rx_pkt_hdr = (void *)local_rx_pd + le16_to_cpu(local_rx_pd->rx_pkt_offset); - if (!memcmp(&rx_pkt_hdr->rfc1042_hdr, rfc1042_header, - sizeof(rfc1042_header))) { + if ((!memcmp(&rx_pkt_hdr->rfc1042_hdr, bridge_tunnel_header, + sizeof(bridge_tunnel_header))) || + (!memcmp(&rx_pkt_hdr->rfc1042_hdr, rfc1042_header, + sizeof(rfc1042_header)) && + ntohs(rx_pkt_hdr->rfc1042_hdr.snap_type) != ETH_P_AARP && + ntohs(rx_pkt_hdr->rfc1042_hdr.snap_type) != ETH_P_IPX)) { /* * Replace the 803 header and rfc1042 header (llc/snap) with an * EthernetII header, keep the src/dst and snap_type diff --git a/drivers/net/wireless/mwifiex/uap_txrx.c b/drivers/net/wireless/mwifiex/uap_txrx.c index 0d4b7d62ebc..a0bd954b3ab 100644 --- a/drivers/net/wireless/mwifiex/uap_txrx.c +++ b/drivers/net/wireless/mwifiex/uap_txrx.c @@ -111,8 +111,12 @@ static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv, return; } - if (!memcmp(&rx_pkt_hdr->rfc1042_hdr, rfc1042_header, - sizeof(rfc1042_header))) { + if ((!memcmp(&rx_pkt_hdr->rfc1042_hdr, bridge_tunnel_header, + sizeof(bridge_tunnel_header))) || + (!memcmp(&rx_pkt_hdr->rfc1042_hdr, rfc1042_header, + sizeof(rfc1042_header)) && + ntohs(rx_pkt_hdr->rfc1042_hdr.snap_type) != ETH_P_AARP && + ntohs(rx_pkt_hdr->rfc1042_hdr.snap_type) != ETH_P_IPX)) { /* Replace the 803 header and rfc1042 header (llc/snap) with * an Ethernet II header, keep the src/dst and snap_type * (ethertype). -- cgit v1.2.3-70-g09d2 From f8eb5ee5f56f09278b80100e65df08975867f03c Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Mon, 2 Dec 2013 23:17:52 -0800 Subject: mwifiex: avoid using variable name eth_hdr eth_hdr is defined in kernel. Use a different variable name in our functions. Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/sta_rx.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/mwifiex/sta_rx.c b/drivers/net/wireless/mwifiex/sta_rx.c index 45238995952..d74192d6265 100644 --- a/drivers/net/wireless/mwifiex/sta_rx.c +++ b/drivers/net/wireless/mwifiex/sta_rx.c @@ -36,12 +36,12 @@ mwifiex_discard_gratuitous_arp(struct mwifiex_private *priv, struct sk_buff *skb) { const struct mwifiex_arp_eth_header *arp; - struct ethhdr *eth_hdr; + struct ethhdr *eth; struct ipv6hdr *ipv6; struct icmp6hdr *icmpv6; - eth_hdr = (struct ethhdr *)skb->data; - switch (ntohs(eth_hdr->h_proto)) { + eth = (struct ethhdr *)skb->data; + switch (ntohs(eth->h_proto)) { case ETH_P_ARP: arp = (void *)(skb->data + sizeof(struct ethhdr)); if (arp->hdr.ar_op == htons(ARPOP_REPLY) || @@ -87,7 +87,7 @@ int mwifiex_process_rx_packet(struct mwifiex_private *priv, struct rx_packet_hdr *rx_pkt_hdr; struct rxpd *local_rx_pd; int hdr_chop; - struct ethhdr *eth_hdr; + struct ethhdr *eth; local_rx_pd = (struct rxpd *) (skb->data); @@ -109,7 +109,7 @@ int mwifiex_process_rx_packet(struct mwifiex_private *priv, * To create the Ethernet II, just move the src, dst address * right before the snap_type. */ - eth_hdr = (struct ethhdr *) + eth = (struct ethhdr *) ((u8 *) &rx_pkt_hdr->eth803_hdr + sizeof(rx_pkt_hdr->eth803_hdr) + sizeof(rx_pkt_hdr->rfc1042_hdr) @@ -117,14 +117,14 @@ int mwifiex_process_rx_packet(struct mwifiex_private *priv, - sizeof(rx_pkt_hdr->eth803_hdr.h_source) - sizeof(rx_pkt_hdr->rfc1042_hdr.snap_type)); - memcpy(eth_hdr->h_source, rx_pkt_hdr->eth803_hdr.h_source, - sizeof(eth_hdr->h_source)); - memcpy(eth_hdr->h_dest, rx_pkt_hdr->eth803_hdr.h_dest, - sizeof(eth_hdr->h_dest)); + memcpy(eth->h_source, rx_pkt_hdr->eth803_hdr.h_source, + sizeof(eth->h_source)); + memcpy(eth->h_dest, rx_pkt_hdr->eth803_hdr.h_dest, + sizeof(eth->h_dest)); /* Chop off the rxpd + the excess memory from the 802.2/llc/snap header that was removed. */ - hdr_chop = (u8 *) eth_hdr - (u8 *) local_rx_pd; + hdr_chop = (u8 *) eth - (u8 *) local_rx_pd; } else { /* Chop off the rxpd */ hdr_chop = (u8 *) &rx_pkt_hdr->eth803_hdr - -- cgit v1.2.3-70-g09d2 From ca8d6dfc929ad6e59eb523e7c057804b55e5673e Mon Sep 17 00:00:00 2001 From: Ujjal Roy Date: Mon, 2 Dec 2013 23:17:53 -0800 Subject: mwifiex: fix rx_pending count imbalance RX packets are handled in different paths. Not all paths have decrement of rx_pending counter. This patch fixes the counter imbalance. Signed-off-by: Ujjal Roy Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/init.c | 3 ++- drivers/net/wireless/mwifiex/main.h | 2 +- drivers/net/wireless/mwifiex/sta_rx.c | 15 +++------------ drivers/net/wireless/mwifiex/txrx.c | 11 +++++++++-- drivers/net/wireless/mwifiex/uap_txrx.c | 15 +++------------ drivers/net/wireless/mwifiex/usb.c | 4 +--- 6 files changed, 19 insertions(+), 31 deletions(-) diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 6499117fce4..1d0a817f2bf 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -643,7 +643,8 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) if (priv) priv->stats.rx_dropped++; - adapter->if_ops.data_complete(adapter, skb); + dev_kfree_skb_any(skb); + adapter->if_ops.data_complete(adapter); } } diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 1d72f13adb9..dc34457557f 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -615,7 +615,7 @@ struct mwifiex_if_ops { void (*cleanup_mpa_buf) (struct mwifiex_adapter *); int (*cmdrsp_complete) (struct mwifiex_adapter *, struct sk_buff *); int (*event_complete) (struct mwifiex_adapter *, struct sk_buff *); - int (*data_complete) (struct mwifiex_adapter *, struct sk_buff *); + int (*data_complete) (struct mwifiex_adapter *); int (*init_fw_port) (struct mwifiex_adapter *); int (*dnld_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *); void (*card_reset) (struct mwifiex_adapter *); diff --git a/drivers/net/wireless/mwifiex/sta_rx.c b/drivers/net/wireless/mwifiex/sta_rx.c index d74192d6265..0bb510de807 100644 --- a/drivers/net/wireless/mwifiex/sta_rx.c +++ b/drivers/net/wireless/mwifiex/sta_rx.c @@ -188,12 +188,7 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_private *priv, "wrong rx packet: len=%d, rx_pkt_offset=%d, rx_pkt_length=%d\n", skb->len, rx_pkt_offset, rx_pkt_length); priv->stats.rx_dropped++; - - if (adapter->if_ops.data_complete) - adapter->if_ops.data_complete(adapter, skb); - else - dev_kfree_skb_any(skb); - + dev_kfree_skb_any(skb); return ret; } @@ -247,12 +242,8 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_private *priv, ret = mwifiex_11n_rx_reorder_pkt(priv, seq_num, local_rx_pd->priority, ta, (u8) rx_pkt_type, skb); - if (ret || (rx_pkt_type == PKT_TYPE_BAR)) { - if (adapter->if_ops.data_complete) - adapter->if_ops.data_complete(adapter, skb); - else - dev_kfree_skb_any(skb); - } + if (ret || (rx_pkt_type == PKT_TYPE_BAR)) + dev_kfree_skb_any(skb); if (ret) priv->stats.rx_dropped++; diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c index 8f923d0d2ba..8dd145cf803 100644 --- a/drivers/net/wireless/mwifiex/txrx.c +++ b/drivers/net/wireless/mwifiex/txrx.c @@ -40,6 +40,7 @@ int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter, mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); struct rxpd *local_rx_pd; struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); + int ret; local_rx_pd = (struct rxpd *) (skb->data); /* Get the BSS number from rxpd, get corresponding priv */ @@ -58,9 +59,15 @@ int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter, rx_info->bss_type = priv->bss_type; if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) - return mwifiex_process_uap_rx_packet(priv, skb); + ret = mwifiex_process_uap_rx_packet(priv, skb); + else + ret = mwifiex_process_sta_rx_packet(priv, skb); + + /* Decrement RX pending counter for each packet */ + if (adapter->if_ops.data_complete) + adapter->if_ops.data_complete(adapter); - return mwifiex_process_sta_rx_packet(priv, skb); + return ret; } EXPORT_SYMBOL_GPL(mwifiex_handle_rx_packet); diff --git a/drivers/net/wireless/mwifiex/uap_txrx.c b/drivers/net/wireless/mwifiex/uap_txrx.c index a0bd954b3ab..6c0a31a8df9 100644 --- a/drivers/net/wireless/mwifiex/uap_txrx.c +++ b/drivers/net/wireless/mwifiex/uap_txrx.c @@ -267,12 +267,7 @@ int mwifiex_process_uap_rx_packet(struct mwifiex_private *priv, skb->len, le16_to_cpu(uap_rx_pd->rx_pkt_offset), le16_to_cpu(uap_rx_pd->rx_pkt_length)); priv->stats.rx_dropped++; - - if (adapter->if_ops.data_complete) - adapter->if_ops.data_complete(adapter, skb); - else - dev_kfree_skb_any(skb); - + dev_kfree_skb_any(skb); return 0; } @@ -326,12 +321,8 @@ int mwifiex_process_uap_rx_packet(struct mwifiex_private *priv, uap_rx_pd->priority, ta, pkt_type, skb); - if (ret || (rx_pkt_type == PKT_TYPE_BAR)) { - if (adapter->if_ops.data_complete) - adapter->if_ops.data_complete(adapter, skb); - else - dev_kfree_skb_any(skb); - } + if (ret || (rx_pkt_type == PKT_TYPE_BAR)) + dev_kfree_skb_any(skb); if (ret) priv->stats.rx_dropped++; diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index edf5b7a2490..a9240a2083f 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c @@ -938,11 +938,9 @@ static int mwifiex_usb_cmd_event_complete(struct mwifiex_adapter *adapter, return 0; } -static int mwifiex_usb_data_complete(struct mwifiex_adapter *adapter, - struct sk_buff *skb) +static int mwifiex_usb_data_complete(struct mwifiex_adapter *adapter) { atomic_dec(&adapter->rx_pending); - dev_kfree_skb_any(skb); return 0; } -- cgit v1.2.3-70-g09d2 From f49c6e814274a12295dbd13e1c8ef2b7edd5ab87 Mon Sep 17 00:00:00 2001 From: Ujjal Roy Date: Mon, 2 Dec 2013 23:17:54 -0800 Subject: mwifiex: correct RX byte count statistics The skb is modified in processing the RX packet. Save the original packet length to a variable so that we can get the correct statistics update. Signed-off-by: Ujjal Roy Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/util.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index 5d9e150f411..9b82e225880 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c @@ -191,6 +191,9 @@ int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb) if (!skb) return -1; + priv->stats.rx_bytes += skb->len; + priv->stats.rx_packets++; + skb->dev = priv->netdev; skb->protocol = eth_type_trans(skb, priv->netdev); skb->ip_summed = CHECKSUM_NONE; @@ -217,8 +220,6 @@ int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb) (skb->truesize > MWIFIEX_RX_DATA_BUF_SIZE)) skb->truesize += (skb->len - MWIFIEX_RX_DATA_BUF_SIZE); - priv->stats.rx_bytes += skb->len; - priv->stats.rx_packets++; if (in_interrupt()) netif_rx(skb); else -- cgit v1.2.3-70-g09d2 From a1ed484960066c413712cd9c4d50a350cf67eba3 Mon Sep 17 00:00:00 2001 From: Ujjal Roy Date: Mon, 2 Dec 2013 23:17:55 -0800 Subject: mwifiex: correct TX byte count statistics The skb is modified in sending the TX packet. Save the original packet length to a variable so that we can get the correct statistics update. Signed-off-by: Ujjal Roy Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cfg80211.c | 1 + drivers/net/wireless/mwifiex/decl.h | 1 + drivers/net/wireless/mwifiex/main.c | 1 + drivers/net/wireless/mwifiex/sta_tx.c | 1 + drivers/net/wireless/mwifiex/txrx.c | 2 +- 5 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index d9b7330c902..4d23647faef 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -222,6 +222,7 @@ mwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, tx_info = MWIFIEX_SKB_TXCB(skb); tx_info->bss_num = priv->bss_num; tx_info->bss_type = priv->bss_type; + tx_info->pkt_len = pkt_len; mwifiex_form_mgmt_frame(skb, buf, len); mwifiex_queue_tx_pkt(priv, skb); diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index 5c85d7803d0..3a21bd03d6d 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h @@ -130,6 +130,7 @@ struct mwifiex_txinfo { u8 flags; u8 bss_num; u8 bss_type; + u32 pkt_len; }; enum mwifiex_wmm_ac_e { diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 78e8a6666cc..36c79cff492 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -648,6 +648,7 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) tx_info = MWIFIEX_SKB_TXCB(skb); tx_info->bss_num = priv->bss_num; tx_info->bss_type = priv->bss_type; + tx_info->pkt_len = skb->len; /* Record the current time the packet was queued; used to * determine the amount of time the packet was queued in diff --git a/drivers/net/wireless/mwifiex/sta_tx.c b/drivers/net/wireless/mwifiex/sta_tx.c index 7b581af24f5..354d64c9606 100644 --- a/drivers/net/wireless/mwifiex/sta_tx.c +++ b/drivers/net/wireless/mwifiex/sta_tx.c @@ -148,6 +148,7 @@ int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags) tx_info = MWIFIEX_SKB_TXCB(skb); tx_info->bss_num = priv->bss_num; tx_info->bss_type = priv->bss_type; + tx_info->pkt_len = data_len - (sizeof(struct txpd) + INTF_HEADER_LEN); skb_reserve(skb, sizeof(struct txpd) + INTF_HEADER_LEN); skb_push(skb, sizeof(struct txpd)); diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c index 8dd145cf803..3446da6792c 100644 --- a/drivers/net/wireless/mwifiex/txrx.c +++ b/drivers/net/wireless/mwifiex/txrx.c @@ -175,7 +175,7 @@ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter, mwifiex_set_trans_start(priv->netdev); if (!status) { priv->stats.tx_packets++; - priv->stats.tx_bytes += skb->len; + priv->stats.tx_bytes += tx_info->pkt_len; if (priv->tx_timeout_cnt) priv->tx_timeout_cnt = 0; } else { -- cgit v1.2.3-70-g09d2 From f7b598532f3dccfb7b57f57b1163a0e1b3bc50cf Mon Sep 17 00:00:00 2001 From: Ujjal Roy Date: Mon, 2 Dec 2013 23:17:56 -0800 Subject: mwifiex: update statistics for bridged packets on AP interface The bridged packets are updated to statistics on both TX and RX paths. Also fix a typo in the comment. Signed-off-by: Ujjal Roy Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/uap_txrx.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mwifiex/uap_txrx.c b/drivers/net/wireless/mwifiex/uap_txrx.c index 6c0a31a8df9..3c74eb25492 100644 --- a/drivers/net/wireless/mwifiex/uap_txrx.c +++ b/drivers/net/wireless/mwifiex/uap_txrx.c @@ -147,7 +147,7 @@ static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv, hdr_chop = (u8 *)&rx_pkt_hdr->eth803_hdr - (u8 *)uap_rx_pd; } - /* Chop off the leading header bytes so the it points + /* Chop off the leading header bytes so that it points * to the start of either the reconstructed EthII frame * or the 802.2/llc/snap frame. */ @@ -179,6 +179,19 @@ static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv, tx_info->bss_type = priv->bss_type; tx_info->flags |= MWIFIEX_BUF_FLAG_BRIDGED_PKT; + if (is_unicast_ether_addr(rx_pkt_hdr->eth803_hdr.h_dest)) { + /* Update bridge packet statistics as the + * packet is not going to kernel/upper layer. + */ + priv->stats.rx_bytes += skb->len; + priv->stats.rx_packets++; + + /* Sending bridge packet to TX queue, so save the packet + * length in TXCB to update statistics in TX complete. + */ + tx_info->pkt_len = skb->len; + } + do_gettimeofday(&tv); skb->tstamp = timeval_to_ktime(tv); mwifiex_wmm_add_buf_txqueue(priv, skb); -- cgit v1.2.3-70-g09d2 From c2868adebdb1c3233562e152d99a834f084cc07e Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Mon, 2 Dec 2013 23:17:57 -0800 Subject: mwifiex: remove redundant goto exit_remove statement The check for 'priv' pointer is redundant. 'priv' won't be used later in this routine. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/main.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 36c79cff492..6bf58aba51d 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -992,12 +992,8 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) rtnl_unlock(); } - priv = adapter->priv[0]; - if (!priv || !priv->wdev) - goto exit_remove; - - wiphy_unregister(priv->wdev->wiphy); - wiphy_free(priv->wdev->wiphy); + wiphy_unregister(adapter->wiphy); + wiphy_free(adapter->wiphy); mwifiex_terminate_workqueue(adapter); -- cgit v1.2.3-70-g09d2 From bd2a864a14ebd0ffa2166c0d8005e44437436713 Mon Sep 17 00:00:00 2001 From: Ujjal Roy Date: Mon, 2 Dec 2013 23:17:59 -0800 Subject: mwifiex: do not flood kmsg/dmesg with USB debug messages When TX data URB reaches high water mark the message "data: -ENOSR is returned" is printed. This is not an error case, so change it to debug print. Signed-off-by: Ujjal Roy Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/txrx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c index 3446da6792c..37f26afd431 100644 --- a/drivers/net/wireless/mwifiex/txrx.c +++ b/drivers/net/wireless/mwifiex/txrx.c @@ -112,7 +112,7 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, switch (ret) { case -ENOSR: - dev_err(adapter->dev, "data: -ENOSR is returned\n"); + dev_dbg(adapter->dev, "data: -ENOSR is returned\n"); break; case -EBUSY: if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && -- cgit v1.2.3-70-g09d2 From 997b179ba3d4da8a25d28cf4f1de8962a32e588a Mon Sep 17 00:00:00 2001 From: Chun-Yeow Yeoh Date: Wed, 4 Dec 2013 18:46:54 +0800 Subject: ath9k: enable dfs for mesh mode Signed-off-by: Chun-Yeow Yeoh Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/init.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 8f4c1674b76..5a0b7e82c85 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -856,6 +856,9 @@ static const struct ieee80211_iface_limit if_limits[] = { static const struct ieee80211_iface_limit if_dfs_limits[] = { { .max = 1, .types = BIT(NL80211_IFTYPE_AP) | +#ifdef CONFIG_MAC80211_MESH + BIT(NL80211_IFTYPE_MESH_POINT) | +#endif BIT(NL80211_IFTYPE_ADHOC) }, }; -- cgit v1.2.3-70-g09d2 From fa643ae2ce4e75413623a51845a2fd5c9fae4ec0 Mon Sep 17 00:00:00 2001 From: Chun-Yeow Yeoh Date: Fri, 6 Dec 2013 11:28:02 +0800 Subject: wcn36xx: enable the beaconing in mesh mode Enable the beaconing in wnc36xx by tweaking the tim offset and force the use of AP-style beaconing. Otherwise, beaconing is not working. The tim offset is set to 256. Otherwise, this will overwrite mesh beacon submitted by mac80211. Signed-off-by: Chun-Yeow Yeoh Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wcn36xx/smd.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index 823631cdb87..8f37562e0b1 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -1151,14 +1151,14 @@ int wcn36xx_smd_config_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif, /* STA */ bss->oper_mode = 1; bss->wcn36xx_hal_persona = WCN36XX_HAL_STA_MODE; - } else if (vif->type == NL80211_IFTYPE_AP) { + } else if (vif->type == NL80211_IFTYPE_AP || + vif->type == NL80211_IFTYPE_MESH_POINT) { bss->bss_type = WCN36XX_HAL_INFRA_AP_MODE; /* AP */ bss->oper_mode = 0; bss->wcn36xx_hal_persona = WCN36XX_HAL_STA_SAP_MODE; - } else if (vif->type == NL80211_IFTYPE_ADHOC || - vif->type == NL80211_IFTYPE_MESH_POINT) { + } else if (vif->type == NL80211_IFTYPE_ADHOC) { bss->bss_type = WCN36XX_HAL_IBSS_MODE; /* STA */ @@ -1309,7 +1309,11 @@ int wcn36xx_smd_send_beacon(struct wcn36xx *wcn, struct ieee80211_vif *vif, memcpy(msg_body.bssid, vif->addr, ETH_ALEN); /* TODO need to find out why this is needed? */ - msg_body.tim_ie_offset = tim_off+4; + if (vif->type == NL80211_IFTYPE_MESH_POINT) + /* mesh beacon don't need this, so push further down */ + msg_body.tim_ie_offset = 256; + else + msg_body.tim_ie_offset = tim_off+4; msg_body.p2p_ie_offset = p2p_off; PREPARE_HAL_BUF(wcn->hal_buf, msg_body); -- cgit v1.2.3-70-g09d2 From 7f3dbb563658f6f24ba52ba336f652d9f9b5fca4 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 5 Dec 2013 22:07:12 -0600 Subject: rtlwifi: rtl8192c-common: Fix sparse warning Sparse reports the following: CHECK drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c:570:34: warning: dubious: !x & y There should be a parens around the expression. Reported-by: Dan Carpenter Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c index fd7e4a7c94d..eb78fd8607f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c @@ -567,7 +567,7 @@ static void rtl92c_dm_dig(struct ieee80211_hw *hw) if (rtlpriv->dm.dm_initialgain_enable == false) return; - if (!rtlpriv->dm.dm_flag & DYNAMIC_FUNC_DIG) + if (!(rtlpriv->dm.dm_flag & DYNAMIC_FUNC_DIG)) return; rtl92c_dm_ctrl_initgain_by_twoport(hw); -- cgit v1.2.3-70-g09d2 From 98b2e1fdf1603f30db195a11cc1ffcc2170d42a8 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 6 Dec 2013 16:28:39 +0530 Subject: ath9k: Add initval arrays for DFS channels Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h | 7 +++++++ drivers/net/wireless/ath/ath9k/ar9340_initvals.h | 2 ++ drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h | 13 +++++++++++-- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h index e7cdf1100f5..97b4bd1e2e1 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h @@ -1745,4 +1745,11 @@ static const u32 ar9300_2p2_baseband_core_txfir_coeff_japan_2484[][2] = { {0x0000a3a0, 0xca9228ee}, }; +static const u32 ar9300_2p2_baseband_postamble_dfs_channel[][3] = { + /* Addr 5G 2G */ + {0x00009824, 0x5ac668d0, 0x5ac668d0}, + {0x00009e0c, 0x6d4000e2, 0x6d4000e2}, + {0x00009e14, 0x37b9625e, 0x37b9625e}, +}; + #endif /* INITVALS_9003_2P2_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9340_initvals.h b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h index 7f22cb2a494..a01f0edb651 100644 --- a/drivers/net/wireless/ath/ath9k/ar9340_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h @@ -30,6 +30,8 @@ #define ar9340_1p0_baseband_core_txfir_coeff_japan_2484 ar9300_2p2_baseband_core_txfir_coeff_japan_2484 +#define ar9340_1p0_baseband_postamble_dfs_channel ar9300_2p2_baseband_postamble_dfs_channel + static const u32 ar9340_1p0_radio_postamble[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x000160ac, 0xa4646800, 0xa4646800, 0xa4646800, 0xa4646800}, diff --git a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h index 75bef1179d0..e6aec2c0207 100644 --- a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h @@ -57,8 +57,6 @@ static const u32 ar9580_1p0_baseband_core[][2] = { {0x00009804, 0xfd14e000}, {0x00009808, 0x9c0a9f6b}, {0x0000980c, 0x04900000}, - {0x00009814, 0x3280c00a}, - {0x00009818, 0x00000000}, {0x0000981c, 0x00020028}, {0x00009834, 0x6400a190}, {0x00009838, 0x0108ecff}, @@ -1133,6 +1131,8 @@ static const u32 ar9580_1p0_rx_gain_table[][2] = { static const u32 ar9580_1p0_baseband_postamble[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011}, + {0x00009814, 0x3280c00a, 0x3280c00a, 0x3280c00a, 0x3280c00a}, + {0x00009818, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e}, {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, @@ -1207,4 +1207,13 @@ static const u32 ar9580_1p0_pcie_phy_pll_on_clkreq[][2] = { {0x00004044, 0x00000000}, }; +static const u32 ar9580_1p0_baseband_postamble_dfs_channel[][3] = { + /* Addr 5G 2G */ + {0x00009814, 0x3400c00f, 0x3400c00f}, + {0x00009824, 0x5ac668d0, 0x5ac668d0}, + {0x00009828, 0x06903080, 0x06903080}, + {0x00009e0c, 0x6d4000e2, 0x6d4000e2}, + {0x00009e14, 0x37b9625e, 0x37b9625e}, +}; + #endif /* INITVALS_9580_1P0_H */ -- cgit v1.2.3-70-g09d2 From 4a878b9f8916eaeb5f8cea1379956b485e32450f Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 6 Dec 2013 16:28:40 +0530 Subject: ath9k: Initialize baseband for DFS channels Certain baseband registers require different values to be programmed when operating in a DFS channel to ensure that radar detection works correctly. This is required for AR9300, AR9340 and AR9580. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_hw.c | 6 ++++++ drivers/net/wireless/ath/ath9k/ar9003_phy.c | 6 ++++++ drivers/net/wireless/ath/ath9k/hw.h | 1 + 3 files changed, 13 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index d8c1eee8ea5..4e8ae4a79dc 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -152,6 +152,8 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ar9340Modes_fast_clock_1p0); INIT_INI_ARRAY(&ah->iniCckfirJapan2484, ar9340_1p0_baseband_core_txfir_coeff_japan_2484); + INIT_INI_ARRAY(&ah->ini_dfs, + ar9340_1p0_baseband_postamble_dfs_channel); if (!ah->is_clk_25mhz) INIT_INI_ARRAY(&ah->iniAdditional, @@ -340,6 +342,8 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ar9580_1p0_modes_fast_clock); INIT_INI_ARRAY(&ah->iniCckfirJapan2484, ar9580_1p0_baseband_core_txfir_coeff_japan_2484); + INIT_INI_ARRAY(&ah->ini_dfs, + ar9580_1p0_baseband_postamble_dfs_channel); } else if (AR_SREV_9565_11_OR_LATER(ah)) { INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], ar9565_1p1_mac_core); @@ -458,6 +462,8 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ar9300Modes_fast_clock_2p2); INIT_INI_ARRAY(&ah->iniCckfirJapan2484, ar9300_2p2_baseband_core_txfir_coeff_japan_2484); + INIT_INI_ARRAY(&ah->ini_dfs, + ar9300_2p2_baseband_postamble_dfs_channel); } } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 39b71b3d691..9f051a08e14 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -1332,6 +1332,7 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah) static void ar9003_hw_set_radar_params(struct ath_hw *ah, struct ath_hw_radar_conf *conf) { + unsigned int regWrites = 0; u32 radar_0 = 0, radar_1 = 0; if (!conf) { @@ -1358,6 +1359,11 @@ static void ar9003_hw_set_radar_params(struct ath_hw *ah, REG_SET_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA); else REG_CLR_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA); + + if (AR_SREV_9300(ah) || AR_SREV_9340(ah) || AR_SREV_9580(ah)) { + REG_WRITE_ARRAY(&ah->ini_dfs, + IS_CHAN_HT40(ah->curchan) ? 2 : 1, regWrites); + } } static void ar9003_hw_set_radar_conf(struct ath_hw *ah) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index e5084360098..7490047acd1 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -864,6 +864,7 @@ struct ath_hw { u32 gpio_mask; u32 gpio_val; + struct ar5416IniArray ini_dfs; struct ar5416IniArray iniModes; struct ar5416IniArray iniCommon; struct ar5416IniArray iniBB_RfGain; -- cgit v1.2.3-70-g09d2 From bc73902a031d9a9bf5123b3c11889d85ce8fc6ad Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 6 Dec 2013 16:28:41 +0530 Subject: ath9k: Update mac_postamble for AR9003 family Enable the ALWAYS_KEYSEARCH bit in the initvals. Currently this is done in the driver, but adding this to the initvals makes it easier to be in sync with the INI files given by the systems engineering team. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h index 97b4bd1e2e1..72436744615 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h @@ -303,7 +303,7 @@ static const u32 ar9300_2p2_mac_postamble[][5] = { {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, - {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, + {0x00008120, 0x18f04800, 0x18f04800, 0x18f04810, 0x18f04810}, {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, }; -- cgit v1.2.3-70-g09d2 From 11295126e3cfb1cd64a2fa8a4134956ab4dc26d3 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 6 Dec 2013 16:28:42 +0530 Subject: ath9k: Remove AR955x INI duplicates Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- .../net/wireless/ath/ath9k/ar955x_1p0_initvals.h | 540 +-------------------- 1 file changed, 8 insertions(+), 532 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h index ccc5b6c99ad..74d8bc05b31 100644 --- a/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h @@ -20,6 +20,14 @@ /* AR955X 1.0 */ +#define ar955x_1p0_soc_postamble ar9300_2p2_soc_postamble + +#define ar955x_1p0_common_rx_gain_table ar9300Common_rx_gain_table_2p2 + +#define ar955x_1p0_common_wo_xlna_rx_gain_table ar9300Common_wo_xlna_rx_gain_table_2p2 + +#define ar955x_1p0_baseband_core_txfir_coeff_japan_2484 ar9300_2p2_baseband_core_txfir_coeff_japan_2484 + static const u32 ar955x_1p0_radio_postamble[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00016098, 0xd2dd5554, 0xd2dd5554, 0xd28b3330, 0xd28b3330}, @@ -37,13 +45,6 @@ static const u32 ar955x_1p0_radio_postamble[][5] = { {0x00016940, 0x10804008, 0x10804008, 0x10804008, 0x10804008}, }; -static const u32 ar955x_1p0_baseband_core_txfir_coeff_japan_2484[][2] = { - /* Addr allmodes */ - {0x0000a398, 0x00000000}, - {0x0000a39c, 0x6f7f0301}, - {0x0000a3a0, 0xca9228ee}, -}; - static const u32 ar955x_1p0_baseband_postamble[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011}, @@ -473,266 +474,6 @@ static const u32 ar955x_1p0_mac_core[][2] = { {0x000083d0, 0x8c7901ff}, }; -static const u32 ar955x_1p0_common_rx_gain_table[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x00010000}, - {0x0000a004, 0x00030002}, - {0x0000a008, 0x00050004}, - {0x0000a00c, 0x00810080}, - {0x0000a010, 0x00830082}, - {0x0000a014, 0x01810180}, - {0x0000a018, 0x01830182}, - {0x0000a01c, 0x01850184}, - {0x0000a020, 0x01890188}, - {0x0000a024, 0x018b018a}, - {0x0000a028, 0x018d018c}, - {0x0000a02c, 0x01910190}, - {0x0000a030, 0x01930192}, - {0x0000a034, 0x01950194}, - {0x0000a038, 0x038a0196}, - {0x0000a03c, 0x038c038b}, - {0x0000a040, 0x0390038d}, - {0x0000a044, 0x03920391}, - {0x0000a048, 0x03940393}, - {0x0000a04c, 0x03960395}, - {0x0000a050, 0x00000000}, - {0x0000a054, 0x00000000}, - {0x0000a058, 0x00000000}, - {0x0000a05c, 0x00000000}, - {0x0000a060, 0x00000000}, - {0x0000a064, 0x00000000}, - {0x0000a068, 0x00000000}, - {0x0000a06c, 0x00000000}, - {0x0000a070, 0x00000000}, - {0x0000a074, 0x00000000}, - {0x0000a078, 0x00000000}, - {0x0000a07c, 0x00000000}, - {0x0000a080, 0x22222229}, - {0x0000a084, 0x1d1d1d1d}, - {0x0000a088, 0x1d1d1d1d}, - {0x0000a08c, 0x1d1d1d1d}, - {0x0000a090, 0x171d1d1d}, - {0x0000a094, 0x11111717}, - {0x0000a098, 0x00030311}, - {0x0000a09c, 0x00000000}, - {0x0000a0a0, 0x00000000}, - {0x0000a0a4, 0x00000000}, - {0x0000a0a8, 0x00000000}, - {0x0000a0ac, 0x00000000}, - {0x0000a0b0, 0x00000000}, - {0x0000a0b4, 0x00000000}, - {0x0000a0b8, 0x00000000}, - {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x001f0000}, - {0x0000a0c4, 0x01000101}, - {0x0000a0c8, 0x011e011f}, - {0x0000a0cc, 0x011c011d}, - {0x0000a0d0, 0x02030204}, - {0x0000a0d4, 0x02010202}, - {0x0000a0d8, 0x021f0200}, - {0x0000a0dc, 0x0302021e}, - {0x0000a0e0, 0x03000301}, - {0x0000a0e4, 0x031e031f}, - {0x0000a0e8, 0x0402031d}, - {0x0000a0ec, 0x04000401}, - {0x0000a0f0, 0x041e041f}, - {0x0000a0f4, 0x0502041d}, - {0x0000a0f8, 0x05000501}, - {0x0000a0fc, 0x051e051f}, - {0x0000a100, 0x06010602}, - {0x0000a104, 0x061f0600}, - {0x0000a108, 0x061d061e}, - {0x0000a10c, 0x07020703}, - {0x0000a110, 0x07000701}, - {0x0000a114, 0x00000000}, - {0x0000a118, 0x00000000}, - {0x0000a11c, 0x00000000}, - {0x0000a120, 0x00000000}, - {0x0000a124, 0x00000000}, - {0x0000a128, 0x00000000}, - {0x0000a12c, 0x00000000}, - {0x0000a130, 0x00000000}, - {0x0000a134, 0x00000000}, - {0x0000a138, 0x00000000}, - {0x0000a13c, 0x00000000}, - {0x0000a140, 0x001f0000}, - {0x0000a144, 0x01000101}, - {0x0000a148, 0x011e011f}, - {0x0000a14c, 0x011c011d}, - {0x0000a150, 0x02030204}, - {0x0000a154, 0x02010202}, - {0x0000a158, 0x021f0200}, - {0x0000a15c, 0x0302021e}, - {0x0000a160, 0x03000301}, - {0x0000a164, 0x031e031f}, - {0x0000a168, 0x0402031d}, - {0x0000a16c, 0x04000401}, - {0x0000a170, 0x041e041f}, - {0x0000a174, 0x0502041d}, - {0x0000a178, 0x05000501}, - {0x0000a17c, 0x051e051f}, - {0x0000a180, 0x06010602}, - {0x0000a184, 0x061f0600}, - {0x0000a188, 0x061d061e}, - {0x0000a18c, 0x07020703}, - {0x0000a190, 0x07000701}, - {0x0000a194, 0x00000000}, - {0x0000a198, 0x00000000}, - {0x0000a19c, 0x00000000}, - {0x0000a1a0, 0x00000000}, - {0x0000a1a4, 0x00000000}, - {0x0000a1a8, 0x00000000}, - {0x0000a1ac, 0x00000000}, - {0x0000a1b0, 0x00000000}, - {0x0000a1b4, 0x00000000}, - {0x0000a1b8, 0x00000000}, - {0x0000a1bc, 0x00000000}, - {0x0000a1c0, 0x00000000}, - {0x0000a1c4, 0x00000000}, - {0x0000a1c8, 0x00000000}, - {0x0000a1cc, 0x00000000}, - {0x0000a1d0, 0x00000000}, - {0x0000a1d4, 0x00000000}, - {0x0000a1d8, 0x00000000}, - {0x0000a1dc, 0x00000000}, - {0x0000a1e0, 0x00000000}, - {0x0000a1e4, 0x00000000}, - {0x0000a1e8, 0x00000000}, - {0x0000a1ec, 0x00000000}, - {0x0000a1f0, 0x00000396}, - {0x0000a1f4, 0x00000396}, - {0x0000a1f8, 0x00000396}, - {0x0000a1fc, 0x00000196}, - {0x0000b000, 0x00010000}, - {0x0000b004, 0x00030002}, - {0x0000b008, 0x00050004}, - {0x0000b00c, 0x00810080}, - {0x0000b010, 0x00830082}, - {0x0000b014, 0x01810180}, - {0x0000b018, 0x01830182}, - {0x0000b01c, 0x01850184}, - {0x0000b020, 0x02810280}, - {0x0000b024, 0x02830282}, - {0x0000b028, 0x02850284}, - {0x0000b02c, 0x02890288}, - {0x0000b030, 0x028b028a}, - {0x0000b034, 0x0388028c}, - {0x0000b038, 0x038a0389}, - {0x0000b03c, 0x038c038b}, - {0x0000b040, 0x0390038d}, - {0x0000b044, 0x03920391}, - {0x0000b048, 0x03940393}, - {0x0000b04c, 0x03960395}, - {0x0000b050, 0x00000000}, - {0x0000b054, 0x00000000}, - {0x0000b058, 0x00000000}, - {0x0000b05c, 0x00000000}, - {0x0000b060, 0x00000000}, - {0x0000b064, 0x00000000}, - {0x0000b068, 0x00000000}, - {0x0000b06c, 0x00000000}, - {0x0000b070, 0x00000000}, - {0x0000b074, 0x00000000}, - {0x0000b078, 0x00000000}, - {0x0000b07c, 0x00000000}, - {0x0000b080, 0x23232323}, - {0x0000b084, 0x21232323}, - {0x0000b088, 0x19191c1e}, - {0x0000b08c, 0x12141417}, - {0x0000b090, 0x07070e0e}, - {0x0000b094, 0x03030305}, - {0x0000b098, 0x00000003}, - {0x0000b09c, 0x00000000}, - {0x0000b0a0, 0x00000000}, - {0x0000b0a4, 0x00000000}, - {0x0000b0a8, 0x00000000}, - {0x0000b0ac, 0x00000000}, - {0x0000b0b0, 0x00000000}, - {0x0000b0b4, 0x00000000}, - {0x0000b0b8, 0x00000000}, - {0x0000b0bc, 0x00000000}, - {0x0000b0c0, 0x003f0020}, - {0x0000b0c4, 0x00400041}, - {0x0000b0c8, 0x0140005f}, - {0x0000b0cc, 0x0160015f}, - {0x0000b0d0, 0x017e017f}, - {0x0000b0d4, 0x02410242}, - {0x0000b0d8, 0x025f0240}, - {0x0000b0dc, 0x027f0260}, - {0x0000b0e0, 0x0341027e}, - {0x0000b0e4, 0x035f0340}, - {0x0000b0e8, 0x037f0360}, - {0x0000b0ec, 0x04400441}, - {0x0000b0f0, 0x0460045f}, - {0x0000b0f4, 0x0541047f}, - {0x0000b0f8, 0x055f0540}, - {0x0000b0fc, 0x057f0560}, - {0x0000b100, 0x06400641}, - {0x0000b104, 0x0660065f}, - {0x0000b108, 0x067e067f}, - {0x0000b10c, 0x07410742}, - {0x0000b110, 0x075f0740}, - {0x0000b114, 0x077f0760}, - {0x0000b118, 0x07800781}, - {0x0000b11c, 0x07a0079f}, - {0x0000b120, 0x07c107bf}, - {0x0000b124, 0x000007c0}, - {0x0000b128, 0x00000000}, - {0x0000b12c, 0x00000000}, - {0x0000b130, 0x00000000}, - {0x0000b134, 0x00000000}, - {0x0000b138, 0x00000000}, - {0x0000b13c, 0x00000000}, - {0x0000b140, 0x003f0020}, - {0x0000b144, 0x00400041}, - {0x0000b148, 0x0140005f}, - {0x0000b14c, 0x0160015f}, - {0x0000b150, 0x017e017f}, - {0x0000b154, 0x02410242}, - {0x0000b158, 0x025f0240}, - {0x0000b15c, 0x027f0260}, - {0x0000b160, 0x0341027e}, - {0x0000b164, 0x035f0340}, - {0x0000b168, 0x037f0360}, - {0x0000b16c, 0x04400441}, - {0x0000b170, 0x0460045f}, - {0x0000b174, 0x0541047f}, - {0x0000b178, 0x055f0540}, - {0x0000b17c, 0x057f0560}, - {0x0000b180, 0x06400641}, - {0x0000b184, 0x0660065f}, - {0x0000b188, 0x067e067f}, - {0x0000b18c, 0x07410742}, - {0x0000b190, 0x075f0740}, - {0x0000b194, 0x077f0760}, - {0x0000b198, 0x07800781}, - {0x0000b19c, 0x07a0079f}, - {0x0000b1a0, 0x07c107bf}, - {0x0000b1a4, 0x000007c0}, - {0x0000b1a8, 0x00000000}, - {0x0000b1ac, 0x00000000}, - {0x0000b1b0, 0x00000000}, - {0x0000b1b4, 0x00000000}, - {0x0000b1b8, 0x00000000}, - {0x0000b1bc, 0x00000000}, - {0x0000b1c0, 0x00000000}, - {0x0000b1c4, 0x00000000}, - {0x0000b1c8, 0x00000000}, - {0x0000b1cc, 0x00000000}, - {0x0000b1d0, 0x00000000}, - {0x0000b1d4, 0x00000000}, - {0x0000b1d8, 0x00000000}, - {0x0000b1dc, 0x00000000}, - {0x0000b1e0, 0x00000000}, - {0x0000b1e4, 0x00000000}, - {0x0000b1e8, 0x00000000}, - {0x0000b1ec, 0x00000000}, - {0x0000b1f0, 0x00000396}, - {0x0000b1f4, 0x00000396}, - {0x0000b1f8, 0x00000396}, - {0x0000b1fc, 0x00000196}, -}; - static const u32 ar955x_1p0_baseband_core[][2] = { /* Addr allmodes */ {0x00009800, 0xafe68e30}, @@ -891,266 +632,6 @@ static const u32 ar955x_1p0_baseband_core[][2] = { {0x0000c420, 0x00000000}, }; -static const u32 ar955x_1p0_common_wo_xlna_rx_gain_table[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x00010000}, - {0x0000a004, 0x00030002}, - {0x0000a008, 0x00050004}, - {0x0000a00c, 0x00810080}, - {0x0000a010, 0x00830082}, - {0x0000a014, 0x01810180}, - {0x0000a018, 0x01830182}, - {0x0000a01c, 0x01850184}, - {0x0000a020, 0x01890188}, - {0x0000a024, 0x018b018a}, - {0x0000a028, 0x018d018c}, - {0x0000a02c, 0x03820190}, - {0x0000a030, 0x03840383}, - {0x0000a034, 0x03880385}, - {0x0000a038, 0x038a0389}, - {0x0000a03c, 0x038c038b}, - {0x0000a040, 0x0390038d}, - {0x0000a044, 0x03920391}, - {0x0000a048, 0x03940393}, - {0x0000a04c, 0x03960395}, - {0x0000a050, 0x00000000}, - {0x0000a054, 0x00000000}, - {0x0000a058, 0x00000000}, - {0x0000a05c, 0x00000000}, - {0x0000a060, 0x00000000}, - {0x0000a064, 0x00000000}, - {0x0000a068, 0x00000000}, - {0x0000a06c, 0x00000000}, - {0x0000a070, 0x00000000}, - {0x0000a074, 0x00000000}, - {0x0000a078, 0x00000000}, - {0x0000a07c, 0x00000000}, - {0x0000a080, 0x29292929}, - {0x0000a084, 0x29292929}, - {0x0000a088, 0x29292929}, - {0x0000a08c, 0x29292929}, - {0x0000a090, 0x22292929}, - {0x0000a094, 0x1d1d2222}, - {0x0000a098, 0x0c111117}, - {0x0000a09c, 0x00030303}, - {0x0000a0a0, 0x00000000}, - {0x0000a0a4, 0x00000000}, - {0x0000a0a8, 0x00000000}, - {0x0000a0ac, 0x00000000}, - {0x0000a0b0, 0x00000000}, - {0x0000a0b4, 0x00000000}, - {0x0000a0b8, 0x00000000}, - {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x001f0000}, - {0x0000a0c4, 0x01000101}, - {0x0000a0c8, 0x011e011f}, - {0x0000a0cc, 0x011c011d}, - {0x0000a0d0, 0x02030204}, - {0x0000a0d4, 0x02010202}, - {0x0000a0d8, 0x021f0200}, - {0x0000a0dc, 0x0302021e}, - {0x0000a0e0, 0x03000301}, - {0x0000a0e4, 0x031e031f}, - {0x0000a0e8, 0x0402031d}, - {0x0000a0ec, 0x04000401}, - {0x0000a0f0, 0x041e041f}, - {0x0000a0f4, 0x0502041d}, - {0x0000a0f8, 0x05000501}, - {0x0000a0fc, 0x051e051f}, - {0x0000a100, 0x06010602}, - {0x0000a104, 0x061f0600}, - {0x0000a108, 0x061d061e}, - {0x0000a10c, 0x07020703}, - {0x0000a110, 0x07000701}, - {0x0000a114, 0x00000000}, - {0x0000a118, 0x00000000}, - {0x0000a11c, 0x00000000}, - {0x0000a120, 0x00000000}, - {0x0000a124, 0x00000000}, - {0x0000a128, 0x00000000}, - {0x0000a12c, 0x00000000}, - {0x0000a130, 0x00000000}, - {0x0000a134, 0x00000000}, - {0x0000a138, 0x00000000}, - {0x0000a13c, 0x00000000}, - {0x0000a140, 0x001f0000}, - {0x0000a144, 0x01000101}, - {0x0000a148, 0x011e011f}, - {0x0000a14c, 0x011c011d}, - {0x0000a150, 0x02030204}, - {0x0000a154, 0x02010202}, - {0x0000a158, 0x021f0200}, - {0x0000a15c, 0x0302021e}, - {0x0000a160, 0x03000301}, - {0x0000a164, 0x031e031f}, - {0x0000a168, 0x0402031d}, - {0x0000a16c, 0x04000401}, - {0x0000a170, 0x041e041f}, - {0x0000a174, 0x0502041d}, - {0x0000a178, 0x05000501}, - {0x0000a17c, 0x051e051f}, - {0x0000a180, 0x06010602}, - {0x0000a184, 0x061f0600}, - {0x0000a188, 0x061d061e}, - {0x0000a18c, 0x07020703}, - {0x0000a190, 0x07000701}, - {0x0000a194, 0x00000000}, - {0x0000a198, 0x00000000}, - {0x0000a19c, 0x00000000}, - {0x0000a1a0, 0x00000000}, - {0x0000a1a4, 0x00000000}, - {0x0000a1a8, 0x00000000}, - {0x0000a1ac, 0x00000000}, - {0x0000a1b0, 0x00000000}, - {0x0000a1b4, 0x00000000}, - {0x0000a1b8, 0x00000000}, - {0x0000a1bc, 0x00000000}, - {0x0000a1c0, 0x00000000}, - {0x0000a1c4, 0x00000000}, - {0x0000a1c8, 0x00000000}, - {0x0000a1cc, 0x00000000}, - {0x0000a1d0, 0x00000000}, - {0x0000a1d4, 0x00000000}, - {0x0000a1d8, 0x00000000}, - {0x0000a1dc, 0x00000000}, - {0x0000a1e0, 0x00000000}, - {0x0000a1e4, 0x00000000}, - {0x0000a1e8, 0x00000000}, - {0x0000a1ec, 0x00000000}, - {0x0000a1f0, 0x00000396}, - {0x0000a1f4, 0x00000396}, - {0x0000a1f8, 0x00000396}, - {0x0000a1fc, 0x00000196}, - {0x0000b000, 0x00010000}, - {0x0000b004, 0x00030002}, - {0x0000b008, 0x00050004}, - {0x0000b00c, 0x00810080}, - {0x0000b010, 0x00830082}, - {0x0000b014, 0x01810180}, - {0x0000b018, 0x01830182}, - {0x0000b01c, 0x01850184}, - {0x0000b020, 0x02810280}, - {0x0000b024, 0x02830282}, - {0x0000b028, 0x02850284}, - {0x0000b02c, 0x02890288}, - {0x0000b030, 0x028b028a}, - {0x0000b034, 0x0388028c}, - {0x0000b038, 0x038a0389}, - {0x0000b03c, 0x038c038b}, - {0x0000b040, 0x0390038d}, - {0x0000b044, 0x03920391}, - {0x0000b048, 0x03940393}, - {0x0000b04c, 0x03960395}, - {0x0000b050, 0x00000000}, - {0x0000b054, 0x00000000}, - {0x0000b058, 0x00000000}, - {0x0000b05c, 0x00000000}, - {0x0000b060, 0x00000000}, - {0x0000b064, 0x00000000}, - {0x0000b068, 0x00000000}, - {0x0000b06c, 0x00000000}, - {0x0000b070, 0x00000000}, - {0x0000b074, 0x00000000}, - {0x0000b078, 0x00000000}, - {0x0000b07c, 0x00000000}, - {0x0000b080, 0x32323232}, - {0x0000b084, 0x2f2f3232}, - {0x0000b088, 0x23282a2d}, - {0x0000b08c, 0x1c1e2123}, - {0x0000b090, 0x14171919}, - {0x0000b094, 0x0e0e1214}, - {0x0000b098, 0x03050707}, - {0x0000b09c, 0x00030303}, - {0x0000b0a0, 0x00000000}, - {0x0000b0a4, 0x00000000}, - {0x0000b0a8, 0x00000000}, - {0x0000b0ac, 0x00000000}, - {0x0000b0b0, 0x00000000}, - {0x0000b0b4, 0x00000000}, - {0x0000b0b8, 0x00000000}, - {0x0000b0bc, 0x00000000}, - {0x0000b0c0, 0x003f0020}, - {0x0000b0c4, 0x00400041}, - {0x0000b0c8, 0x0140005f}, - {0x0000b0cc, 0x0160015f}, - {0x0000b0d0, 0x017e017f}, - {0x0000b0d4, 0x02410242}, - {0x0000b0d8, 0x025f0240}, - {0x0000b0dc, 0x027f0260}, - {0x0000b0e0, 0x0341027e}, - {0x0000b0e4, 0x035f0340}, - {0x0000b0e8, 0x037f0360}, - {0x0000b0ec, 0x04400441}, - {0x0000b0f0, 0x0460045f}, - {0x0000b0f4, 0x0541047f}, - {0x0000b0f8, 0x055f0540}, - {0x0000b0fc, 0x057f0560}, - {0x0000b100, 0x06400641}, - {0x0000b104, 0x0660065f}, - {0x0000b108, 0x067e067f}, - {0x0000b10c, 0x07410742}, - {0x0000b110, 0x075f0740}, - {0x0000b114, 0x077f0760}, - {0x0000b118, 0x07800781}, - {0x0000b11c, 0x07a0079f}, - {0x0000b120, 0x07c107bf}, - {0x0000b124, 0x000007c0}, - {0x0000b128, 0x00000000}, - {0x0000b12c, 0x00000000}, - {0x0000b130, 0x00000000}, - {0x0000b134, 0x00000000}, - {0x0000b138, 0x00000000}, - {0x0000b13c, 0x00000000}, - {0x0000b140, 0x003f0020}, - {0x0000b144, 0x00400041}, - {0x0000b148, 0x0140005f}, - {0x0000b14c, 0x0160015f}, - {0x0000b150, 0x017e017f}, - {0x0000b154, 0x02410242}, - {0x0000b158, 0x025f0240}, - {0x0000b15c, 0x027f0260}, - {0x0000b160, 0x0341027e}, - {0x0000b164, 0x035f0340}, - {0x0000b168, 0x037f0360}, - {0x0000b16c, 0x04400441}, - {0x0000b170, 0x0460045f}, - {0x0000b174, 0x0541047f}, - {0x0000b178, 0x055f0540}, - {0x0000b17c, 0x057f0560}, - {0x0000b180, 0x06400641}, - {0x0000b184, 0x0660065f}, - {0x0000b188, 0x067e067f}, - {0x0000b18c, 0x07410742}, - {0x0000b190, 0x075f0740}, - {0x0000b194, 0x077f0760}, - {0x0000b198, 0x07800781}, - {0x0000b19c, 0x07a0079f}, - {0x0000b1a0, 0x07c107bf}, - {0x0000b1a4, 0x000007c0}, - {0x0000b1a8, 0x00000000}, - {0x0000b1ac, 0x00000000}, - {0x0000b1b0, 0x00000000}, - {0x0000b1b4, 0x00000000}, - {0x0000b1b8, 0x00000000}, - {0x0000b1bc, 0x00000000}, - {0x0000b1c0, 0x00000000}, - {0x0000b1c4, 0x00000000}, - {0x0000b1c8, 0x00000000}, - {0x0000b1cc, 0x00000000}, - {0x0000b1d0, 0x00000000}, - {0x0000b1d4, 0x00000000}, - {0x0000b1d8, 0x00000000}, - {0x0000b1dc, 0x00000000}, - {0x0000b1e0, 0x00000000}, - {0x0000b1e4, 0x00000000}, - {0x0000b1e8, 0x00000000}, - {0x0000b1ec, 0x00000000}, - {0x0000b1f0, 0x00000396}, - {0x0000b1f4, 0x00000396}, - {0x0000b1f8, 0x00000396}, - {0x0000b1fc, 0x00000196}, -}; - static const u32 ar955x_1p0_soc_preamble[][2] = { /* Addr allmodes */ {0x00007000, 0x00000000}, @@ -1263,11 +744,6 @@ static const u32 ar955x_1p0_modes_no_xpa_tx_gain_table[][9] = { {0x00016848, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401}, }; -static const u32 ar955x_1p0_soc_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00007010, 0x00000023, 0x00000023, 0x00000023, 0x00000023}, -}; - static const u32 ar955x_1p0_modes_fast_clock[][3] = { /* Addr 5G_HT20 5G_HT40 */ {0x00001030, 0x00000268, 0x000004d0}, -- cgit v1.2.3-70-g09d2 From 367ba05f3ef31abca9a06939a4fd633c8147ce7f Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 6 Dec 2013 16:28:43 +0530 Subject: ath9k: Update AR9331 v1.1 initvals * Update radio/baseband/gain tables. * Mark ar9331_modes_high_power_tx_gain_1p1 as a duplicate * ar9331_1p1_mac_postamble is not a duplicate. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- .../net/wireless/ath/ath9k/ar9330_1p1_initvals.h | 128 ++++----------------- 1 file changed, 24 insertions(+), 104 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9330_1p1_initvals.h b/drivers/net/wireless/ath/ath9k/ar9330_1p1_initvals.h index 6e1756bc383..f76139bbb74 100644 --- a/drivers/net/wireless/ath/ath9k/ar9330_1p1_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9330_1p1_initvals.h @@ -18,6 +18,10 @@ #ifndef INITVALS_9330_1P1_H #define INITVALS_9330_1P1_H +#define ar9331_1p1_baseband_core_txfir_coeff_japan_2484 ar9300_2p2_baseband_core_txfir_coeff_japan_2484 + +#define ar9331_modes_high_power_tx_gain_1p1 ar9331_modes_lowest_ob_db_tx_gain_1p1 + static const u32 ar9331_1p1_baseband_postamble[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a8005}, @@ -55,7 +59,7 @@ static const u32 ar9331_1p1_baseband_postamble[][5] = { {0x0000a284, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, + {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00058d18, 0x00058d18}, {0x0000a2d0, 0x00071982, 0x00071982, 0x00071982, 0x00071982}, {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a}, {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, @@ -252,7 +256,7 @@ static const u32 ar9331_modes_low_ob_db_tx_gain_1p1[][5] = { {0x0000a2e0, 0xffffcc84, 0xffffcc84, 0xffffcc84, 0xffffcc84}, {0x0000a2e4, 0xfffff000, 0xfffff000, 0xfffff000, 0xfffff000}, {0x0000a2e8, 0xfffe0000, 0xfffe0000, 0xfffe0000, 0xfffe0000}, - {0x0000a410, 0x000050d7, 0x000050d7, 0x000050d0, 0x000050d0}, + {0x0000a410, 0x000050d7, 0x000050d7, 0x000050d4, 0x000050d4}, {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, @@ -337,8 +341,6 @@ static const u32 ar9331_modes_low_ob_db_tx_gain_1p1[][5] = { {0x00016284, 0x14d3f000, 0x14d3f000, 0x14d3f000, 0x14d3f000}, }; -#define ar9331_1p1_baseband_core_txfir_coeff_japan_2484 ar9462_2p0_baseband_core_txfir_coeff_japan_2484 - static const u32 ar9331_1p1_xtal_25M[][2] = { /* Addr allmodes */ {0x00007038, 0x000002f8}, @@ -373,17 +375,17 @@ static const u32 ar9331_1p1_radio_core[][2] = { {0x000160b4, 0x92480040}, {0x000160c0, 0x006db6db}, {0x000160c4, 0x0186db60}, - {0x000160c8, 0x6db4db6c}, + {0x000160c8, 0x6db6db6c}, {0x000160cc, 0x6de6c300}, {0x000160d0, 0x14500820}, {0x00016100, 0x04cb0001}, {0x00016104, 0xfff80015}, {0x00016108, 0x00080010}, {0x0001610c, 0x00170000}, - {0x00016140, 0x10800000}, + {0x00016140, 0x50804000}, {0x00016144, 0x01884080}, {0x00016148, 0x000080c0}, - {0x00016280, 0x01000015}, + {0x00016280, 0x01001015}, {0x00016284, 0x14d20000}, {0x00016288, 0x00318000}, {0x0001628c, 0x50000000}, @@ -622,12 +624,12 @@ static const u32 ar9331_1p1_baseband_core[][2] = { {0x0000a370, 0x00000000}, {0x0000a390, 0x00000001}, {0x0000a394, 0x00000444}, - {0x0000a398, 0x001f0e0f}, - {0x0000a39c, 0x0075393f}, - {0x0000a3a0, 0xb79f6427}, - {0x0000a3a4, 0x00000000}, - {0x0000a3a8, 0xaaaaaaaa}, - {0x0000a3ac, 0x3c466478}, + {0x0000a398, 0x00000000}, + {0x0000a39c, 0x210d0401}, + {0x0000a3a0, 0xab9a7144}, + {0x0000a3a4, 0x00000011}, + {0x0000a3a8, 0x3c3c003d}, + {0x0000a3ac, 0x30310030}, {0x0000a3c0, 0x20202020}, {0x0000a3c4, 0x22222220}, {0x0000a3c8, 0x20200020}, @@ -686,100 +688,18 @@ static const u32 ar9331_1p1_baseband_core[][2] = { {0x0000a7dc, 0x00000001}, }; -static const u32 ar9331_modes_high_power_tx_gain_1p1[][5] = { +static const u32 ar9331_1p1_mac_postamble[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a2d8, 0x7999a83a, 0x7999a83a, 0x7999a83a, 0x7999a83a}, - {0x0000a2dc, 0xffff2a52, 0xffff2a52, 0xffff2a52, 0xffff2a52}, - {0x0000a2e0, 0xffffcc84, 0xffffcc84, 0xffffcc84, 0xffffcc84}, - {0x0000a2e4, 0xfffff000, 0xfffff000, 0xfffff000, 0xfffff000}, - {0x0000a2e8, 0xfffe0000, 0xfffe0000, 0xfffe0000, 0xfffe0000}, - {0x0000a410, 0x000050d7, 0x000050d7, 0x000050d0, 0x000050d0}, - {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, - {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, - {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, - {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200}, - {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202}, - {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400}, - {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402}, - {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404}, - {0x0000a520, 0x2f001f04, 0x2f001f04, 0x23000a00, 0x23000a00}, - {0x0000a524, 0x35001fc4, 0x35001fc4, 0x27000a02, 0x27000a02}, - {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2b000a04, 0x2b000a04}, - {0x0000a52c, 0x41023e85, 0x41023e85, 0x2d000a20, 0x2d000a20}, - {0x0000a530, 0x48023ec6, 0x48023ec6, 0x31000a22, 0x31000a22}, - {0x0000a534, 0x4d023f01, 0x4d023f01, 0x35000a24, 0x35000a24}, - {0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000a43, 0x38000a43}, - {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3b000e42, 0x3b000e42}, - {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x3f000e44, 0x3f000e44}, - {0x0000a544, 0x6502feca, 0x6502feca, 0x42000e64, 0x42000e64}, - {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46000e66, 0x46000e66}, - {0x0000a54c, 0x7203feca, 0x7203feca, 0x4a000ea6, 0x4a000ea6}, - {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4a000ea6, 0x4a000ea6}, - {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4a000ea6, 0x4a000ea6}, - {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x4a000ea6, 0x4a000ea6}, - {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x4a000ea6, 0x4a000ea6}, - {0x0000a560, 0x900fff0b, 0x900fff0b, 0x4a000ea6, 0x4a000ea6}, - {0x0000a564, 0x960fffcb, 0x960fffcb, 0x4a000ea6, 0x4a000ea6}, - {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x4a000ea6, 0x4a000ea6}, - {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x4a000ea6, 0x4a000ea6}, - {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x4a000ea6, 0x4a000ea6}, - {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x4a000ea6, 0x4a000ea6}, - {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x4a000ea6, 0x4a000ea6}, - {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x4a000ea6, 0x4a000ea6}, - {0x0000a580, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, - {0x0000a584, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, - {0x0000a588, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, - {0x0000a58c, 0x11062202, 0x11062202, 0x0b000200, 0x0b000200}, - {0x0000a590, 0x17022e00, 0x17022e00, 0x0f000202, 0x0f000202}, - {0x0000a594, 0x1d000ec2, 0x1d000ec2, 0x11000400, 0x11000400}, - {0x0000a598, 0x25020ec0, 0x25020ec0, 0x15000402, 0x15000402}, - {0x0000a59c, 0x2b020ec3, 0x2b020ec3, 0x19000404, 0x19000404}, - {0x0000a5a0, 0x2f001f04, 0x2f001f04, 0x1b000603, 0x1b000603}, - {0x0000a5a4, 0x35001fc4, 0x35001fc4, 0x1f000a02, 0x1f000a02}, - {0x0000a5a8, 0x3c022f04, 0x3c022f04, 0x23000a04, 0x23000a04}, - {0x0000a5ac, 0x41023e85, 0x41023e85, 0x26000a20, 0x26000a20}, - {0x0000a5b0, 0x48023ec6, 0x48023ec6, 0x2a000e20, 0x2a000e20}, - {0x0000a5b4, 0x4d023f01, 0x4d023f01, 0x2e000e22, 0x2e000e22}, - {0x0000a5b8, 0x53023f4b, 0x53023f4b, 0x31000e24, 0x31000e24}, - {0x0000a5bc, 0x5a027f09, 0x5a027f09, 0x34001640, 0x34001640}, - {0x0000a5c0, 0x5f027fc9, 0x5f027fc9, 0x38001660, 0x38001660}, - {0x0000a5c4, 0x6502feca, 0x6502feca, 0x3b001861, 0x3b001861}, - {0x0000a5c8, 0x6b02ff4a, 0x6b02ff4a, 0x3e001a81, 0x3e001a81}, - {0x0000a5cc, 0x7203feca, 0x7203feca, 0x42001a83, 0x42001a83}, - {0x0000a5d0, 0x7703ff0b, 0x7703ff0b, 0x44001c84, 0x44001c84}, - {0x0000a5d4, 0x7d06ffcb, 0x7d06ffcb, 0x48001ce3, 0x48001ce3}, - {0x0000a5d8, 0x8407ff0b, 0x8407ff0b, 0x4c001ce5, 0x4c001ce5}, - {0x0000a5dc, 0x8907ffcb, 0x8907ffcb, 0x50001ce9, 0x50001ce9}, - {0x0000a5e0, 0x900fff0b, 0x900fff0b, 0x54001ceb, 0x54001ceb}, - {0x0000a5e4, 0x960fffcb, 0x960fffcb, 0x56001eec, 0x56001eec}, - {0x0000a5e8, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, - {0x0000a5ec, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, - {0x0000a5f0, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, - {0x0000a5f4, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, - {0x0000a5f8, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, - {0x0000a5fc, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, - {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000}, - {0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501}, - {0x0000a61c, 0x02008802, 0x02008802, 0x02008802, 0x02008802}, - {0x0000a620, 0x0280c802, 0x0280c802, 0x0280c802, 0x0280c802}, - {0x0000a624, 0x03010a03, 0x03010a03, 0x03010a03, 0x03010a03}, - {0x0000a628, 0x03010c04, 0x03010c04, 0x03010c04, 0x03010c04}, - {0x0000a62c, 0x03010c04, 0x03010c04, 0x03010c04, 0x03010c04}, - {0x0000a630, 0x03010c04, 0x03010c04, 0x03010c04, 0x03010c04}, - {0x0000a634, 0x03010c04, 0x03010c04, 0x03010c04, 0x03010c04}, - {0x0000a638, 0x03010c04, 0x03010c04, 0x03010c04, 0x03010c04}, - {0x0000a63c, 0x03010c04, 0x03010c04, 0x03010c04, 0x03010c04}, - {0x00016044, 0x034922db, 0x034922db, 0x034922db, 0x034922db}, - {0x00016284, 0x14d3f000, 0x14d3f000, 0x14d3f000, 0x14d3f000}, + {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, + {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c}, + {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, + {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, + {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, + {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, + {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, + {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, }; -#define ar9331_1p1_mac_postamble ar9300_2p2_mac_postamble - static const u32 ar9331_1p1_soc_preamble[][2] = { /* Addr allmodes */ {0x00007020, 0x00000000}, -- cgit v1.2.3-70-g09d2 From 492f478d89b28c97166e4540aa13ac0e7abaa29f Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 6 Dec 2013 16:28:44 +0530 Subject: ath9k: Update AR9331 v1.2 initvals Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- .../net/wireless/ath/ath9k/ar9330_1p2_initvals.h | 401 +++++++++++++++++---- 1 file changed, 333 insertions(+), 68 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9330_1p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9330_1p2_initvals.h index 57ed8a11217..0ac8be96097 100644 --- a/drivers/net/wireless/ath/ath9k/ar9330_1p2_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9330_1p2_initvals.h @@ -18,6 +18,28 @@ #ifndef INITVALS_9330_1P2_H #define INITVALS_9330_1P2_H +#define ar9331_modes_high_power_tx_gain_1p2 ar9331_modes_high_ob_db_tx_gain_1p2 + +#define ar9331_modes_low_ob_db_tx_gain_1p2 ar9331_modes_high_ob_db_tx_gain_1p2 + +#define ar9331_modes_lowest_ob_db_tx_gain_1p2 ar9331_modes_high_ob_db_tx_gain_1p2 + +#define ar9331_1p2_baseband_core_txfir_coeff_japan_2484 ar9331_1p1_baseband_core_txfir_coeff_japan_2484 + +#define ar9331_1p2_xtal_25M ar9331_1p1_xtal_25M + +#define ar9331_1p2_xtal_40M ar9331_1p1_xtal_40M + +#define ar9331_1p2_soc_postamble ar9331_1p1_soc_postamble + +#define ar9331_1p2_mac_postamble ar9331_1p1_mac_postamble + +#define ar9331_1p2_soc_preamble ar9331_1p1_soc_preamble + +#define ar9331_1p2_mac_core ar9331_1p1_mac_core + +#define ar9331_common_wo_xlna_rx_gain_1p2 ar9331_common_wo_xlna_rx_gain_1p1 + static const u32 ar9331_modes_high_ob_db_tx_gain_1p2[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x0000a410, 0x000050d7, 0x000050d7, 0x000050d7, 0x000050d7}, @@ -103,57 +125,6 @@ static const u32 ar9331_modes_high_ob_db_tx_gain_1p2[][5] = { {0x0000a63c, 0x04011004, 0x04011004, 0x04011004, 0x04011004}, }; -#define ar9331_modes_high_power_tx_gain_1p2 ar9331_modes_high_ob_db_tx_gain_1p2 - -#define ar9331_modes_low_ob_db_tx_gain_1p2 ar9331_modes_high_power_tx_gain_1p2 - -#define ar9331_modes_lowest_ob_db_tx_gain_1p2 ar9331_modes_low_ob_db_tx_gain_1p2 - -static const u32 ar9331_1p2_baseband_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a8005}, - {0x00009820, 0x206a002e, 0x206a002e, 0x206a002e, 0x206a002e}, - {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, - {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, - {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, - {0x00009830, 0x0000059c, 0x0000059c, 0x0000059c, 0x0000059c}, - {0x00009c00, 0x00000044, 0x00000044, 0x00000044, 0x00000044}, - {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a4, 0x037216a4}, - {0x00009e04, 0x00182020, 0x00182020, 0x00182020, 0x00182020}, - {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, - {0x00009e10, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e}, - {0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e}, - {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, - {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, - {0x00009e2c, 0x0000001c, 0x0000001c, 0x00003221, 0x00003221}, - {0x00009e3c, 0xcf946222, 0xcf946222, 0xcf946222, 0xcf946222}, - {0x00009e44, 0x02321e27, 0x02321e27, 0x02282324, 0x02282324}, - {0x00009e48, 0x5030201a, 0x5030201a, 0x50302010, 0x50302010}, - {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, - {0x0000a204, 0x00003fc0, 0x00003fc4, 0x00003fc4, 0x00003fc0}, - {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, - {0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b}, - {0x0000a234, 0x00000fff, 0x00000fff, 0x10000fff, 0x00000fff}, - {0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018}, - {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, - {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, - {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002}, - {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e}, - {0x0000a260, 0x3a021501, 0x3a021501, 0x3a021501, 0x3a021501}, - {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, - {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, - {0x0000a284, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, - {0x0000a2d0, 0x00071981, 0x00071981, 0x00071981, 0x00071981}, - {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a}, - {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000ae04, 0x00802020, 0x00802020, 0x00802020, 0x00802020}, - {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -}; - static const u32 ar9331_1p2_radio_core[][2] = { /* Addr allmodes */ {0x00016000, 0x36db6db6}, @@ -219,24 +190,318 @@ static const u32 ar9331_1p2_radio_core[][2] = { {0x000163d4, 0x00000000}, }; -#define ar9331_1p2_baseband_core_txfir_coeff_japan_2484 ar9331_1p1_baseband_core_txfir_coeff_japan_2484 - -#define ar9331_1p2_xtal_25M ar9331_1p1_xtal_25M - -#define ar9331_1p2_xtal_40M ar9331_1p1_xtal_40M - -#define ar9331_1p2_baseband_core ar9331_1p1_baseband_core - -#define ar9331_1p2_soc_postamble ar9331_1p1_soc_postamble - -#define ar9331_1p2_mac_postamble ar9331_1p1_mac_postamble - -#define ar9331_1p2_soc_preamble ar9331_1p1_soc_preamble - -#define ar9331_1p2_mac_core ar9331_1p1_mac_core +static const u32 ar9331_1p2_baseband_core[][2] = { + /* Addr allmodes */ + {0x00009800, 0xafe68e30}, + {0x00009804, 0xfd14e000}, + {0x00009808, 0x9c0a8f6b}, + {0x0000980c, 0x04800000}, + {0x00009814, 0x9280c00a}, + {0x00009818, 0x00000000}, + {0x0000981c, 0x00020028}, + {0x00009834, 0x5f3ca3de}, + {0x00009838, 0x0108ecff}, + {0x0000983c, 0x14750600}, + {0x00009880, 0x201fff00}, + {0x00009884, 0x00001042}, + {0x000098a4, 0x00200400}, + {0x000098b0, 0x32840bbe}, + {0x000098d0, 0x004b6a8e}, + {0x000098d4, 0x00000820}, + {0x000098dc, 0x00000000}, + {0x000098f0, 0x00000000}, + {0x000098f4, 0x00000000}, + {0x00009c04, 0x00000000}, + {0x00009c08, 0x03200000}, + {0x00009c0c, 0x00000000}, + {0x00009c10, 0x00000000}, + {0x00009c14, 0x00046384}, + {0x00009c18, 0x05b6b440}, + {0x00009c1c, 0x00b6b440}, + {0x00009d00, 0xc080a333}, + {0x00009d04, 0x40206c10}, + {0x00009d08, 0x009c4060}, + {0x00009d0c, 0x1883800a}, + {0x00009d10, 0x01834061}, + {0x00009d14, 0x00c00400}, + {0x00009d18, 0x00000000}, + {0x00009e08, 0x0038233c}, + {0x00009e24, 0x9927b515}, + {0x00009e28, 0x12ef0200}, + {0x00009e30, 0x06336f77}, + {0x00009e34, 0x6af6532f}, + {0x00009e38, 0x0cc80c00}, + {0x00009e40, 0x0d261820}, + {0x00009e4c, 0x00001004}, + {0x00009e50, 0x00ff03f1}, + {0x00009fc0, 0x803e4788}, + {0x00009fc4, 0x0001efb5}, + {0x00009fcc, 0x40000014}, + {0x0000a20c, 0x00000000}, + {0x0000a220, 0x00000000}, + {0x0000a224, 0x00000000}, + {0x0000a228, 0x10002310}, + {0x0000a23c, 0x00000000}, + {0x0000a244, 0x0c000000}, + {0x0000a2a0, 0x00000001}, + {0x0000a2c0, 0x00000001}, + {0x0000a2c8, 0x00000000}, + {0x0000a2cc, 0x18c43433}, + {0x0000a2d4, 0x00000000}, + {0x0000a2dc, 0x00000000}, + {0x0000a2e0, 0x00000000}, + {0x0000a2e4, 0x00000000}, + {0x0000a2e8, 0x00000000}, + {0x0000a2ec, 0x00000000}, + {0x0000a2f0, 0x00000000}, + {0x0000a2f4, 0x00000000}, + {0x0000a2f8, 0x00000000}, + {0x0000a344, 0x00000000}, + {0x0000a34c, 0x00000000}, + {0x0000a350, 0x0000a000}, + {0x0000a364, 0x00000000}, + {0x0000a370, 0x00000000}, + {0x0000a390, 0x00000001}, + {0x0000a394, 0x00000444}, + {0x0000a398, 0x001f0e0f}, + {0x0000a39c, 0x0075393f}, + {0x0000a3a0, 0xb79f6427}, + {0x0000a3a4, 0x00000000}, + {0x0000a3a8, 0xaaaaaaaa}, + {0x0000a3ac, 0x3c466478}, + {0x0000a3c0, 0x20202020}, + {0x0000a3c4, 0x22222220}, + {0x0000a3c8, 0x20200020}, + {0x0000a3cc, 0x20202020}, + {0x0000a3d0, 0x20202020}, + {0x0000a3d4, 0x20202020}, + {0x0000a3d8, 0x20202020}, + {0x0000a3dc, 0x20202020}, + {0x0000a3e0, 0x20202020}, + {0x0000a3e4, 0x20202020}, + {0x0000a3e8, 0x20202020}, + {0x0000a3ec, 0x20202020}, + {0x0000a3f0, 0x00000000}, + {0x0000a3f4, 0x00000006}, + {0x0000a3f8, 0x0cdbd380}, + {0x0000a3fc, 0x000f0f01}, + {0x0000a400, 0x8fa91f01}, + {0x0000a404, 0x00000000}, + {0x0000a408, 0x0e79e5c6}, + {0x0000a40c, 0x00820820}, + {0x0000a414, 0x1ce739ce}, + {0x0000a418, 0x2d001dce}, + {0x0000a41c, 0x1ce739ce}, + {0x0000a420, 0x000001ce}, + {0x0000a424, 0x1ce739ce}, + {0x0000a428, 0x000001ce}, + {0x0000a42c, 0x1ce739ce}, + {0x0000a430, 0x1ce739ce}, + {0x0000a434, 0x00000000}, + {0x0000a438, 0x00001801}, + {0x0000a43c, 0x00000000}, + {0x0000a440, 0x00000000}, + {0x0000a444, 0x00000000}, + {0x0000a448, 0x04000000}, + {0x0000a44c, 0x00000001}, + {0x0000a450, 0x00010000}, + {0x0000a458, 0x00000000}, + {0x0000a640, 0x00000000}, + {0x0000a644, 0x3fad9d74}, + {0x0000a648, 0x0048060a}, + {0x0000a64c, 0x00003c37}, + {0x0000a670, 0x03020100}, + {0x0000a674, 0x09080504}, + {0x0000a678, 0x0d0c0b0a}, + {0x0000a67c, 0x13121110}, + {0x0000a680, 0x31301514}, + {0x0000a684, 0x35343332}, + {0x0000a688, 0x00000036}, + {0x0000a690, 0x00000838}, + {0x0000a7c0, 0x00000000}, + {0x0000a7c4, 0xfffffffc}, + {0x0000a7c8, 0x00000000}, + {0x0000a7cc, 0x00000000}, + {0x0000a7d0, 0x00000000}, + {0x0000a7d4, 0x00000004}, + {0x0000a7dc, 0x00000001}, +}; -#define ar9331_common_wo_xlna_rx_gain_1p2 ar9331_common_wo_xlna_rx_gain_1p1 +static const u32 ar9331_1p2_baseband_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a8005}, + {0x00009820, 0x206a002e, 0x206a002e, 0x206a002e, 0x206a002e}, + {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, + {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, + {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, + {0x00009830, 0x0000059c, 0x0000059c, 0x0000059c, 0x0000059c}, + {0x00009c00, 0x00000044, 0x00000044, 0x00000044, 0x00000044}, + {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a4, 0x037216a4}, + {0x00009e04, 0x00182020, 0x00182020, 0x00182020, 0x00182020}, + {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, + {0x00009e10, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e}, + {0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e}, + {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, + {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, + {0x00009e2c, 0x0000001c, 0x0000001c, 0x00003221, 0x00003221}, + {0x00009e3c, 0xcf946222, 0xcf946222, 0xcf946222, 0xcf946222}, + {0x00009e44, 0x02321e27, 0x02321e27, 0x02282324, 0x02282324}, + {0x00009e48, 0x5030201a, 0x5030201a, 0x50302010, 0x50302010}, + {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, + {0x0000a204, 0x00003fc0, 0x00003fc4, 0x00003fc4, 0x00003fc0}, + {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, + {0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b}, + {0x0000a234, 0x00000fff, 0x00000fff, 0x10000fff, 0x00000fff}, + {0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018}, + {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, + {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, + {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002}, + {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e}, + {0x0000a260, 0x3a021501, 0x3a021501, 0x3a021501, 0x3a021501}, + {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, + {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, + {0x0000a284, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, + {0x0000a2d0, 0x00071981, 0x00071981, 0x00071981, 0x00071981}, + {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a}, + {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000ae04, 0x00802020, 0x00802020, 0x00802020, 0x00802020}, + {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +}; -#define ar9331_common_rx_gain_1p2 ar9485_common_rx_gain_1_1 +static const u32 ar9331_common_rx_gain_1p2[][2] = { + /* Addr allmodes */ + {0x0000a000, 0x00010000}, + {0x0000a004, 0x00030002}, + {0x0000a008, 0x00050004}, + {0x0000a00c, 0x00810080}, + {0x0000a010, 0x01800082}, + {0x0000a014, 0x01820181}, + {0x0000a018, 0x01840183}, + {0x0000a01c, 0x01880185}, + {0x0000a020, 0x018a0189}, + {0x0000a024, 0x02850284}, + {0x0000a028, 0x02890288}, + {0x0000a02c, 0x03850384}, + {0x0000a030, 0x03890388}, + {0x0000a034, 0x038b038a}, + {0x0000a038, 0x038d038c}, + {0x0000a03c, 0x03910390}, + {0x0000a040, 0x03930392}, + {0x0000a044, 0x03950394}, + {0x0000a048, 0x00000396}, + {0x0000a04c, 0x00000000}, + {0x0000a050, 0x00000000}, + {0x0000a054, 0x00000000}, + {0x0000a058, 0x00000000}, + {0x0000a05c, 0x00000000}, + {0x0000a060, 0x00000000}, + {0x0000a064, 0x00000000}, + {0x0000a068, 0x00000000}, + {0x0000a06c, 0x00000000}, + {0x0000a070, 0x00000000}, + {0x0000a074, 0x00000000}, + {0x0000a078, 0x00000000}, + {0x0000a07c, 0x00000000}, + {0x0000a080, 0x28282828}, + {0x0000a084, 0x28282828}, + {0x0000a088, 0x28282828}, + {0x0000a08c, 0x28282828}, + {0x0000a090, 0x28282828}, + {0x0000a094, 0x21212128}, + {0x0000a098, 0x171c1c1c}, + {0x0000a09c, 0x02020212}, + {0x0000a0a0, 0x00000202}, + {0x0000a0a4, 0x00000000}, + {0x0000a0a8, 0x00000000}, + {0x0000a0ac, 0x00000000}, + {0x0000a0b0, 0x00000000}, + {0x0000a0b4, 0x00000000}, + {0x0000a0b8, 0x00000000}, + {0x0000a0bc, 0x00000000}, + {0x0000a0c0, 0x001f0000}, + {0x0000a0c4, 0x111f1100}, + {0x0000a0c8, 0x111d111e}, + {0x0000a0cc, 0x111b111c}, + {0x0000a0d0, 0x22032204}, + {0x0000a0d4, 0x22012202}, + {0x0000a0d8, 0x221f2200}, + {0x0000a0dc, 0x221d221e}, + {0x0000a0e0, 0x33013302}, + {0x0000a0e4, 0x331f3300}, + {0x0000a0e8, 0x4402331e}, + {0x0000a0ec, 0x44004401}, + {0x0000a0f0, 0x441e441f}, + {0x0000a0f4, 0x55015502}, + {0x0000a0f8, 0x551f5500}, + {0x0000a0fc, 0x6602551e}, + {0x0000a100, 0x66006601}, + {0x0000a104, 0x661e661f}, + {0x0000a108, 0x7703661d}, + {0x0000a10c, 0x77017702}, + {0x0000a110, 0x00007700}, + {0x0000a114, 0x00000000}, + {0x0000a118, 0x00000000}, + {0x0000a11c, 0x00000000}, + {0x0000a120, 0x00000000}, + {0x0000a124, 0x00000000}, + {0x0000a128, 0x00000000}, + {0x0000a12c, 0x00000000}, + {0x0000a130, 0x00000000}, + {0x0000a134, 0x00000000}, + {0x0000a138, 0x00000000}, + {0x0000a13c, 0x00000000}, + {0x0000a140, 0x001f0000}, + {0x0000a144, 0x111f1100}, + {0x0000a148, 0x111d111e}, + {0x0000a14c, 0x111b111c}, + {0x0000a150, 0x22032204}, + {0x0000a154, 0x22012202}, + {0x0000a158, 0x221f2200}, + {0x0000a15c, 0x221d221e}, + {0x0000a160, 0x33013302}, + {0x0000a164, 0x331f3300}, + {0x0000a168, 0x4402331e}, + {0x0000a16c, 0x44004401}, + {0x0000a170, 0x441e441f}, + {0x0000a174, 0x55015502}, + {0x0000a178, 0x551f5500}, + {0x0000a17c, 0x6602551e}, + {0x0000a180, 0x66006601}, + {0x0000a184, 0x661e661f}, + {0x0000a188, 0x7703661d}, + {0x0000a18c, 0x77017702}, + {0x0000a190, 0x00007700}, + {0x0000a194, 0x00000000}, + {0x0000a198, 0x00000000}, + {0x0000a19c, 0x00000000}, + {0x0000a1a0, 0x00000000}, + {0x0000a1a4, 0x00000000}, + {0x0000a1a8, 0x00000000}, + {0x0000a1ac, 0x00000000}, + {0x0000a1b0, 0x00000000}, + {0x0000a1b4, 0x00000000}, + {0x0000a1b8, 0x00000000}, + {0x0000a1bc, 0x00000000}, + {0x0000a1c0, 0x00000000}, + {0x0000a1c4, 0x00000000}, + {0x0000a1c8, 0x00000000}, + {0x0000a1cc, 0x00000000}, + {0x0000a1d0, 0x00000000}, + {0x0000a1d4, 0x00000000}, + {0x0000a1d8, 0x00000000}, + {0x0000a1dc, 0x00000000}, + {0x0000a1e0, 0x00000000}, + {0x0000a1e4, 0x00000000}, + {0x0000a1e8, 0x00000000}, + {0x0000a1ec, 0x00000000}, + {0x0000a1f0, 0x00000396}, + {0x0000a1f4, 0x00000396}, + {0x0000a1f8, 0x00000396}, + {0x0000a1fc, 0x00000296}, +}; #endif /* INITVALS_9330_1P2_H */ -- cgit v1.2.3-70-g09d2 From 0f978bfaf2600040f9826f394eb12e023bef3068 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 6 Dec 2013 16:28:45 +0530 Subject: ath9k: Use a separate TX gain table for WZR-HP-G450H The Buffalo device WZR-HP-G450H uses the index 3 for TX gain, which is set to the high_power table currently. Later variants of the router use the same index, but instead refer to the low_ob_db gain table. This is not handled in the driver since there is no way to distinguish board revisions and the high_power table is used (incorrectly) for the newer variants. By default, devices based on AR9300 using the TX gain index 3 have to use the high_power table. To make sure that WZR-HP-G450H is not broken when the high_power table is updated, use a separate array based on information obtained from the platform data. The current situation where only the original variant of WZR-HP-G450H works properly stays unchanged. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- .../wireless/ath/ath9k/ar9003_buffalo_initvals.h | 126 +++++++++++++++++++++ drivers/net/wireless/ath/ath9k/ar9003_hw.c | 12 +- drivers/net/wireless/ath/ath9k/hw.h | 1 + drivers/net/wireless/ath/ath9k/init.c | 36 ++++-- include/linux/ath9k_platform.h | 2 + 5 files changed, 165 insertions(+), 12 deletions(-) create mode 100644 drivers/net/wireless/ath/ath9k/ar9003_buffalo_initvals.h diff --git a/drivers/net/wireless/ath/ath9k/ar9003_buffalo_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_buffalo_initvals.h new file mode 100644 index 00000000000..59cf738f70d --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9003_buffalo_initvals.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2013 Qualcomm Atheros Inc. + * + * 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. + */ + +#ifndef INITVALS_9003_BUFFALO_H +#define INITVALS_9003_BUFFALO_H + +static const u32 ar9300Modes_high_power_tx_gain_table_buffalo[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, + {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, + {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004}, + {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400}, + {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402}, + {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404}, + {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603}, + {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02}, + {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04}, + {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20}, + {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20}, + {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22}, + {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24}, + {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640}, + {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660}, + {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861}, + {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81}, + {0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83}, + {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84}, + {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3}, + {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5}, + {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9}, + {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb}, + {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000}, + {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002}, + {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004}, + {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200}, + {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400}, + {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402}, + {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603}, + {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02}, + {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04}, + {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20}, + {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20}, + {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22}, + {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24}, + {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640}, + {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660}, + {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861}, + {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81}, + {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83}, + {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84}, + {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3}, + {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5}, + {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9}, + {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb}, + {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000}, + {0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000}, + {0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501}, + {0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501}, + {0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03}, + {0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04}, + {0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04}, + {0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, + {0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, + {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, + {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, + {0x00016448, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, + {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, + {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, + {0x00016848, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, + {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, +}; + +#endif /* INITVALS_9003_BUFFALO_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 4e8ae4a79dc..29613ebbc5d 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -17,6 +17,7 @@ #include "hw.h" #include "ar9003_mac.h" #include "ar9003_2p2_initvals.h" +#include "ar9003_buffalo_initvals.h" #include "ar9485_initvals.h" #include "ar9340_initvals.h" #include "ar9330_1p1_initvals.h" @@ -592,9 +593,14 @@ static void ar9003_tx_gain_table_mode3(struct ath_hw *ah) else if (AR_SREV_9565(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9565_1p0_modes_high_power_tx_gain_table); - else - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9300Modes_high_power_tx_gain_table_2p2); + else { + if (ah->config.tx_gain_buffalo) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9300Modes_high_power_tx_gain_table_buffalo); + else + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9300Modes_high_power_tx_gain_table_2p2); + } } static void ar9003_tx_gain_table_mode4(struct ath_hw *ah) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 7490047acd1..b1ff54631dc 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -316,6 +316,7 @@ struct ath9k_ops_config { bool xatten_margin_cfg; bool alt_mingainidx; bool no_pll_pwrsave; + bool tx_gain_buffalo; }; enum ath9k_int { diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 5a0b7e82c85..609b7e13f3f 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -554,7 +554,7 @@ static void ath9k_init_misc(struct ath_softc *sc) sc->spec_config.fft_period = 0xF; } -static void ath9k_init_platform(struct ath_softc *sc) +static void ath9k_init_pcoem_platform(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; struct ath9k_hw_capabilities *pCap = &ah->caps; @@ -664,6 +664,27 @@ static void ath9k_eeprom_release(struct ath_softc *sc) release_firmware(sc->sc_ah->eeprom_blob); } +static int ath9k_init_soc_platform(struct ath_softc *sc) +{ + struct ath9k_platform_data *pdata = sc->dev->platform_data; + struct ath_hw *ah = sc->sc_ah; + int ret = 0; + + if (!pdata) + return 0; + + if (pdata->eeprom_name) { + ret = ath9k_eeprom_request(sc, pdata->eeprom_name); + if (ret) + return ret; + } + + if (pdata->tx_gain_buffalo) + ah->config.tx_gain_buffalo = true; + + return ret; +} + static int ath9k_init_softc(u16 devid, struct ath_softc *sc, const struct ath_bus_ops *bus_ops) { @@ -717,7 +738,11 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, /* * Platform quirks. */ - ath9k_init_platform(sc); + ath9k_init_pcoem_platform(sc); + + ret = ath9k_init_soc_platform(sc); + if (ret) + return ret; /* * Enable WLAN/BT RX Antenna diversity only when: @@ -731,7 +756,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, common->bt_ant_diversity = 1; spin_lock_init(&common->cc_lock); - spin_lock_init(&sc->sc_serial_rw); spin_lock_init(&sc->sc_pm_lock); mutex_init(&sc->mutex); @@ -753,12 +777,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, ath_read_cachesize(common, &csz); common->cachelsz = csz << 2; /* convert to bytes */ - if (pdata && pdata->eeprom_name) { - ret = ath9k_eeprom_request(sc, pdata->eeprom_name); - if (ret) - return ret; - } - /* Initializes the hardware for all supported chipsets */ ret = ath9k_hw_init(ah); if (ret) diff --git a/include/linux/ath9k_platform.h b/include/linux/ath9k_platform.h index fcdd81bd531..8598f8eacb2 100644 --- a/include/linux/ath9k_platform.h +++ b/include/linux/ath9k_platform.h @@ -32,6 +32,8 @@ struct ath9k_platform_data { u32 gpio_val; bool is_clk_25mhz; + bool tx_gain_buffalo; + int (*get_mac_revision)(void); int (*external_reset)(void); }; -- cgit v1.2.3-70-g09d2 From 98d7401dbbebec3da608697a77f9ca507fd8afc3 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 6 Dec 2013 16:28:46 +0530 Subject: ath9k: Update high power gain table for AR9300 Now that the Buffalo-specific initvals have been moved to a separate array, update the default high power TX gain table for all AR9300 v2.2 devices. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- .../net/wireless/ath/ath9k/ar9003_2p2_initvals.h | 182 ++++++++++----------- 1 file changed, 91 insertions(+), 91 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h index 72436744615..0a6163e9248 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h @@ -534,107 +534,107 @@ static const u32 ar9300_2p2_baseband_core[][2] = { static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, - {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, - {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000a2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800}, {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, - {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, - {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, - {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, - {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004}, - {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200}, - {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202}, - {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400}, - {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402}, - {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404}, - {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603}, - {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02}, - {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04}, - {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20}, - {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20}, - {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22}, - {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24}, - {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640}, - {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660}, - {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861}, - {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81}, - {0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83}, - {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84}, - {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3}, - {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5}, - {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9}, - {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb}, - {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000}, - {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002}, - {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004}, - {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200}, - {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202}, - {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400}, - {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402}, - {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404}, - {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603}, - {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02}, - {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04}, - {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20}, - {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20}, - {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22}, - {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24}, - {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640}, - {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660}, - {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861}, - {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81}, - {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83}, - {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84}, - {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3}, - {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5}, - {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9}, - {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb}, - {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, + {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, + {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x15000028, 0x15000028, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x1b00002b, 0x1b00002b, 0x12000400, 0x12000400}, + {0x0000a518, 0x1f020028, 0x1f020028, 0x16000402, 0x16000402}, + {0x0000a51c, 0x2502002b, 0x2502002b, 0x19000404, 0x19000404}, + {0x0000a520, 0x2a04002a, 0x2a04002a, 0x1c000603, 0x1c000603}, + {0x0000a524, 0x2e06002a, 0x2e06002a, 0x21000a02, 0x21000a02}, + {0x0000a528, 0x3302202d, 0x3302202d, 0x25000a04, 0x25000a04}, + {0x0000a52c, 0x3804202c, 0x3804202c, 0x28000a20, 0x28000a20}, + {0x0000a530, 0x3c06202c, 0x3c06202c, 0x2c000e20, 0x2c000e20}, + {0x0000a534, 0x4108202d, 0x4108202d, 0x30000e22, 0x30000e22}, + {0x0000a538, 0x4506402d, 0x4506402d, 0x34000e24, 0x34000e24}, + {0x0000a53c, 0x4906222d, 0x4906222d, 0x38001640, 0x38001640}, + {0x0000a540, 0x4d062231, 0x4d062231, 0x3c001660, 0x3c001660}, + {0x0000a544, 0x50082231, 0x50082231, 0x3f001861, 0x3f001861}, + {0x0000a548, 0x5608422e, 0x5608422e, 0x43001a81, 0x43001a81}, + {0x0000a54c, 0x5e08442e, 0x5e08442e, 0x47001a83, 0x47001a83}, + {0x0000a550, 0x620a4431, 0x620a4431, 0x4a001c84, 0x4a001c84}, + {0x0000a554, 0x640a4432, 0x640a4432, 0x4e001ce3, 0x4e001ce3}, + {0x0000a558, 0x680a4434, 0x680a4434, 0x52001ce5, 0x52001ce5}, + {0x0000a55c, 0x6c0a6434, 0x6c0a6434, 0x56001ce9, 0x56001ce9}, + {0x0000a560, 0x6f0a6633, 0x6f0a6633, 0x5a001ceb, 0x5a001ceb}, + {0x0000a564, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a568, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a56c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a570, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a574, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a578, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a57c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, + {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, + {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, + {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200}, + {0x0000a590, 0x15800028, 0x15800028, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x1b80002b, 0x1b80002b, 0x12800400, 0x12800400}, + {0x0000a598, 0x1f820028, 0x1f820028, 0x16800402, 0x16800402}, + {0x0000a59c, 0x2582002b, 0x2582002b, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x2a84002a, 0x2a84002a, 0x1c800603, 0x1c800603}, + {0x0000a5a4, 0x2e86002a, 0x2e86002a, 0x21800a02, 0x21800a02}, + {0x0000a5a8, 0x3382202d, 0x3382202d, 0x25800a04, 0x25800a04}, + {0x0000a5ac, 0x3884202c, 0x3884202c, 0x28800a20, 0x28800a20}, + {0x0000a5b0, 0x3c86202c, 0x3c86202c, 0x2c800e20, 0x2c800e20}, + {0x0000a5b4, 0x4188202d, 0x4188202d, 0x30800e22, 0x30800e22}, + {0x0000a5b8, 0x4586402d, 0x4586402d, 0x34800e24, 0x34800e24}, + {0x0000a5bc, 0x4986222d, 0x4986222d, 0x38801640, 0x38801640}, + {0x0000a5c0, 0x4d862231, 0x4d862231, 0x3c801660, 0x3c801660}, + {0x0000a5c4, 0x50882231, 0x50882231, 0x3f801861, 0x3f801861}, + {0x0000a5c8, 0x5688422e, 0x5688422e, 0x43801a81, 0x43801a81}, + {0x0000a5cc, 0x5e88442e, 0x5e88442e, 0x47801a83, 0x47801a83}, + {0x0000a5d0, 0x628a4431, 0x628a4431, 0x4a801c84, 0x4a801c84}, + {0x0000a5d4, 0x648a4432, 0x648a4432, 0x4e801ce3, 0x4e801ce3}, + {0x0000a5d8, 0x688a4434, 0x688a4434, 0x52801ce5, 0x52801ce5}, + {0x0000a5dc, 0x6c8a6434, 0x6c8a6434, 0x56801ce9, 0x56801ce9}, + {0x0000a5e0, 0x6f8a6633, 0x6f8a6633, 0x5a801ceb, 0x5a801ceb}, + {0x0000a5e4, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, + {0x0000a5e8, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, + {0x0000a5ec, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, + {0x0000a5f0, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, + {0x0000a5f4, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, + {0x0000a5f8, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, + {0x0000a5fc, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000}, - {0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000}, - {0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501}, - {0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501}, - {0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03}, - {0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04}, - {0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04}, - {0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, - {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, - {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000a608, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, + {0x0000a60c, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, + {0x0000a610, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, + {0x0000a614, 0x01804601, 0x01804601, 0x01404000, 0x01404000}, + {0x0000a618, 0x01804601, 0x01804601, 0x01404501, 0x01404501}, + {0x0000a61c, 0x01804601, 0x01804601, 0x02008501, 0x02008501}, + {0x0000a620, 0x03408d02, 0x03408d02, 0x0280ca03, 0x0280ca03}, + {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04}, + {0x0000a628, 0x03410d04, 0x03410d04, 0x04014c04, 0x04014c04}, + {0x0000a62c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, + {0x0000a630, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, + {0x0000a634, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, + {0x0000a638, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, + {0x0000a63c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, + {0x0000b2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, + {0x0000b2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, + {0x0000b2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800}, {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, - {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, - {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, - {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000c2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, + {0x0000c2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, + {0x0000c2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800}, {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, - {0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, + {0x00016048, 0x61200001, 0x61200001, 0x66480001, 0x66480001}, {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, - {0x00016448, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, + {0x00016448, 0x61200001, 0x61200001, 0x66480001, 0x66480001}, {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, - {0x00016848, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, + {0x00016848, 0x61200001, 0x61200001, 0x66480001, 0x66480001}, {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, }; -- cgit v1.2.3-70-g09d2 From 4b0ec82818758892dc2d4cb6934ac385024258f8 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 6 Dec 2013 16:28:47 +0530 Subject: ath9k: Identify duplicate AR9485 initvals Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9485_initvals.h | 117 +---------------------- 1 file changed, 5 insertions(+), 112 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h index 7c1845221e1..ce83ce47a1c 100644 --- a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h @@ -20,17 +20,11 @@ /* AR9485 1.1 */ -static const u32 ar9485_1_1_mac_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, - {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c}, - {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, - {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, - {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, - {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, - {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, - {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, -}; +#define ar9485_modes_lowest_ob_db_tx_gain_1_1 ar9485Modes_low_ob_db_tx_gain_1_1 + +#define ar9485_1_1_mac_postamble ar9331_1p1_mac_postamble + +#define ar9485_1_1_baseband_core_txfir_coeff_japan_2484 ar9300_2p2_baseband_core_txfir_coeff_japan_2484 static const u32 ar9485Common_wo_xlna_rx_gain_1_1[][2] = { /* Addr allmodes */ @@ -546,100 +540,6 @@ static const u32 ar9485Modes_low_ob_db_tx_gain_1_1[][5] = { {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260}, }; -static const u32 ar9485_modes_lowest_ob_db_tx_gain_1_1[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002}, - {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0x7999a83a, 0x7999a83a}, - {0x0000a2dc, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552}, - {0x0000a2e0, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552}, - {0x0000a2e4, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552}, - {0x0000a2e8, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552}, - {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, - {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, - {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, - {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, - {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200}, - {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202}, - {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400}, - {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402}, - {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404}, - {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603}, - {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605}, - {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03}, - {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04}, - {0x0000a530, 0x48023ec6, 0x48023ec6, 0x34000e20, 0x34000e20}, - {0x0000a534, 0x4d023f01, 0x4d023f01, 0x35000e21, 0x35000e21}, - {0x0000a538, 0x53023f4b, 0x53023f4b, 0x43000e62, 0x43000e62}, - {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x45000e63, 0x45000e63}, - {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x49000e65, 0x49000e65}, - {0x0000a544, 0x6502feca, 0x6502feca, 0x4b000e66, 0x4b000e66}, - {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4d001645, 0x4d001645}, - {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865}, - {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86}, - {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9}, - {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb}, - {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, - {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, - {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a580, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a584, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a588, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a58c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a590, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a594, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a598, 0x00000000, 0x00000000, 0x01404501, 0x01404501}, - {0x0000a59c, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02}, - {0x0000a5a0, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02}, - {0x0000a5a4, 0x00000000, 0x00000000, 0x02808803, 0x02808803}, - {0x0000a5a8, 0x00000000, 0x00000000, 0x04c14b04, 0x04c14b04}, - {0x0000a5ac, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, - {0x0000a5b0, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, - {0x0000a5b4, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, - {0x0000a5b8, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, - {0x0000a5bc, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, - {0x0000b500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b504, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b508, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b50c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b510, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b514, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b518, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b51c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b520, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b524, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b528, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b52c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b530, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b534, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b538, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b53c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b540, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b544, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b548, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b54c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b550, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b554, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b558, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b55c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b560, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b564, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b568, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b56c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b570, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b574, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b578, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b57c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db}, - {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260}, -}; - static const u32 ar9485Modes_green_spur_ob_db_tx_gain_1_1[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x000098bc, 0x00000003, 0x00000003, 0x00000003, 0x00000003}, @@ -1323,13 +1223,6 @@ static const u32 ar9485_1_1_mac_core[][2] = { {0x000083d0, 0x000301ff}, }; -static const u32 ar9485_1_1_baseband_core_txfir_coeff_japan_2484[][2] = { - /* Addr allmodes */ - {0x0000a398, 0x00000000}, - {0x0000a39c, 0x6f7f0301}, - {0x0000a3a0, 0xca9228ee}, -}; - static const u32 ar9485_1_1_pcie_phy_clkreq_disable_L1[][2] = { /* Addr allmodes */ {0x00018c00, 0x18013e5e}, -- cgit v1.2.3-70-g09d2 From ceb1512ffc2529eba731e2407b02421f22c0025e Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 6 Dec 2013 16:28:48 +0530 Subject: ath9k: Identify duplicate AR9462 v2.0 initvals Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- .../net/wireless/ath/ath9k/ar9462_2p0_initvals.h | 697 +++------------------ 1 file changed, 83 insertions(+), 614 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h index 73909438436..1cc13569b17 100644 --- a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h @@ -20,6 +20,14 @@ /* AR9462 2.0 */ +#define ar9462_2p0_mac_postamble ar9331_1p1_mac_postamble + +#define ar9462_2p0_common_wo_xlna_rx_gain ar9300Common_wo_xlna_rx_gain_table_2p2 + +#define ar9462_2p0_common_5g_xlna_only_rxgain ar9462_2p0_common_mixed_rx_gain + +#define ar9462_2p0_baseband_core_txfir_coeff_japan_2484 ar9300_2p2_baseband_core_txfir_coeff_japan_2484 + static const u32 ar9462_2p0_modes_fast_clock[][3] = { /* Addr 5G_HT20 5G_HT40 */ {0x00001030, 0x00000268, 0x000004d0}, @@ -366,348 +374,81 @@ static const u32 ar9462_2p0_radio_postamble_sys2ant[][5] = { {0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, }; -static const u32 ar9462_2p0_common_wo_xlna_rx_gain[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x00010000}, - {0x0000a004, 0x00030002}, - {0x0000a008, 0x00050004}, - {0x0000a00c, 0x00810080}, - {0x0000a010, 0x00830082}, - {0x0000a014, 0x01810180}, - {0x0000a018, 0x01830182}, - {0x0000a01c, 0x01850184}, - {0x0000a020, 0x01890188}, - {0x0000a024, 0x018b018a}, - {0x0000a028, 0x018d018c}, - {0x0000a02c, 0x03820190}, - {0x0000a030, 0x03840383}, - {0x0000a034, 0x03880385}, - {0x0000a038, 0x038a0389}, - {0x0000a03c, 0x038c038b}, - {0x0000a040, 0x0390038d}, - {0x0000a044, 0x03920391}, - {0x0000a048, 0x03940393}, - {0x0000a04c, 0x03960395}, - {0x0000a050, 0x00000000}, - {0x0000a054, 0x00000000}, - {0x0000a058, 0x00000000}, - {0x0000a05c, 0x00000000}, - {0x0000a060, 0x00000000}, - {0x0000a064, 0x00000000}, - {0x0000a068, 0x00000000}, - {0x0000a06c, 0x00000000}, - {0x0000a070, 0x00000000}, - {0x0000a074, 0x00000000}, - {0x0000a078, 0x00000000}, - {0x0000a07c, 0x00000000}, - {0x0000a080, 0x29292929}, - {0x0000a084, 0x29292929}, - {0x0000a088, 0x29292929}, - {0x0000a08c, 0x29292929}, - {0x0000a090, 0x22292929}, - {0x0000a094, 0x1d1d2222}, - {0x0000a098, 0x0c111117}, - {0x0000a09c, 0x00030303}, - {0x0000a0a0, 0x00000000}, - {0x0000a0a4, 0x00000000}, - {0x0000a0a8, 0x00000000}, - {0x0000a0ac, 0x00000000}, - {0x0000a0b0, 0x00000000}, - {0x0000a0b4, 0x00000000}, - {0x0000a0b8, 0x00000000}, - {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x001f0000}, - {0x0000a0c4, 0x01000101}, - {0x0000a0c8, 0x011e011f}, - {0x0000a0cc, 0x011c011d}, - {0x0000a0d0, 0x02030204}, - {0x0000a0d4, 0x02010202}, - {0x0000a0d8, 0x021f0200}, - {0x0000a0dc, 0x0302021e}, - {0x0000a0e0, 0x03000301}, - {0x0000a0e4, 0x031e031f}, - {0x0000a0e8, 0x0402031d}, - {0x0000a0ec, 0x04000401}, - {0x0000a0f0, 0x041e041f}, - {0x0000a0f4, 0x0502041d}, - {0x0000a0f8, 0x05000501}, - {0x0000a0fc, 0x051e051f}, - {0x0000a100, 0x06010602}, - {0x0000a104, 0x061f0600}, - {0x0000a108, 0x061d061e}, - {0x0000a10c, 0x07020703}, - {0x0000a110, 0x07000701}, - {0x0000a114, 0x00000000}, - {0x0000a118, 0x00000000}, - {0x0000a11c, 0x00000000}, - {0x0000a120, 0x00000000}, - {0x0000a124, 0x00000000}, - {0x0000a128, 0x00000000}, - {0x0000a12c, 0x00000000}, - {0x0000a130, 0x00000000}, - {0x0000a134, 0x00000000}, - {0x0000a138, 0x00000000}, - {0x0000a13c, 0x00000000}, - {0x0000a140, 0x001f0000}, - {0x0000a144, 0x01000101}, - {0x0000a148, 0x011e011f}, - {0x0000a14c, 0x011c011d}, - {0x0000a150, 0x02030204}, - {0x0000a154, 0x02010202}, - {0x0000a158, 0x021f0200}, - {0x0000a15c, 0x0302021e}, - {0x0000a160, 0x03000301}, - {0x0000a164, 0x031e031f}, - {0x0000a168, 0x0402031d}, - {0x0000a16c, 0x04000401}, - {0x0000a170, 0x041e041f}, - {0x0000a174, 0x0502041d}, - {0x0000a178, 0x05000501}, - {0x0000a17c, 0x051e051f}, - {0x0000a180, 0x06010602}, - {0x0000a184, 0x061f0600}, - {0x0000a188, 0x061d061e}, - {0x0000a18c, 0x07020703}, - {0x0000a190, 0x07000701}, - {0x0000a194, 0x00000000}, - {0x0000a198, 0x00000000}, - {0x0000a19c, 0x00000000}, - {0x0000a1a0, 0x00000000}, - {0x0000a1a4, 0x00000000}, - {0x0000a1a8, 0x00000000}, - {0x0000a1ac, 0x00000000}, - {0x0000a1b0, 0x00000000}, - {0x0000a1b4, 0x00000000}, - {0x0000a1b8, 0x00000000}, - {0x0000a1bc, 0x00000000}, - {0x0000a1c0, 0x00000000}, - {0x0000a1c4, 0x00000000}, - {0x0000a1c8, 0x00000000}, - {0x0000a1cc, 0x00000000}, - {0x0000a1d0, 0x00000000}, - {0x0000a1d4, 0x00000000}, - {0x0000a1d8, 0x00000000}, - {0x0000a1dc, 0x00000000}, - {0x0000a1e0, 0x00000000}, - {0x0000a1e4, 0x00000000}, - {0x0000a1e8, 0x00000000}, - {0x0000a1ec, 0x00000000}, - {0x0000a1f0, 0x00000396}, - {0x0000a1f4, 0x00000396}, - {0x0000a1f8, 0x00000396}, - {0x0000a1fc, 0x00000196}, - {0x0000b000, 0x00010000}, - {0x0000b004, 0x00030002}, - {0x0000b008, 0x00050004}, - {0x0000b00c, 0x00810080}, - {0x0000b010, 0x00830082}, - {0x0000b014, 0x01810180}, - {0x0000b018, 0x01830182}, - {0x0000b01c, 0x01850184}, - {0x0000b020, 0x02810280}, - {0x0000b024, 0x02830282}, - {0x0000b028, 0x02850284}, - {0x0000b02c, 0x02890288}, - {0x0000b030, 0x028b028a}, - {0x0000b034, 0x0388028c}, - {0x0000b038, 0x038a0389}, - {0x0000b03c, 0x038c038b}, - {0x0000b040, 0x0390038d}, - {0x0000b044, 0x03920391}, - {0x0000b048, 0x03940393}, - {0x0000b04c, 0x03960395}, - {0x0000b050, 0x00000000}, - {0x0000b054, 0x00000000}, - {0x0000b058, 0x00000000}, - {0x0000b05c, 0x00000000}, - {0x0000b060, 0x00000000}, - {0x0000b064, 0x00000000}, - {0x0000b068, 0x00000000}, - {0x0000b06c, 0x00000000}, - {0x0000b070, 0x00000000}, - {0x0000b074, 0x00000000}, - {0x0000b078, 0x00000000}, - {0x0000b07c, 0x00000000}, - {0x0000b080, 0x32323232}, - {0x0000b084, 0x2f2f3232}, - {0x0000b088, 0x23282a2d}, - {0x0000b08c, 0x1c1e2123}, - {0x0000b090, 0x14171919}, - {0x0000b094, 0x0e0e1214}, - {0x0000b098, 0x03050707}, - {0x0000b09c, 0x00030303}, - {0x0000b0a0, 0x00000000}, - {0x0000b0a4, 0x00000000}, - {0x0000b0a8, 0x00000000}, - {0x0000b0ac, 0x00000000}, - {0x0000b0b0, 0x00000000}, - {0x0000b0b4, 0x00000000}, - {0x0000b0b8, 0x00000000}, - {0x0000b0bc, 0x00000000}, - {0x0000b0c0, 0x003f0020}, - {0x0000b0c4, 0x00400041}, - {0x0000b0c8, 0x0140005f}, - {0x0000b0cc, 0x0160015f}, - {0x0000b0d0, 0x017e017f}, - {0x0000b0d4, 0x02410242}, - {0x0000b0d8, 0x025f0240}, - {0x0000b0dc, 0x027f0260}, - {0x0000b0e0, 0x0341027e}, - {0x0000b0e4, 0x035f0340}, - {0x0000b0e8, 0x037f0360}, - {0x0000b0ec, 0x04400441}, - {0x0000b0f0, 0x0460045f}, - {0x0000b0f4, 0x0541047f}, - {0x0000b0f8, 0x055f0540}, - {0x0000b0fc, 0x057f0560}, - {0x0000b100, 0x06400641}, - {0x0000b104, 0x0660065f}, - {0x0000b108, 0x067e067f}, - {0x0000b10c, 0x07410742}, - {0x0000b110, 0x075f0740}, - {0x0000b114, 0x077f0760}, - {0x0000b118, 0x07800781}, - {0x0000b11c, 0x07a0079f}, - {0x0000b120, 0x07c107bf}, - {0x0000b124, 0x000007c0}, - {0x0000b128, 0x00000000}, - {0x0000b12c, 0x00000000}, - {0x0000b130, 0x00000000}, - {0x0000b134, 0x00000000}, - {0x0000b138, 0x00000000}, - {0x0000b13c, 0x00000000}, - {0x0000b140, 0x003f0020}, - {0x0000b144, 0x00400041}, - {0x0000b148, 0x0140005f}, - {0x0000b14c, 0x0160015f}, - {0x0000b150, 0x017e017f}, - {0x0000b154, 0x02410242}, - {0x0000b158, 0x025f0240}, - {0x0000b15c, 0x027f0260}, - {0x0000b160, 0x0341027e}, - {0x0000b164, 0x035f0340}, - {0x0000b168, 0x037f0360}, - {0x0000b16c, 0x04400441}, - {0x0000b170, 0x0460045f}, - {0x0000b174, 0x0541047f}, - {0x0000b178, 0x055f0540}, - {0x0000b17c, 0x057f0560}, - {0x0000b180, 0x06400641}, - {0x0000b184, 0x0660065f}, - {0x0000b188, 0x067e067f}, - {0x0000b18c, 0x07410742}, - {0x0000b190, 0x075f0740}, - {0x0000b194, 0x077f0760}, - {0x0000b198, 0x07800781}, - {0x0000b19c, 0x07a0079f}, - {0x0000b1a0, 0x07c107bf}, - {0x0000b1a4, 0x000007c0}, - {0x0000b1a8, 0x00000000}, - {0x0000b1ac, 0x00000000}, - {0x0000b1b0, 0x00000000}, - {0x0000b1b4, 0x00000000}, - {0x0000b1b8, 0x00000000}, - {0x0000b1bc, 0x00000000}, - {0x0000b1c0, 0x00000000}, - {0x0000b1c4, 0x00000000}, - {0x0000b1c8, 0x00000000}, - {0x0000b1cc, 0x00000000}, - {0x0000b1d0, 0x00000000}, - {0x0000b1d4, 0x00000000}, - {0x0000b1d8, 0x00000000}, - {0x0000b1dc, 0x00000000}, - {0x0000b1e0, 0x00000000}, - {0x0000b1e4, 0x00000000}, - {0x0000b1e8, 0x00000000}, - {0x0000b1ec, 0x00000000}, - {0x0000b1f0, 0x00000396}, - {0x0000b1f4, 0x00000396}, - {0x0000b1f8, 0x00000396}, - {0x0000b1fc, 0x00000196}, -}; - -static const u32 ar9462_2p0_baseband_core_txfir_coeff_japan_2484[][2] = { - /* Addr allmodes */ - {0x0000a398, 0x00000000}, - {0x0000a39c, 0x6f7f0301}, - {0x0000a3a0, 0xca9228ee}, -}; - -static const u32 ar9462_2p0_modes_low_ob_db_tx_gain[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002}, - {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, - {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, - {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, - {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, - {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, - {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, - {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, - {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, - {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, - {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400}, - {0x0000a518, 0x21020220, 0x21020220, 0x16000402, 0x16000402}, - {0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404}, - {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603}, - {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02}, - {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04}, - {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20}, - {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20}, - {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22}, - {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24}, - {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640}, - {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660}, - {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861}, - {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81}, - {0x0000a54c, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83}, - {0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84}, - {0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3}, - {0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5}, - {0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9}, - {0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb}, - {0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a57c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000}, - {0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501}, - {0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501}, - {0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03}, - {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04}, - {0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04}, - {0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005}, - {0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, - {0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, - {0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, - {0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, - {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, - {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, - {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, - {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, - {0x00016044, 0x012482d4, 0x012482d4, 0x012482d4, 0x012482d4}, - {0x00016048, 0x64992060, 0x64992060, 0x64992060, 0x64992060}, - {0x00016054, 0x6db60000, 0x6db60000, 0x6db60000, 0x6db60000}, - {0x00016444, 0x012482d4, 0x012482d4, 0x012482d4, 0x012482d4}, - {0x00016448, 0x64992000, 0x64992000, 0x64992000, 0x64992000}, - {0x00016454, 0x6db60000, 0x6db60000, 0x6db60000, 0x6db60000}, -}; - -static const u32 ar9462_2p0_soc_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00007010, 0x00000033, 0x00000033, 0x00000033, 0x00000033}, -}; - -static const u32 ar9462_2p0_baseband_core[][2] = { +static const u32 ar9462_2p0_modes_low_ob_db_tx_gain[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002}, + {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, + {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, + {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, + {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400}, + {0x0000a518, 0x21020220, 0x21020220, 0x16000402, 0x16000402}, + {0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404}, + {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603}, + {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02}, + {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04}, + {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20}, + {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20}, + {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22}, + {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24}, + {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640}, + {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660}, + {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861}, + {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81}, + {0x0000a54c, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83}, + {0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84}, + {0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3}, + {0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5}, + {0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9}, + {0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb}, + {0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a57c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000}, + {0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501}, + {0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501}, + {0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03}, + {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04}, + {0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04}, + {0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005}, + {0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x00016044, 0x012482d4, 0x012482d4, 0x012482d4, 0x012482d4}, + {0x00016048, 0x64992060, 0x64992060, 0x64992060, 0x64992060}, + {0x00016054, 0x6db60000, 0x6db60000, 0x6db60000, 0x6db60000}, + {0x00016444, 0x012482d4, 0x012482d4, 0x012482d4, 0x012482d4}, + {0x00016448, 0x64992000, 0x64992000, 0x64992000, 0x64992000}, + {0x00016454, 0x6db60000, 0x6db60000, 0x6db60000, 0x6db60000}, +}; + +static const u32 ar9462_2p0_soc_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00007010, 0x00000033, 0x00000033, 0x00000033, 0x00000033}, +}; + +static const u32 ar9462_2p0_baseband_core[][2] = { /* Addr allmodes */ {0x00009800, 0xafe68e30}, {0x00009804, 0xfd14e000}, @@ -1226,18 +967,6 @@ static const u32 ar9462_2p0_mac_core[][2] = { {0x000083d0, 0x000301ff}, }; -static const u32 ar9462_2p0_mac_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, - {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c}, - {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, - {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, - {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, - {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, - {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, - {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, -}; - static const u32 ar9462_2p0_common_mixed_rx_gain[][2] = { /* Addr allmodes */ {0x0000a000, 0x00010000}, @@ -1503,266 +1232,6 @@ static const u32 ar9462_2p0_baseband_postamble_5g_xlna[][5] = { {0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c282}, }; -static const u32 ar9462_2p0_common_5g_xlna_only_rxgain[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x00010000}, - {0x0000a004, 0x00030002}, - {0x0000a008, 0x00050004}, - {0x0000a00c, 0x00810080}, - {0x0000a010, 0x00830082}, - {0x0000a014, 0x01810180}, - {0x0000a018, 0x01830182}, - {0x0000a01c, 0x01850184}, - {0x0000a020, 0x01890188}, - {0x0000a024, 0x018b018a}, - {0x0000a028, 0x018d018c}, - {0x0000a02c, 0x03820190}, - {0x0000a030, 0x03840383}, - {0x0000a034, 0x03880385}, - {0x0000a038, 0x038a0389}, - {0x0000a03c, 0x038c038b}, - {0x0000a040, 0x0390038d}, - {0x0000a044, 0x03920391}, - {0x0000a048, 0x03940393}, - {0x0000a04c, 0x03960395}, - {0x0000a050, 0x00000000}, - {0x0000a054, 0x00000000}, - {0x0000a058, 0x00000000}, - {0x0000a05c, 0x00000000}, - {0x0000a060, 0x00000000}, - {0x0000a064, 0x00000000}, - {0x0000a068, 0x00000000}, - {0x0000a06c, 0x00000000}, - {0x0000a070, 0x00000000}, - {0x0000a074, 0x00000000}, - {0x0000a078, 0x00000000}, - {0x0000a07c, 0x00000000}, - {0x0000a080, 0x29292929}, - {0x0000a084, 0x29292929}, - {0x0000a088, 0x29292929}, - {0x0000a08c, 0x29292929}, - {0x0000a090, 0x22292929}, - {0x0000a094, 0x1d1d2222}, - {0x0000a098, 0x0c111117}, - {0x0000a09c, 0x00030303}, - {0x0000a0a0, 0x00000000}, - {0x0000a0a4, 0x00000000}, - {0x0000a0a8, 0x00000000}, - {0x0000a0ac, 0x00000000}, - {0x0000a0b0, 0x00000000}, - {0x0000a0b4, 0x00000000}, - {0x0000a0b8, 0x00000000}, - {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x001f0000}, - {0x0000a0c4, 0x01000101}, - {0x0000a0c8, 0x011e011f}, - {0x0000a0cc, 0x011c011d}, - {0x0000a0d0, 0x02030204}, - {0x0000a0d4, 0x02010202}, - {0x0000a0d8, 0x021f0200}, - {0x0000a0dc, 0x0302021e}, - {0x0000a0e0, 0x03000301}, - {0x0000a0e4, 0x031e031f}, - {0x0000a0e8, 0x0402031d}, - {0x0000a0ec, 0x04000401}, - {0x0000a0f0, 0x041e041f}, - {0x0000a0f4, 0x0502041d}, - {0x0000a0f8, 0x05000501}, - {0x0000a0fc, 0x051e051f}, - {0x0000a100, 0x06010602}, - {0x0000a104, 0x061f0600}, - {0x0000a108, 0x061d061e}, - {0x0000a10c, 0x07020703}, - {0x0000a110, 0x07000701}, - {0x0000a114, 0x00000000}, - {0x0000a118, 0x00000000}, - {0x0000a11c, 0x00000000}, - {0x0000a120, 0x00000000}, - {0x0000a124, 0x00000000}, - {0x0000a128, 0x00000000}, - {0x0000a12c, 0x00000000}, - {0x0000a130, 0x00000000}, - {0x0000a134, 0x00000000}, - {0x0000a138, 0x00000000}, - {0x0000a13c, 0x00000000}, - {0x0000a140, 0x001f0000}, - {0x0000a144, 0x01000101}, - {0x0000a148, 0x011e011f}, - {0x0000a14c, 0x011c011d}, - {0x0000a150, 0x02030204}, - {0x0000a154, 0x02010202}, - {0x0000a158, 0x021f0200}, - {0x0000a15c, 0x0302021e}, - {0x0000a160, 0x03000301}, - {0x0000a164, 0x031e031f}, - {0x0000a168, 0x0402031d}, - {0x0000a16c, 0x04000401}, - {0x0000a170, 0x041e041f}, - {0x0000a174, 0x0502041d}, - {0x0000a178, 0x05000501}, - {0x0000a17c, 0x051e051f}, - {0x0000a180, 0x06010602}, - {0x0000a184, 0x061f0600}, - {0x0000a188, 0x061d061e}, - {0x0000a18c, 0x07020703}, - {0x0000a190, 0x07000701}, - {0x0000a194, 0x00000000}, - {0x0000a198, 0x00000000}, - {0x0000a19c, 0x00000000}, - {0x0000a1a0, 0x00000000}, - {0x0000a1a4, 0x00000000}, - {0x0000a1a8, 0x00000000}, - {0x0000a1ac, 0x00000000}, - {0x0000a1b0, 0x00000000}, - {0x0000a1b4, 0x00000000}, - {0x0000a1b8, 0x00000000}, - {0x0000a1bc, 0x00000000}, - {0x0000a1c0, 0x00000000}, - {0x0000a1c4, 0x00000000}, - {0x0000a1c8, 0x00000000}, - {0x0000a1cc, 0x00000000}, - {0x0000a1d0, 0x00000000}, - {0x0000a1d4, 0x00000000}, - {0x0000a1d8, 0x00000000}, - {0x0000a1dc, 0x00000000}, - {0x0000a1e0, 0x00000000}, - {0x0000a1e4, 0x00000000}, - {0x0000a1e8, 0x00000000}, - {0x0000a1ec, 0x00000000}, - {0x0000a1f0, 0x00000396}, - {0x0000a1f4, 0x00000396}, - {0x0000a1f8, 0x00000396}, - {0x0000a1fc, 0x00000196}, - {0x0000b000, 0x00010000}, - {0x0000b004, 0x00030002}, - {0x0000b008, 0x00050004}, - {0x0000b00c, 0x00810080}, - {0x0000b010, 0x00830082}, - {0x0000b014, 0x01810180}, - {0x0000b018, 0x01830182}, - {0x0000b01c, 0x01850184}, - {0x0000b020, 0x02810280}, - {0x0000b024, 0x02830282}, - {0x0000b028, 0x02850284}, - {0x0000b02c, 0x02890288}, - {0x0000b030, 0x028b028a}, - {0x0000b034, 0x0388028c}, - {0x0000b038, 0x038a0389}, - {0x0000b03c, 0x038c038b}, - {0x0000b040, 0x0390038d}, - {0x0000b044, 0x03920391}, - {0x0000b048, 0x03940393}, - {0x0000b04c, 0x03960395}, - {0x0000b050, 0x00000000}, - {0x0000b054, 0x00000000}, - {0x0000b058, 0x00000000}, - {0x0000b05c, 0x00000000}, - {0x0000b060, 0x00000000}, - {0x0000b064, 0x00000000}, - {0x0000b068, 0x00000000}, - {0x0000b06c, 0x00000000}, - {0x0000b070, 0x00000000}, - {0x0000b074, 0x00000000}, - {0x0000b078, 0x00000000}, - {0x0000b07c, 0x00000000}, - {0x0000b080, 0x2a2d2f32}, - {0x0000b084, 0x21232328}, - {0x0000b088, 0x19191c1e}, - {0x0000b08c, 0x12141417}, - {0x0000b090, 0x07070e0e}, - {0x0000b094, 0x03030305}, - {0x0000b098, 0x00000003}, - {0x0000b09c, 0x00000000}, - {0x0000b0a0, 0x00000000}, - {0x0000b0a4, 0x00000000}, - {0x0000b0a8, 0x00000000}, - {0x0000b0ac, 0x00000000}, - {0x0000b0b0, 0x00000000}, - {0x0000b0b4, 0x00000000}, - {0x0000b0b8, 0x00000000}, - {0x0000b0bc, 0x00000000}, - {0x0000b0c0, 0x003f0020}, - {0x0000b0c4, 0x00400041}, - {0x0000b0c8, 0x0140005f}, - {0x0000b0cc, 0x0160015f}, - {0x0000b0d0, 0x017e017f}, - {0x0000b0d4, 0x02410242}, - {0x0000b0d8, 0x025f0240}, - {0x0000b0dc, 0x027f0260}, - {0x0000b0e0, 0x0341027e}, - {0x0000b0e4, 0x035f0340}, - {0x0000b0e8, 0x037f0360}, - {0x0000b0ec, 0x04400441}, - {0x0000b0f0, 0x0460045f}, - {0x0000b0f4, 0x0541047f}, - {0x0000b0f8, 0x055f0540}, - {0x0000b0fc, 0x057f0560}, - {0x0000b100, 0x06400641}, - {0x0000b104, 0x0660065f}, - {0x0000b108, 0x067e067f}, - {0x0000b10c, 0x07410742}, - {0x0000b110, 0x075f0740}, - {0x0000b114, 0x077f0760}, - {0x0000b118, 0x07800781}, - {0x0000b11c, 0x07a0079f}, - {0x0000b120, 0x07c107bf}, - {0x0000b124, 0x000007c0}, - {0x0000b128, 0x00000000}, - {0x0000b12c, 0x00000000}, - {0x0000b130, 0x00000000}, - {0x0000b134, 0x00000000}, - {0x0000b138, 0x00000000}, - {0x0000b13c, 0x00000000}, - {0x0000b140, 0x003f0020}, - {0x0000b144, 0x00400041}, - {0x0000b148, 0x0140005f}, - {0x0000b14c, 0x0160015f}, - {0x0000b150, 0x017e017f}, - {0x0000b154, 0x02410242}, - {0x0000b158, 0x025f0240}, - {0x0000b15c, 0x027f0260}, - {0x0000b160, 0x0341027e}, - {0x0000b164, 0x035f0340}, - {0x0000b168, 0x037f0360}, - {0x0000b16c, 0x04400441}, - {0x0000b170, 0x0460045f}, - {0x0000b174, 0x0541047f}, - {0x0000b178, 0x055f0540}, - {0x0000b17c, 0x057f0560}, - {0x0000b180, 0x06400641}, - {0x0000b184, 0x0660065f}, - {0x0000b188, 0x067e067f}, - {0x0000b18c, 0x07410742}, - {0x0000b190, 0x075f0740}, - {0x0000b194, 0x077f0760}, - {0x0000b198, 0x07800781}, - {0x0000b19c, 0x07a0079f}, - {0x0000b1a0, 0x07c107bf}, - {0x0000b1a4, 0x000007c0}, - {0x0000b1a8, 0x00000000}, - {0x0000b1ac, 0x00000000}, - {0x0000b1b0, 0x00000000}, - {0x0000b1b4, 0x00000000}, - {0x0000b1b8, 0x00000000}, - {0x0000b1bc, 0x00000000}, - {0x0000b1c0, 0x00000000}, - {0x0000b1c4, 0x00000000}, - {0x0000b1c8, 0x00000000}, - {0x0000b1cc, 0x00000000}, - {0x0000b1d0, 0x00000000}, - {0x0000b1d4, 0x00000000}, - {0x0000b1d8, 0x00000000}, - {0x0000b1dc, 0x00000000}, - {0x0000b1e0, 0x00000000}, - {0x0000b1e4, 0x00000000}, - {0x0000b1e8, 0x00000000}, - {0x0000b1ec, 0x00000000}, - {0x0000b1f0, 0x00000396}, - {0x0000b1f4, 0x00000396}, - {0x0000b1f8, 0x00000396}, - {0x0000b1fc, 0x00000196}, -}; - static const u32 ar9462_2p0_baseband_core_mix_rxgain[][2] = { /* Addr allmodes */ {0x00009fd0, 0x0a2d6b93}, -- cgit v1.2.3-70-g09d2 From ca488b921e98951217f1f9fdc7629febef19ccba Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 6 Dec 2013 16:28:49 +0530 Subject: ath9k: Identify duplicate AR9565 v1.0 initvals Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- .../net/wireless/ath/ath9k/ar9565_1p0_initvals.h | 85 ++-------------------- 1 file changed, 6 insertions(+), 79 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9565_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9565_1p0_initvals.h index a8c757b6124..10d4a6cb1c3 100644 --- a/drivers/net/wireless/ath/ath9k/ar9565_1p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9565_1p0_initvals.h @@ -20,6 +20,12 @@ /* AR9565 1.0 */ +#define ar9565_1p0_mac_postamble ar9331_1p1_mac_postamble + +#define ar9565_1p0_Modes_lowest_ob_db_tx_gain_table ar9565_1p0_modes_low_ob_db_tx_gain_table + +#define ar9565_1p0_baseband_core_txfir_coeff_japan_2484 ar9300_2p2_baseband_core_txfir_coeff_japan_2484 + static const u32 ar9565_1p0_mac_core[][2] = { /* Addr allmodes */ {0x00000008, 0x00000000}, @@ -182,18 +188,6 @@ static const u32 ar9565_1p0_mac_core[][2] = { {0x000083d0, 0x800301ff}, }; -static const u32 ar9565_1p0_mac_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, - {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c}, - {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, - {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, - {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, - {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, - {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, - {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, -}; - static const u32 ar9565_1p0_baseband_core[][2] = { /* Addr allmodes */ {0x00009800, 0xafe68e30}, @@ -711,66 +705,6 @@ static const u32 ar9565_1p0_Common_rx_gain_table[][2] = { {0x0000b1fc, 0x00000196}, }; -static const u32 ar9565_1p0_Modes_lowest_ob_db_tx_gain_table[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a2dc, 0xfc0a9380, 0xfc0a9380, 0xfdab5b52, 0xfdab5b52}, - {0x0000a2e0, 0xffecec00, 0xffecec00, 0xfd339c84, 0xfd339c84}, - {0x0000a2e4, 0xfc0f0000, 0xfc0f0000, 0xfec3e000, 0xfec3e000}, - {0x0000a2e8, 0xfc100000, 0xfc100000, 0xfffc0000, 0xfffc0000}, - {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, - {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, - {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, - {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, - {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, - {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400}, - {0x0000a518, 0x21020220, 0x21020220, 0x16000402, 0x16000402}, - {0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404}, - {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603}, - {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02}, - {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04}, - {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20}, - {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20}, - {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22}, - {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24}, - {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640}, - {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660}, - {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861}, - {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81}, - {0x0000a54c, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83}, - {0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84}, - {0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3}, - {0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5}, - {0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9}, - {0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb}, - {0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a57c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a614, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a618, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a61c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a620, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a624, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a628, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a62c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a630, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a634, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a638, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a63c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00016044, 0x012482d4, 0x012482d4, 0x012482d4, 0x012482d4}, - {0x00016048, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00016054, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -}; - static const u32 ar9565_1p0_pciephy_clkreq_disable_L1[][2] = { /* Addr allmodes */ {0x00018c00, 0x18212ede}, @@ -1231,11 +1165,4 @@ static const u32 ar9565_1p0_modes_high_power_tx_gain_table[][5] = { {0x00016054, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, }; -static const u32 ar9565_1p0_baseband_core_txfir_coeff_japan_2484[][2] = { - /* Addr allmodes */ - {0x0000a398, 0x00000000}, - {0x0000a39c, 0x6f7f0301}, - {0x0000a3a0, 0xca9228ee}, -}; - #endif /* INITVALS_9565_1P0_H */ -- cgit v1.2.3-70-g09d2 From 0c7c2bb4daebb23b08b86c24fe70189c3c049f78 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 6 Dec 2013 16:28:50 +0530 Subject: ath9k: Fix regulatory compliance Adjusting the CCA registers for maximum permissible noise floor in ETSI/Japan domains has to be done for all AR9003 family chips. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_phy.h | 5 +++-- drivers/net/wireless/ath/ath9k/hw.c | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index 2af667beb27..bbbfc4dc59e 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -341,14 +341,15 @@ #define AR_PHY_CCA_MAX_GOOD_VAL_9300_2GHZ -95 #define AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ -100 +#define AR_PHY_CCA_MAX_GOOD_VAL_9300_FCC_2GHZ -95 +#define AR_PHY_CCA_MAX_GOOD_VAL_9300_FCC_5GHZ -100 + #define AR_PHY_CCA_NOM_VAL_9462_2GHZ -127 #define AR_PHY_CCA_MIN_GOOD_VAL_9462_2GHZ -127 #define AR_PHY_CCA_MAX_GOOD_VAL_9462_2GHZ -60 -#define AR_PHY_CCA_MAX_GOOD_VAL_9462_FCC_2GHZ -95 #define AR_PHY_CCA_NOM_VAL_9462_5GHZ -127 #define AR_PHY_CCA_MIN_GOOD_VAL_9462_5GHZ -127 #define AR_PHY_CCA_MAX_GOOD_VAL_9462_5GHZ -60 -#define AR_PHY_CCA_MAX_GOOD_VAL_9462_FCC_5GHZ -100 #define AR_PHY_CCA_NOM_VAL_9330_2GHZ -118 diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 779d38a98a0..4ee24b1eec3 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -548,11 +548,11 @@ static int ath9k_hw_post_init(struct ath_hw *ah) * EEPROM needs to be initialized before we do this. * This is required for regulatory compliance. */ - if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) { + if (AR_SREV_9300_20_OR_LATER(ah)) { u16 regdmn = ah->eep_ops->get_eeprom(ah, EEP_REG_0); if ((regdmn & 0xF0) == CTL_FCC) { - ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9462_FCC_2GHZ; - ah->nf_5g.max = AR_PHY_CCA_MAX_GOOD_VAL_9462_FCC_5GHZ; + ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9300_FCC_2GHZ; + ah->nf_5g.max = AR_PHY_CCA_MAX_GOOD_VAL_9300_FCC_5GHZ; } } -- cgit v1.2.3-70-g09d2 From 6b416d0511153916a140feeabe58cd5443c97fd8 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 6 Dec 2013 16:28:51 +0530 Subject: ath9k: Remove AR9330 v1.0 macro as it's not supported Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/reg.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 259a4b30770..9ad007312c9 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -883,9 +883,6 @@ #define AR_SREV_9330(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9330)) -#define AR_SREV_9330_10(_ah) \ - (AR_SREV_9330((_ah)) && \ - ((_ah)->hw_version.macRev == AR_SREV_REVISION_9330_10)) #define AR_SREV_9330_11(_ah) \ (AR_SREV_9330((_ah)) && \ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9330_11)) -- cgit v1.2.3-70-g09d2 From bb46662894c24dce9be1414400b4ce969dafc1dd Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 6 Dec 2013 16:28:52 +0530 Subject: ath9k: Enable manual peak calibration for AR9331 v1.1 Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_calib.c | 29 ++++++++++++++++++--------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index aa012726574..97e09d5f3a4 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -898,7 +898,7 @@ static void ar9003_hw_tx_iq_cal_reload(struct ath_hw *ah) static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g) { - int offset[8], total = 0, test; + int offset[8] = {0}, total = 0, test; int agc_out, i; REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain), @@ -923,12 +923,18 @@ static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g) AR_PHY_65NM_RXRF_AGC_AGC_ON_OVR, 0x1); REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0x1); - if (is_2g) - REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), - AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR, 0x0); - else + + if (AR_SREV_9330_11(ah)) { REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), - AR_PHY_65NM_RXRF_AGC_AGC5G_DBDAC_OVR, 0x0); + AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR, 0x0); + } else { + if (is_2g) + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), + AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR, 0x0); + else + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), + AR_PHY_65NM_RXRF_AGC_AGC5G_DBDAC_OVR, 0x0); + } for (i = 6; i > 0; i--) { offset[i] = BIT(i - 1); @@ -964,9 +970,9 @@ static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g) AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0); } -static void ar9003_hw_do_manual_peak_cal(struct ath_hw *ah, - struct ath9k_channel *chan, - bool run_rtt_cal) +static void ar9003_hw_do_pcoem_manual_peak_cal(struct ath_hw *ah, + struct ath9k_channel *chan, + bool run_rtt_cal) { struct ath9k_hw_cal_data *caldata = ah->caldata; int i; @@ -1145,7 +1151,7 @@ skip_tx_iqcal: AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT); - ar9003_hw_do_manual_peak_cal(ah, chan, run_rtt_cal); + ar9003_hw_do_pcoem_manual_peak_cal(ah, chan, run_rtt_cal); } if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE) { @@ -1267,6 +1273,9 @@ static bool ar9003_hw_init_cal_soc(struct ath_hw *ah, skip_tx_iqcal: if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) { + if (AR_SREV_9330_11(ah)) + ar9003_hw_manual_peak_cal(ah, 0, IS_CHAN_2GHZ(chan)); + /* Calibrate the AGC */ REG_WRITE(ah, AR_PHY_AGC_CONTROL, REG_READ(ah, AR_PHY_AGC_CONTROL) | -- cgit v1.2.3-70-g09d2 From e6d53bdcc38d451fa6afbe412a759f132d44f361 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 6 Dec 2013 16:28:53 +0530 Subject: ath9k: Fix internal regulator for AR955x The internal regulator needs to be programmed correctly for AR955x. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 130657db5c4..2845ace0d9e 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -4122,7 +4122,7 @@ static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah, ar9003_hw_xlna_bias_strength_apply(ah, is2ghz); ar9003_hw_atten_apply(ah, chan); ar9003_hw_quick_drop_apply(ah, chan->channel); - if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah) && !AR_SREV_9550(ah)) + if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah)) ar9003_hw_internal_regulator_apply(ah); ar9003_hw_apply_tuning_caps(ah); ar9003_hw_txend_to_xpa_off_apply(ah, is2ghz); -- cgit v1.2.3-70-g09d2 From d6b5075d73adbc10fac873ca86798e30c115a018 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 6 Dec 2013 16:28:54 +0530 Subject: ath9k: Apply tuning caps for AR9330 and AR9485 Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 2845ace0d9e..ec317d6937d 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3965,7 +3965,7 @@ static void ar9003_hw_apply_tuning_caps(struct ath_hw *ah) struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; u8 tuning_caps_param = eep->baseEepHeader.params_for_tuning_caps[0]; - if (AR_SREV_9485(ah) || AR_SREV_9330(ah) || AR_SREV_9340(ah)) + if (AR_SREV_9340(ah)) return; if (eep->baseEepHeader.featureEnable & 0x40) { -- cgit v1.2.3-70-g09d2 From 3166950070ce6b9d1443758d82c0a42779a02153 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Mon, 9 Dec 2013 12:24:07 +0900 Subject: net: sfc: remove unnecessary pci_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/efx.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 958d8c7fa02..12f60e78286 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -2643,7 +2643,6 @@ static void efx_pci_remove(struct pci_dev *pci_dev) netif_dbg(efx, drv, efx->net_dev, "shutdown successful\n"); efx_fini_struct(efx); - pci_set_drvdata(pci_dev, NULL); free_netdev(efx->net_dev); pci_disable_pcie_error_reporting(pci_dev); @@ -2837,7 +2836,6 @@ static int efx_pci_probe(struct pci_dev *pci_dev, fail2: efx_fini_struct(efx); fail1: - pci_set_drvdata(pci_dev, NULL); WARN_ON(rc > 0); netif_dbg(efx, drv, efx->net_dev, "initialisation failed. rc=%d\n", rc); free_netdev(net_dev); -- cgit v1.2.3-70-g09d2 From e104637e35501a91d61f0434f3b9a7bbacd2b70a Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Mon, 9 Dec 2013 12:25:44 +0900 Subject: net: sis900: remove unnecessary pci_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Signed-off-by: David S. Miller --- drivers/net/ethernet/sis/sis900.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/ethernet/sis/sis900.c b/drivers/net/ethernet/sis/sis900.c index 975dc2d8e54..ff57a46388e 100644 --- a/drivers/net/ethernet/sis/sis900.c +++ b/drivers/net/ethernet/sis/sis900.c @@ -576,7 +576,6 @@ err_unmap_tx: err_out_unmap: pci_iounmap(pci_dev, ioaddr); err_out_cleardev: - pci_set_drvdata(pci_dev, NULL); pci_release_regions(pci_dev); err_out: free_netdev(net_dev); @@ -2427,7 +2426,6 @@ static void sis900_remove(struct pci_dev *pci_dev) pci_iounmap(pci_dev, sis_priv->ioaddr); free_netdev(net_dev); pci_release_regions(pci_dev); - pci_set_drvdata(pci_dev, NULL); } #ifdef CONFIG_PM -- cgit v1.2.3-70-g09d2 From add0cdb43a421239c1ca6ebe6fc2b591b37dbc00 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Mon, 9 Dec 2013 12:26:44 +0900 Subject: net: bna: remove unnecessary pci_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Signed-off-by: David S. Miller --- drivers/net/ethernet/brocade/bna/bnad.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/brocade/bna/bnad.c b/drivers/net/ethernet/brocade/bna/bnad.c index 248bc37cb41..3d151bd1635 100644 --- a/drivers/net/ethernet/brocade/bna/bnad.c +++ b/drivers/net/ethernet/brocade/bna/bnad.c @@ -3262,7 +3262,6 @@ bnad_uninit(struct bnad *bnad) if (bnad->bar0) iounmap(bnad->bar0); - pci_set_drvdata(bnad->pcidev, NULL); } /* -- cgit v1.2.3-70-g09d2 From e28f4d595186cc02beaffd1952b82d3d8147c556 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Mon, 9 Dec 2013 12:27:27 +0900 Subject: net: ns83820: remove unnecessary pci_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Signed-off-by: David S. Miller --- drivers/net/ethernet/natsemi/ns83820.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/ethernet/natsemi/ns83820.c b/drivers/net/ethernet/natsemi/ns83820.c index 5213e73f0ea..dbccf1de49e 100644 --- a/drivers/net/ethernet/natsemi/ns83820.c +++ b/drivers/net/ethernet/natsemi/ns83820.c @@ -2235,7 +2235,6 @@ out_disable: pci_disable_device(pci_dev); out_free: free_netdev(ndev); - pci_set_drvdata(pci_dev, NULL); out: return err; } @@ -2259,7 +2258,6 @@ static void ns83820_remove_one(struct pci_dev *pci_dev) dev->rx_info.descs, dev->rx_info.phy_descs); pci_disable_device(dev->pci_dev); free_netdev(ndev); - pci_set_drvdata(pci_dev, NULL); } static DEFINE_PCI_DEVICE_TABLE(ns83820_pci_tbl) = { -- cgit v1.2.3-70-g09d2 From 3722c1b094f33322da55b69fdfafa9cbeb1a3177 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Mon, 9 Dec 2013 12:27:50 +0900 Subject: net: forcedeth: remove unnecessary pci_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Signed-off-by: David S. Miller --- drivers/net/ethernet/nvidia/forcedeth.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c index ab67babbfdd..d8bdaf6d82d 100644 --- a/drivers/net/ethernet/nvidia/forcedeth.c +++ b/drivers/net/ethernet/nvidia/forcedeth.c @@ -6017,7 +6017,6 @@ static int nv_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) out_error: if (phystate_orig) writel(phystate|NVREG_ADAPTCTL_RUNNING, base + NvRegAdapterControl); - pci_set_drvdata(pci_dev, NULL); out_freering: free_rings(dev); out_unmap: @@ -6088,7 +6087,6 @@ static void nv_remove(struct pci_dev *pci_dev) pci_release_regions(pci_dev); pci_disable_device(pci_dev); free_netdev(dev); - pci_set_drvdata(pci_dev, NULL); } #ifdef CONFIG_PM_SLEEP -- cgit v1.2.3-70-g09d2 From 12c51e13a1e54a2604e311b6fba01cb61636210b Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Mon, 9 Dec 2013 12:28:28 +0900 Subject: irda: via-ircc: remove unnecessary pci_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Signed-off-by: David S. Miller --- drivers/net/irda/via-ircc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c index 26cb45d5970..2900af091c2 100644 --- a/drivers/net/irda/via-ircc.c +++ b/drivers/net/irda/via-ircc.c @@ -407,7 +407,6 @@ static int via_ircc_open(struct pci_dev *pdev, chipio_t *info, unsigned int id) err_out2: release_region(self->io.fir_base, self->io.fir_ext); err_out1: - pci_set_drvdata(pdev, NULL); free_netdev(dev); return err; } @@ -441,7 +440,6 @@ static void via_remove_one(struct pci_dev *pdev) if (self->rx_buff.head) dma_free_coherent(&pdev->dev, self->rx_buff.truesize, self->rx_buff.head, self->rx_buff_dma); - pci_set_drvdata(pdev, NULL); free_netdev(self->netdev); -- cgit v1.2.3-70-g09d2 From 825d15de0e6698ba23790870edb031a5c120819b Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Mon, 9 Dec 2013 12:29:08 +0900 Subject: irda: vlsi_ir: remove unnecessary pci_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Signed-off-by: David S. Miller --- drivers/net/irda/vlsi_ir.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index cc9b8665e73..485006604bb 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -1693,7 +1693,6 @@ out_freedev: out_disable: pci_disable_device(pdev); out: - pci_set_drvdata(pdev, NULL); return -ENODEV; } @@ -1719,8 +1718,6 @@ static void vlsi_irda_remove(struct pci_dev *pdev) free_netdev(ndev); - pci_set_drvdata(pdev, NULL); - IRDA_MESSAGE("%s: %s removed\n", drivername, pci_name(pdev)); } -- cgit v1.2.3-70-g09d2 From 3c0d6d32eacf0f331636b804188ff8a2c9d740eb Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Mon, 9 Dec 2013 12:29:46 +0900 Subject: wan: dscc4: remove unnecessary pci_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Signed-off-by: David S. Miller --- drivers/net/wan/dscc4.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index 851dc7b7e8b..288610df205 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -699,8 +699,6 @@ static void dscc4_free1(struct pci_dev *pdev) for (i = 0; i < dev_per_card; i++) unregister_hdlc_device(dscc4_to_dev(root + i)); - pci_set_drvdata(pdev, NULL); - for (i = 0; i < dev_per_card; i++) free_netdev(root[i].dev); kfree(root); -- cgit v1.2.3-70-g09d2 From 94d6b538c7d2b273c34f36b2c55a332074b4940d Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Mon, 9 Dec 2013 12:30:41 +0900 Subject: wan: lmc: remove unnecessary pci_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Signed-off-by: David S. Miller --- drivers/net/wan/lmc/lmc_main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c index 7ef435bab42..c59b91f0366 100644 --- a/drivers/net/wan/lmc/lmc_main.c +++ b/drivers/net/wan/lmc/lmc_main.c @@ -973,7 +973,6 @@ static int lmc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) return 0; err_hdlcdev: - pci_set_drvdata(pdev, NULL); kfree(sc); err_kzalloc: pci_release_regions(pdev); @@ -995,7 +994,6 @@ static void lmc_remove_one(struct pci_dev *pdev) free_netdev(dev); pci_release_regions(pdev); pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); } } -- cgit v1.2.3-70-g09d2 From 06bbd681904d80aa76ed132fcc37d8887799b1cd Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Mon, 9 Dec 2013 12:31:12 +0900 Subject: wan: pc300too: remove unnecessary pci_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Signed-off-by: David S. Miller --- drivers/net/wan/pc300too.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wan/pc300too.c b/drivers/net/wan/pc300too.c index 53efc57fcac..5b72f7f8c51 100644 --- a/drivers/net/wan/pc300too.c +++ b/drivers/net/wan/pc300too.c @@ -281,7 +281,6 @@ static void pc300_pci_remove_one(struct pci_dev *pdev) pci_release_regions(pdev); pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); if (card->ports[0].netdev) free_netdev(card->ports[0].netdev); if (card->ports[1].netdev) -- cgit v1.2.3-70-g09d2 From 9e2c921f1dd2fa7695cbfebe6adad1b65fef67b5 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Mon, 9 Dec 2013 12:31:46 +0900 Subject: wan: pci200syn: remove unnecessary pci_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Signed-off-by: David S. Miller --- drivers/net/wan/pci200syn.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wan/pci200syn.c b/drivers/net/wan/pci200syn.c index ddbce54040e..fe4e3ece3c4 100644 --- a/drivers/net/wan/pci200syn.c +++ b/drivers/net/wan/pci200syn.c @@ -260,7 +260,6 @@ static void pci200_pci_remove_one(struct pci_dev *pdev) pci_release_regions(pdev); pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); if (card->ports[0].netdev) free_netdev(card->ports[0].netdev); if (card->ports[1].netdev) -- cgit v1.2.3-70-g09d2 From 42cd36abdf686264f25e6cb44e318fece3ab8805 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Mon, 9 Dec 2013 12:32:10 +0900 Subject: wan: wanxl: remove unnecessary pci_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Signed-off-by: David S. Miller --- drivers/net/wan/wanxl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c index 4c0a69779b8..f76aa908158 100644 --- a/drivers/net/wan/wanxl.c +++ b/drivers/net/wan/wanxl.c @@ -542,7 +542,6 @@ static void wanxl_pci_remove_one(struct pci_dev *pdev) pci_release_regions(pdev); pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); kfree(card); } -- cgit v1.2.3-70-g09d2 From 95dc19299f741c986227ec33e23cbf9b3321f812 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 5 Dec 2013 11:12:02 -0800 Subject: pkt_sched: give visibility to mq slave qdiscs Commit 6da7c8fcbcbd ("qdisc: allow setting default queuing discipline") added the ability to change default qdisc from pfifo_fast to say fq But as most modern ethernet devices are multiqueue, we cant really see all the statistics from "tc -s qdisc show", as the default root qdisc is mq. This patch adds the calls to qdisc_list_add() to mq and mqprio Signed-off-by: Eric Dumazet Cc: Stephen Hemminger Signed-off-by: David S. Miller --- include/net/pkt_sched.h | 1 + net/sched/sch_api.c | 3 ++- net/sched/sch_mq.c | 13 +++++++++---- net/sched/sch_mqprio.c | 10 ++++++---- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h index 59ec3cd15d6..891d80d2c4d 100644 --- a/include/net/pkt_sched.h +++ b/include/net/pkt_sched.h @@ -88,6 +88,7 @@ int unregister_qdisc(struct Qdisc_ops *qops); void qdisc_get_default(char *id, size_t len); int qdisc_set_default(const char *id); +void qdisc_list_add(struct Qdisc *q); void qdisc_list_del(struct Qdisc *q); struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle); struct Qdisc *qdisc_lookup_class(struct net_device *dev, u32 handle); diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index cd81505662b..547b4a88ae2 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -271,11 +271,12 @@ static struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle) return NULL; } -static void qdisc_list_add(struct Qdisc *q) +void qdisc_list_add(struct Qdisc *q) { if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) list_add_tail(&q->list, &qdisc_dev(q)->qdisc->list); } +EXPORT_SYMBOL(qdisc_list_add); void qdisc_list_del(struct Qdisc *q) { diff --git a/net/sched/sch_mq.c b/net/sched/sch_mq.c index 2e56185736d..a8b2864a696 100644 --- a/net/sched/sch_mq.c +++ b/net/sched/sch_mq.c @@ -78,14 +78,19 @@ static void mq_attach(struct Qdisc *sch) { struct net_device *dev = qdisc_dev(sch); struct mq_sched *priv = qdisc_priv(sch); - struct Qdisc *qdisc; + struct Qdisc *qdisc, *old; unsigned int ntx; for (ntx = 0; ntx < dev->num_tx_queues; ntx++) { qdisc = priv->qdiscs[ntx]; - qdisc = dev_graft_qdisc(qdisc->dev_queue, qdisc); - if (qdisc) - qdisc_destroy(qdisc); + old = dev_graft_qdisc(qdisc->dev_queue, qdisc); + if (old) + qdisc_destroy(old); +#ifdef CONFIG_NET_SCHED + if (ntx < dev->real_num_tx_queues) + qdisc_list_add(qdisc); +#endif + } kfree(priv->qdiscs); priv->qdiscs = NULL; diff --git a/net/sched/sch_mqprio.c b/net/sched/sch_mqprio.c index d44c868cb53..6749e2f540d 100644 --- a/net/sched/sch_mqprio.c +++ b/net/sched/sch_mqprio.c @@ -167,15 +167,17 @@ static void mqprio_attach(struct Qdisc *sch) { struct net_device *dev = qdisc_dev(sch); struct mqprio_sched *priv = qdisc_priv(sch); - struct Qdisc *qdisc; + struct Qdisc *qdisc, *old; unsigned int ntx; /* Attach underlying qdisc */ for (ntx = 0; ntx < dev->num_tx_queues; ntx++) { qdisc = priv->qdiscs[ntx]; - qdisc = dev_graft_qdisc(qdisc->dev_queue, qdisc); - if (qdisc) - qdisc_destroy(qdisc); + old = dev_graft_qdisc(qdisc->dev_queue, qdisc); + if (old) + qdisc_destroy(old); + if (ntx < dev->real_num_tx_queues) + qdisc_list_add(qdisc); } kfree(priv->qdiscs); priv->qdiscs = NULL; -- cgit v1.2.3-70-g09d2 From 4262e5ccbbb5171abd2921eed16ed339633d6478 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Fri, 6 Dec 2013 11:36:16 +0100 Subject: net: dev: move inline skb_needs_linearize helper to header As we need it elsewhere, move the inline helper function of skb_needs_linearize() over to skbuff.h include file. While at it, also convert the return to 'bool' instead of 'int' and add a proper kernel doc. Signed-off-by: Daniel Borkmann Signed-off-by: Jesper Dangaard Brouer Signed-off-by: David S. Miller --- include/linux/skbuff.h | 18 ++++++++++++++++++ net/core/dev.c | 15 --------------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 215b5ea1cb3..77c7aae1c6b 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -2392,6 +2392,24 @@ static inline void *skb_header_pointer(const struct sk_buff *skb, int offset, return buffer; } +/** + * skb_needs_linearize - check if we need to linearize a given skb + * depending on the given device features. + * @skb: socket buffer to check + * @features: net device features + * + * Returns true if either: + * 1. skb has frag_list and the device doesn't support FRAGLIST, or + * 2. skb is fragmented and the device does not support SG. + */ +static inline bool skb_needs_linearize(struct sk_buff *skb, + netdev_features_t features) +{ + return skb_is_nonlinear(skb) && + ((skb_has_frag_list(skb) && !(features & NETIF_F_FRAGLIST)) || + (skb_shinfo(skb)->nr_frags && !(features & NETIF_F_SG))); +} + static inline void skb_copy_from_linear_data(const struct sk_buff *skb, void *to, const unsigned int len) diff --git a/net/core/dev.c b/net/core/dev.c index 6cc98dd49c7..355df36360b 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2535,21 +2535,6 @@ netdev_features_t netif_skb_features(struct sk_buff *skb) } EXPORT_SYMBOL(netif_skb_features); -/* - * Returns true if either: - * 1. skb has frag_list and the device doesn't support FRAGLIST, or - * 2. skb is fragmented and the device does not support SG. - */ -static inline int skb_needs_linearize(struct sk_buff *skb, - netdev_features_t features) -{ - return skb_is_nonlinear(skb) && - ((skb_has_frag_list(skb) && - !(features & NETIF_F_FRAGLIST)) || - (skb_shinfo(skb)->nr_frags && - !(features & NETIF_F_SG))); -} - int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, struct netdev_queue *txq, void *accel_priv) { -- cgit v1.2.3-70-g09d2 From d346a3fae3ff1d99f5d0c819bf86edf9094a26a1 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Fri, 6 Dec 2013 11:36:17 +0100 Subject: packet: introduce PACKET_QDISC_BYPASS socket option This patch introduces a PACKET_QDISC_BYPASS socket option, that allows for using a similar xmit() function as in pktgen instead of taking the dev_queue_xmit() path. This can be very useful when PF_PACKET applications are required to be used in a similar scenario as pktgen, but with full, flexible packet payload that needs to be provided, for example. On default, nothing changes in behaviour for normal PF_PACKET TX users, so everything stays as is for applications. New users, however, can now set PACKET_QDISC_BYPASS if needed to prevent own packets from i) reentering packet_rcv() and ii) to directly push the frame to the driver. In doing so we can increase pps (here 64 byte packets) for PF_PACKET a bit: # CPUs -- QDISC_BYPASS -- qdisc path -- qdisc path[**] 1 CPU == 1,509,628 pps -- 1,208,708 -- 1,247,436 2 CPUs == 3,198,659 pps -- 2,536,012 -- 1,605,779 3 CPUs == 4,787,992 pps -- 3,788,740 -- 1,735,610 4 CPUs == 6,173,956 pps -- 4,907,799 -- 1,909,114 5 CPUs == 7,495,676 pps -- 5,956,499 -- 2,014,422 6 CPUs == 9,001,496 pps -- 7,145,064 -- 2,155,261 7 CPUs == 10,229,776 pps -- 8,190,596 -- 2,220,619 8 CPUs == 11,040,732 pps -- 9,188,544 -- 2,241,879 9 CPUs == 12,009,076 pps -- 10,275,936 -- 2,068,447 10 CPUs == 11,380,052 pps -- 11,265,337 -- 1,578,689 11 CPUs == 11,672,676 pps -- 11,845,344 -- 1,297,412 [...] 20 CPUs == 11,363,192 pps -- 11,014,933 -- 1,245,081 [**]: qdisc path with packet_rcv(), how probably most people seem to use it (hopefully not anymore if not needed) The test was done using a modified trafgen, sending a simple static 64 bytes packet, on all CPUs. The trick in the fast "qdisc path" case, is to avoid reentering packet_rcv() by setting the RAW socket protocol to zero, like: socket(PF_PACKET, SOCK_RAW, 0); Tradeoffs are documented as well in this patch, clearly, if queues are busy, we will drop more packets, tc disciplines are ignored, and these packets are not visible to taps anymore. For a pktgen like scenario, we argue that this is acceptable. The pointer to the xmit function has been placed in packet socket structure hole between cached_dev and prot_hook that is hot anyway as we're working on cached_dev in each send path. Done in joint work together with Jesper Dangaard Brouer. Signed-off-by: Daniel Borkmann Signed-off-by: Jesper Dangaard Brouer Signed-off-by: David S. Miller --- Documentation/networking/packet_mmap.txt | 21 ++++++++ include/uapi/linux/if_packet.h | 1 + net/packet/af_packet.c | 91 +++++++++++++++++++++++++++----- net/packet/internal.h | 1 + 4 files changed, 102 insertions(+), 12 deletions(-) diff --git a/Documentation/networking/packet_mmap.txt b/Documentation/networking/packet_mmap.txt index 8e48e3b1422..4288ffafba9 100644 --- a/Documentation/networking/packet_mmap.txt +++ b/Documentation/networking/packet_mmap.txt @@ -952,6 +952,27 @@ int main(int argc, char **argp) return 0; } +------------------------------------------------------------------------------- ++ PACKET_QDISC_BYPASS +------------------------------------------------------------------------------- + +If there is a requirement to load the network with many packets in a similar +fashion as pktgen does, you might set the following option after socket +creation: + + int one = 1; + setsockopt(fd, SOL_PACKET, PACKET_QDISC_BYPASS, &one, sizeof(one)); + +This has the side-effect, that packets sent through PF_PACKET will bypass the +kernel's qdisc layer and are forcedly pushed to the driver directly. Meaning, +packet are not buffered, tc disciplines are ignored, increased loss can occur +and such packets are also not visible to other PF_PACKET sockets anymore. So, +you have been warned; generally, this can be useful for stress testing various +components of a system. + +On default, PACKET_QDISC_BYPASS is disabled and needs to be explicitly enabled +on PF_PACKET sockets. + ------------------------------------------------------------------------------- + PACKET_TIMESTAMP ------------------------------------------------------------------------------- diff --git a/include/uapi/linux/if_packet.h b/include/uapi/linux/if_packet.h index dbf06667394..1e24aa701cb 100644 --- a/include/uapi/linux/if_packet.h +++ b/include/uapi/linux/if_packet.h @@ -51,6 +51,7 @@ struct sockaddr_ll { #define PACKET_TIMESTAMP 17 #define PACKET_FANOUT 18 #define PACKET_TX_HAS_OFF 19 +#define PACKET_QDISC_BYPASS 20 #define PACKET_FANOUT_HASH 0 #define PACKET_FANOUT_LB 1 diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index e4171dd9859..9d70f134992 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -237,6 +237,48 @@ struct packet_skb_cb { static void __fanout_unlink(struct sock *sk, struct packet_sock *po); static void __fanout_link(struct sock *sk, struct packet_sock *po); +static int packet_direct_xmit(struct sk_buff *skb) +{ + struct net_device *dev = skb->dev; + const struct net_device_ops *ops = dev->netdev_ops; + netdev_features_t features; + struct netdev_queue *txq; + u16 queue_map; + int ret; + + if (unlikely(!netif_running(dev) || + !netif_carrier_ok(dev))) { + kfree_skb(skb); + return NET_XMIT_DROP; + } + + features = netif_skb_features(skb); + if (skb_needs_linearize(skb, features) && + __skb_linearize(skb)) { + kfree_skb(skb); + return NET_XMIT_DROP; + } + + queue_map = skb_get_queue_mapping(skb); + txq = netdev_get_tx_queue(dev, queue_map); + + __netif_tx_lock_bh(txq); + if (unlikely(netif_xmit_frozen_or_stopped(txq))) { + ret = NETDEV_TX_BUSY; + kfree_skb(skb); + goto out; + } + + ret = ops->ndo_start_xmit(skb, dev); + if (likely(dev_xmit_complete(ret))) + txq_trans_update(txq); + else + kfree_skb(skb); +out: + __netif_tx_unlock_bh(txq); + return ret; +} + static struct net_device *packet_cached_dev_get(struct packet_sock *po) { struct net_device *dev; @@ -261,6 +303,16 @@ static void packet_cached_dev_reset(struct packet_sock *po) RCU_INIT_POINTER(po->cached_dev, NULL); } +static bool packet_use_direct_xmit(const struct packet_sock *po) +{ + return po->xmit == packet_direct_xmit; +} + +static u16 packet_pick_tx_queue(struct net_device *dev) +{ + return (u16) smp_processor_id() % dev->real_num_tx_queues; +} + /* register_prot_hook must be invoked with the po->bind_lock held, * or from a context in which asynchronous accesses to the packet * socket is not possible (packet_create()). @@ -1994,9 +2046,10 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, skb_reserve(skb, hlen); skb_reset_network_header(skb); - skb_probe_transport_header(skb, 0); - if (po->tp_tx_has_off) { + if (!packet_use_direct_xmit(po)) + skb_probe_transport_header(skb, 0); + if (unlikely(po->tp_tx_has_off)) { int off_min, off_max, off; off_min = po->tp_hdrlen - sizeof(struct sockaddr_ll); off_max = po->tx_ring.frame_size - tp_len; @@ -2166,12 +2219,13 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) } } + skb_set_queue_mapping(skb, packet_pick_tx_queue(dev)); skb->destructor = tpacket_destruct_skb; __packet_set_status(po, ph, TP_STATUS_SENDING); atomic_inc(&po->tx_ring.pending); status = TP_STATUS_SEND_REQUEST; - err = dev_queue_xmit(skb); + err = po->xmit(skb); if (unlikely(err > 0)) { err = net_xmit_errno(err); if (err && __packet_get_status(po, ph) == @@ -2230,8 +2284,7 @@ static struct sk_buff *packet_alloc_skb(struct sock *sk, size_t prepad, return skb; } -static int packet_snd(struct socket *sock, - struct msghdr *msg, size_t len) +static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) { struct sock *sk = sock->sk; struct sockaddr_ll *saddr = (struct sockaddr_ll *)msg->msg_name; @@ -2376,6 +2429,7 @@ static int packet_snd(struct socket *sock, skb->dev = dev; skb->priority = sk->sk_priority; skb->mark = sk->sk_mark; + skb_set_queue_mapping(skb, packet_pick_tx_queue(dev)); if (po->has_vnet_hdr) { if (vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) { @@ -2396,16 +2450,12 @@ static int packet_snd(struct socket *sock, len += vnet_hdr_len; } - skb_probe_transport_header(skb, reserve); - + if (!packet_use_direct_xmit(po)) + skb_probe_transport_header(skb, reserve); if (unlikely(extra_len == 4)) skb->no_fcs = 1; - /* - * Now send it - */ - - err = dev_queue_xmit(skb); + err = po->xmit(skb); if (err > 0 && (err = net_xmit_errno(err)) != 0) goto out_unlock; @@ -2427,6 +2477,7 @@ static int packet_sendmsg(struct kiocb *iocb, struct socket *sock, { struct sock *sk = sock->sk; struct packet_sock *po = pkt_sk(sk); + if (po->tx_ring.pg_vec) return tpacket_snd(po, msg); else @@ -2641,6 +2692,7 @@ static int packet_create(struct net *net, struct socket *sock, int protocol, po = pkt_sk(sk); sk->sk_family = PF_PACKET; po->num = proto; + po->xmit = dev_queue_xmit; packet_cached_dev_reset(po); @@ -3220,6 +3272,18 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv po->tp_tx_has_off = !!val; return 0; } + case PACKET_QDISC_BYPASS: + { + int val; + + if (optlen != sizeof(val)) + return -EINVAL; + if (copy_from_user(&val, optval, sizeof(val))) + return -EFAULT; + + po->xmit = val ? packet_direct_xmit : dev_queue_xmit; + return 0; + } default: return -ENOPROTOOPT; } @@ -3312,6 +3376,9 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, case PACKET_TX_HAS_OFF: val = po->tp_tx_has_off; break; + case PACKET_QDISC_BYPASS: + val = packet_use_direct_xmit(po); + break; default: return -ENOPROTOOPT; } diff --git a/net/packet/internal.h b/net/packet/internal.h index 1035fa2d909..0a87d7b36c9 100644 --- a/net/packet/internal.h +++ b/net/packet/internal.h @@ -114,6 +114,7 @@ struct packet_sock { unsigned int tp_tx_has_off:1; unsigned int tp_tstamp; struct net_device __rcu *cached_dev; + int (*xmit)(struct sk_buff *skb); struct packet_type prot_hook ____cacheline_aligned_in_smp; }; -- cgit v1.2.3-70-g09d2 From b73e9e3cf06ef8180c75a6bd28cdd1b833d22a3a Mon Sep 17 00:00:00 2001 From: wangweidong Date: Fri, 6 Dec 2013 19:24:33 +0800 Subject: x25: convert printks to pr_ use pr_ instead of printk(LEVEL) Suggested-by: Joe Perches Signed-off-by: Wang Weidong Signed-off-by: David S. Miller --- net/x25/af_x25.c | 4 +++- net/x25/x25_dev.c | 10 ++++++---- net/x25/x25_facilities.c | 14 ++++++++------ net/x25/x25_forward.c | 5 ++++- net/x25/x25_in.c | 4 +++- net/x25/x25_link.c | 6 ++++-- net/x25/x25_subr.c | 6 ++++-- 7 files changed, 32 insertions(+), 17 deletions(-) diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 7622789d375..c8a8297cd4b 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -35,6 +35,8 @@ * response */ +#define pr_fmt(fmt) "X25: " fmt + #include #include #include @@ -1809,7 +1811,7 @@ static int __init x25_init(void) if (rc != 0) goto out_sock; - printk(KERN_INFO "X.25 for Linux Version 0.2\n"); + pr_info("Linux Version 0.2\n"); x25_register_sysctl(); rc = x25_proc_init(); diff --git a/net/x25/x25_dev.c b/net/x25/x25_dev.c index a8a236338e6..39231237e1c 100644 --- a/net/x25/x25_dev.c +++ b/net/x25/x25_dev.c @@ -17,6 +17,8 @@ * 2000-09-04 Henner Eisen Prevent freeing a dangling skb. */ +#define pr_fmt(fmt) "X25: " fmt + #include #include #include @@ -89,7 +91,7 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *nb) */ if (frametype != X25_CLEAR_CONFIRMATION) - printk(KERN_DEBUG "x25_receive_data(): unknown frame type %2x\n",frametype); + pr_debug("x25_receive_data(): unknown frame type %2x\n",frametype); return 0; } @@ -114,7 +116,7 @@ int x25_lapb_receive_frame(struct sk_buff *skb, struct net_device *dev, */ nb = x25_get_neigh(dev); if (!nb) { - printk(KERN_DEBUG "X.25: unknown neighbour - %s\n", dev->name); + pr_debug("unknown neighbour - %s\n", dev->name); goto drop; } @@ -154,7 +156,7 @@ void x25_establish_link(struct x25_neigh *nb) switch (nb->dev->type) { case ARPHRD_X25: if ((skb = alloc_skb(1, GFP_ATOMIC)) == NULL) { - printk(KERN_ERR "x25_dev: out of memory\n"); + pr_err("x25_dev: out of memory\n"); return; } ptr = skb_put(skb, 1); @@ -189,7 +191,7 @@ void x25_terminate_link(struct x25_neigh *nb) skb = alloc_skb(1, GFP_ATOMIC); if (!skb) { - printk(KERN_ERR "x25_dev: out of memory\n"); + pr_err("x25_dev: out of memory\n"); return; } diff --git a/net/x25/x25_facilities.c b/net/x25/x25_facilities.c index b8253250d72..7ecd04c2136 100644 --- a/net/x25/x25_facilities.c +++ b/net/x25/x25_facilities.c @@ -21,6 +21,8 @@ * on response. */ +#define pr_fmt(fmt) "X25: " fmt + #include #include #include @@ -109,7 +111,7 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities, case X25_MARKER: break; default: - printk(KERN_DEBUG "X.25: unknown facility " + pr_debug("unknown facility " "%02X, value %02X\n", p[0], p[1]); break; @@ -132,7 +134,7 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities, *vc_fac_mask |= X25_MASK_WINDOW_SIZE; break; default: - printk(KERN_DEBUG "X.25: unknown facility " + pr_debug("unknown facility " "%02X, values %02X, %02X\n", p[0], p[1], p[2]); break; @@ -143,7 +145,7 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities, case X25_FAC_CLASS_C: if (len < 4) return -1; - printk(KERN_DEBUG "X.25: unknown facility %02X, " + pr_debug("unknown facility %02X, " "values %02X, %02X, %02X\n", p[0], p[1], p[2], p[3]); p += 4; @@ -172,7 +174,7 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities, *vc_fac_mask |= X25_MASK_CALLED_AE; break; default: - printk(KERN_DEBUG "X.25: unknown facility %02X," + pr_debug("unknown facility %02X," "length %d\n", p[0], p[1]); break; } @@ -341,12 +343,12 @@ void x25_limit_facilities(struct x25_facilities *facilities, if (!nb->extended) { if (facilities->winsize_in > 7) { - printk(KERN_DEBUG "X.25: incoming winsize limited to 7\n"); + pr_debug("incoming winsize limited to 7\n"); facilities->winsize_in = 7; } if (facilities->winsize_out > 7) { facilities->winsize_out = 7; - printk( KERN_DEBUG "X.25: outgoing winsize limited to 7\n"); + pr_debug("outgoing winsize limited to 7\n"); } } } diff --git a/net/x25/x25_forward.c b/net/x25/x25_forward.c index c541b622ae1..cf561f1613e 100644 --- a/net/x25/x25_forward.c +++ b/net/x25/x25_forward.c @@ -8,6 +8,9 @@ * History * 03-01-2007 Added forwarding for x.25 Andrew Hendry */ + +#define pr_fmt(fmt) "X25: " fmt + #include #include #include @@ -51,7 +54,7 @@ int x25_forward_call(struct x25_address *dest_addr, struct x25_neigh *from, list_for_each(entry, &x25_forward_list) { x25_frwd = list_entry(entry, struct x25_forward, node); if (x25_frwd->lci == lci) { - printk(KERN_WARNING "X.25: call request for lci which is already registered!, transmitting but not registering new pair\n"); + pr_warn("call request for lci which is already registered!, transmitting but not registering new pair\n"); same_lci = 1; } } diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c index a49cd4ec551..d1b0dc79bb6 100644 --- a/net/x25/x25_in.c +++ b/net/x25/x25_in.c @@ -23,6 +23,8 @@ * i-frames. */ +#define pr_fmt(fmt) "X25: " fmt + #include #include #include @@ -317,7 +319,7 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp break; default: - printk(KERN_WARNING "x25: unknown %02X in state 3\n", frametype); + pr_warn("unknown %02X in state 3\n", frametype); break; } diff --git a/net/x25/x25_link.c b/net/x25/x25_link.c index 4acacf3c661..fd5ffb25873 100644 --- a/net/x25/x25_link.c +++ b/net/x25/x25_link.c @@ -21,6 +21,8 @@ * 2000-09-04 Henner Eisen dev_hold() / dev_put() for x25_neigh. */ +#define pr_fmt(fmt) "X25: " fmt + #include #include #include @@ -93,13 +95,13 @@ void x25_link_control(struct sk_buff *skb, struct x25_neigh *nb, if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 4)) break; - printk(KERN_WARNING "x25: diagnostic #%d - %02X %02X %02X\n", + pr_warn("diagnostic #%d - %02X %02X %02X\n", skb->data[3], skb->data[4], skb->data[5], skb->data[6]); break; default: - printk(KERN_WARNING "x25: received unknown %02X with LCI 000\n", + pr_warn("received unknown %02X with LCI 000\n", frametype); break; } diff --git a/net/x25/x25_subr.c b/net/x25/x25_subr.c index 5170d52bfd9..6b5af65f491 100644 --- a/net/x25/x25_subr.c +++ b/net/x25/x25_subr.c @@ -23,6 +23,8 @@ * restriction on response. */ +#define pr_fmt(fmt) "X25: " fmt + #include #include #include @@ -148,7 +150,7 @@ void x25_write_internal(struct sock *sk, int frametype) case X25_RESET_CONFIRMATION: break; default: - printk(KERN_ERR "X.25: invalid frame type %02X\n", frametype); + pr_err("invalid frame type %02X\n", frametype); return; } @@ -338,7 +340,7 @@ int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q, } } - printk(KERN_DEBUG "X.25: invalid PLP frame %02X %02X %02X\n", + pr_debug("invalid PLP frame %02X %02X %02X\n", frame[0], frame[1], frame[2]); return X25_ILLEGAL; -- cgit v1.2.3-70-g09d2 From 512137eeff00f73a8a62e481a6575f1556cf962c Mon Sep 17 00:00:00 2001 From: Erik Hugne Date: Fri, 6 Dec 2013 10:08:00 -0500 Subject: tipc: remove interface state mirroring in bearer struct 'tipc_bearer' is a generic representation of the underlying media type, and exists in a one-to-one relationship to each interface TIPC is using. The struct contains a 'blocked' flag that mirrors the operational and execution state of the represented interface, and is updated through notification calls from the latter. The users of tipc_bearer are checking this flag before each attempt to send a packet via the interface. This state mirroring serves no purpose in the current code base. TIPC links will not discover a media failure any faster through this mechanism, and in reality the flag only adds overhead at packet sending and reception. Furthermore, the fact that the flag needs to be protected by a spinlock aggregated into tipc_bearer has turned out to cause a serious and completely unnecessary deadlock problem. CPU0 CPU1 ---- ---- Time 0: bearer_disable() link_timeout() Time 1: spin_lock_bh(&b_ptr->lock) tipc_link_push_queue() Time 2: tipc_link_delete() tipc_bearer_blocked(b_ptr) Time 3: k_cancel_timer(&req->timer) spin_lock_bh(&b_ptr->lock) Time 4: del_timer_sync(&req->timer) I.e., del_timer_sync() on CPU0 never returns, because the timer handler on CPU1 is waiting for the bearer lock. We eliminate the 'blocked' flag from struct tipc_bearer, along with all tests on this flag. This not only resolves the deadlock, but also simplifies and speeds up the data path execution of TIPC. It also fits well into our ongoing effort to make the locking policy simpler and more manageable. An effect of this change is that we can get rid of functions such as tipc_bearer_blocked(), tipc_continue() and tipc_block_bearer(). We replace the latter with a new function, tipc_reset_bearer(), which resets all links associated to the bearer immediately after an interface goes down. A user might notice one slight change in link behaviour after this change. When an interface goes down, (e.g. through a NETDEV_DOWN event) all attached links will be reset immediately, instead of leaving it to each link to detect the failure through a timer-driven mechanism. We consider this an improvement, and see no obvious risks with the new behavior. Signed-off-by: Erik Hugne Reviewed-by: Ying Xue Reviewed-by: Paul Gortmaker Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/bcast.c | 6 ------ net/tipc/bearer.c | 33 +++---------------------------- net/tipc/bearer.h | 6 +----- net/tipc/discover.c | 17 ++++------------ net/tipc/eth_media.c | 14 ++----------- net/tipc/ib_media.c | 14 ++----------- net/tipc/link.c | 55 +++++++++++++++------------------------------------- 7 files changed, 28 insertions(+), 117 deletions(-) diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 0d4402587fd..4c2a80b3c01 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -621,12 +621,6 @@ static int tipc_bcbearer_send(struct sk_buff *buf, struct tipc_bearer *unused1, if (!p) break; /* No more bearers to try */ - if (tipc_bearer_blocked(p)) { - if (!s || tipc_bearer_blocked(s)) - continue; /* Can't use either bearer */ - b = s; - } - tipc_nmap_diff(&bcbearer->remains, &b->nodes, &bcbearer->remains_new); if (bcbearer->remains_new.count == bcbearer->remains.count) diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 3f9707a16d0..c2101c0bfd6 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -275,31 +275,6 @@ void tipc_bearer_remove_dest(struct tipc_bearer *b_ptr, u32 dest) tipc_disc_remove_dest(b_ptr->link_req); } -/* - * Interrupt enabling new requests after bearer blocking: - * See bearer_send(). - */ -void tipc_continue(struct tipc_bearer *b) -{ - spin_lock_bh(&b->lock); - b->blocked = 0; - spin_unlock_bh(&b->lock); -} - -/* - * tipc_bearer_blocked - determines if bearer is currently blocked - */ -int tipc_bearer_blocked(struct tipc_bearer *b) -{ - int res; - - spin_lock_bh(&b->lock); - res = b->blocked; - spin_unlock_bh(&b->lock); - - return res; -} - /** * tipc_enable_bearer - enable bearer with the given name */ @@ -420,17 +395,16 @@ exit: } /** - * tipc_block_bearer - Block the bearer, and reset all its links + * tipc_reset_bearer - Reset all links established over this bearer */ -int tipc_block_bearer(struct tipc_bearer *b_ptr) +int tipc_reset_bearer(struct tipc_bearer *b_ptr) { struct tipc_link *l_ptr; struct tipc_link *temp_l_ptr; read_lock_bh(&tipc_net_lock); - pr_info("Blocking bearer <%s>\n", b_ptr->name); + pr_info("Resetting bearer <%s>\n", b_ptr->name); spin_lock_bh(&b_ptr->lock); - b_ptr->blocked = 1; list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) { struct tipc_node *n_ptr = l_ptr->owner; @@ -456,7 +430,6 @@ static void bearer_disable(struct tipc_bearer *b_ptr) pr_info("Disabling bearer <%s>\n", b_ptr->name); spin_lock_bh(&b_ptr->lock); - b_ptr->blocked = 1; b_ptr->media->disable_media(b_ptr); list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) { tipc_link_delete(l_ptr); diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h index e5e04be6fff..cc780bbedbb 100644 --- a/net/tipc/bearer.h +++ b/net/tipc/bearer.h @@ -108,7 +108,6 @@ struct tipc_media { * struct tipc_bearer - TIPC bearer structure * @usr_handle: pointer to additional media-specific information about bearer * @mtu: max packet size bearer can support - * @blocked: non-zero if bearer is blocked * @lock: spinlock for controlling access to bearer * @addr: media-specific address associated with bearer * @name: bearer name (format = media:interface) @@ -130,7 +129,6 @@ struct tipc_media { struct tipc_bearer { void *usr_handle; /* initalized by media */ u32 mtu; /* initalized by media */ - int blocked; /* initalized by media */ struct tipc_media_addr addr; /* initalized by media */ char name[TIPC_MAX_BEARER_NAME]; spinlock_t lock; @@ -163,8 +161,7 @@ int tipc_register_media(struct tipc_media *m_ptr); void tipc_recv_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr); -int tipc_block_bearer(struct tipc_bearer *b_ptr); -void tipc_continue(struct tipc_bearer *tb_ptr); +int tipc_reset_bearer(struct tipc_bearer *b_ptr); int tipc_enable_bearer(const char *bearer_name, u32 disc_domain, u32 priority); int tipc_disable_bearer(const char *name); @@ -194,7 +191,6 @@ void tipc_bearer_remove_dest(struct tipc_bearer *b_ptr, u32 dest); struct tipc_bearer *tipc_bearer_find(const char *name); struct tipc_bearer *tipc_bearer_find_interface(const char *if_name); struct tipc_media *tipc_media_find(const char *name); -int tipc_bearer_blocked(struct tipc_bearer *b_ptr); void tipc_bearer_stop(void); /** diff --git a/net/tipc/discover.c b/net/tipc/discover.c index ecc758c6eac..bc849f1efa1 100644 --- a/net/tipc/discover.c +++ b/net/tipc/discover.c @@ -239,7 +239,7 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr) /* Accept discovery message & send response, if necessary */ link_fully_up = link_working_working(link); - if ((type == DSC_REQ_MSG) && !link_fully_up && !b_ptr->blocked) { + if ((type == DSC_REQ_MSG) && !link_fully_up) { rbuf = tipc_disc_init_msg(DSC_RESP_MSG, orig, b_ptr); if (rbuf) { tipc_bearer_send(b_ptr, rbuf, &media_addr); @@ -287,16 +287,6 @@ void tipc_disc_remove_dest(struct tipc_link_req *req) disc_update(req); } -/** - * disc_send_msg - send link setup request message - * @req: ptr to link request structure - */ -static void disc_send_msg(struct tipc_link_req *req) -{ - if (!req->bearer->blocked) - tipc_bearer_send(req->bearer, req->buf, &req->dest); -} - /** * disc_timeout - send a periodic link setup request * @req: ptr to link request structure @@ -322,7 +312,8 @@ static void disc_timeout(struct tipc_link_req *req) * hold at fast polling rate if don't have any associated nodes, * otherwise hold at slow polling rate */ - disc_send_msg(req); + tipc_bearer_send(req->bearer, req->buf, &req->dest); + req->timer_intv *= 2; if (req->num_nodes) @@ -368,7 +359,7 @@ int tipc_disc_create(struct tipc_bearer *b_ptr, struct tipc_media_addr *dest, k_init_timer(&req->timer, (Handler)disc_timeout, (unsigned long)req); k_start_timer(&req->timer, req->timer_intv); b_ptr->link_req = req; - disc_send_msg(req); + tipc_bearer_send(req->bearer, req->buf, &req->dest); return 0; } diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c index f80d59f5a16..1e3c33250db 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c @@ -199,7 +199,6 @@ static int enable_media(struct tipc_bearer *tb_ptr) tb_ptr->bcast_addr.media_id = TIPC_MEDIA_TYPE_ETH; tb_ptr->bcast_addr.broadcast = 1; tb_ptr->mtu = dev->mtu; - tb_ptr->blocked = 0; eth_media_addr_set(tb_ptr, &tb_ptr->addr, (char *)dev->dev_addr); return 0; } @@ -263,20 +262,11 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt, switch (evt) { case NETDEV_CHANGE: if (netif_carrier_ok(dev)) - tipc_continue(eb_ptr->bearer); - else - tipc_block_bearer(eb_ptr->bearer); - break; - case NETDEV_UP: - tipc_continue(eb_ptr->bearer); - break; + break; case NETDEV_DOWN: - tipc_block_bearer(eb_ptr->bearer); - break; case NETDEV_CHANGEMTU: case NETDEV_CHANGEADDR: - tipc_block_bearer(eb_ptr->bearer); - tipc_continue(eb_ptr->bearer); + tipc_reset_bearer(eb_ptr->bearer); break; case NETDEV_UNREGISTER: case NETDEV_CHANGENAME: diff --git a/net/tipc/ib_media.c b/net/tipc/ib_media.c index c1398929746..cbe7fe15cc7 100644 --- a/net/tipc/ib_media.c +++ b/net/tipc/ib_media.c @@ -192,7 +192,6 @@ static int enable_media(struct tipc_bearer *tb_ptr) tb_ptr->bcast_addr.media_id = TIPC_MEDIA_TYPE_IB; tb_ptr->bcast_addr.broadcast = 1; tb_ptr->mtu = dev->mtu; - tb_ptr->blocked = 0; ib_media_addr_set(tb_ptr, &tb_ptr->addr, (char *)dev->dev_addr); return 0; } @@ -256,20 +255,11 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt, switch (evt) { case NETDEV_CHANGE: if (netif_carrier_ok(dev)) - tipc_continue(ib_ptr->bearer); - else - tipc_block_bearer(ib_ptr->bearer); - break; - case NETDEV_UP: - tipc_continue(ib_ptr->bearer); - break; + break; case NETDEV_DOWN: - tipc_block_bearer(ib_ptr->bearer); - break; case NETDEV_CHANGEMTU: case NETDEV_CHANGEADDR: - tipc_block_bearer(ib_ptr->bearer); - tipc_continue(ib_ptr->bearer); + tipc_reset_bearer(ib_ptr->bearer); break; case NETDEV_UNREGISTER: case NETDEV_CHANGENAME: diff --git a/net/tipc/link.c b/net/tipc/link.c index 69cd9bf3f56..fd340ad742e 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -790,8 +790,7 @@ int tipc_link_send_buf(struct tipc_link *l_ptr, struct sk_buff *buf) return link_send_long_buf(l_ptr, buf); /* Packet can be queued or sent. */ - if (likely(!tipc_bearer_blocked(l_ptr->b_ptr) && - !link_congested(l_ptr))) { + if (likely(!link_congested(l_ptr))) { link_add_to_outqueue(l_ptr, buf, msg); tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr); @@ -957,14 +956,13 @@ static int link_send_buf_fast(struct tipc_link *l_ptr, struct sk_buff *buf, if (likely(!link_congested(l_ptr))) { if (likely(msg_size(msg) <= l_ptr->max_pkt)) { - if (likely(!tipc_bearer_blocked(l_ptr->b_ptr))) { - link_add_to_outqueue(l_ptr, buf, msg); - tipc_bearer_send(l_ptr->b_ptr, buf, - &l_ptr->media_addr); - l_ptr->unacked_window = 0; - return res; - } - } else + link_add_to_outqueue(l_ptr, buf, msg); + tipc_bearer_send(l_ptr->b_ptr, buf, + &l_ptr->media_addr); + l_ptr->unacked_window = 0; + return res; + } + else *used_max_pkt = l_ptr->max_pkt; } return tipc_link_send_buf(l_ptr, buf); /* All other cases */ @@ -1013,8 +1011,7 @@ exit: } /* Exit if link (or bearer) is congested */ - if (link_congested(l_ptr) || - tipc_bearer_blocked(l_ptr->b_ptr)) { + if (link_congested(l_ptr)) { res = link_schedule_port(l_ptr, sender->ref, res); goto exit; @@ -1281,9 +1278,6 @@ void tipc_link_push_queue(struct tipc_link *l_ptr) { u32 res; - if (tipc_bearer_blocked(l_ptr->b_ptr)) - return; - do { res = tipc_link_push_packet(l_ptr); } while (!res); @@ -1370,26 +1364,15 @@ void tipc_link_retransmit(struct tipc_link *l_ptr, struct sk_buff *buf, msg = buf_msg(buf); - if (tipc_bearer_blocked(l_ptr->b_ptr)) { - if (l_ptr->retransm_queue_size == 0) { - l_ptr->retransm_queue_head = msg_seqno(msg); - l_ptr->retransm_queue_size = retransmits; - } else { - pr_err("Unexpected retransmit on link %s (qsize=%d)\n", - l_ptr->name, l_ptr->retransm_queue_size); + /* Detect repeated retransmit failures */ + if (l_ptr->last_retransmitted == msg_seqno(msg)) { + if (++l_ptr->stale_count > 100) { + link_retransmit_failure(l_ptr, buf); + return; } - return; } else { - /* Detect repeated retransmit failures on unblocked bearer */ - if (l_ptr->last_retransmitted == msg_seqno(msg)) { - if (++l_ptr->stale_count > 100) { - link_retransmit_failure(l_ptr, buf); - return; - } - } else { - l_ptr->last_retransmitted = msg_seqno(msg); - l_ptr->stale_count = 1; - } + l_ptr->last_retransmitted = msg_seqno(msg); + l_ptr->stale_count = 1; } while (retransmits && (buf != l_ptr->next_out) && buf) { @@ -1861,12 +1844,6 @@ void tipc_link_send_proto_msg(struct tipc_link *l_ptr, u32 msg_typ, skb_copy_to_linear_data(buf, msg, sizeof(l_ptr->proto_msg)); buf->priority = TC_PRIO_CONTROL; - /* Defer message if bearer is already blocked */ - if (tipc_bearer_blocked(l_ptr->b_ptr)) { - l_ptr->proto_msg_queue = buf; - return; - } - tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr); l_ptr->unacked_window = 0; kfree_skb(buf); -- cgit v1.2.3-70-g09d2 From ca2f09f2b2c6c25047cfc545d057c4edfcfe561c Mon Sep 17 00:00:00 2001 From: Paul Durrant Date: Fri, 6 Dec 2013 16:36:07 +0000 Subject: xen-netback: improve guest-receive-side flow control The way that flow control works without this patch is that, in start_xmit() the code uses xenvif_count_skb_slots() to predict how many slots xenvif_gop_skb() will consume and then adds this to a 'req_cons_peek' counter which it then uses to determine if the shared ring has that amount of space available by checking whether 'req_prod' has passed that value. If the ring doesn't have space the tx queue is stopped. xenvif_gop_skb() will then consume slots and update 'req_cons' and issue responses, updating 'rsp_prod' as it goes. The frontend will consume those responses and post new requests, by updating req_prod. So, req_prod chases req_cons which chases rsp_prod, and can never exceed that value. Thus if xenvif_count_skb_slots() ever returns a number of slots greater than xenvif_gop_skb() uses, req_cons_peek will get to a value that req_prod cannot possibly achieve (since it's limited by the 'real' req_cons) and, if this happens enough times, req_cons_peek gets more than a ring size ahead of req_cons and the tx queue then remains stopped forever waiting for an unachievable amount of space to become available in the ring. Having two routines trying to calculate the same value is always going to be fragile, so this patch does away with that. All we essentially need to do is make sure that we have 'enough stuff' on our internal queue without letting it build up uncontrollably. So start_xmit() makes a cheap optimistic check of how much space is needed for an skb and only turns the queue off if that is unachievable. net_rx_action() is the place where we could do with an accurate predicition but, since that has proven tricky to calculate, a cheap worse-case (but not too bad) estimate is all we really need since the only thing we *must* prevent is xenvif_gop_skb() consuming more slots than are available. Without this patch I can trivially stall netback permanently by just doing a large guest to guest file copy between two Windows Server 2008R2 VMs on a single host. Patch tested with frontends in: - Windows Server 2008R2 - CentOS 6.0 - Debian Squeeze - Debian Wheezy - SLES11 Signed-off-by: Paul Durrant Cc: Wei Liu Cc: Ian Campbell Cc: David Vrabel Cc: Annie Li Cc: Konrad Rzeszutek Wilk Acked-by: Wei Liu Signed-off-by: David S. Miller --- drivers/net/xen-netback/common.h | 27 ++--- drivers/net/xen-netback/interface.c | 47 ++++---- drivers/net/xen-netback/netback.c | 217 ++++++++++++------------------------ 3 files changed, 106 insertions(+), 185 deletions(-) diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 08ae01b41c8..ba30a6d9fef 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -136,12 +136,10 @@ struct xenvif { char rx_irq_name[IFNAMSIZ+4]; /* DEVNAME-rx */ struct xen_netif_rx_back_ring rx; struct sk_buff_head rx_queue; - - /* Allow xenvif_start_xmit() to peek ahead in the rx request - * ring. This is a prediction of what rx_req_cons will be - * once all queued skbs are put on the ring. + /* Set when the RX interrupt is triggered by the frontend. + * The worker thread may need to wake the queue. */ - RING_IDX rx_req_cons_peek; + bool rx_event; /* Given MAX_BUFFER_OFFSET of 4096 the worst case is that each * head/fragment page uses 2 copy operations because it @@ -198,8 +196,6 @@ void xenvif_xenbus_fini(void); int xenvif_schedulable(struct xenvif *vif); -int xenvif_rx_ring_full(struct xenvif *vif); - int xenvif_must_stop_queue(struct xenvif *vif); /* (Un)Map communication rings. */ @@ -211,21 +207,20 @@ int xenvif_map_frontend_rings(struct xenvif *vif, /* Check for SKBs from frontend and schedule backend processing */ void xenvif_check_rx_xenvif(struct xenvif *vif); -/* Queue an SKB for transmission to the frontend */ -void xenvif_queue_tx_skb(struct xenvif *vif, struct sk_buff *skb); -/* Notify xenvif that ring now has space to send an skb to the frontend */ -void xenvif_notify_tx_completion(struct xenvif *vif); - /* Prevent the device from generating any further traffic. */ void xenvif_carrier_off(struct xenvif *vif); -/* Returns number of ring slots required to send an skb to the frontend */ -unsigned int xenvif_count_skb_slots(struct xenvif *vif, struct sk_buff *skb); - int xenvif_tx_action(struct xenvif *vif, int budget); -void xenvif_rx_action(struct xenvif *vif); int xenvif_kthread(void *data); +void xenvif_kick_thread(struct xenvif *vif); + +/* Determine whether the needed number of slots (req) are available, + * and set req_event if not. + */ +bool xenvif_rx_ring_slots_available(struct xenvif *vif, int needed); + +void xenvif_stop_queue(struct xenvif *vif); extern bool separate_tx_rx_irq; diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index 870f1fa5837..1dcb9606e6e 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -46,11 +46,6 @@ int xenvif_schedulable(struct xenvif *vif) return netif_running(vif->dev) && netif_carrier_ok(vif->dev); } -static int xenvif_rx_schedulable(struct xenvif *vif) -{ - return xenvif_schedulable(vif) && !xenvif_rx_ring_full(vif); -} - static irqreturn_t xenvif_tx_interrupt(int irq, void *dev_id) { struct xenvif *vif = dev_id; @@ -104,8 +99,8 @@ static irqreturn_t xenvif_rx_interrupt(int irq, void *dev_id) { struct xenvif *vif = dev_id; - if (xenvif_rx_schedulable(vif)) - netif_wake_queue(vif->dev); + vif->rx_event = true; + xenvif_kick_thread(vif); return IRQ_HANDLED; } @@ -121,24 +116,35 @@ static irqreturn_t xenvif_interrupt(int irq, void *dev_id) static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct xenvif *vif = netdev_priv(dev); + int min_slots_needed; BUG_ON(skb->dev != dev); /* Drop the packet if vif is not ready */ - if (vif->task == NULL) + if (vif->task == NULL || !xenvif_schedulable(vif)) goto drop; - /* Drop the packet if the target domain has no receive buffers. */ - if (!xenvif_rx_schedulable(vif)) - goto drop; + /* At best we'll need one slot for the header and one for each + * frag. + */ + min_slots_needed = 1 + skb_shinfo(skb)->nr_frags; - /* Reserve ring slots for the worst-case number of fragments. */ - vif->rx_req_cons_peek += xenvif_count_skb_slots(vif, skb); + /* If the skb is GSO then we'll also need an extra slot for the + * metadata. + */ + if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4 || + skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) + min_slots_needed++; - if (vif->can_queue && xenvif_must_stop_queue(vif)) - netif_stop_queue(dev); + /* If the skb can't possibly fit in the remaining slots + * then turn off the queue to give the ring a chance to + * drain. + */ + if (!xenvif_rx_ring_slots_available(vif, min_slots_needed)) + xenvif_stop_queue(vif); - xenvif_queue_tx_skb(vif, skb); + skb_queue_tail(&vif->rx_queue, skb); + xenvif_kick_thread(vif); return NETDEV_TX_OK; @@ -148,12 +154,6 @@ static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } -void xenvif_notify_tx_completion(struct xenvif *vif) -{ - if (netif_queue_stopped(vif->dev) && xenvif_rx_schedulable(vif)) - netif_wake_queue(vif->dev); -} - static struct net_device_stats *xenvif_get_stats(struct net_device *dev) { struct xenvif *vif = netdev_priv(dev); @@ -378,6 +378,8 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref, if (err < 0) goto err; + init_waitqueue_head(&vif->wq); + if (tx_evtchn == rx_evtchn) { /* feature-split-event-channels == 0 */ err = bind_interdomain_evtchn_to_irqhandler( @@ -410,7 +412,6 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref, disable_irq(vif->rx_irq); } - init_waitqueue_head(&vif->wq); task = kthread_create(xenvif_kthread, (void *)vif, "%s", vif->dev->name); if (IS_ERR(task)) { diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index acf13920e6d..43341b82649 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -138,36 +138,26 @@ static inline pending_ring_idx_t nr_pending_reqs(struct xenvif *vif) vif->pending_prod + vif->pending_cons; } -static int max_required_rx_slots(struct xenvif *vif) +bool xenvif_rx_ring_slots_available(struct xenvif *vif, int needed) { - int max = DIV_ROUND_UP(vif->dev->mtu, PAGE_SIZE); + RING_IDX prod, cons; - /* XXX FIXME: RX path dependent on MAX_SKB_FRAGS */ - if (vif->can_sg || vif->gso_mask || vif->gso_prefix_mask) - max += MAX_SKB_FRAGS + 1; /* extra_info + frags */ - - return max; -} - -int xenvif_rx_ring_full(struct xenvif *vif) -{ - RING_IDX peek = vif->rx_req_cons_peek; - RING_IDX needed = max_required_rx_slots(vif); + do { + prod = vif->rx.sring->req_prod; + cons = vif->rx.req_cons; - return ((vif->rx.sring->req_prod - peek) < needed) || - ((vif->rx.rsp_prod_pvt + XEN_NETIF_RX_RING_SIZE - peek) < needed); -} + if (prod - cons >= needed) + return true; -int xenvif_must_stop_queue(struct xenvif *vif) -{ - if (!xenvif_rx_ring_full(vif)) - return 0; + vif->rx.sring->req_event = prod + 1; - vif->rx.sring->req_event = vif->rx_req_cons_peek + - max_required_rx_slots(vif); - mb(); /* request notification /then/ check the queue */ + /* Make sure event is visible before we check prod + * again. + */ + mb(); + } while (vif->rx.sring->req_prod != prod); - return xenvif_rx_ring_full(vif); + return false; } /* @@ -210,93 +200,6 @@ static bool start_new_rx_buffer(int offset, unsigned long size, int head) return false; } -struct xenvif_count_slot_state { - unsigned long copy_off; - bool head; -}; - -unsigned int xenvif_count_frag_slots(struct xenvif *vif, - unsigned long offset, unsigned long size, - struct xenvif_count_slot_state *state) -{ - unsigned count = 0; - - offset &= ~PAGE_MASK; - - while (size > 0) { - unsigned long bytes; - - bytes = PAGE_SIZE - offset; - - if (bytes > size) - bytes = size; - - if (start_new_rx_buffer(state->copy_off, bytes, state->head)) { - count++; - state->copy_off = 0; - } - - if (state->copy_off + bytes > MAX_BUFFER_OFFSET) - bytes = MAX_BUFFER_OFFSET - state->copy_off; - - state->copy_off += bytes; - - offset += bytes; - size -= bytes; - - if (offset == PAGE_SIZE) - offset = 0; - - state->head = false; - } - - return count; -} - -/* - * Figure out how many ring slots we're going to need to send @skb to - * the guest. This function is essentially a dry run of - * xenvif_gop_frag_copy. - */ -unsigned int xenvif_count_skb_slots(struct xenvif *vif, struct sk_buff *skb) -{ - struct xenvif_count_slot_state state; - unsigned int count; - unsigned char *data; - unsigned i; - - state.head = true; - state.copy_off = 0; - - /* Slot for the first (partial) page of data. */ - count = 1; - - /* Need a slot for the GSO prefix for GSO extra data? */ - if (skb_shinfo(skb)->gso_size) - count++; - - data = skb->data; - while (data < skb_tail_pointer(skb)) { - unsigned long offset = offset_in_page(data); - unsigned long size = PAGE_SIZE - offset; - - if (data + size > skb_tail_pointer(skb)) - size = skb_tail_pointer(skb) - data; - - count += xenvif_count_frag_slots(vif, offset, size, &state); - - data += size; - } - - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - unsigned long size = skb_frag_size(&skb_shinfo(skb)->frags[i]); - unsigned long offset = skb_shinfo(skb)->frags[i].page_offset; - - count += xenvif_count_frag_slots(vif, offset, size, &state); - } - return count; -} - struct netrx_pending_operations { unsigned copy_prod, copy_cons; unsigned meta_prod, meta_cons; @@ -557,12 +460,12 @@ struct skb_cb_overlay { int meta_slots_used; }; -static void xenvif_kick_thread(struct xenvif *vif) +void xenvif_kick_thread(struct xenvif *vif) { wake_up(&vif->wq); } -void xenvif_rx_action(struct xenvif *vif) +static void xenvif_rx_action(struct xenvif *vif) { s8 status; u16 flags; @@ -571,8 +474,6 @@ void xenvif_rx_action(struct xenvif *vif) struct sk_buff *skb; LIST_HEAD(notify); int ret; - int nr_frags; - int count; unsigned long offset; struct skb_cb_overlay *sco; int need_to_notify = 0; @@ -584,29 +485,44 @@ void xenvif_rx_action(struct xenvif *vif) skb_queue_head_init(&rxq); - count = 0; - while ((skb = skb_dequeue(&vif->rx_queue)) != NULL) { - vif = netdev_priv(skb->dev); - nr_frags = skb_shinfo(skb)->nr_frags; + int max_slots_needed; + int i; + + /* We need a cheap worse case estimate for the number of + * slots we'll use. + */ + + max_slots_needed = DIV_ROUND_UP(offset_in_page(skb->data) + + skb_headlen(skb), + PAGE_SIZE); + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + unsigned int size; + size = skb_frag_size(&skb_shinfo(skb)->frags[i]); + max_slots_needed += DIV_ROUND_UP(size, PAGE_SIZE); + } + if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4 || + skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) + max_slots_needed++; + + /* If the skb may not fit then bail out now */ + if (!xenvif_rx_ring_slots_available(vif, max_slots_needed)) { + skb_queue_head(&vif->rx_queue, skb); + need_to_notify = 1; + break; + } sco = (struct skb_cb_overlay *)skb->cb; sco->meta_slots_used = xenvif_gop_skb(skb, &npo); - - count += nr_frags + 1; + BUG_ON(sco->meta_slots_used > max_slots_needed); __skb_queue_tail(&rxq, skb); - - /* Filled the batch queue? */ - /* XXX FIXME: RX path dependent on MAX_SKB_FRAGS */ - if (count + MAX_SKB_FRAGS >= XEN_NETIF_RX_RING_SIZE) - break; } BUG_ON(npo.meta_prod > ARRAY_SIZE(vif->meta)); if (!npo.copy_prod) - return; + goto done; BUG_ON(npo.copy_prod > ARRAY_SIZE(vif->grant_copy_op)); gnttab_batch_copy(vif->grant_copy_op, npo.copy_prod); @@ -614,8 +530,6 @@ void xenvif_rx_action(struct xenvif *vif) while ((skb = __skb_dequeue(&rxq)) != NULL) { sco = (struct skb_cb_overlay *)skb->cb; - vif = netdev_priv(skb->dev); - if ((1 << vif->meta[npo.meta_cons].gso_type) & vif->gso_prefix_mask) { resp = RING_GET_RESPONSE(&vif->rx, @@ -681,25 +595,13 @@ void xenvif_rx_action(struct xenvif *vif) if (ret) need_to_notify = 1; - xenvif_notify_tx_completion(vif); - npo.meta_cons += sco->meta_slots_used; dev_kfree_skb(skb); } +done: if (need_to_notify) notify_remote_via_irq(vif->rx_irq); - - /* More work to do? */ - if (!skb_queue_empty(&vif->rx_queue)) - xenvif_kick_thread(vif); -} - -void xenvif_queue_tx_skb(struct xenvif *vif, struct sk_buff *skb) -{ - skb_queue_tail(&vif->rx_queue, skb); - - xenvif_kick_thread(vif); } void xenvif_check_rx_xenvif(struct xenvif *vif) @@ -1804,7 +1706,7 @@ static struct xen_netif_rx_response *make_rx_response(struct xenvif *vif, static inline int rx_work_todo(struct xenvif *vif) { - return !skb_queue_empty(&vif->rx_queue); + return !skb_queue_empty(&vif->rx_queue) || vif->rx_event; } static inline int tx_work_todo(struct xenvif *vif) @@ -1854,8 +1756,6 @@ int xenvif_map_frontend_rings(struct xenvif *vif, rxs = (struct xen_netif_rx_sring *)addr; BACK_RING_INIT(&vif->rx, rxs, PAGE_SIZE); - vif->rx_req_cons_peek = 0; - return 0; err: @@ -1863,9 +1763,24 @@ err: return err; } +void xenvif_stop_queue(struct xenvif *vif) +{ + if (!vif->can_queue) + return; + + netif_stop_queue(vif->dev); +} + +static void xenvif_start_queue(struct xenvif *vif) +{ + if (xenvif_schedulable(vif)) + netif_wake_queue(vif->dev); +} + int xenvif_kthread(void *data) { struct xenvif *vif = data; + struct sk_buff *skb; while (!kthread_should_stop()) { wait_event_interruptible(vif->wq, @@ -1874,12 +1789,22 @@ int xenvif_kthread(void *data) if (kthread_should_stop()) break; - if (rx_work_todo(vif)) + if (!skb_queue_empty(&vif->rx_queue)) xenvif_rx_action(vif); + vif->rx_event = false; + + if (skb_queue_empty(&vif->rx_queue) && + netif_queue_stopped(vif->dev)) + xenvif_start_queue(vif); + cond_resched(); } + /* Bin any remaining skbs */ + while ((skb = skb_dequeue(&vif->rx_queue)) != NULL) + dev_kfree_skb(skb); + return 0; } -- cgit v1.2.3-70-g09d2 From 41e4af69a5984a3193ba3108fb4e067b0e34dc73 Mon Sep 17 00:00:00 2001 From: Zhi Yong Wu Date: Sat, 7 Dec 2013 04:54:59 +0800 Subject: macvtap: remove useless codes in macvtap_aio_read() and macvtap_recvmsg() By checking related codes, it is impossible that ret > len or total_len, so we should remove some useless coeds in both above functions. Signed-off-by: Zhi Yong Wu Signed-off-by: David S. Miller --- drivers/net/macvtap.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 4a34bcb6549..2aa5e973ef1 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -871,7 +871,6 @@ static ssize_t macvtap_aio_read(struct kiocb *iocb, const struct iovec *iv, } ret = macvtap_do_read(q, iv, len, file->f_flags & O_NONBLOCK); - ret = min_t(ssize_t, ret, len); /* XXX copied from tun.c. Why? */ if (ret > 0) iocb->ki_pos = ret; out: @@ -1106,10 +1105,6 @@ static int macvtap_recvmsg(struct kiocb *iocb, struct socket *sock, return -EINVAL; ret = macvtap_do_read(q, m->msg_iov, total_len, flags & MSG_DONTWAIT); - if (ret > total_len) { - m->msg_flags |= MSG_TRUNC; - ret = flags & MSG_TRUNC ? ret : total_len; - } return ret; } -- cgit v1.2.3-70-g09d2 From 73713357ab58aacda1af715bb5a623528dbbfd79 Mon Sep 17 00:00:00 2001 From: Zhi Yong Wu Date: Sat, 7 Dec 2013 04:55:00 +0800 Subject: tun: remove useless codes in tun_chr_aio_read() and tun_recvmsg() By checking related codes, it is impossible that ret > len or total_len, so we should remove some useless codes in both above functions. Signed-off-by: Zhi Yong Wu Signed-off-by: David S. Miller --- drivers/net/tun.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 3c5a8d8cde5..bbb69351291 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1354,7 +1354,6 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv, ret = tun_do_read(tun, tfile, iv, len, file->f_flags & O_NONBLOCK); - ret = min_t(ssize_t, ret, len); if (ret > 0) iocb->ki_pos = ret; out: @@ -1455,10 +1454,6 @@ static int tun_recvmsg(struct kiocb *iocb, struct socket *sock, } ret = tun_do_read(tun, tfile, m->msg_iov, total_len, flags & MSG_DONTWAIT); - if (ret > total_len) { - m->msg_flags |= MSG_TRUNC; - ret = flags & MSG_TRUNC ? ret : total_len; - } out: tun_put(tun); return ret; -- cgit v1.2.3-70-g09d2 From 114002bc1af6c63de4c003f8c5d3ca0bb430d987 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 6 Dec 2013 13:01:30 -0800 Subject: net: phy: report link partner features through ethtool The PHY library already reads the MII_STAT1000 and MII_LPA registers in genphy_read_status(), so extend it to also populate the PHY device link partner advertised features such that we can feed this back into ethtool when asked for it in phy_ethtool_gset(). Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 1 + drivers/net/phy/phy_device.c | 6 ++++++ include/linux/phy.h | 5 +++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 36c6994436b..05cb8fe742f 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -289,6 +289,7 @@ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd) cmd->supported = phydev->supported; cmd->advertising = phydev->advertising; + cmd->lp_advertising = phydev->lp_advertising; ethtool_cmd_speed_set(cmd, phydev->speed); cmd->duplex = phydev->duplex; diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index d6447b3f740..6db36595eac 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -839,6 +839,8 @@ int genphy_read_status(struct phy_device *phydev) if (err) return err; + phydev->lp_advertising = 0; + if (AUTONEG_ENABLE == phydev->autoneg) { if (phydev->supported & (SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)) { @@ -852,6 +854,8 @@ int genphy_read_status(struct phy_device *phydev) if (adv < 0) return adv; + phydev->lp_advertising = + mii_stat1000_to_ethtool_lpa_t(lpagb); lpagb &= adv << 2; } @@ -860,6 +864,8 @@ int genphy_read_status(struct phy_device *phydev) if (lpa < 0) return lpa; + phydev->lp_advertising |= mii_lpa_to_ethtool_lpa_t(lpa); + adv = phy_read(phydev, MII_ADVERTISE); if (adv < 0) diff --git a/include/linux/phy.h b/include/linux/phy.h index 7ff751ae6f0..90a666e0884 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -287,8 +287,8 @@ struct phy_c45_device_ids { * adjust_state: Callback for the enet driver to respond to * changes in the state machine. * - * speed, duplex, pause, supported, advertising, and - * autoneg are used like in mii_if_info + * speed, duplex, pause, supported, advertising, lp_advertising, + * and autoneg are used like in mii_if_info * * interrupts currently only supports enabled or disabled, * but could be changed in the future to support enabling @@ -340,6 +340,7 @@ struct phy_device { /* See mii.h for more info */ u32 supported; u32 advertising; + u32 lp_advertising; int autoneg; -- cgit v1.2.3-70-g09d2 From 2613f95f614b39681f77a5036046ea395e306e28 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 6 Dec 2013 13:01:31 -0800 Subject: net: phy: use phy_init_hw instead of open-coding it Use phy_init_hw() instead of open-coding it in phy_mii_ioctl(), this improves consistenty and makes sure that we will not duplicate the same routine somewhere else. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 05cb8fe742f..5d7101b3b60 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -361,11 +361,8 @@ int phy_mii_ioctl(struct phy_device *phydev, mii_data->reg_num, val); if (mii_data->reg_num == MII_BMCR && - val & BMCR_RESET && - phydev->drv->config_init) { - phy_scan_fixups(phydev); - phydev->drv->config_init(phydev); - } + val & BMCR_RESET) + phy_init_hw(phydev); break; case SIOCSHWTSTAMP: -- cgit v1.2.3-70-g09d2 From f0528ce7a43d51090b45cf27c53e4b343facaade Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 6 Dec 2013 13:01:32 -0800 Subject: net: greth: use phy_read_status() In case the greth driver is bound to anything but the Generic PHY driver or the PHY has a special read_status callback implemented, unexpected things will happen. Make sure we that we use phy_read_status() which does the proper abstraction of calling the driver specific read_status() callback for a given PHY. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/aeroflex/greth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/aeroflex/greth.c b/drivers/net/ethernet/aeroflex/greth.c index e0669455514..b20cbf0323e 100644 --- a/drivers/net/ethernet/aeroflex/greth.c +++ b/drivers/net/ethernet/aeroflex/greth.c @@ -1361,7 +1361,7 @@ static int greth_mdio_init(struct greth_private *greth) timeout = jiffies + 6*HZ; while (!phy_aneg_done(greth->phy) && time_before(jiffies, timeout)) { } - genphy_read_status(greth->phy); + phy_read_status(greth->phy); greth_link_change(greth->netdev); } -- cgit v1.2.3-70-g09d2 From 06d87cec73d883690f690e72da498e7f0334f9bc Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 6 Dec 2013 13:01:33 -0800 Subject: net: bfin_mac: do not reset PHY after phy_start() The PHY is already reset during driver probing, and this manual reset after calling phy_start() will wipe out board-specific PHY fixups and driver specific configuration initialization. Remove that explicit PHY reset. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/adi/bfin_mac.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/adi/bfin_mac.c b/drivers/net/ethernet/adi/bfin_mac.c index 0d4f2957987..c0f68dcd1dc 100644 --- a/drivers/net/ethernet/adi/bfin_mac.c +++ b/drivers/net/ethernet/adi/bfin_mac.c @@ -1557,7 +1557,6 @@ static int bfin_mac_open(struct net_device *dev) return ret; phy_start(lp->phydev); - phy_write(lp->phydev, MII_BMCR, BMCR_RESET); setup_system_regs(dev); setup_mac_addr(dev->dev_addr); -- cgit v1.2.3-70-g09d2 From 87aa9f9c61ad56d505641681812e92ad976f8608 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 6 Dec 2013 13:01:34 -0800 Subject: net: phy: consolidate PHY reset in phy_init_hw() There are quite a lot of drivers touching a PHY device MII_BMCR register to reset the PHY without taking care of: 1) ensuring that BMCR_RESET is cleared after a given timeout 2) the PHY state machine resuming to the proper state and re-applying potentially changed settings such as auto-negotiation Introduce phy_poll_reset() which will take care of polling the MII_BMCR for the BMCR_RESET bit to be cleared after a given timeout or return a timeout error code. In order to make sure the PHY is in a correct state, phy_init_hw() first issues a software reset through MII_BMCR and then applies any fixups. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- Documentation/networking/phy.txt | 3 ++- drivers/net/phy/phy.c | 5 ++-- drivers/net/phy/phy_device.c | 56 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 60 insertions(+), 4 deletions(-) diff --git a/Documentation/networking/phy.txt b/Documentation/networking/phy.txt index d5b1a393524..ebf27071940 100644 --- a/Documentation/networking/phy.txt +++ b/Documentation/networking/phy.txt @@ -255,7 +255,8 @@ Writing a PHY driver config_init: configures PHY into a sane state after a reset. For instance, a Davicom PHY requires descrambling disabled. - probe: Does any setup needed by the driver + probe: Allocate phy->priv, optionally refuse to bind. + PHY may not have been reset or had fixups run yet. suspend/resume: power management config_aneg: Changes the speed/duplex/negotiation settings read_status: Reads the current speed/duplex/negotiation settings diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 5d7101b3b60..e3dd69100da 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -318,6 +318,7 @@ int phy_mii_ioctl(struct phy_device *phydev, { struct mii_ioctl_data *mii_data = if_mii(ifr); u16 val = mii_data->val_in; + int ret = 0; switch (cmd) { case SIOCGMIIPHY: @@ -362,7 +363,7 @@ int phy_mii_ioctl(struct phy_device *phydev, if (mii_data->reg_num == MII_BMCR && val & BMCR_RESET) - phy_init_hw(phydev); + ret = phy_init_hw(phydev); break; case SIOCSHWTSTAMP: @@ -374,7 +375,7 @@ int phy_mii_ioctl(struct phy_device *phydev, return -EOPNOTSUPP; } - return 0; + return ret; } EXPORT_SYMBOL(phy_mii_ioctl); diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 6db36595eac..5a619f0dcf7 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -364,7 +364,11 @@ int phy_device_register(struct phy_device *phydev) phydev->bus->phy_map[phydev->addr] = phydev; /* Run all of the fixups for this PHY */ - phy_scan_fixups(phydev); + err = phy_init_hw(phydev); + if (err) { + pr_err("PHY %d failed to initialize\n", phydev->addr); + goto out; + } err = device_add(&phydev->dev); if (err) { @@ -497,6 +501,47 @@ void phy_disconnect(struct phy_device *phydev) } EXPORT_SYMBOL(phy_disconnect); +/** + * phy_poll_reset - Safely wait until a PHY reset has properly completed + * @phydev: The PHY device to poll + * + * Description: According to IEEE 802.3, Section 2, Subsection 22.2.4.1.1, as + * published in 2008, a PHY reset may take up to 0.5 seconds. The MII BMCR + * register must be polled until the BMCR_RESET bit clears. + * + * Furthermore, any attempts to write to PHY registers may have no effect + * or even generate MDIO bus errors until this is complete. + * + * Some PHYs (such as the Marvell 88E1111) don't entirely conform to the + * standard and do not fully reset after the BMCR_RESET bit is set, and may + * even *REQUIRE* a soft-reset to properly restart autonegotiation. In an + * effort to support such broken PHYs, this function is separate from the + * standard phy_init_hw() which will zero all the other bits in the BMCR + * and reapply all driver-specific and board-specific fixups. + */ +static int phy_poll_reset(struct phy_device *phydev) +{ + /* Poll until the reset bit clears (50ms per retry == 0.6 sec) */ + unsigned int retries = 12; + int ret; + + do { + msleep(50); + ret = phy_read(phydev, MII_BMCR); + if (ret < 0) + return ret; + } while (ret & BMCR_RESET && --retries); + if (ret & BMCR_RESET) + return -ETIMEDOUT; + + /* + * Some chips (smsc911x) may still need up to another 1ms after the + * BMCR_RESET bit is cleared before they are usable. + */ + msleep(1); + return 0; +} + int phy_init_hw(struct phy_device *phydev) { int ret; @@ -504,12 +549,21 @@ int phy_init_hw(struct phy_device *phydev) if (!phydev->drv || !phydev->drv->config_init) return 0; + ret = phy_write(phydev, MII_BMCR, BMCR_RESET); + if (ret < 0) + return ret; + + ret = phy_poll_reset(phydev); + if (ret < 0) + return ret; + ret = phy_scan_fixups(phydev); if (ret < 0) return ret; return phydev->drv->config_init(phydev); } +EXPORT_SYMBOL(phy_init_hw); /** * phy_attach_direct - attach a network device to a given PHY device pointer -- cgit v1.2.3-70-g09d2 From 7cd1463664c2a15721ff4ccfb61d4d970815cb3d Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 6 Dec 2013 13:01:35 -0800 Subject: net: mv643xx_eth: use phy_init_hw to reset PHY Instead of open-coding a PHY reset through the MII BMCR register, use phy_init_hw() which does that for us and will also make sure that PHY fixups are applied if required. We also remove a call to phy_reset() due to the following sequence of calls in the driver: phy_scan() -> phy_connect() -> phy_connect_direct() -> phy_attach_direct() -> phy_init_hw() and we only have a call to phy_init() after phy_scan(). Signed-off-by: Florian Fainelli Tested-by: Sebastian Hesselbarth Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mv643xx_eth.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c index fa905052fbf..b3d9327f78b 100644 --- a/drivers/net/ethernet/marvell/mv643xx_eth.c +++ b/drivers/net/ethernet/marvell/mv643xx_eth.c @@ -2066,23 +2066,6 @@ static inline void oom_timer_wrapper(unsigned long data) napi_schedule(&mp->napi); } -static void phy_reset(struct mv643xx_eth_private *mp) -{ - int data; - - data = phy_read(mp->phy, MII_BMCR); - if (data < 0) - return; - - data |= BMCR_RESET; - if (phy_write(mp->phy, MII_BMCR, data) < 0) - return; - - do { - data = phy_read(mp->phy, MII_BMCR); - } while (data >= 0 && data & BMCR_RESET); -} - static void port_start(struct mv643xx_eth_private *mp) { u32 pscr; @@ -2095,7 +2078,7 @@ static void port_start(struct mv643xx_eth_private *mp) struct ethtool_cmd cmd; mv643xx_eth_get_settings(mp->dev, &cmd); - phy_reset(mp); + phy_init_hw(mp->phy); mv643xx_eth_set_settings(mp->dev, &cmd); } @@ -2763,8 +2746,6 @@ static void phy_init(struct mv643xx_eth_private *mp, int speed, int duplex) { struct phy_device *phy = mp->phy; - phy_reset(mp); - if (speed == 0) { phy->autoneg = AUTONEG_ENABLE; phy->speed = 0; -- cgit v1.2.3-70-g09d2 From 78de53f05c58784e366b9115575058a5815c89d6 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 6 Dec 2013 13:01:36 -0800 Subject: net: pxa168_eth: use phy_init_hw for PHY reset Instead of open-coding a PHY reset through the MII BMCR register, use phy_init_hw() which does this for us and ensures that PHY device fixups are also applied. We also remove a call to ethernet_phy_reset() which is now unncessary since phy_attach() calls phy_attach_direct() which in turns calls phy_init_hw(). Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/pxa168_eth.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/drivers/net/ethernet/marvell/pxa168_eth.c b/drivers/net/ethernet/marvell/pxa168_eth.c index 2ad32417a52..452e81de33d 100644 --- a/drivers/net/ethernet/marvell/pxa168_eth.c +++ b/drivers/net/ethernet/marvell/pxa168_eth.c @@ -320,23 +320,6 @@ static void ethernet_phy_set_addr(struct pxa168_eth_private *pep, int phy_addr) wrl(pep, PHY_ADDRESS, reg_data); } -static void ethernet_phy_reset(struct pxa168_eth_private *pep) -{ - int data; - - data = phy_read(pep->phy, MII_BMCR); - if (data < 0) - return; - - data |= BMCR_RESET; - if (phy_write(pep->phy, MII_BMCR, data) < 0) - return; - - do { - data = phy_read(pep->phy, MII_BMCR); - } while (data >= 0 && data & BMCR_RESET); -} - static void rxq_refill(struct net_device *dev) { struct pxa168_eth_private *pep = netdev_priv(dev); @@ -645,7 +628,7 @@ static void eth_port_start(struct net_device *dev) struct ethtool_cmd cmd; pxa168_get_settings(pep->dev, &cmd); - ethernet_phy_reset(pep); + phy_init_hw(pep->phy); pxa168_set_settings(pep->dev, &cmd); } @@ -1382,7 +1365,6 @@ static struct phy_device *phy_scan(struct pxa168_eth_private *pep, int phy_addr) static void phy_init(struct pxa168_eth_private *pep, int speed, int duplex) { struct phy_device *phy = pep->phy; - ethernet_phy_reset(pep); phy_attach(pep->dev, dev_name(&phy->dev), PHY_INTERFACE_MODE_MII); -- cgit v1.2.3-70-g09d2 From 01b0114e068480226bc22fea18c3bccbd815ce8b Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 6 Dec 2013 13:01:37 -0800 Subject: net: tc35815: use phy_init_hw for PHY reset Instead of open-coding the PHY reset through MII BMCR, use phy_init_hw() which does that for us and also makes sure that any PHY specific fixups are applied. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/toshiba/tc35815.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/toshiba/tc35815.c b/drivers/net/ethernet/toshiba/tc35815.c index 1322546d92a..f6b3212ec33 100644 --- a/drivers/net/ethernet/toshiba/tc35815.c +++ b/drivers/net/ethernet/toshiba/tc35815.c @@ -1170,19 +1170,12 @@ static int tc35815_tx_full(struct net_device *dev) static void tc35815_restart(struct net_device *dev) { struct tc35815_local *lp = netdev_priv(dev); + int ret; if (lp->phy_dev) { - int timeout; - - phy_write(lp->phy_dev, MII_BMCR, BMCR_RESET); - timeout = 100; - while (--timeout) { - if (!(phy_read(lp->phy_dev, MII_BMCR) & BMCR_RESET)) - break; - udelay(1); - } - if (!timeout) - printk(KERN_ERR "%s: BMCR reset failed.\n", dev->name); + ret = phy_init_hw(lp->phy_dev); + if (ret) + printk(KERN_ERR "%s: PHY init failed.\n", dev->name); } spin_lock_bh(&lp->rx_lock); -- cgit v1.2.3-70-g09d2 From 0c9eb5b931c3da3a79faa889b903dc7bd318203c Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 6 Dec 2013 13:01:38 -0800 Subject: net: sh_eth: do not issue a wild PHY reset through BMCR The sh_eth driver issues an uncontrolled PHY reset through the MII register BMCR but fails to wait for the reset to complete, and will also implicitely wipe out all possible PHY fixups applied. Use phy_init_hw() which remedies both problems. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/sh_eth.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index d256ce19d4d..6761dde7007 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -1704,7 +1704,10 @@ static int sh_eth_phy_start(struct net_device *ndev) return ret; /* reset phy - this also wakes it from PDOWN */ - phy_write(mdp->phydev, MII_BMCR, BMCR_RESET); + ret = phy_init_hw(mdp->phydev); + if (ret) + return ret; + phy_start(mdp->phydev); return 0; -- cgit v1.2.3-70-g09d2 From 1f9248e5606afc6485255e38ad57bdac08fa7711 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 7 Dec 2013 19:26:53 +0100 Subject: neigh: convert parms to an array This patch converts the neigh param members to an array. This allows easier manipulation which will be needed later on to provide better management of default values. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- include/net/neighbour.h | 48 +++++-- net/802/hippi.c | 4 +- net/core/neighbour.c | 327 ++++++++++++++++++++---------------------------- net/decnet/dn_neigh.c | 28 +++-- net/ipv4/arp.c | 33 ++--- net/ipv6/addrconf.c | 12 +- net/ipv6/ndisc.c | 43 ++++--- 7 files changed, 238 insertions(+), 257 deletions(-) diff --git a/include/net/neighbour.h b/include/net/neighbour.h index 536501a3e58..4cb5478e2f6 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h @@ -37,6 +37,32 @@ struct neighbour; +enum { + NEIGH_VAR_MCAST_PROBES, + NEIGH_VAR_UCAST_PROBES, + NEIGH_VAR_APP_PROBES, + NEIGH_VAR_RETRANS_TIME, + NEIGH_VAR_BASE_REACHABLE_TIME, + NEIGH_VAR_DELAY_PROBE_TIME, + NEIGH_VAR_GC_STALETIME, + NEIGH_VAR_QUEUE_LEN_BYTES, + NEIGH_VAR_PROXY_QLEN, + NEIGH_VAR_ANYCAST_DELAY, + NEIGH_VAR_PROXY_DELAY, + NEIGH_VAR_LOCKTIME, +#define NEIGH_VAR_DATA_MAX (NEIGH_VAR_LOCKTIME + 1) + /* Following are used as a second way to access one of the above */ + NEIGH_VAR_QUEUE_LEN, /* same data as NEIGH_VAR_QUEUE_LEN_BYTES */ + NEIGH_VAR_RETRANS_TIME_MS, /* same data as NEIGH_VAR_RETRANS_TIME */ + NEIGH_VAR_BASE_REACHABLE_TIME_MS, /* same data as NEIGH_VAR_BASE_REACHABLE_TIME */ + /* Following are used by "default" only */ + NEIGH_VAR_GC_INTERVAL, + NEIGH_VAR_GC_THRESH1, + NEIGH_VAR_GC_THRESH2, + NEIGH_VAR_GC_THRESH3, + NEIGH_VAR_MAX +}; + struct neigh_parms { #ifdef CONFIG_NET_NS struct net *net; @@ -53,22 +79,18 @@ struct neigh_parms { atomic_t refcnt; struct rcu_head rcu_head; - int base_reachable_time; - int retrans_time; - int gc_staletime; int reachable_time; - int delay_probe_time; - - int queue_len_bytes; - int ucast_probes; - int app_probes; - int mcast_probes; - int anycast_delay; - int proxy_delay; - int proxy_qlen; - int locktime; + int data[NEIGH_VAR_DATA_MAX]; }; +static inline void neigh_var_set(struct neigh_parms *p, int index, int val) +{ + p->data[index] = val; +} + +#define NEIGH_VAR(p, attr) ((p)->data[NEIGH_VAR_ ## attr]) +#define NEIGH_VAR_SET(p, attr, val) neigh_var_set(p, NEIGH_VAR_ ## attr, val) + struct neigh_statistics { unsigned long allocs; /* number of allocated neighs */ unsigned long destroys; /* number of destroyed neighs */ diff --git a/net/802/hippi.c b/net/802/hippi.c index 51a1f530417..a97a3bde77b 100644 --- a/net/802/hippi.c +++ b/net/802/hippi.c @@ -172,14 +172,14 @@ EXPORT_SYMBOL(hippi_mac_addr); int hippi_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p) { /* Never send broadcast/multicast ARP messages */ - p->mcast_probes = 0; + NEIGH_VAR_SET(p, MCAST_PROBES, 0); /* In IPv6 unicast probes are valid even on NBMA, * because they are encapsulated in normal IPv6 protocol. * Should be a generic flag. */ if (p->tbl->family != AF_INET6) - p->ucast_probes = 0; + NEIGH_VAR_SET(p, UCAST_PROBES, 0); return 0; } EXPORT_SYMBOL(hippi_neigh_setup_dev); diff --git a/net/core/neighbour.c b/net/core/neighbour.c index ca15f32821f..742fa10d437 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -497,7 +497,7 @@ struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey, goto out_neigh_release; } - n->confirmed = jiffies - (n->parms->base_reachable_time << 1); + n->confirmed = jiffies - (NEIGH_VAR(n->parms, BASE_REACHABLE_TIME) << 1); write_lock_bh(&tbl->lock); nht = rcu_dereference_protected(tbl->nht, @@ -776,7 +776,7 @@ static void neigh_periodic_work(struct work_struct *work) tbl->last_rand = jiffies; for (p = &tbl->parms; p; p = p->next) p->reachable_time = - neigh_rand_reach_time(p->base_reachable_time); + neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME)); } for (i = 0 ; i < (1 << nht->hash_shift); i++) { @@ -799,7 +799,7 @@ static void neigh_periodic_work(struct work_struct *work) if (atomic_read(&n->refcnt) == 1 && (state == NUD_FAILED || - time_after(jiffies, n->used + n->parms->gc_staletime))) { + time_after(jiffies, n->used + NEIGH_VAR(n->parms, GC_STALETIME)))) { *np = n->next; n->dead = 1; write_unlock(&n->lock); @@ -822,12 +822,12 @@ next_elt: lockdep_is_held(&tbl->lock)); } out: - /* Cycle through all hash buckets every base_reachable_time/2 ticks. - * ARP entry timeouts range from 1/2 base_reachable_time to 3/2 - * base_reachable_time. + /* Cycle through all hash buckets every BASE_REACHABLE_TIME/2 ticks. + * ARP entry timeouts range from 1/2 BASE_REACHABLE_TIME to 3/2 + * BASE_REACHABLE_TIME. */ schedule_delayed_work(&tbl->gc_work, - tbl->parms.base_reachable_time >> 1); + NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME) >> 1); write_unlock_bh(&tbl->lock); } @@ -835,8 +835,9 @@ static __inline__ int neigh_max_probes(struct neighbour *n) { struct neigh_parms *p = n->parms; return (n->nud_state & NUD_PROBE) ? - p->ucast_probes : - p->ucast_probes + p->app_probes + p->mcast_probes; + NEIGH_VAR(p, UCAST_PROBES) : + NEIGH_VAR(p, UCAST_PROBES) + NEIGH_VAR(p, APP_PROBES) + + NEIGH_VAR(p, MCAST_PROBES); } static void neigh_invalidate(struct neighbour *neigh) @@ -901,12 +902,13 @@ static void neigh_timer_handler(unsigned long arg) neigh_dbg(2, "neigh %p is still alive\n", neigh); next = neigh->confirmed + neigh->parms->reachable_time; } else if (time_before_eq(now, - neigh->used + neigh->parms->delay_probe_time)) { + neigh->used + + NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) { neigh_dbg(2, "neigh %p is delayed\n", neigh); neigh->nud_state = NUD_DELAY; neigh->updated = jiffies; neigh_suspect(neigh); - next = now + neigh->parms->delay_probe_time; + next = now + NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME); } else { neigh_dbg(2, "neigh %p is suspected\n", neigh); neigh->nud_state = NUD_STALE; @@ -916,7 +918,8 @@ static void neigh_timer_handler(unsigned long arg) } } else if (state & NUD_DELAY) { if (time_before_eq(now, - neigh->confirmed + neigh->parms->delay_probe_time)) { + neigh->confirmed + + NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) { neigh_dbg(2, "neigh %p is now reachable\n", neigh); neigh->nud_state = NUD_REACHABLE; neigh->updated = jiffies; @@ -928,11 +931,11 @@ static void neigh_timer_handler(unsigned long arg) neigh->nud_state = NUD_PROBE; neigh->updated = jiffies; atomic_set(&neigh->probes, 0); - next = now + neigh->parms->retrans_time; + next = now + NEIGH_VAR(neigh->parms, RETRANS_TIME); } } else { /* NUD_PROBE|NUD_INCOMPLETE */ - next = now + neigh->parms->retrans_time; + next = now + NEIGH_VAR(neigh->parms, RETRANS_TIME); } if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) && @@ -973,13 +976,16 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb) goto out_unlock_bh; if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) { - if (neigh->parms->mcast_probes + neigh->parms->app_probes) { + if (NEIGH_VAR(neigh->parms, MCAST_PROBES) + + NEIGH_VAR(neigh->parms, APP_PROBES)) { unsigned long next, now = jiffies; - atomic_set(&neigh->probes, neigh->parms->ucast_probes); + atomic_set(&neigh->probes, + NEIGH_VAR(neigh->parms, UCAST_PROBES)); neigh->nud_state = NUD_INCOMPLETE; neigh->updated = now; - next = now + max(neigh->parms->retrans_time, HZ/2); + next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME), + HZ/2); neigh_add_timer(neigh, next); immediate_probe = true; } else { @@ -994,14 +1000,14 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb) neigh_dbg(2, "neigh %p is delayed\n", neigh); neigh->nud_state = NUD_DELAY; neigh->updated = jiffies; - neigh_add_timer(neigh, - jiffies + neigh->parms->delay_probe_time); + neigh_add_timer(neigh, jiffies + + NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME)); } if (neigh->nud_state == NUD_INCOMPLETE) { if (skb) { while (neigh->arp_queue_len_bytes + skb->truesize > - neigh->parms->queue_len_bytes) { + NEIGH_VAR(neigh->parms, QUEUE_LEN_BYTES)) { struct sk_buff *buff; buff = __skb_dequeue(&neigh->arp_queue); @@ -1170,7 +1176,7 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, neigh_update_hhs(neigh); if (!(new & NUD_CONNECTED)) neigh->confirmed = jiffies - - (neigh->parms->base_reachable_time << 1); + (NEIGH_VAR(neigh->parms, BASE_REACHABLE_TIME) << 1); notify = 1; } if (new == old) @@ -1391,9 +1397,10 @@ void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p, struct sk_buff *skb) { unsigned long now = jiffies; - unsigned long sched_next = now + (net_random() % p->proxy_delay); + unsigned long sched_next = now + (net_random() % + NEIGH_VAR(p, PROXY_DELAY)); - if (tbl->proxy_queue.qlen > p->proxy_qlen) { + if (tbl->proxy_queue.qlen > NEIGH_VAR(p, PROXY_QLEN)) { kfree_skb(skb); return; } @@ -1440,7 +1447,7 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev, p->tbl = tbl; atomic_set(&p->refcnt, 1); p->reachable_time = - neigh_rand_reach_time(p->base_reachable_time); + neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME)); dev_hold(dev); p->dev = dev; write_pnet(&p->net, hold_net(net)); @@ -1509,7 +1516,7 @@ static void neigh_table_init_no_netlink(struct neigh_table *tbl) write_pnet(&tbl->parms.net, &init_net); atomic_set(&tbl->parms.refcnt, 1); tbl->parms.reachable_time = - neigh_rand_reach_time(tbl->parms.base_reachable_time); + neigh_rand_reach_time(NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME)); tbl->stats = alloc_percpu(struct neigh_statistics); if (!tbl->stats) @@ -1777,24 +1784,32 @@ static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms) if ((parms->dev && nla_put_u32(skb, NDTPA_IFINDEX, parms->dev->ifindex)) || nla_put_u32(skb, NDTPA_REFCNT, atomic_read(&parms->refcnt)) || - nla_put_u32(skb, NDTPA_QUEUE_LENBYTES, parms->queue_len_bytes) || + nla_put_u32(skb, NDTPA_QUEUE_LENBYTES, + NEIGH_VAR(parms, QUEUE_LEN_BYTES)) || /* approximative value for deprecated QUEUE_LEN (in packets) */ nla_put_u32(skb, NDTPA_QUEUE_LEN, - parms->queue_len_bytes / SKB_TRUESIZE(ETH_FRAME_LEN)) || - nla_put_u32(skb, NDTPA_PROXY_QLEN, parms->proxy_qlen) || - nla_put_u32(skb, NDTPA_APP_PROBES, parms->app_probes) || - nla_put_u32(skb, NDTPA_UCAST_PROBES, parms->ucast_probes) || - nla_put_u32(skb, NDTPA_MCAST_PROBES, parms->mcast_probes) || + NEIGH_VAR(parms, QUEUE_LEN_BYTES) / SKB_TRUESIZE(ETH_FRAME_LEN)) || + nla_put_u32(skb, NDTPA_PROXY_QLEN, NEIGH_VAR(parms, PROXY_QLEN)) || + nla_put_u32(skb, NDTPA_APP_PROBES, NEIGH_VAR(parms, APP_PROBES)) || + nla_put_u32(skb, NDTPA_UCAST_PROBES, + NEIGH_VAR(parms, UCAST_PROBES)) || + nla_put_u32(skb, NDTPA_MCAST_PROBES, + NEIGH_VAR(parms, MCAST_PROBES)) || nla_put_msecs(skb, NDTPA_REACHABLE_TIME, parms->reachable_time) || nla_put_msecs(skb, NDTPA_BASE_REACHABLE_TIME, - parms->base_reachable_time) || - nla_put_msecs(skb, NDTPA_GC_STALETIME, parms->gc_staletime) || + NEIGH_VAR(parms, BASE_REACHABLE_TIME)) || + nla_put_msecs(skb, NDTPA_GC_STALETIME, + NEIGH_VAR(parms, GC_STALETIME)) || nla_put_msecs(skb, NDTPA_DELAY_PROBE_TIME, - parms->delay_probe_time) || - nla_put_msecs(skb, NDTPA_RETRANS_TIME, parms->retrans_time) || - nla_put_msecs(skb, NDTPA_ANYCAST_DELAY, parms->anycast_delay) || - nla_put_msecs(skb, NDTPA_PROXY_DELAY, parms->proxy_delay) || - nla_put_msecs(skb, NDTPA_LOCKTIME, parms->locktime)) + NEIGH_VAR(parms, DELAY_PROBE_TIME)) || + nla_put_msecs(skb, NDTPA_RETRANS_TIME, + NEIGH_VAR(parms, RETRANS_TIME)) || + nla_put_msecs(skb, NDTPA_ANYCAST_DELAY, + NEIGH_VAR(parms, ANYCAST_DELAY)) || + nla_put_msecs(skb, NDTPA_PROXY_DELAY, + NEIGH_VAR(parms, PROXY_DELAY)) || + nla_put_msecs(skb, NDTPA_LOCKTIME, + NEIGH_VAR(parms, LOCKTIME))) goto nla_put_failure; return nla_nest_end(skb, nest); @@ -2010,44 +2025,54 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh) switch (i) { case NDTPA_QUEUE_LEN: - p->queue_len_bytes = nla_get_u32(tbp[i]) * - SKB_TRUESIZE(ETH_FRAME_LEN); + NEIGH_VAR_SET(p, QUEUE_LEN_BYTES, + nla_get_u32(tbp[i]) * + SKB_TRUESIZE(ETH_FRAME_LEN)); break; case NDTPA_QUEUE_LENBYTES: - p->queue_len_bytes = nla_get_u32(tbp[i]); + NEIGH_VAR_SET(p, QUEUE_LEN_BYTES, + nla_get_u32(tbp[i])); break; case NDTPA_PROXY_QLEN: - p->proxy_qlen = nla_get_u32(tbp[i]); + NEIGH_VAR_SET(p, PROXY_QLEN, + nla_get_u32(tbp[i])); break; case NDTPA_APP_PROBES: - p->app_probes = nla_get_u32(tbp[i]); + NEIGH_VAR_SET(p, APP_PROBES, + nla_get_u32(tbp[i])); break; case NDTPA_UCAST_PROBES: - p->ucast_probes = nla_get_u32(tbp[i]); + NEIGH_VAR_SET(p, UCAST_PROBES, + nla_get_u32(tbp[i])); break; case NDTPA_MCAST_PROBES: - p->mcast_probes = nla_get_u32(tbp[i]); + NEIGH_VAR_SET(p, MCAST_PROBES, + nla_get_u32(tbp[i])); break; case NDTPA_BASE_REACHABLE_TIME: - p->base_reachable_time = nla_get_msecs(tbp[i]); + NEIGH_VAR_SET(p, BASE_REACHABLE_TIME, + nla_get_msecs(tbp[i])); break; case NDTPA_GC_STALETIME: - p->gc_staletime = nla_get_msecs(tbp[i]); + NEIGH_VAR_SET(p, GC_STALETIME, + nla_get_msecs(tbp[i])); break; case NDTPA_DELAY_PROBE_TIME: - p->delay_probe_time = nla_get_msecs(tbp[i]); + NEIGH_VAR_SET(p, DELAY_PROBE_TIME, + nla_get_msecs(tbp[i])); break; case NDTPA_RETRANS_TIME: - p->retrans_time = nla_get_msecs(tbp[i]); + NEIGH_VAR_SET(p, RETRANS_TIME, + nla_get_msecs(tbp[i])); break; case NDTPA_ANYCAST_DELAY: - p->anycast_delay = nla_get_msecs(tbp[i]); + NEIGH_VAR_SET(p, ANYCAST_DELAY, nla_get_msecs(tbp[i])); break; case NDTPA_PROXY_DELAY: - p->proxy_delay = nla_get_msecs(tbp[i]); + NEIGH_VAR_SET(p, PROXY_DELAY, nla_get_msecs(tbp[i])); break; case NDTPA_LOCKTIME: - p->locktime = nla_get_msecs(tbp[i]); + NEIGH_VAR_SET(p, LOCKTIME, nla_get_msecs(tbp[i])); break; } } @@ -2788,133 +2813,68 @@ static int proc_unres_qlen(struct ctl_table *ctl, int write, return ret; } -enum { - NEIGH_VAR_MCAST_PROBE, - NEIGH_VAR_UCAST_PROBE, - NEIGH_VAR_APP_PROBE, - NEIGH_VAR_RETRANS_TIME, - NEIGH_VAR_BASE_REACHABLE_TIME, - NEIGH_VAR_DELAY_PROBE_TIME, - NEIGH_VAR_GC_STALETIME, - NEIGH_VAR_QUEUE_LEN, - NEIGH_VAR_QUEUE_LEN_BYTES, - NEIGH_VAR_PROXY_QLEN, - NEIGH_VAR_ANYCAST_DELAY, - NEIGH_VAR_PROXY_DELAY, - NEIGH_VAR_LOCKTIME, - NEIGH_VAR_RETRANS_TIME_MS, - NEIGH_VAR_BASE_REACHABLE_TIME_MS, - NEIGH_VAR_GC_INTERVAL, - NEIGH_VAR_GC_THRESH1, - NEIGH_VAR_GC_THRESH2, - NEIGH_VAR_GC_THRESH3, - NEIGH_VAR_MAX -}; +static int neigh_proc_dointvec_zero_intmax(struct ctl_table *ctl, int write, + void __user *buffer, + size_t *lenp, loff_t *ppos) +{ + struct ctl_table tmp = *ctl; + + tmp.extra1 = &zero; + tmp.extra2 = &int_max; + + return proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); +} + +#define NEIGH_PARMS_DATA_OFFSET(index) \ + (&((struct neigh_parms *) 0)->data[index]) + +#define NEIGH_SYSCTL_ENTRY(attr, data_attr, name, mval, proc) \ + [NEIGH_VAR_ ## attr] = { \ + .procname = name, \ + .data = NEIGH_PARMS_DATA_OFFSET(NEIGH_VAR_ ## data_attr), \ + .maxlen = sizeof(int), \ + .mode = mval, \ + .proc_handler = proc, \ + } + +#define NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(attr, name) \ + NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_zero_intmax) + +#define NEIGH_SYSCTL_JIFFIES_ENTRY(attr, name) \ + NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, proc_dointvec_jiffies) + +#define NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(attr, name) \ + NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, proc_dointvec_userhz_jiffies) + +#define NEIGH_SYSCTL_MS_JIFFIES_ENTRY(attr, name) \ + NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, proc_dointvec_ms_jiffies) + +#define NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(attr, data_attr, name) \ + NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, proc_dointvec_ms_jiffies) + +#define NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(attr, data_attr, name) \ + NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, proc_unres_qlen) static struct neigh_sysctl_table { struct ctl_table_header *sysctl_header; struct ctl_table neigh_vars[NEIGH_VAR_MAX + 1]; } neigh_sysctl_template __read_mostly = { .neigh_vars = { - [NEIGH_VAR_MCAST_PROBE] = { - .procname = "mcast_solicit", - .maxlen = sizeof(int), - .mode = 0644, - .extra1 = &zero, - .extra2 = &int_max, - .proc_handler = proc_dointvec_minmax, - }, - [NEIGH_VAR_UCAST_PROBE] = { - .procname = "ucast_solicit", - .maxlen = sizeof(int), - .mode = 0644, - .extra1 = &zero, - .extra2 = &int_max, - .proc_handler = proc_dointvec_minmax, - }, - [NEIGH_VAR_APP_PROBE] = { - .procname = "app_solicit", - .maxlen = sizeof(int), - .mode = 0644, - .extra1 = &zero, - .extra2 = &int_max, - .proc_handler = proc_dointvec_minmax, - }, - [NEIGH_VAR_RETRANS_TIME] = { - .procname = "retrans_time", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_userhz_jiffies, - }, - [NEIGH_VAR_BASE_REACHABLE_TIME] = { - .procname = "base_reachable_time", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - [NEIGH_VAR_DELAY_PROBE_TIME] = { - .procname = "delay_first_probe_time", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - [NEIGH_VAR_GC_STALETIME] = { - .procname = "gc_stale_time", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - [NEIGH_VAR_QUEUE_LEN] = { - .procname = "unres_qlen", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_unres_qlen, - }, - [NEIGH_VAR_QUEUE_LEN_BYTES] = { - .procname = "unres_qlen_bytes", - .maxlen = sizeof(int), - .mode = 0644, - .extra1 = &zero, - .proc_handler = proc_dointvec_minmax, - }, - [NEIGH_VAR_PROXY_QLEN] = { - .procname = "proxy_qlen", - .maxlen = sizeof(int), - .mode = 0644, - .extra1 = &zero, - .extra2 = &int_max, - .proc_handler = proc_dointvec_minmax, - }, - [NEIGH_VAR_ANYCAST_DELAY] = { - .procname = "anycast_delay", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_userhz_jiffies, - }, - [NEIGH_VAR_PROXY_DELAY] = { - .procname = "proxy_delay", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_userhz_jiffies, - }, - [NEIGH_VAR_LOCKTIME] = { - .procname = "locktime", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_userhz_jiffies, - }, - [NEIGH_VAR_RETRANS_TIME_MS] = { - .procname = "retrans_time_ms", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_ms_jiffies, - }, - [NEIGH_VAR_BASE_REACHABLE_TIME_MS] = { - .procname = "base_reachable_time_ms", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_ms_jiffies, - }, + NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(MCAST_PROBES, "mcast_solicit"), + NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(UCAST_PROBES, "ucast_solicit"), + NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(APP_PROBES, "app_solicit"), + NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(RETRANS_TIME, "retrans_time"), + NEIGH_SYSCTL_JIFFIES_ENTRY(BASE_REACHABLE_TIME, "base_reachable_time"), + NEIGH_SYSCTL_JIFFIES_ENTRY(DELAY_PROBE_TIME, "delay_first_probe_time"), + NEIGH_SYSCTL_JIFFIES_ENTRY(GC_STALETIME, "gc_stale_time"), + NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(QUEUE_LEN_BYTES, "unres_qlen_bytes"), + NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(PROXY_QLEN, "proxy_qlen"), + NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(ANYCAST_DELAY, "anycast_delay"), + NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(PROXY_DELAY, "proxy_delay"), + NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(LOCKTIME, "locktime"), + NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(QUEUE_LEN, QUEUE_LEN_BYTES, "unres_qlen"), + NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(RETRANS_TIME_MS, RETRANS_TIME, "retrans_time_ms"), + NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(BASE_REACHABLE_TIME_MS, BASE_REACHABLE_TIME, "base_reachable_time_ms"), [NEIGH_VAR_GC_INTERVAL] = { .procname = "gc_interval", .maxlen = sizeof(int), @@ -2952,29 +2912,17 @@ static struct neigh_sysctl_table { int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p, char *p_name, proc_handler *handler) { + int i; struct neigh_sysctl_table *t; - const char *dev_name_source = NULL; + const char *dev_name_source; char neigh_path[ sizeof("net//neigh/") + IFNAMSIZ + IFNAMSIZ ]; t = kmemdup(&neigh_sysctl_template, sizeof(*t), GFP_KERNEL); if (!t) goto err; - t->neigh_vars[NEIGH_VAR_MCAST_PROBE].data = &p->mcast_probes; - t->neigh_vars[NEIGH_VAR_UCAST_PROBE].data = &p->ucast_probes; - t->neigh_vars[NEIGH_VAR_APP_PROBE].data = &p->app_probes; - t->neigh_vars[NEIGH_VAR_RETRANS_TIME].data = &p->retrans_time; - t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].data = &p->base_reachable_time; - t->neigh_vars[NEIGH_VAR_DELAY_PROBE_TIME].data = &p->delay_probe_time; - t->neigh_vars[NEIGH_VAR_GC_STALETIME].data = &p->gc_staletime; - t->neigh_vars[NEIGH_VAR_QUEUE_LEN].data = &p->queue_len_bytes; - t->neigh_vars[NEIGH_VAR_QUEUE_LEN_BYTES].data = &p->queue_len_bytes; - t->neigh_vars[NEIGH_VAR_PROXY_QLEN].data = &p->proxy_qlen; - t->neigh_vars[NEIGH_VAR_ANYCAST_DELAY].data = &p->anycast_delay; - t->neigh_vars[NEIGH_VAR_PROXY_DELAY].data = &p->proxy_delay; - t->neigh_vars[NEIGH_VAR_LOCKTIME].data = &p->locktime; - t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].data = &p->retrans_time; - t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].data = &p->base_reachable_time; + for (i = 0; i < ARRAY_SIZE(t->neigh_vars); i++) + t->neigh_vars[i].data += (long) p; if (dev) { dev_name_source = dev->name; @@ -2989,7 +2937,6 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p, t->neigh_vars[NEIGH_VAR_GC_THRESH3].data = (int *)(p + 1) + 3; } - if (handler) { /* RetransTime */ t->neigh_vars[NEIGH_VAR_RETRANS_TIME].proc_handler = handler; diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c index f8637f93d31..c8121ceddb9 100644 --- a/net/decnet/dn_neigh.c +++ b/net/decnet/dn_neigh.c @@ -102,19 +102,21 @@ struct neigh_table dn_neigh_table = { .id = "dn_neigh_cache", .parms ={ .tbl = &dn_neigh_table, - .base_reachable_time = 30 * HZ, - .retrans_time = 1 * HZ, - .gc_staletime = 60 * HZ, - .reachable_time = 30 * HZ, - .delay_probe_time = 5 * HZ, - .queue_len_bytes = 64*1024, - .ucast_probes = 0, - .app_probes = 0, - .mcast_probes = 0, - .anycast_delay = 0, - .proxy_delay = 0, - .proxy_qlen = 0, - .locktime = 1 * HZ, + .reachable_time = 30 * HZ, + .data = { + [NEIGH_VAR_MCAST_PROBES] = 0, + [NEIGH_VAR_UCAST_PROBES] = 0, + [NEIGH_VAR_APP_PROBES] = 0, + [NEIGH_VAR_RETRANS_TIME] = 1 * HZ, + [NEIGH_VAR_BASE_REACHABLE_TIME] = 30 * HZ, + [NEIGH_VAR_DELAY_PROBE_TIME] = 5 * HZ, + [NEIGH_VAR_GC_STALETIME] = 60 * HZ, + [NEIGH_VAR_QUEUE_LEN_BYTES] = 64*1024, + [NEIGH_VAR_PROXY_QLEN] = 0, + [NEIGH_VAR_ANYCAST_DELAY] = 0, + [NEIGH_VAR_PROXY_DELAY] = 0, + [NEIGH_VAR_LOCKTIME] = 1 * HZ, + }, }, .gc_interval = 30 * HZ, .gc_thresh1 = 128, diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 7808093cede..3a37c7df2a2 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -166,18 +166,20 @@ struct neigh_table arp_tbl = { .id = "arp_cache", .parms = { .tbl = &arp_tbl, - .base_reachable_time = 30 * HZ, - .retrans_time = 1 * HZ, - .gc_staletime = 60 * HZ, .reachable_time = 30 * HZ, - .delay_probe_time = 5 * HZ, - .queue_len_bytes = 64*1024, - .ucast_probes = 3, - .mcast_probes = 3, - .anycast_delay = 1 * HZ, - .proxy_delay = (8 * HZ) / 10, - .proxy_qlen = 64, - .locktime = 1 * HZ, + .data = { + [NEIGH_VAR_MCAST_PROBES] = 3, + [NEIGH_VAR_UCAST_PROBES] = 3, + [NEIGH_VAR_RETRANS_TIME] = 1 * HZ, + [NEIGH_VAR_BASE_REACHABLE_TIME] = 30 * HZ, + [NEIGH_VAR_DELAY_PROBE_TIME] = 5 * HZ, + [NEIGH_VAR_GC_STALETIME] = 60 * HZ, + [NEIGH_VAR_QUEUE_LEN_BYTES] = 64 * 1024, + [NEIGH_VAR_PROXY_QLEN] = 64, + [NEIGH_VAR_ANYCAST_DELAY] = 1 * HZ, + [NEIGH_VAR_PROXY_DELAY] = (8 * HZ) / 10, + [NEIGH_VAR_LOCKTIME] = 1 * HZ, + }, }, .gc_interval = 30 * HZ, .gc_thresh1 = 128, @@ -359,14 +361,14 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb) if (!saddr) saddr = inet_select_addr(dev, target, RT_SCOPE_LINK); - probes -= neigh->parms->ucast_probes; + probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES); if (probes < 0) { if (!(neigh->nud_state & NUD_VALID)) pr_debug("trying to ucast probe in NUD_INVALID\n"); neigh_ha_snapshot(dst_ha, neigh, dev); dst_hw = dst_ha; } else { - probes -= neigh->parms->app_probes; + probes -= NEIGH_VAR(neigh->parms, APP_PROBES); if (probes < 0) { neigh_app_ns(neigh); return; @@ -871,7 +873,7 @@ static int arp_process(struct sk_buff *skb) if (NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED || skb->pkt_type == PACKET_HOST || - in_dev->arp_parms->proxy_delay == 0) { + NEIGH_VAR(in_dev->arp_parms, PROXY_DELAY) == 0) { arp_send(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha, dev->dev_addr, sha); @@ -910,7 +912,8 @@ static int arp_process(struct sk_buff *skb) agents are active. Taking the first reply prevents arp trashing and chooses the fastest router. */ - override = time_after(jiffies, n->updated + n->parms->locktime); + override = time_after(jiffies, n->updated + + NEIGH_VAR(n->parms, LOCKTIME)); /* Broadcast replies and request packets do not assert neighbour reachability. diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 5087cc5cb81..55dc56f9072 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1071,7 +1071,7 @@ retry: regen_advance = idev->cnf.regen_max_retry * idev->cnf.dad_transmits * - idev->nd_parms->retrans_time / HZ; + NEIGH_VAR(idev->nd_parms, RETRANS_TIME) / HZ; write_unlock_bh(&idev->lock); /* A temporary address is created only if this calculated Preferred @@ -1888,7 +1888,8 @@ static void ipv6_regen_rndid(unsigned long data) expires = jiffies + idev->cnf.temp_prefered_lft * HZ - - idev->cnf.regen_max_retry * idev->cnf.dad_transmits * idev->nd_parms->retrans_time - + idev->cnf.regen_max_retry * idev->cnf.dad_transmits * + NEIGH_VAR(idev->nd_parms, RETRANS_TIME) - idev->cnf.max_desync_factor * HZ; if (time_before(expires, jiffies)) { pr_warn("%s: too short regeneration interval; timer disabled for %s\n", @@ -3188,7 +3189,8 @@ static void addrconf_dad_timer(unsigned long data) } ifp->dad_probes--; - addrconf_mod_dad_timer(ifp, ifp->idev->nd_parms->retrans_time); + addrconf_mod_dad_timer(ifp, + NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME)); spin_unlock(&ifp->lock); write_unlock(&idev->lock); @@ -3509,7 +3511,7 @@ restart: !(ifp->flags&IFA_F_TENTATIVE)) { unsigned long regen_advance = ifp->idev->cnf.regen_max_retry * ifp->idev->cnf.dad_transmits * - ifp->idev->nd_parms->retrans_time / HZ; + NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME) / HZ; if (age >= ifp->prefered_lft - regen_advance) { struct inet6_ifaddr *ifpub = ifp->ifpub; @@ -4231,7 +4233,7 @@ static int inet6_fill_ifla6_attrs(struct sk_buff *skb, struct inet6_dev *idev) ci.max_reasm_len = IPV6_MAXPLEN; ci.tstamp = cstamp_delta(idev->tstamp); ci.reachable_time = jiffies_to_msecs(idev->nd_parms->reachable_time); - ci.retrans_time = jiffies_to_msecs(idev->nd_parms->retrans_time); + ci.retrans_time = jiffies_to_msecs(NEIGH_VAR(idev->nd_parms, RETRANS_TIME)); if (nla_put(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci)) goto nla_put_failure; nla = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32)); diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 30086517139..0da0986a929 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -125,17 +125,19 @@ struct neigh_table nd_tbl = { .id = "ndisc_cache", .parms = { .tbl = &nd_tbl, - .base_reachable_time = ND_REACHABLE_TIME, - .retrans_time = ND_RETRANS_TIMER, - .gc_staletime = 60 * HZ, .reachable_time = ND_REACHABLE_TIME, - .delay_probe_time = 5 * HZ, - .queue_len_bytes = 64*1024, - .ucast_probes = 3, - .mcast_probes = 3, - .anycast_delay = 1 * HZ, - .proxy_delay = (8 * HZ) / 10, - .proxy_qlen = 64, + .data = { + [NEIGH_VAR_MCAST_PROBES] = 3, + [NEIGH_VAR_UCAST_PROBES] = 3, + [NEIGH_VAR_RETRANS_TIME] = ND_RETRANS_TIMER, + [NEIGH_VAR_BASE_REACHABLE_TIME] = ND_REACHABLE_TIME, + [NEIGH_VAR_DELAY_PROBE_TIME] = 5 * HZ, + [NEIGH_VAR_GC_STALETIME] = 60 * HZ, + [NEIGH_VAR_QUEUE_LEN_BYTES] = 64 * 1024, + [NEIGH_VAR_PROXY_QLEN] = 64, + [NEIGH_VAR_ANYCAST_DELAY] = 1 * HZ, + [NEIGH_VAR_PROXY_DELAY] = (8 * HZ) / 10, + }, }, .gc_interval = 30 * HZ, .gc_thresh1 = 128, @@ -656,14 +658,14 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb) if (skb && ipv6_chk_addr(dev_net(dev), &ipv6_hdr(skb)->saddr, dev, 1)) saddr = &ipv6_hdr(skb)->saddr; - if ((probes -= neigh->parms->ucast_probes) < 0) { + if ((probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES)) < 0) { if (!(neigh->nud_state & NUD_VALID)) { ND_PRINTK(1, dbg, "%s: trying to ucast probe in NUD_INVALID: %pI6\n", __func__, target); } ndisc_send_ns(dev, neigh, target, target, saddr); - } else if ((probes -= neigh->parms->app_probes) < 0) { + } else if ((probes -= NEIGH_VAR(neigh->parms, APP_PROBES)) < 0) { neigh_app_ns(neigh); } else { addrconf_addr_solict_mult(target, &mcaddr); @@ -790,7 +792,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) && skb->pkt_type != PACKET_HOST && inc && - idev->nd_parms->proxy_delay != 0) { + NEIGH_VAR(idev->nd_parms, PROXY_DELAY) != 0) { /* * for anycast or proxy, * sender should delay its response @@ -1210,7 +1212,7 @@ skip_defrtr: rtime = (rtime*HZ)/1000; if (rtime < HZ/10) rtime = HZ/10; - in6_dev->nd_parms->retrans_time = rtime; + NEIGH_VAR_SET(in6_dev->nd_parms, RETRANS_TIME, rtime); in6_dev->tstamp = jiffies; inet6_ifinfo_notify(RTM_NEWLINK, in6_dev); } @@ -1222,9 +1224,11 @@ skip_defrtr: if (rtime < HZ/10) rtime = HZ/10; - if (rtime != in6_dev->nd_parms->base_reachable_time) { - in6_dev->nd_parms->base_reachable_time = rtime; - in6_dev->nd_parms->gc_staletime = 3 * rtime; + if (rtime != NEIGH_VAR(in6_dev->nd_parms, BASE_REACHABLE_TIME)) { + NEIGH_VAR_SET(in6_dev->nd_parms, + BASE_REACHABLE_TIME, rtime); + NEIGH_VAR_SET(in6_dev->nd_parms, + GC_STALETIME, 3 * rtime); in6_dev->nd_parms->reachable_time = neigh_rand_reach_time(rtime); in6_dev->tstamp = jiffies; inet6_ifinfo_notify(RTM_NEWLINK, in6_dev); @@ -1665,8 +1669,9 @@ int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, int write, void __user *bu ret = -1; if (write && ret == 0 && dev && (idev = in6_dev_get(dev)) != NULL) { - if (ctl->data == &idev->nd_parms->base_reachable_time) - idev->nd_parms->reachable_time = neigh_rand_reach_time(idev->nd_parms->base_reachable_time); + if (ctl->data == &NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME)) + idev->nd_parms->reachable_time = + neigh_rand_reach_time(NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME)); idev->tstamp = jiffies; inet6_ifinfo_notify(RTM_NEWLINK, idev); in6_dev_put(idev); -- cgit v1.2.3-70-g09d2 From cb5b09c17fe60056bc8f127ffc987d361c40ed4b Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 7 Dec 2013 19:26:54 +0100 Subject: neigh: wrap proc dointvec functions This will be needed later on to provide better management of default values. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- include/net/neighbour.h | 9 ++++++++ net/core/neighbour.c | 55 ++++++++++++++++++++++++++++++++++++++++--------- net/ipv6/ndisc.c | 10 ++++----- 3 files changed, 59 insertions(+), 15 deletions(-) diff --git a/include/net/neighbour.h b/include/net/neighbour.h index 4cb5478e2f6..ed7eba04529 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h @@ -296,6 +296,15 @@ void *neigh_seq_start(struct seq_file *, loff_t *, struct neigh_table *, void *neigh_seq_next(struct seq_file *, void *, loff_t *); void neigh_seq_stop(struct seq_file *, void *); +int neigh_proc_dointvec(struct ctl_table *ctl, int write, + void __user *buffer, size_t *lenp, loff_t *ppos); +int neigh_proc_dointvec_jiffies(struct ctl_table *ctl, int write, + void __user *buffer, + size_t *lenp, loff_t *ppos); +int neigh_proc_dointvec_ms_jiffies(struct ctl_table *ctl, int write, + void __user *buffer, + size_t *lenp, loff_t *ppos); + int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p, char *p_name, proc_handler *proc_handler); void neigh_sysctl_unregister(struct neigh_parms *p); diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 742fa10d437..60edd97ad2b 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -2825,6 +2825,43 @@ static int neigh_proc_dointvec_zero_intmax(struct ctl_table *ctl, int write, return proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); } +int neigh_proc_dointvec(struct ctl_table *ctl, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + return proc_dointvec(ctl, write, buffer, lenp, ppos); +} +EXPORT_SYMBOL(neigh_proc_dointvec); + +int neigh_proc_dointvec_jiffies(struct ctl_table *ctl, int write, + void __user *buffer, + size_t *lenp, loff_t *ppos) +{ + return proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos); +} +EXPORT_SYMBOL(neigh_proc_dointvec_jiffies); + +static int neigh_proc_dointvec_userhz_jiffies(struct ctl_table *ctl, int write, + void __user *buffer, + size_t *lenp, loff_t *ppos) +{ + return proc_dointvec_userhz_jiffies(ctl, write, buffer, lenp, ppos); +} + +int neigh_proc_dointvec_ms_jiffies(struct ctl_table *ctl, int write, + void __user *buffer, + size_t *lenp, loff_t *ppos) +{ + return proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos); +} +EXPORT_SYMBOL(neigh_proc_dointvec_ms_jiffies); + +static int neigh_proc_dointvec_unres_qlen(struct ctl_table *ctl, int write, + void __user *buffer, + size_t *lenp, loff_t *ppos) +{ + return proc_unres_qlen(ctl, write, buffer, lenp, ppos); +} + #define NEIGH_PARMS_DATA_OFFSET(index) \ (&((struct neigh_parms *) 0)->data[index]) @@ -2841,19 +2878,19 @@ static int neigh_proc_dointvec_zero_intmax(struct ctl_table *ctl, int write, NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_zero_intmax) #define NEIGH_SYSCTL_JIFFIES_ENTRY(attr, name) \ - NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, proc_dointvec_jiffies) + NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_jiffies) #define NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(attr, name) \ - NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, proc_dointvec_userhz_jiffies) + NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_userhz_jiffies) #define NEIGH_SYSCTL_MS_JIFFIES_ENTRY(attr, name) \ - NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, proc_dointvec_ms_jiffies) + NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_ms_jiffies) #define NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(attr, data_attr, name) \ - NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, proc_dointvec_ms_jiffies) + NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_ms_jiffies) #define NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(attr, data_attr, name) \ - NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, proc_unres_qlen) + NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_unres_qlen) static struct neigh_sysctl_table { struct ctl_table_header *sysctl_header; @@ -2921,8 +2958,10 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p, if (!t) goto err; - for (i = 0; i < ARRAY_SIZE(t->neigh_vars); i++) + for (i = 0; i < ARRAY_SIZE(t->neigh_vars); i++) { t->neigh_vars[i].data += (long) p; + t->neigh_vars[i].extra1 = dev; + } if (dev) { dev_name_source = dev->name; @@ -2940,16 +2979,12 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p, if (handler) { /* RetransTime */ t->neigh_vars[NEIGH_VAR_RETRANS_TIME].proc_handler = handler; - t->neigh_vars[NEIGH_VAR_RETRANS_TIME].extra1 = dev; /* ReachableTime */ t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler = handler; - t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].extra1 = dev; /* RetransTime (in milliseconds)*/ t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].proc_handler = handler; - t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].extra1 = dev; /* ReachableTime (in milliseconds) */ t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler = handler; - t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].extra1 = dev; } /* Don't export sysctls to unprivileged users */ diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 0da0986a929..5fc6f69652b 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1655,16 +1655,16 @@ int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, int write, void __user *bu ndisc_warn_deprecated_sysctl(ctl, "syscall", dev ? dev->name : "default"); if (strcmp(ctl->procname, "retrans_time") == 0) - ret = proc_dointvec(ctl, write, buffer, lenp, ppos); + ret = neigh_proc_dointvec(ctl, write, buffer, lenp, ppos); else if (strcmp(ctl->procname, "base_reachable_time") == 0) - ret = proc_dointvec_jiffies(ctl, write, - buffer, lenp, ppos); + ret = neigh_proc_dointvec_jiffies(ctl, write, + buffer, lenp, ppos); else if ((strcmp(ctl->procname, "retrans_time_ms") == 0) || (strcmp(ctl->procname, "base_reachable_time_ms") == 0)) - ret = proc_dointvec_ms_jiffies(ctl, write, - buffer, lenp, ppos); + ret = neigh_proc_dointvec_ms_jiffies(ctl, write, + buffer, lenp, ppos); else ret = -1; -- cgit v1.2.3-70-g09d2 From 73af614aedd221df8495fc8c9993c50e87f899f2 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 7 Dec 2013 19:26:55 +0100 Subject: neigh: use tbl->family to distinguish ipv4 from ipv6 Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- include/net/neighbour.h | 7 ++++++- net/core/neighbour.c | 14 +++++++++++++- net/ipv4/arp.c | 2 +- net/ipv4/devinet.c | 2 +- net/ipv6/addrconf.c | 2 +- net/ipv6/ndisc.c | 2 +- 6 files changed, 23 insertions(+), 6 deletions(-) diff --git a/include/net/neighbour.h b/include/net/neighbour.h index ed7eba04529..95615c9ad13 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h @@ -202,6 +202,11 @@ struct neigh_table { struct pneigh_entry **phash_buckets; }; +static inline int neigh_parms_family(struct neigh_parms *p) +{ + return p->tbl->family; +} + #define NEIGH_PRIV_ALIGN sizeof(long long) #define NEIGH_ENTRY_SIZE(size) ALIGN((size), NEIGH_PRIV_ALIGN) @@ -306,7 +311,7 @@ int neigh_proc_dointvec_ms_jiffies(struct ctl_table *ctl, int write, size_t *lenp, loff_t *ppos); int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p, - char *p_name, proc_handler *proc_handler); + proc_handler *proc_handler); void neigh_sysctl_unregister(struct neigh_parms *p); static inline void __neigh_parms_put(struct neigh_parms *parms) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 60edd97ad2b..65ead080167 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -2947,12 +2947,13 @@ static struct neigh_sysctl_table { }; int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p, - char *p_name, proc_handler *handler) + proc_handler *handler) { int i; struct neigh_sysctl_table *t; const char *dev_name_source; char neigh_path[ sizeof("net//neigh/") + IFNAMSIZ + IFNAMSIZ ]; + char *p_name; t = kmemdup(&neigh_sysctl_template, sizeof(*t), GFP_KERNEL); if (!t) @@ -2991,6 +2992,17 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p, if (neigh_parms_net(p)->user_ns != &init_user_ns) t->neigh_vars[0].procname = NULL; + switch (neigh_parms_family(p)) { + case AF_INET: + p_name = "ipv4"; + break; + case AF_INET6: + p_name = "ipv6"; + break; + default: + BUG(); + } + snprintf(neigh_path, sizeof(neigh_path), "net/%s/neigh/%s", p_name, dev_name_source); t->sysctl_header = diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 3a37c7df2a2..f0418586394 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -1287,7 +1287,7 @@ void __init arp_init(void) dev_add_pack(&arp_packet_type); arp_proc_init(); #ifdef CONFIG_SYSCTL - neigh_sysctl_register(NULL, &arp_tbl.parms, "ipv4", NULL); + neigh_sysctl_register(NULL, &arp_tbl.parms, NULL); #endif register_netdevice_notifier(&arp_netdev_notifier); } diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index a1b5bcbd04a..e1c19535fe3 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -2160,7 +2160,7 @@ static void __devinet_sysctl_unregister(struct ipv4_devconf *cnf) static void devinet_sysctl_register(struct in_device *idev) { - neigh_sysctl_register(idev->dev, idev->arp_parms, "ipv4", NULL); + neigh_sysctl_register(idev->dev, idev->arp_parms, NULL); __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name, &idev->cnf); } diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 55dc56f9072..ea8a475fa8c 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -5028,7 +5028,7 @@ static void __addrconf_sysctl_unregister(struct ipv6_devconf *p) static void addrconf_sysctl_register(struct inet6_dev *idev) { - neigh_sysctl_register(idev->dev, idev->nd_parms, "ipv6", + neigh_sysctl_register(idev->dev, idev->nd_parms, &ndisc_ifinfo_sysctl_change); __addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name, idev, &idev->cnf); diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 5fc6f69652b..09a22f4f36c 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1730,7 +1730,7 @@ int __init ndisc_init(void) neigh_table_init(&nd_tbl); #ifdef CONFIG_SYSCTL - err = neigh_sysctl_register(NULL, &nd_tbl.parms, "ipv6", + err = neigh_sysctl_register(NULL, &nd_tbl.parms, &ndisc_ifinfo_sysctl_change); if (err) goto out_unregister_pernet; -- cgit v1.2.3-70-g09d2 From 1d4c8c29841b9991cdf3c7cc4ba7f96a94f104ca Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 7 Dec 2013 19:26:56 +0100 Subject: neigh: restore old behaviour of default parms values Previously inet devices were only constructed when addresses are added. Therefore the default neigh parms values they get are the ones at the time of these operations. Now that we're creating inet devices earlier, this changes the behaviour of default neigh parms values in an incompatible way (see bug #8519). This patch creates a compromise by setting the default values at the same point as before but only for those that have not been explicitly set by the user since the inet device's creation. Introduced by: commit 8030f54499925d073a88c09f30d5d844fb1b3190 Author: Herbert Xu Date: Thu Feb 22 01:53:47 2007 +0900 [IPV4] devinet: Register inetdev earlier. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- include/linux/inetdevice.h | 7 +++++ include/net/neighbour.h | 13 ++++++++ net/core/neighbour.c | 74 ++++++++++++++++++++++++++++++++++++++++++---- net/ipv4/devinet.c | 2 ++ net/ipv4/ipmr.c | 2 ++ 5 files changed, 92 insertions(+), 6 deletions(-) diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h index 0d678aefe69..ae174ca565c 100644 --- a/include/linux/inetdevice.h +++ b/include/linux/inetdevice.h @@ -220,6 +220,13 @@ static inline struct in_device *__in_dev_get_rtnl(const struct net_device *dev) return rtnl_dereference(dev->ip_ptr); } +static inline struct neigh_parms *__in_dev_arp_parms_get_rcu(const struct net_device *dev) +{ + struct in_device *in_dev = __in_dev_get_rcu(dev); + + return in_dev ? in_dev->arp_parms : NULL; +} + void in_dev_finish_destroy(struct in_device *idev); static inline void in_dev_put(struct in_device *idev) diff --git a/include/net/neighbour.h b/include/net/neighbour.h index 95615c9ad13..41b1ce6c96a 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -81,16 +82,28 @@ struct neigh_parms { int reachable_time; int data[NEIGH_VAR_DATA_MAX]; + DECLARE_BITMAP(data_state, NEIGH_VAR_DATA_MAX); }; static inline void neigh_var_set(struct neigh_parms *p, int index, int val) { + set_bit(index, p->data_state); p->data[index] = val; } #define NEIGH_VAR(p, attr) ((p)->data[NEIGH_VAR_ ## attr]) #define NEIGH_VAR_SET(p, attr, val) neigh_var_set(p, NEIGH_VAR_ ## attr, val) +static inline void neigh_parms_data_state_setall(struct neigh_parms *p) +{ + bitmap_fill(p->data_state, NEIGH_VAR_DATA_MAX); +} + +static inline void neigh_parms_data_state_cleanall(struct neigh_parms *p) +{ + bitmap_zero(p->data_state, NEIGH_VAR_DATA_MAX); +} + struct neigh_statistics { unsigned long allocs; /* number of allocated neighs */ unsigned long destroys; /* number of destroyed neighs */ diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 65ead080167..c4a7879bfb1 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -38,6 +38,7 @@ #include #include #include +#include #define DEBUG #define NEIGH_DEBUG 1 @@ -1464,6 +1465,8 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev, p->next = tbl->parms.next; tbl->parms.next = p; write_unlock_bh(&tbl->lock); + + neigh_parms_data_state_cleanall(p); } return p; } @@ -2813,22 +2816,68 @@ static int proc_unres_qlen(struct ctl_table *ctl, int write, return ret; } +static struct neigh_parms *neigh_get_dev_parms_rcu(struct net_device *dev, + int family) +{ + if (family == AF_INET) + return __in_dev_arp_parms_get_rcu(dev); + return NULL; +} + +static void neigh_copy_dflt_parms(struct net *net, struct neigh_parms *p, + int index) +{ + struct net_device *dev; + int family = neigh_parms_family(p); + + rcu_read_lock(); + for_each_netdev_rcu(net, dev) { + struct neigh_parms *dst_p = + neigh_get_dev_parms_rcu(dev, family); + + if (dst_p && !test_bit(index, dst_p->data_state)) + dst_p->data[index] = p->data[index]; + } + rcu_read_unlock(); +} + +static void neigh_proc_update(struct ctl_table *ctl, int write) +{ + struct net_device *dev = ctl->extra1; + struct neigh_parms *p = ctl->extra2; + struct net *net = p->net; + int index = (int *) ctl->data - p->data; + + if (!write) + return; + + set_bit(index, p->data_state); + if (!dev) /* NULL dev means this is default value */ + neigh_copy_dflt_parms(net, p, index); +} + static int neigh_proc_dointvec_zero_intmax(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { struct ctl_table tmp = *ctl; + int ret; tmp.extra1 = &zero; tmp.extra2 = &int_max; - return proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); + ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); + neigh_proc_update(ctl, write); + return ret; } int neigh_proc_dointvec(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { - return proc_dointvec(ctl, write, buffer, lenp, ppos); + int ret = proc_dointvec(ctl, write, buffer, lenp, ppos); + + neigh_proc_update(ctl, write); + return ret; } EXPORT_SYMBOL(neigh_proc_dointvec); @@ -2836,7 +2885,10 @@ int neigh_proc_dointvec_jiffies(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { - return proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos); + int ret = proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos); + + neigh_proc_update(ctl, write); + return ret; } EXPORT_SYMBOL(neigh_proc_dointvec_jiffies); @@ -2844,14 +2896,20 @@ static int neigh_proc_dointvec_userhz_jiffies(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { - return proc_dointvec_userhz_jiffies(ctl, write, buffer, lenp, ppos); + int ret = proc_dointvec_userhz_jiffies(ctl, write, buffer, lenp, ppos); + + neigh_proc_update(ctl, write); + return ret; } int neigh_proc_dointvec_ms_jiffies(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { - return proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos); + int ret = proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos); + + neigh_proc_update(ctl, write); + return ret; } EXPORT_SYMBOL(neigh_proc_dointvec_ms_jiffies); @@ -2859,7 +2917,10 @@ static int neigh_proc_dointvec_unres_qlen(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { - return proc_unres_qlen(ctl, write, buffer, lenp, ppos); + int ret = proc_unres_qlen(ctl, write, buffer, lenp, ppos); + + neigh_proc_update(ctl, write); + return ret; } #define NEIGH_PARMS_DATA_OFFSET(index) \ @@ -2962,6 +3023,7 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p, for (i = 0; i < ARRAY_SIZE(t->neigh_vars); i++) { t->neigh_vars[i].data += (long) p; t->neigh_vars[i].extra1 = dev; + t->neigh_vars[i].extra2 = p; } if (dev) { diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index e1c19535fe3..43065be3630 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -500,6 +500,7 @@ static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa) return -ENOBUFS; } ipv4_devconf_setall(in_dev); + neigh_parms_data_state_setall(in_dev->arp_parms); if (ifa->ifa_dev != in_dev) { WARN_ON(ifa->ifa_dev); in_dev_hold(in_dev); @@ -747,6 +748,7 @@ static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh, goto errout; ipv4_devconf_setall(in_dev); + neigh_parms_data_state_setall(in_dev->arp_parms); in_dev_hold(in_dev); if (tb[IFA_ADDRESS] == NULL) diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 62212c772a4..421a24934ff 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -425,6 +425,7 @@ struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v) goto failure; ipv4_devconf_setall(in_dev); + neigh_parms_data_state_setall(in_dev->arp_parms); IPV4_DEVCONF(in_dev->cnf, RP_FILTER) = 0; if (dev_open(dev)) @@ -517,6 +518,7 @@ static struct net_device *ipmr_reg_vif(struct net *net, struct mr_table *mrt) } ipv4_devconf_setall(in_dev); + neigh_parms_data_state_setall(in_dev->arp_parms); IPV4_DEVCONF(in_dev->cnf, RP_FILTER) = 0; rcu_read_unlock(); -- cgit v1.2.3-70-g09d2 From bba24896f022d4d239494bebf18e713cd8aec7a5 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 7 Dec 2013 19:26:57 +0100 Subject: neigh: ipv6: respect default values set before an address is assigned to device Make the behaviour similar to ipv4. This will allow user to set sysctl default neigh param values and these values will be respected even by devices registered before (that ones what do not have address set yet). Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- include/net/addrconf.h | 7 +++++++ net/core/neighbour.c | 7 ++++++- net/ipv6/addrconf.c | 2 ++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/include/net/addrconf.h b/include/net/addrconf.h index e70278eef12..66c4a44d8f5 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -248,6 +248,13 @@ static inline struct inet6_dev *in6_dev_get(const struct net_device *dev) return idev; } +static inline struct neigh_parms *__in6_dev_nd_parms_get_rcu(const struct net_device *dev) +{ + struct inet6_dev *idev = __in6_dev_get(dev); + + return idev ? idev->nd_parms : NULL; +} + void in6_dev_finish_destroy(struct inet6_dev *idev); static inline void in6_dev_put(struct inet6_dev *idev) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index c4a7879bfb1..ce2b77515a9 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -39,6 +39,7 @@ #include #include #include +#include #define DEBUG #define NEIGH_DEBUG 1 @@ -2819,8 +2820,12 @@ static int proc_unres_qlen(struct ctl_table *ctl, int write, static struct neigh_parms *neigh_get_dev_parms_rcu(struct net_device *dev, int family) { - if (family == AF_INET) + switch (family) { + case AF_INET: return __in_dev_arp_parms_get_rcu(dev); + case AF_INET6: + return __in6_dev_nd_parms_get_rcu(dev); + } return NULL; } diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index ea8a475fa8c..be4dbbd17d3 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -834,6 +834,8 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, goto out; } + neigh_parms_data_state_setall(idev->nd_parms); + ifa->addr = *addr; if (peer_addr) ifa->peer_addr = *peer_addr; -- cgit v1.2.3-70-g09d2 From 73eaef87e98a96fe8b8a586f916b2721bf512efa Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Fri, 6 Dec 2013 14:21:01 -0800 Subject: etherdevice: Add ether_addr_equal_unaligned Add a generic routine to test if possibly unaligned to u16 Ethernet addresses are equal. If CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is set, this uses the slightly faster generic routine ether_addr_equal, otherwise this uses memcmp. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- include/linux/etherdevice.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h index 3526e819d7a..2f0e3d0818b 100644 --- a/include/linux/etherdevice.h +++ b/include/linux/etherdevice.h @@ -265,6 +265,24 @@ static inline bool ether_addr_equal_64bits(const u8 addr1[6+2], #endif } +/** + * ether_addr_equal_unaligned - Compare two not u16 aligned Ethernet addresses + * @addr1: Pointer to a six-byte array containing the Ethernet address + * @addr2: Pointer other six-byte array containing the Ethernet address + * + * Compare two Ethernet addresses, returns true if equal + * + * Please note: Use only when any Ethernet address may not be u16 aligned. + */ +static inline bool ether_addr_equal_unaligned(const u8 *addr1, const u8 *addr2) +{ +#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) + return ether_addr_equal(addr1, addr2); +#else + return memcmp(addr1, addr2, ETH_ALEN) == 0; +#endif +} + /** * is_etherdev_addr - Tell if given Ethernet address belongs to the device. * @dev: Pointer to a device structure -- cgit v1.2.3-70-g09d2 From d9cd4fe5ef4373e0f5b2e752b1859bee33bc5644 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Fri, 6 Dec 2013 14:39:46 -0800 Subject: batadv: Slight optimization of batadv_compare_eth Use the newly added generic routine ether_addr_equal_unaligned to test if possibly unaligned to u16 Ethernet addresses are equal. This slightly improves comparison time for systems with CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- net/batman-adv/main.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h index f94f287b867..322dd732373 100644 --- a/net/batman-adv/main.h +++ b/net/batman-adv/main.h @@ -266,7 +266,7 @@ static inline void batadv_dbg(int type __always_unused, */ static inline int batadv_compare_eth(const void *data1, const void *data2) { - return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); + return ether_addr_equal_unaligned(data1, data2); } /** -- cgit v1.2.3-70-g09d2 From 2c722fe1c821a100ca87fcc36e90a9bceb497c7c Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Fri, 6 Dec 2013 15:44:21 -0800 Subject: etherdevice: Optimize a few is__ether_addr functions If CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is set, several is__ether_addr functions can be slightly improved by using u32 dereferences. I believe all current uses of is_zero_ether_addr and is_broadcast_ether_addr are u16 aligned, so always use u16 references to improve those functions performance. Document the u16 alignment requirements. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- include/linux/etherdevice.h | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h index 2f0e3d0818b..f344ac04f85 100644 --- a/include/linux/etherdevice.h +++ b/include/linux/etherdevice.h @@ -61,6 +61,8 @@ static const u8 eth_reserved_addr_base[ETH_ALEN] __aligned(2) = * * Return true if address is link local reserved addr (01:80:c2:00:00:0X) per * IEEE 802.1Q 8.6.3 Frame filtering. + * + * Please note: addr must be aligned to u16. */ static inline bool is_link_local_ether_addr(const u8 *addr) { @@ -68,7 +70,12 @@ static inline bool is_link_local_ether_addr(const u8 *addr) static const __be16 *b = (const __be16 *)eth_reserved_addr_base; static const __be16 m = cpu_to_be16(0xfff0); +#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) + return (((*(const u32 *)addr) ^ (*(const u32 *)b)) | + ((a[2] ^ b[2]) & m)) == 0; +#else return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | ((a[2] ^ b[2]) & m)) == 0; +#endif } /** @@ -76,10 +83,18 @@ static inline bool is_link_local_ether_addr(const u8 *addr) * @addr: Pointer to a six-byte array containing the Ethernet address * * Return true if the address is all zeroes. + * + * Please note: addr must be aligned to u16. */ static inline bool is_zero_ether_addr(const u8 *addr) { - return !(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5]); +#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) + return ((*(const u32 *)addr) | (*(const u16 *)(addr + 4))) == 0; +#else + return (*(const u16 *)(addr + 0) | + *(const u16 *)(addr + 2) | + *(const u16 *)(addr + 4)) == 0; +#endif } /** @@ -110,10 +125,14 @@ static inline bool is_local_ether_addr(const u8 *addr) * @addr: Pointer to a six-byte array containing the Ethernet address * * Return true if the address is the broadcast address. + * + * Please note: addr must be aligned to u16. */ static inline bool is_broadcast_ether_addr(const u8 *addr) { - return (addr[0] & addr[1] & addr[2] & addr[3] & addr[4] & addr[5]) == 0xff; + return (*(const u16 *)(addr + 0) & + *(const u16 *)(addr + 2) & + *(const u16 *)(addr + 4)) == 0xffff; } /** @@ -135,6 +154,8 @@ static inline bool is_unicast_ether_addr(const u8 *addr) * a multicast address, and is not FF:FF:FF:FF:FF:FF. * * Return true if the address is valid. + * + * Please note: addr must be aligned to u16. */ static inline bool is_valid_ether_addr(const u8 *addr) { -- cgit v1.2.3-70-g09d2 From 5824d2d16d39a9c57aa3bacf955fbd0c2134061f Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Sat, 7 Dec 2013 00:53:55 +0100 Subject: bgmac: connect to PHY and make use of PHY device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We were already registering MDIO bus, but we were not connecting bgmac to the PHY. Add proper call and implement adjust link function to switch MAC into requested state. At the same time it's possible to drop our internal PHY management. This is a "standard" PHY, so the "Generic PHY" driver works perfectly fine with this. Don't duplicate the code. Finally make use of phy_ethtool_[gs]set functions instead implementing them from scratch. This change was successfully tested on BCM5357. I was able to autonegotiate 1000Mb/s full duplex, as well as force any of the 10/100/1000 half/full modes. Signed-off-by: Rafał Miłecki Acked-by: Florian Fainelli Acked-by: Hauke Mehrtens Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bgmac.c | 190 +++++++++++----------------------- drivers/net/ethernet/broadcom/bgmac.h | 12 +-- 2 files changed, 64 insertions(+), 138 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c index e2aa09ce6af..0452937227f 100644 --- a/drivers/net/ethernet/broadcom/bgmac.c +++ b/drivers/net/ethernet/broadcom/bgmac.c @@ -682,70 +682,6 @@ static int bgmac_phy_write(struct bgmac *bgmac, u8 phyaddr, u8 reg, u16 value) return 0; } -/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyforce */ -static void bgmac_phy_force(struct bgmac *bgmac) -{ - u16 ctl; - u16 mask = ~(BGMAC_PHY_CTL_SPEED | BGMAC_PHY_CTL_SPEED_MSB | - BGMAC_PHY_CTL_ANENAB | BGMAC_PHY_CTL_DUPLEX); - - if (bgmac->phyaddr == BGMAC_PHY_NOREGS) - return; - - if (bgmac->autoneg) - return; - - ctl = bgmac_phy_read(bgmac, bgmac->phyaddr, BGMAC_PHY_CTL); - ctl &= mask; - if (bgmac->full_duplex) - ctl |= BGMAC_PHY_CTL_DUPLEX; - if (bgmac->speed == BGMAC_SPEED_100) - ctl |= BGMAC_PHY_CTL_SPEED_100; - else if (bgmac->speed == BGMAC_SPEED_1000) - ctl |= BGMAC_PHY_CTL_SPEED_1000; - bgmac_phy_write(bgmac, bgmac->phyaddr, BGMAC_PHY_CTL, ctl); -} - -/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyadvertise */ -static void bgmac_phy_advertise(struct bgmac *bgmac) -{ - u16 adv; - - if (bgmac->phyaddr == BGMAC_PHY_NOREGS) - return; - - if (!bgmac->autoneg) - return; - - /* Adv selected 10/100 speeds */ - adv = bgmac_phy_read(bgmac, bgmac->phyaddr, BGMAC_PHY_ADV); - adv &= ~(BGMAC_PHY_ADV_10HALF | BGMAC_PHY_ADV_10FULL | - BGMAC_PHY_ADV_100HALF | BGMAC_PHY_ADV_100FULL); - if (!bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_10) - adv |= BGMAC_PHY_ADV_10HALF; - if (!bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_100) - adv |= BGMAC_PHY_ADV_100HALF; - if (bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_10) - adv |= BGMAC_PHY_ADV_10FULL; - if (bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_100) - adv |= BGMAC_PHY_ADV_100FULL; - bgmac_phy_write(bgmac, bgmac->phyaddr, BGMAC_PHY_ADV, adv); - - /* Adv selected 1000 speeds */ - adv = bgmac_phy_read(bgmac, bgmac->phyaddr, BGMAC_PHY_ADV2); - adv &= ~(BGMAC_PHY_ADV2_1000HALF | BGMAC_PHY_ADV2_1000FULL); - if (!bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_1000) - adv |= BGMAC_PHY_ADV2_1000HALF; - if (bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_1000) - adv |= BGMAC_PHY_ADV2_1000FULL; - bgmac_phy_write(bgmac, bgmac->phyaddr, BGMAC_PHY_ADV2, adv); - - /* Restart */ - bgmac_phy_write(bgmac, bgmac->phyaddr, BGMAC_PHY_CTL, - bgmac_phy_read(bgmac, bgmac->phyaddr, BGMAC_PHY_CTL) | - BGMAC_PHY_CTL_RESTART); -} - /* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyinit */ static void bgmac_phy_init(struct bgmac *bgmac) { @@ -876,19 +812,28 @@ static void bgmac_clear_mib(struct bgmac *bgmac) } /* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/gmac_speed */ -static void bgmac_speed(struct bgmac *bgmac, int speed) +static void bgmac_mac_speed(struct bgmac *bgmac) { u32 mask = ~(BGMAC_CMDCFG_ES_MASK | BGMAC_CMDCFG_HD); u32 set = 0; - if (speed & BGMAC_SPEED_10) + switch (bgmac->mac_speed) { + case SPEED_10: set |= BGMAC_CMDCFG_ES_10; - if (speed & BGMAC_SPEED_100) + break; + case SPEED_100: set |= BGMAC_CMDCFG_ES_100; - if (speed & BGMAC_SPEED_1000) + break; + case SPEED_1000: set |= BGMAC_CMDCFG_ES_1000; - if (!bgmac->full_duplex) + break; + default: + bgmac_err(bgmac, "Unsupported speed: %d\n", bgmac->mac_speed); + } + + if (bgmac->mac_duplex == DUPLEX_HALF) set |= BGMAC_CMDCFG_HD; + bgmac_cmdcfg_maskset(bgmac, mask, set, true); } @@ -897,10 +842,9 @@ static void bgmac_miiconfig(struct bgmac *bgmac) u8 imode = (bgmac_read(bgmac, BGMAC_DEV_STATUS) & BGMAC_DS_MM_MASK) >> BGMAC_DS_MM_SHIFT; if (imode == 0 || imode == 1) { - if (bgmac->autoneg) - bgmac_speed(bgmac, BGMAC_SPEED_100); - else - bgmac_speed(bgmac, bgmac->speed); + bgmac->mac_speed = SPEED_100; + bgmac->mac_duplex = DUPLEX_FULL; + bgmac_mac_speed(bgmac); } } @@ -1108,13 +1052,6 @@ static void bgmac_chip_init(struct bgmac *bgmac, bool full_init) bgmac_write(bgmac, BGMAC_RXMAX_LENGTH, 32 + ETHER_MAX_LEN); - if (!bgmac->autoneg) { - bgmac_speed(bgmac, bgmac->speed); - bgmac_phy_force(bgmac); - } else if (bgmac->speed) { /* if there is anything to adv */ - bgmac_phy_advertise(bgmac); - } - if (full_init) { bgmac_dma_init(bgmac); if (1) /* FIXME: is there any case we don't want IRQs? */ @@ -1294,61 +1231,16 @@ static int bgmac_get_settings(struct net_device *net_dev, { struct bgmac *bgmac = netdev_priv(net_dev); - cmd->supported = SUPPORTED_10baseT_Half | - SUPPORTED_10baseT_Full | - SUPPORTED_100baseT_Half | - SUPPORTED_100baseT_Full | - SUPPORTED_1000baseT_Half | - SUPPORTED_1000baseT_Full | - SUPPORTED_Autoneg; - - if (bgmac->autoneg) { - WARN_ON(cmd->advertising); - if (bgmac->full_duplex) { - if (bgmac->speed & BGMAC_SPEED_10) - cmd->advertising |= ADVERTISED_10baseT_Full; - if (bgmac->speed & BGMAC_SPEED_100) - cmd->advertising |= ADVERTISED_100baseT_Full; - if (bgmac->speed & BGMAC_SPEED_1000) - cmd->advertising |= ADVERTISED_1000baseT_Full; - } else { - if (bgmac->speed & BGMAC_SPEED_10) - cmd->advertising |= ADVERTISED_10baseT_Half; - if (bgmac->speed & BGMAC_SPEED_100) - cmd->advertising |= ADVERTISED_100baseT_Half; - if (bgmac->speed & BGMAC_SPEED_1000) - cmd->advertising |= ADVERTISED_1000baseT_Half; - } - } else { - switch (bgmac->speed) { - case BGMAC_SPEED_10: - ethtool_cmd_speed_set(cmd, SPEED_10); - break; - case BGMAC_SPEED_100: - ethtool_cmd_speed_set(cmd, SPEED_100); - break; - case BGMAC_SPEED_1000: - ethtool_cmd_speed_set(cmd, SPEED_1000); - break; - } - } - - cmd->duplex = bgmac->full_duplex ? DUPLEX_FULL : DUPLEX_HALF; - - cmd->autoneg = bgmac->autoneg; - - return 0; + return phy_ethtool_gset(bgmac->phy_dev, cmd); } -#if 0 static int bgmac_set_settings(struct net_device *net_dev, struct ethtool_cmd *cmd) { struct bgmac *bgmac = netdev_priv(net_dev); - return -1; + return phy_ethtool_sset(bgmac->phy_dev, cmd); } -#endif static void bgmac_get_drvinfo(struct net_device *net_dev, struct ethtool_drvinfo *info) @@ -1359,6 +1251,7 @@ static void bgmac_get_drvinfo(struct net_device *net_dev, static const struct ethtool_ops bgmac_ethtool_ops = { .get_settings = bgmac_get_settings, + .set_settings = bgmac_set_settings, .get_drvinfo = bgmac_get_drvinfo, }; @@ -1377,9 +1270,35 @@ static int bgmac_mii_write(struct mii_bus *bus, int mii_id, int regnum, return bgmac_phy_write(bus->priv, mii_id, regnum, value); } +static void bgmac_adjust_link(struct net_device *net_dev) +{ + struct bgmac *bgmac = netdev_priv(net_dev); + struct phy_device *phy_dev = bgmac->phy_dev; + bool update = false; + + if (phy_dev->link) { + if (phy_dev->speed != bgmac->mac_speed) { + bgmac->mac_speed = phy_dev->speed; + update = true; + } + + if (phy_dev->duplex != bgmac->mac_duplex) { + bgmac->mac_duplex = phy_dev->duplex; + update = true; + } + } + + if (update) { + bgmac_mac_speed(bgmac); + phy_print_status(phy_dev); + } +} + static int bgmac_mii_register(struct bgmac *bgmac) { struct mii_bus *mii_bus; + struct phy_device *phy_dev; + char bus_id[MII_BUS_ID_SIZE + 3]; int i, err = 0; mii_bus = mdiobus_alloc(); @@ -1411,8 +1330,22 @@ static int bgmac_mii_register(struct bgmac *bgmac) bgmac->mii_bus = mii_bus; + /* Connect to the PHY */ + snprintf(bus_id, sizeof(bus_id), PHY_ID_FMT, mii_bus->id, + bgmac->phyaddr); + phy_dev = phy_connect(bgmac->net_dev, bus_id, &bgmac_adjust_link, + PHY_INTERFACE_MODE_MII); + if (IS_ERR(phy_dev)) { + bgmac_err(bgmac, "PHY connecton failed\n"); + err = PTR_ERR(phy_dev); + goto err_unregister_bus; + } + bgmac->phy_dev = phy_dev; + return err; +err_unregister_bus: + mdiobus_unregister(mii_bus); err_free_irq: kfree(mii_bus->irq); err_free_bus: @@ -1467,9 +1400,6 @@ static int bgmac_probe(struct bcma_device *core) bcma_set_drvdata(core, bgmac); /* Defaults */ - bgmac->autoneg = true; - bgmac->full_duplex = true; - bgmac->speed = BGMAC_SPEED_10 | BGMAC_SPEED_100 | BGMAC_SPEED_1000; memcpy(bgmac->net_dev->dev_addr, mac, ETH_ALEN); /* On BCM4706 we need common core to access PHY */ diff --git a/drivers/net/ethernet/broadcom/bgmac.h b/drivers/net/ethernet/broadcom/bgmac.h index 66c8afbdc8c..550f2a8e85a 100644 --- a/drivers/net/ethernet/broadcom/bgmac.h +++ b/drivers/net/ethernet/broadcom/bgmac.h @@ -342,10 +342,6 @@ #define BGMAC_CHIPCTL_1_SW_TYPE_RGMII 0x000000C0 #define BGMAC_CHIPCTL_1_RXC_DLL_BYPASS 0x00010000 -#define BGMAC_SPEED_10 0x0001 -#define BGMAC_SPEED_100 0x0002 -#define BGMAC_SPEED_1000 0x0004 - #define BGMAC_WEIGHT 64 #define ETHER_MAX_LEN 1518 @@ -402,6 +398,7 @@ struct bgmac { struct net_device *net_dev; struct napi_struct napi; struct mii_bus *mii_bus; + struct phy_device *phy_dev; /* DMA */ struct bgmac_dma_ring tx_ring[BGMAC_MAX_TX_RINGS]; @@ -416,10 +413,9 @@ struct bgmac { u32 int_mask; u32 int_status; - /* Speed-related */ - int speed; - bool autoneg; - bool full_duplex; + /* Current MAC state */ + int mac_speed; + int mac_duplex; u8 phyaddr; bool has_robosw; -- cgit v1.2.3-70-g09d2 From 1397ed35f22d7c30d0b89ba74b6b7829220dfcfd Mon Sep 17 00:00:00 2001 From: Florent Fourcot Date: Sun, 8 Dec 2013 15:46:57 +0100 Subject: ipv6: add flowinfo for tcp6 pkt_options for all cases The current implementation of IPV6_FLOWINFO only gives a result if pktoptions is available (thanks to the ip6_datagram_recv_ctl function). It gives inconsistent results to user space, sometimes there is a result for getsockopt(IPV6_FLOWINFO), sometimes not. This patch add rcv_flowinfo to store it, and return it to the userspace in the same way than other pkt_options. Signed-off-by: Florent Fourcot Reviewed-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- include/linux/ipv6.h | 1 + net/ipv6/ipv6_sockglue.c | 4 ++++ net/ipv6/tcp_ipv6.c | 4 ++++ 3 files changed, 9 insertions(+) diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index c56c350324e..0b2ebfbbe0f 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -201,6 +201,7 @@ struct ipv6_pinfo { __u8 min_hopcount; __u8 tclass; __u8 rcv_tclass; + __be32 rcv_flowinfo; __u32 dst_cookie; __u32 rx_dst_cookie; diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 1c6ce3119ff..c2db1df4638 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -1034,6 +1034,10 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, int hlim = np->mcast_hops; put_cmsg(&msg, SOL_IPV6, IPV6_2292HOPLIMIT, sizeof(hlim), &hlim); } + if (np->rxopt.bits.rxflow) { + int flowinfo = np->rcv_flowinfo; + put_cmsg(&msg, SOL_IPV6, IPV6_FLOWINFO, sizeof(flowinfo), &flowinfo); + } } len -= msg.msg_controllen; return put_user(len, optlen); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 0740f93a114..79a19636955 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1136,6 +1136,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, newnp->mcast_oif = inet6_iif(skb); newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; newnp->rcv_tclass = ipv6_get_dsfield(ipv6_hdr(skb)); + newnp->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(skb)); /* * No need to charge this sock to the relevant IPv6 refcnt debug socks count @@ -1216,6 +1217,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, newnp->mcast_oif = inet6_iif(skb); newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; newnp->rcv_tclass = ipv6_get_dsfield(ipv6_hdr(skb)); + newnp->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(skb)); /* Clone native IPv6 options from listening socket (if any) @@ -1427,6 +1429,8 @@ ipv6_pktoptions: np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit; if (np->rxopt.bits.rxtclass) np->rcv_tclass = ipv6_get_dsfield(ipv6_hdr(opt_skb)); + if (np->rxopt.bits.rxflow) + np->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(opt_skb)); if (ipv6_opt_accepted(sk, opt_skb)) { skb_set_owner_r(opt_skb, sk); opt_skb = xchg(&np->pktoptions, opt_skb); -- cgit v1.2.3-70-g09d2 From 37cfee909c5a396abccf43e3e0a63a5f5ac998af Mon Sep 17 00:00:00 2001 From: Florent Fourcot Date: Sun, 8 Dec 2013 15:46:58 +0100 Subject: ipv6: move IPV6_TCLASS_MASK definition in ipv6.h Signed-off-by: Florent Fourcot Reviewed-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- include/net/ipv6.h | 1 + net/ipv6/ip6_gre.c | 1 - net/ipv6/ip6_tunnel.c | 1 - 3 files changed, 1 insertion(+), 2 deletions(-) diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 488316e339a..bce802e7bcf 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -238,6 +238,7 @@ struct ip6_flowlabel { #define IPV6_FLOWINFO_MASK cpu_to_be32(0x0FFFFFFF) #define IPV6_FLOWLABEL_MASK cpu_to_be32(0x000FFFFF) +#define IPV6_TCLASS_MASK (IPV6_FLOWINFO_MASK & ~IPV6_FLOWLABEL_MASK) struct ipv6_fl_socklist { struct ipv6_fl_socklist __rcu *next; diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 8acb28621f9..c50de068bea 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -61,7 +61,6 @@ static bool log_ecn_error = true; module_param(log_ecn_error, bool, 0644); MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN"); -#define IPV6_TCLASS_MASK (IPV6_FLOWINFO_MASK & ~IPV6_FLOWLABEL_MASK) #define IPV6_TCLASS_SHIFT 20 #define HASH_SIZE_SHIFT 5 diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index d6062325db0..f5e8a98eb55 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -70,7 +70,6 @@ MODULE_ALIAS_NETDEV("ip6tnl0"); #define IP6_TNL_TRACE(x...) do {;} while(0) #endif -#define IPV6_TCLASS_MASK (IPV6_FLOWINFO_MASK & ~IPV6_FLOWLABEL_MASK) #define IPV6_TCLASS_SHIFT 20 #define HASH_SIZE_SHIFT 5 -- cgit v1.2.3-70-g09d2 From 82e9f105a28006e7ff864220a28cf62ea6d1e280 Mon Sep 17 00:00:00 2001 From: Florent Fourcot Date: Sun, 8 Dec 2013 15:46:59 +0100 Subject: ipv6: remove rcv_tclass of ipv6_pinfo tclass information in now already stored in rcv_flowinfo We do not need to store the same information twice. Signed-off-by: Florent Fourcot Reviewed-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- include/linux/ipv6.h | 1 - net/ipv6/ipv6_sockglue.c | 2 +- net/ipv6/tcp_ipv6.c | 6 +----- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 0b2ebfbbe0f..3fde0664555 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -200,7 +200,6 @@ struct ipv6_pinfo { dontfrag:1; __u8 min_hopcount; __u8 tclass; - __u8 rcv_tclass; __be32 rcv_flowinfo; __u32 dst_cookie; diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index c2db1df4638..7d939150685 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -1019,7 +1019,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, put_cmsg(&msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim); } if (np->rxopt.bits.rxtclass) { - int tclass = np->rcv_tclass; + int tclass = ntohl(np->rcv_flowinfo & IPV6_TCLASS_MASK) >> 20; put_cmsg(&msg, SOL_IPV6, IPV6_TCLASS, sizeof(tclass), &tclass); } if (np->rxopt.bits.rxoinfo) { diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 79a19636955..bd91e7ff482 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1135,7 +1135,6 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, newnp->opt = NULL; newnp->mcast_oif = inet6_iif(skb); newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; - newnp->rcv_tclass = ipv6_get_dsfield(ipv6_hdr(skb)); newnp->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(skb)); /* @@ -1216,7 +1215,6 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, newnp->opt = NULL; newnp->mcast_oif = inet6_iif(skb); newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; - newnp->rcv_tclass = ipv6_get_dsfield(ipv6_hdr(skb)); newnp->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(skb)); /* Clone native IPv6 options from listening socket (if any) @@ -1427,9 +1425,7 @@ ipv6_pktoptions: np->mcast_oif = inet6_iif(opt_skb); if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit; - if (np->rxopt.bits.rxtclass) - np->rcv_tclass = ipv6_get_dsfield(ipv6_hdr(opt_skb)); - if (np->rxopt.bits.rxflow) + if (np->rxopt.bits.rxflow || np->rxopt.bits.rxtclass) np->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(opt_skb)); if (ipv6_opt_accepted(sk, opt_skb)) { skb_set_owner_r(opt_skb, sk); -- cgit v1.2.3-70-g09d2 From 3308de2b841e5f25bdc4a7208a451f52f8cff969 Mon Sep 17 00:00:00 2001 From: Florent Fourcot Date: Sun, 8 Dec 2013 15:47:00 +0100 Subject: ipv6: add ip6_flowlabel helper And use it if possible. Signed-off-by: Florent Fourcot Reviewed-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- include/net/ipv6.h | 5 +++++ net/ipv6/ip6_gre.c | 2 +- net/ipv6/ip6_tunnel.c | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/net/ipv6.h b/include/net/ipv6.h index bce802e7bcf..d0bfe3eeb82 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -679,6 +679,11 @@ static inline __be32 ip6_flowinfo(const struct ipv6hdr *hdr) return *(__be32 *)hdr & IPV6_FLOWINFO_MASK; } +static inline __be32 ip6_flowlabel(const struct ipv6hdr *hdr) +{ + return *(__be32 *)hdr & IPV6_FLOWLABEL_MASK; +} + /* * Prototypes exported by ipv6 */ diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index c50de068bea..e27fb78c61f 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -845,7 +845,7 @@ static inline int ip6gre_xmit_ipv6(struct sk_buff *skb, struct net_device *dev) if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS) fl6.flowlabel |= (*(__be32 *) ipv6h & IPV6_TCLASS_MASK); if (t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL) - fl6.flowlabel |= (*(__be32 *) ipv6h & IPV6_FLOWLABEL_MASK); + fl6.flowlabel |= ip6_flowlabel(ipv6h); if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK) fl6.flowi6_mark = skb->mark; diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index f5e8a98eb55..8d7c9867a44 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -1130,7 +1130,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS) fl6.flowlabel |= (*(__be32 *) ipv6h & IPV6_TCLASS_MASK); if (t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL) - fl6.flowlabel |= (*(__be32 *) ipv6h & IPV6_FLOWLABEL_MASK); + fl6.flowlabel |= ip6_flowlabel(ipv6h); if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK) fl6.flowi6_mark = skb->mark; -- cgit v1.2.3-70-g09d2 From ac1eabcaecfae1ee5cca93c9e21b7cfdac15eaab Mon Sep 17 00:00:00 2001 From: Florent Fourcot Date: Sun, 8 Dec 2013 15:47:01 +0100 Subject: ipv6: use ip6_flowinfo helper Signed-off-by: Florent Fourcot Reviewed-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- net/ipv6/af_inet6.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 4fbdb7046d2..027615ac1b4 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -683,8 +683,7 @@ bool ipv6_opt_accepted(const struct sock *sk, const struct sk_buff *skb) if (np->rxopt.all) { if ((opt->hop && (np->rxopt.bits.hopopts || np->rxopt.bits.ohopopts)) || - ((IPV6_FLOWINFO_MASK & - *(__be32 *)skb_network_header(skb)) && + (ip6_flowinfo((struct ipv6hdr *) skb_network_header(skb)) && np->rxopt.bits.rxflow) || (opt->srcrt && (np->rxopt.bits.srcrt || np->rxopt.bits.osrcrt)) || -- cgit v1.2.3-70-g09d2 From 7c6d74d23a33a946bcf08ba2d3e52d31943b7342 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Sun, 8 Dec 2013 16:50:17 +0200 Subject: mlx4_core: Roll back round robin bitmap allocation commit for CQs, SRQs, and MPTs Commit f4ec9e9 "mlx4_core: Change bitmap allocator to work in round-robin fashion" introduced round-robin allocation (via bitmap) for all resources which allocate via a bitmap. Round robin allocation is desirable for mcgs, counters, pd's, UARs, and xrcds. These are simply numbers, with no involvement of ICM memory mapping. Round robin is required for QPs, since we had a problem with immediate reuse of a 24-bit QP number (commit f4ec9e9). However, for other resources which use the bitmap allocator and involve mapping ICM memory -- MPTs, CQs, SRQs -- round-robin is not desirable. What happens in these cases is the following: ICM memory is allocated and mapped in chunks of 256K. Since the resource allocation index goes up monotonically, the allocator will eventually require mapping a new chunk. Now, chunks are also unmapped when their reference count goes back to zero. Thus, if a single app is running and starts/exits frequently we will have the following situation: When the app starts, a new chunk must be allocated and mapped. When the app exits, the chunk reference count goes back to zero, and the chunk is unmapped and freed. Therefore, the app must pay the cost of allocation and mapping of ICM memory each time it runs (although the price is paid only when allocating the initial entry in the new chunk). For apps which allocate MPTs/SRQs/CQs and which operate as described above, this presented a performance problem. We therefore roll back the round-robin allocator modification for MPTs, CQs, SRQs. Reported-by: Matthew Finlay Signed-off-by: Jack Morgenstein Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/alloc.c | 12 +++++++++--- drivers/net/ethernet/mellanox/mlx4/cq.c | 4 ++-- drivers/net/ethernet/mellanox/mlx4/eq.c | 4 ++-- drivers/net/ethernet/mellanox/mlx4/main.c | 2 +- drivers/net/ethernet/mellanox/mlx4/mcg.c | 6 +++--- drivers/net/ethernet/mellanox/mlx4/mlx4.h | 10 ++++++++-- drivers/net/ethernet/mellanox/mlx4/mr.c | 2 +- drivers/net/ethernet/mellanox/mlx4/pd.c | 6 +++--- drivers/net/ethernet/mellanox/mlx4/qp.c | 2 +- drivers/net/ethernet/mellanox/mlx4/srq.c | 4 ++-- 10 files changed, 32 insertions(+), 20 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/alloc.c b/drivers/net/ethernet/mellanox/mlx4/alloc.c index 06fef5b44f7..c3ad464d062 100644 --- a/drivers/net/ethernet/mellanox/mlx4/alloc.c +++ b/drivers/net/ethernet/mellanox/mlx4/alloc.c @@ -71,9 +71,9 @@ u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap) return obj; } -void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj) +void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj, int use_rr) { - mlx4_bitmap_free_range(bitmap, obj, 1); + mlx4_bitmap_free_range(bitmap, obj, 1, use_rr); } u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align) @@ -118,11 +118,17 @@ u32 mlx4_bitmap_avail(struct mlx4_bitmap *bitmap) return bitmap->avail; } -void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt) +void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt, + int use_rr) { obj &= bitmap->max + bitmap->reserved_top - 1; spin_lock(&bitmap->lock); + if (!use_rr) { + bitmap->last = min(bitmap->last, obj); + bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top) + & bitmap->mask; + } bitmap_clear(bitmap->table, obj, cnt); bitmap->avail += cnt; spin_unlock(&bitmap->lock); diff --git a/drivers/net/ethernet/mellanox/mlx4/cq.c b/drivers/net/ethernet/mellanox/mlx4/cq.c index 22fcbe78311..34c5b87a1c2 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cq.c +++ b/drivers/net/ethernet/mellanox/mlx4/cq.c @@ -187,7 +187,7 @@ err_put: mlx4_table_put(dev, &cq_table->table, *cqn); err_out: - mlx4_bitmap_free(&cq_table->bitmap, *cqn); + mlx4_bitmap_free(&cq_table->bitmap, *cqn, MLX4_NO_RR); return err; } @@ -217,7 +217,7 @@ void __mlx4_cq_free_icm(struct mlx4_dev *dev, int cqn) mlx4_table_put(dev, &cq_table->cmpt_table, cqn); mlx4_table_put(dev, &cq_table->table, cqn); - mlx4_bitmap_free(&cq_table->bitmap, cqn); + mlx4_bitmap_free(&cq_table->bitmap, cqn, MLX4_NO_RR); } static void mlx4_cq_free_icm(struct mlx4_dev *dev, int cqn) diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c index c9cdb2a2c59..ae5212f8f09 100644 --- a/drivers/net/ethernet/mellanox/mlx4/eq.c +++ b/drivers/net/ethernet/mellanox/mlx4/eq.c @@ -963,7 +963,7 @@ err_out_free_mtt: mlx4_mtt_cleanup(dev, &eq->mtt); err_out_free_eq: - mlx4_bitmap_free(&priv->eq_table.bitmap, eq->eqn); + mlx4_bitmap_free(&priv->eq_table.bitmap, eq->eqn, MLX4_USE_RR); err_out_free_pages: for (i = 0; i < npages; ++i) @@ -1018,7 +1018,7 @@ static void mlx4_free_eq(struct mlx4_dev *dev, eq->page_list[i].map); kfree(eq->page_list); - mlx4_bitmap_free(&priv->eq_table.bitmap, eq->eqn); + mlx4_bitmap_free(&priv->eq_table.bitmap, eq->eqn, MLX4_USE_RR); mlx4_free_cmd_mailbox(dev, mailbox); } diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 01fc6515384..b37478db985 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -1654,7 +1654,7 @@ EXPORT_SYMBOL_GPL(mlx4_counter_alloc); void __mlx4_counter_free(struct mlx4_dev *dev, u32 idx) { - mlx4_bitmap_free(&mlx4_priv(dev)->counters_bitmap, idx); + mlx4_bitmap_free(&mlx4_priv(dev)->counters_bitmap, idx, MLX4_USE_RR); return; } diff --git a/drivers/net/ethernet/mellanox/mlx4/mcg.c b/drivers/net/ethernet/mellanox/mlx4/mcg.c index acf9d5f1f92..40594055b83 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mcg.c +++ b/drivers/net/ethernet/mellanox/mlx4/mcg.c @@ -996,7 +996,7 @@ out: index, dev->caps.num_mgms); else mlx4_bitmap_free(&priv->mcg_table.bitmap, - index - dev->caps.num_mgms); + index - dev->caps.num_mgms, MLX4_USE_RR); } mutex_unlock(&priv->mcg_table.mutex); @@ -1087,7 +1087,7 @@ int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], index, amgm_index, dev->caps.num_mgms); else mlx4_bitmap_free(&priv->mcg_table.bitmap, - amgm_index - dev->caps.num_mgms); + amgm_index - dev->caps.num_mgms, MLX4_USE_RR); } } else { /* Remove entry from AMGM */ @@ -1107,7 +1107,7 @@ int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], prev, index, dev->caps.num_mgms); else mlx4_bitmap_free(&priv->mcg_table.bitmap, - index - dev->caps.num_mgms); + index - dev->caps.num_mgms, MLX4_USE_RR); } out: diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index e582a41a802..6ed9dfa5f05 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -783,6 +783,11 @@ enum { MLX4_PCI_DEV_FORCE_SENSE_PORT = 1 << 1, }; +enum { + MLX4_NO_RR = 0, + MLX4_USE_RR = 1, +}; + struct mlx4_priv { struct mlx4_dev dev; @@ -844,9 +849,10 @@ static inline struct mlx4_priv *mlx4_priv(struct mlx4_dev *dev) extern struct workqueue_struct *mlx4_wq; u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap); -void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj); +void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj, int use_rr); u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align); -void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt); +void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt, + int use_rr); u32 mlx4_bitmap_avail(struct mlx4_bitmap *bitmap); int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask, u32 reserved_bot, u32 resetrved_top); diff --git a/drivers/net/ethernet/mellanox/mlx4/mr.c b/drivers/net/ethernet/mellanox/mlx4/mr.c index b3ee9bafff5..0558dddd81e 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mr.c +++ b/drivers/net/ethernet/mellanox/mlx4/mr.c @@ -346,7 +346,7 @@ void __mlx4_mpt_release(struct mlx4_dev *dev, u32 index) { struct mlx4_priv *priv = mlx4_priv(dev); - mlx4_bitmap_free(&priv->mr_table.mpt_bitmap, index); + mlx4_bitmap_free(&priv->mr_table.mpt_bitmap, index, MLX4_NO_RR); } static void mlx4_mpt_release(struct mlx4_dev *dev, u32 index) diff --git a/drivers/net/ethernet/mellanox/mlx4/pd.c b/drivers/net/ethernet/mellanox/mlx4/pd.c index 84cfb40bf45..c6af9619ce6 100644 --- a/drivers/net/ethernet/mellanox/mlx4/pd.c +++ b/drivers/net/ethernet/mellanox/mlx4/pd.c @@ -59,7 +59,7 @@ EXPORT_SYMBOL_GPL(mlx4_pd_alloc); void mlx4_pd_free(struct mlx4_dev *dev, u32 pdn) { - mlx4_bitmap_free(&mlx4_priv(dev)->pd_bitmap, pdn); + mlx4_bitmap_free(&mlx4_priv(dev)->pd_bitmap, pdn, MLX4_USE_RR); } EXPORT_SYMBOL_GPL(mlx4_pd_free); @@ -96,7 +96,7 @@ EXPORT_SYMBOL_GPL(mlx4_xrcd_alloc); void __mlx4_xrcd_free(struct mlx4_dev *dev, u32 xrcdn) { - mlx4_bitmap_free(&mlx4_priv(dev)->xrcd_bitmap, xrcdn); + mlx4_bitmap_free(&mlx4_priv(dev)->xrcd_bitmap, xrcdn, MLX4_USE_RR); } void mlx4_xrcd_free(struct mlx4_dev *dev, u32 xrcdn) @@ -164,7 +164,7 @@ EXPORT_SYMBOL_GPL(mlx4_uar_alloc); void mlx4_uar_free(struct mlx4_dev *dev, struct mlx4_uar *uar) { - mlx4_bitmap_free(&mlx4_priv(dev)->uar_table.bitmap, uar->index); + mlx4_bitmap_free(&mlx4_priv(dev)->uar_table.bitmap, uar->index, MLX4_USE_RR); } EXPORT_SYMBOL_GPL(mlx4_uar_free); diff --git a/drivers/net/ethernet/mellanox/mlx4/qp.c b/drivers/net/ethernet/mellanox/mlx4/qp.c index 2715e61dbb7..06b2d13d531 100644 --- a/drivers/net/ethernet/mellanox/mlx4/qp.c +++ b/drivers/net/ethernet/mellanox/mlx4/qp.c @@ -250,7 +250,7 @@ void __mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt) if (mlx4_is_qp_reserved(dev, (u32) base_qpn)) return; - mlx4_bitmap_free_range(&qp_table->bitmap, base_qpn, cnt); + mlx4_bitmap_free_range(&qp_table->bitmap, base_qpn, cnt, MLX4_USE_RR); } void mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt) diff --git a/drivers/net/ethernet/mellanox/mlx4/srq.c b/drivers/net/ethernet/mellanox/mlx4/srq.c index 8fdf2375377..1d2f9d3862a 100644 --- a/drivers/net/ethernet/mellanox/mlx4/srq.c +++ b/drivers/net/ethernet/mellanox/mlx4/srq.c @@ -117,7 +117,7 @@ err_put: mlx4_table_put(dev, &srq_table->table, *srqn); err_out: - mlx4_bitmap_free(&srq_table->bitmap, *srqn); + mlx4_bitmap_free(&srq_table->bitmap, *srqn, MLX4_NO_RR); return err; } @@ -145,7 +145,7 @@ void __mlx4_srq_free_icm(struct mlx4_dev *dev, int srqn) mlx4_table_put(dev, &srq_table->cmpt_table, srqn); mlx4_table_put(dev, &srq_table->table, srqn); - mlx4_bitmap_free(&srq_table->bitmap, srqn); + mlx4_bitmap_free(&srq_table->bitmap, srqn, MLX4_NO_RR); } static void mlx4_srq_free_icm(struct mlx4_dev *dev, int srqn) -- cgit v1.2.3-70-g09d2 From 71fb419724fadab4efdf98210aa3fe053bd81d29 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 10 Dec 2013 10:52:48 +0200 Subject: Bluetooth: Fix handling of L2CAP Command Reject over LE If we receive an L2CAP command reject message over LE we should take appropriate action on the corresponding channel. This is particularly important when trying to interact with a remote pre-4.1 system using LE CoC signaling messages. If we don't react to the command reject the corresponding socket would not be notified until a connection timeout occurs. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index ae0054ccee5..b6bca64b320 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -5736,6 +5736,31 @@ static inline int l2cap_le_credits(struct l2cap_conn *conn, return 0; } +static inline int l2cap_le_command_rej(struct l2cap_conn *conn, + struct l2cap_cmd_hdr *cmd, u16 cmd_len, + u8 *data) +{ + struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data; + struct l2cap_chan *chan; + + if (cmd_len < sizeof(*rej)) + return -EPROTO; + + mutex_lock(&conn->chan_lock); + + chan = __l2cap_get_chan_by_ident(conn, cmd->ident); + if (!chan) + goto done; + + l2cap_chan_lock(chan); + l2cap_chan_del(chan, ECONNREFUSED); + l2cap_chan_unlock(chan); + +done: + mutex_unlock(&conn->chan_lock); + return 0; +} + static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) @@ -5755,6 +5780,7 @@ static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn, switch (cmd->code) { case L2CAP_COMMAND_REJ: + l2cap_le_command_rej(conn, cmd, cmd_len, data); break; case L2CAP_CONN_PARAM_UPDATE_REQ: -- cgit v1.2.3-70-g09d2 From b03aaa9c733e15d0d13f4f80987f6b93fc6a9e03 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 20 Nov 2013 10:03:06 +0000 Subject: i40e: restrict diag test messages Use the netif_info() macro to restrict messaging to when the HW bit is enabled in the msglvl netdev message mask. Change-Id: I83030d4402991cfb7da100da00f05ce502ada4ae Signed-off-by: Shannon Nelson Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index f0bab1704dd..b04e4337df4 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -711,7 +711,7 @@ static int i40e_link_test(struct net_device *netdev, u64 *data) struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_pf *pf = np->vsi->back; - netdev_info(netdev, "link test\n"); + netif_info(pf, hw, netdev, "link test\n"); if (i40e_get_link_status(&pf->hw)) *data = 0; else @@ -725,7 +725,7 @@ static int i40e_reg_test(struct net_device *netdev, u64 *data) struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_pf *pf = np->vsi->back; - netdev_info(netdev, "register test\n"); + netif_info(pf, hw, netdev, "register test\n"); *data = i40e_diag_reg_test(&pf->hw); i40e_do_reset(pf, (1 << __I40E_PF_RESET_REQUESTED)); @@ -737,7 +737,7 @@ static int i40e_eeprom_test(struct net_device *netdev, u64 *data) struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_pf *pf = np->vsi->back; - netdev_info(netdev, "eeprom test\n"); + netif_info(pf, hw, netdev, "eeprom test\n"); *data = i40e_diag_eeprom_test(&pf->hw); return *data; @@ -749,7 +749,7 @@ static int i40e_intr_test(struct net_device *netdev, u64 *data) struct i40e_pf *pf = np->vsi->back; u16 swc_old = pf->sw_int_count; - netdev_info(netdev, "interrupt test\n"); + netif_info(pf, hw, netdev, "interrupt test\n"); wr32(&pf->hw, I40E_PFINT_DYN_CTL0, (I40E_PFINT_DYN_CTL0_INTENA_MASK | I40E_PFINT_DYN_CTL0_SWINT_TRIG_MASK)); @@ -761,7 +761,10 @@ static int i40e_intr_test(struct net_device *netdev, u64 *data) static int i40e_loopback_test(struct net_device *netdev, u64 *data) { - netdev_info(netdev, "loopback test not implemented\n"); + struct i40e_netdev_priv *np = netdev_priv(netdev); + struct i40e_pf *pf = np->vsi->back; + + netif_info(pf, hw, netdev, "loopback test not implemented\n"); *data = 0; return *data; @@ -776,8 +779,7 @@ static void i40e_diag_test(struct net_device *netdev, set_bit(__I40E_TESTING, &pf->state); if (eth_test->flags == ETH_TEST_FL_OFFLINE) { /* Offline tests */ - - netdev_info(netdev, "offline testing starting\n"); + netif_info(pf, drv, netdev, "offline testing starting\n"); /* Link test performed before hardware reset * so autoneg doesn't interfere with test result @@ -798,8 +800,9 @@ static void i40e_diag_test(struct net_device *netdev, eth_test->flags |= ETH_TEST_FL_FAILED; } else { - netdev_info(netdev, "online test starting\n"); /* Online tests */ + netif_info(pf, drv, netdev, "online testing starting\n"); + if (i40e_link_test(netdev, &data[I40E_ETH_TEST_LINK])) eth_test->flags |= ETH_TEST_FL_FAILED; @@ -811,7 +814,7 @@ static void i40e_diag_test(struct net_device *netdev, } clear_bit(__I40E_TESTING, &pf->state); - netdev_info(netdev, "testing finished\n"); + netif_info(pf, drv, netdev, "testing finished\n"); } static void i40e_get_wol(struct net_device *netdev, -- cgit v1.2.3-70-g09d2 From 639dc3777f2539183d6d1e0d84c992cedff598be Mon Sep 17 00:00:00 2001 From: Kamil Krawczyk Date: Wed, 20 Nov 2013 10:03:07 +0000 Subject: i40e: loopback info and set loopback fix Add information about current loopback mode to data returned from get_link_info function. Minor fix in set_loopback function and update in loopback types enum. Change-Id: I9d1c540a84ab18eef5ea6429be6331f33fc06aca Signed-off-by: Kamil Krawczyk Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_common.c | 1 + drivers/net/ethernet/intel/i40e/i40e_diag.h | 8 ++++---- drivers/net/ethernet/intel/i40e/i40e_type.h | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index 0b52fbc7d56..e526d40e9cf 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -562,6 +562,7 @@ i40e_status i40e_aq_get_link_info(struct i40e_hw *hw, hw_link_info->link_info = resp->link_info; hw_link_info->an_info = resp->an_info; hw_link_info->ext_info = resp->ext_info; + hw_link_info->loopback = resp->loopback; if (resp->command_flags & cpu_to_le16(I40E_AQ_LSE_ENABLE)) hw_link_info->lse_enable = true; diff --git a/drivers/net/ethernet/intel/i40e/i40e_diag.h b/drivers/net/ethernet/intel/i40e/i40e_diag.h index 3d98277f452..d1fc68cd6c9 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_diag.h +++ b/drivers/net/ethernet/intel/i40e/i40e_diag.h @@ -31,10 +31,10 @@ #include "i40e_type.h" enum i40e_lb_mode { - I40E_LB_MODE_NONE = 0, - I40E_LB_MODE_PHY_LOCAL, - I40E_LB_MODE_PHY_REMOTE, - I40E_LB_MODE_MAC_LOCAL, + I40E_LB_MODE_NONE = 0x0, + I40E_LB_MODE_PHY_LOCAL = I40E_AQ_LB_PHY_LOCAL, + I40E_LB_MODE_PHY_REMOTE = I40E_AQ_LB_PHY_REMOTE, + I40E_LB_MODE_MAC_LOCAL = I40E_AQ_LB_MAC_LOCAL, }; struct i40e_diag_reg_test_info { diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 88b37e07b25..8ae64457026 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -172,6 +172,7 @@ struct i40e_link_status { u8 link_info; u8 an_info; u8 ext_info; + u8 loopback; /* is Link Status Event notification to SW enabled */ bool lse_enable; }; -- cgit v1.2.3-70-g09d2 From 1fa18370e4cd88669f2d1569d314b05f45b3538e Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 20 Nov 2013 10:03:08 +0000 Subject: i40e: complain about out-of-range descriptor request Instead of silently clamping the descriptor change request into the proper range, fail the request and complain in the log file. Change-Id: Id55ef59255d93c04bedffa8e25fe7ea796c90f32 Signed-off-by: Shannon Nelson Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index b04e4337df4..fd3e379de6d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -422,15 +422,19 @@ static int i40e_set_ringparam(struct net_device *netdev, if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) return -EINVAL; - new_tx_count = clamp_t(u32, ring->tx_pending, - I40E_MIN_NUM_DESCRIPTORS, - I40E_MAX_NUM_DESCRIPTORS); - new_tx_count = ALIGN(new_tx_count, I40E_REQ_DESCRIPTOR_MULTIPLE); - - new_rx_count = clamp_t(u32, ring->rx_pending, - I40E_MIN_NUM_DESCRIPTORS, - I40E_MAX_NUM_DESCRIPTORS); - new_rx_count = ALIGN(new_rx_count, I40E_REQ_DESCRIPTOR_MULTIPLE); + if (ring->tx_pending > I40E_MAX_NUM_DESCRIPTORS || + ring->tx_pending < I40E_MIN_NUM_DESCRIPTORS || + ring->rx_pending > I40E_MAX_NUM_DESCRIPTORS || + ring->rx_pending < I40E_MIN_NUM_DESCRIPTORS) { + netdev_info(netdev, + "Descriptors requested (Tx: %d / Rx: %d) out of range [%d-%d]\n", + ring->tx_pending, ring->rx_pending, + I40E_MIN_NUM_DESCRIPTORS, I40E_MAX_NUM_DESCRIPTORS); + return -EINVAL; + } + + new_tx_count = ALIGN(ring->tx_pending, I40E_REQ_DESCRIPTOR_MULTIPLE); + new_rx_count = ALIGN(ring->rx_pending, I40E_REQ_DESCRIPTOR_MULTIPLE); /* if nothing to do return success */ if ((new_tx_count == vsi->tx_rings[0]->count) && -- cgit v1.2.3-70-g09d2 From 0319577f8902cd420d3159ac6dd134f1de10b52e Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Wed, 20 Nov 2013 10:03:09 +0000 Subject: i40e: remove and fix confusing define name I40E_ITR_NONE was being used as an ITRN register index by accident because it was easily associated with the I40E_RX_ITR and friends defines. Change the name slightly in order to make it clear that I40E_ITR_NONE is really associated with the DYN_CTL register sets. Change-Id: I04702c027c7495b90a8bf2db85d3e085a2c7d02a Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_txrx.h | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h index db55d9947f1..faabf22fbd2 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h @@ -49,10 +49,23 @@ #define I40E_QUEUE_END_OF_LIST 0x7FF -#define I40E_ITR_NONE 3 -#define I40E_RX_ITR 0 -#define I40E_TX_ITR 1 -#define I40E_PE_ITR 2 +/* this enum matches hardware bits and is meant to be used by DYN_CTLN + * registers and QINT registers or more generally anywhere in the manual + * mentioning ITR_INDX, ITR_NONE cannot be used as an index 'n' into any + * register but instead is a special value meaning "don't update" ITR0/1/2. + */ +enum i40e_dyn_idx_t { + I40E_IDX_ITR0 = 0, + I40E_IDX_ITR1 = 1, + I40E_IDX_ITR2 = 2, + I40E_ITR_NONE = 3 /* ITR_NONE must not be used as an index */ +}; + +/* these are indexes into ITRN registers */ +#define I40E_RX_ITR I40E_IDX_ITR0 +#define I40E_TX_ITR I40E_IDX_ITR1 +#define I40E_PE_ITR I40E_IDX_ITR2 + /* Supported Rx Buffer Sizes */ #define I40E_RXBUFFER_512 512 /* Used for packet split */ #define I40E_RXBUFFER_2048 2048 -- cgit v1.2.3-70-g09d2 From 893238ac136d40d3321f02f4d4702fce4d265f4e Mon Sep 17 00:00:00 2001 From: Catherine Sullivan Date: Wed, 20 Nov 2013 10:03:10 +0000 Subject: i40e: Bump version number Version updated to 0.3.13-k Signed-off-by: Catherine Sullivan Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index d2b48bb237f..a6291e23fe5 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -36,7 +36,7 @@ static const char i40e_driver_string[] = #define DRV_VERSION_MAJOR 0 #define DRV_VERSION_MINOR 3 -#define DRV_VERSION_BUILD 12 +#define DRV_VERSION_BUILD 13 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \ __stringify(DRV_VERSION_MINOR) "." \ __stringify(DRV_VERSION_BUILD) DRV_KERN -- cgit v1.2.3-70-g09d2 From c0832b2c105d3b666bab325e2790267157df6290 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Fri, 22 Nov 2013 05:58:15 +0000 Subject: ixgbevf: update Kconfig description This patch updates the ixgbevf Kconfig description, as the VF driver supports more than just the 82599 device. This patch renames the config menu item, as well as updates the help description to make it more obvious that the driver supports more than just a single device group. Signed-off-by: Jacob Keller Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/Kconfig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig index 149ac85b5f9..41a2fa2fc67 100644 --- a/drivers/net/ethernet/intel/Kconfig +++ b/drivers/net/ethernet/intel/Kconfig @@ -220,12 +220,12 @@ config IXGBE_DCB If unsure, say N. config IXGBEVF - tristate "Intel(R) 82599 Virtual Function Ethernet support" + tristate "Intel(R) 10GbE PCI Express Virtual Function Ethernet support" depends on PCI_MSI ---help--- - This driver supports Intel(R) 82599 virtual functions. For more - information on how to identify your adapter, go to the Adapter & - Driver ID Guide at: + This driver supports Intel(R) PCI Express virtual functions for the + Intel(R) ixgbe driver. For more information on how to identify your + adapter, go to the Adapter & Driver ID Guide at: -- cgit v1.2.3-70-g09d2 From 5cdab2f620de9cb14de297326e30e3dd7ea769de Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Wed, 30 Oct 2013 07:45:39 +0000 Subject: ixgbe: Focus config of head, tail ntc, and ntu all into a single function This patch makes it so that head, tail, next to clean, and next to use are all reset in a single function for the Tx or Rx path. Previously the code for this was spread out over several areas which could make it difficult to track what the values for these were. Signed-off-by: Alexander Duyck Signed-off-by: Don Skidmore Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbevf/ixgbevf.h | 4 +- drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 55 ++++++++--------------- 2 files changed, 19 insertions(+), 40 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h index 8971e2d0a98..eaaa3ecacfd 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h @@ -86,9 +86,7 @@ struct ixgbevf_ring { u64 bp_misses; u64 bp_cleaned; #endif - - u16 head; - u16 tail; + u8 __iomem *tail; u16 reg_idx; /* holds the special value that gets the hardware register * offset associated with this ring, which is different diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index 92ef4cb5a8e..84b55fe7154 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -98,10 +98,11 @@ MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); static void ixgbevf_set_itr(struct ixgbevf_q_vector *q_vector); static void ixgbevf_free_all_rx_resources(struct ixgbevf_adapter *adapter); -static inline void ixgbevf_release_rx_desc(struct ixgbe_hw *hw, - struct ixgbevf_ring *rx_ring, +static inline void ixgbevf_release_rx_desc(struct ixgbevf_ring *rx_ring, u32 val) { + rx_ring->next_to_use = val; + /* * Force memory writes to complete before letting h/w * know there are new descriptors to fetch. (Only @@ -109,7 +110,7 @@ static inline void ixgbevf_release_rx_desc(struct ixgbe_hw *hw, * such as IA-64). */ wmb(); - IXGBE_WRITE_REG(hw, IXGBE_VFRDT(rx_ring->reg_idx), val); + writel(val, rx_ring->tail); } /** @@ -406,10 +407,8 @@ static void ixgbevf_alloc_rx_buffers(struct ixgbevf_adapter *adapter, } no_buffers: - if (rx_ring->next_to_use != i) { - rx_ring->next_to_use = i; - ixgbevf_release_rx_desc(&adapter->hw, rx_ring, i); - } + if (rx_ring->next_to_use != i) + ixgbevf_release_rx_desc(rx_ring, i); } static inline void ixgbevf_irq_enable_queues(struct ixgbevf_adapter *adapter, @@ -1110,8 +1109,9 @@ static void ixgbevf_configure_tx(struct ixgbevf_adapter *adapter) IXGBE_WRITE_REG(hw, IXGBE_VFTDLEN(j), tdlen); IXGBE_WRITE_REG(hw, IXGBE_VFTDH(j), 0); IXGBE_WRITE_REG(hw, IXGBE_VFTDT(j), 0); - adapter->tx_ring[i].head = IXGBE_VFTDH(j); - adapter->tx_ring[i].tail = IXGBE_VFTDT(j); + ring->tail = hw->hw_addr + IXGBE_VFTDT(j); + ring->next_to_clean = 0; + ring->next_to_use = 0; /* Disable Tx Head Writeback RO bit, since this hoses * bookkeeping if things aren't delivered in order. */ @@ -1208,20 +1208,22 @@ static void ixgbevf_configure_rx(struct ixgbevf_adapter *adapter) /* set_rx_buffer_len must be called before ring initialization */ ixgbevf_set_rx_buffer_len(adapter); - rdlen = adapter->rx_ring[0].count * sizeof(union ixgbe_adv_rx_desc); /* Setup the HW Rx Head and Tail Descriptor Pointers and * the Base and Length of the Rx Descriptor Ring */ for (i = 0; i < adapter->num_rx_queues; i++) { - rdba = adapter->rx_ring[i].dma; - j = adapter->rx_ring[i].reg_idx; + struct ixgbevf_ring *ring = &adapter->rx_ring[i]; + rdba = ring->dma; + j = ring->reg_idx; + rdlen = ring->count * sizeof(union ixgbe_adv_rx_desc); IXGBE_WRITE_REG(hw, IXGBE_VFRDBAL(j), (rdba & DMA_BIT_MASK(32))); IXGBE_WRITE_REG(hw, IXGBE_VFRDBAH(j), (rdba >> 32)); IXGBE_WRITE_REG(hw, IXGBE_VFRDLEN(j), rdlen); IXGBE_WRITE_REG(hw, IXGBE_VFRDH(j), 0); IXGBE_WRITE_REG(hw, IXGBE_VFRDT(j), 0); - adapter->rx_ring[i].head = IXGBE_VFRDH(j); - adapter->rx_ring[i].tail = IXGBE_VFRDT(j); + ring->tail = hw->hw_addr + IXGBE_VFRDT(j); + ring->next_to_clean = 0; + ring->next_to_use = 0; ixgbevf_configure_srrctl(adapter, j); } @@ -1402,7 +1404,7 @@ static void ixgbevf_rx_desc_queue_enable(struct ixgbevf_adapter *adapter, hw_dbg(hw, "RXDCTL.ENABLE queue %d not set while polling\n", rxr); - ixgbevf_release_rx_desc(&adapter->hw, &adapter->rx_ring[rxr], + ixgbevf_release_rx_desc(&adapter->rx_ring[rxr], (adapter->rx_ring[rxr].count - 1)); } @@ -1680,14 +1682,6 @@ static void ixgbevf_clean_rx_ring(struct ixgbevf_adapter *adapter, /* Zero out the descriptor ring */ memset(rx_ring->desc, 0, rx_ring->size); - - rx_ring->next_to_clean = 0; - rx_ring->next_to_use = 0; - - if (rx_ring->head) - writel(0, adapter->hw.hw_addr + rx_ring->head); - if (rx_ring->tail) - writel(0, adapter->hw.hw_addr + rx_ring->tail); } /** @@ -1715,14 +1709,6 @@ static void ixgbevf_clean_tx_ring(struct ixgbevf_adapter *adapter, memset(tx_ring->tx_buffer_info, 0, size); memset(tx_ring->desc, 0, tx_ring->size); - - tx_ring->next_to_use = 0; - tx_ring->next_to_clean = 0; - - if (tx_ring->head) - writel(0, adapter->hw.hw_addr + tx_ring->head); - if (tx_ring->tail) - writel(0, adapter->hw.hw_addr + tx_ring->tail); } /** @@ -2473,8 +2459,6 @@ int ixgbevf_setup_tx_resources(struct ixgbevf_adapter *adapter, if (!tx_ring->desc) goto err; - tx_ring->next_to_use = 0; - tx_ring->next_to_clean = 0; return 0; err: @@ -2542,9 +2526,6 @@ int ixgbevf_setup_rx_resources(struct ixgbevf_adapter *adapter, goto alloc_failed; } - rx_ring->next_to_clean = 0; - rx_ring->next_to_use = 0; - return 0; alloc_failed: return -ENOMEM; @@ -3181,7 +3162,7 @@ static int ixgbevf_xmit_frame(struct sk_buff *skb, struct net_device *netdev) ixgbevf_tx_map(tx_ring, skb, tx_flags), first, skb->len, hdr_len); - writel(tx_ring->next_to_use, adapter->hw.hw_addr + tx_ring->tail); + writel(tx_ring->next_to_use, tx_ring->tail); ixgbevf_maybe_stop_tx(tx_ring, DESC_NEEDED); -- cgit v1.2.3-70-g09d2 From 2bdfc4e271c290be448ae5df580be1163b998508 Mon Sep 17 00:00:00 2001 From: Carolyn Wyborny Date: Thu, 17 Oct 2013 05:23:01 +0000 Subject: igb: Add media switching feature for i354 PHY's This patch adds a new feature which is supported in some PHY's on some i354 devices. This feature is Auto Media Detect and allows which ever media is detected first by the PHY to be the media used and configured by the device. This is a media swapping feature that is wholly contained in the Marvell PHY. Signed-off-by: Carolyn Wyborny Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/e1000_82575.c | 76 ++++++++++++++++++++++++++ drivers/net/ethernet/intel/igb/e1000_defines.h | 11 ++++ drivers/net/ethernet/intel/igb/e1000_hw.h | 2 + drivers/net/ethernet/intel/igb/igb.h | 1 + drivers/net/ethernet/intel/igb/igb_main.c | 6 ++ 5 files changed, 96 insertions(+) diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c index 47c2d10df82..fe9db48f908 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.c +++ b/drivers/net/ethernet/intel/igb/e1000_82575.c @@ -112,6 +112,59 @@ static bool igb_sgmii_uses_mdio_82575(struct e1000_hw *hw) return ext_mdio; } +/** + * igb_check_for_link_media_swap - Check which M88E1112 interface linked + * @hw: pointer to the HW structure + * + * Poll the M88E1112 interfaces to see which interface achieved link. + */ +static s32 igb_check_for_link_media_swap(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + u8 port = 0; + + /* Check the copper medium. */ + ret_val = phy->ops.write_reg(hw, E1000_M88E1112_PAGE_ADDR, 0); + if (ret_val) + return ret_val; + + ret_val = phy->ops.read_reg(hw, E1000_M88E1112_STATUS, &data); + if (ret_val) + return ret_val; + + if (data & E1000_M88E1112_STATUS_LINK) + port = E1000_MEDIA_PORT_COPPER; + + /* Check the other medium. */ + ret_val = phy->ops.write_reg(hw, E1000_M88E1112_PAGE_ADDR, 1); + if (ret_val) + return ret_val; + + ret_val = phy->ops.read_reg(hw, E1000_M88E1112_STATUS, &data); + if (ret_val) + return ret_val; + + /* reset page to 0 */ + ret_val = phy->ops.write_reg(hw, E1000_M88E1112_PAGE_ADDR, 0); + if (ret_val) + return ret_val; + + if (data & E1000_M88E1112_STATUS_LINK) + port = E1000_MEDIA_PORT_OTHER; + + /* Determine if a swap needs to happen. */ + if (port && (hw->dev_spec._82575.media_port != port)) { + hw->dev_spec._82575.media_port = port; + hw->dev_spec._82575.media_changed = true; + } else { + ret_val = igb_check_for_link_82575(hw); + } + + return E1000_SUCCESS; +} + /** * igb_init_phy_params_82575 - Init PHY func ptrs. * @hw: pointer to the HW structure @@ -189,6 +242,29 @@ static s32 igb_init_phy_params_82575(struct e1000_hw *hw) else phy->ops.get_cable_length = igb_get_cable_length_m88; phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_m88; + /* Check if this PHY is confgured for media swap. */ + if (phy->id == M88E1112_E_PHY_ID) { + u16 data; + + ret_val = phy->ops.write_reg(hw, + E1000_M88E1112_PAGE_ADDR, + 2); + if (ret_val) + goto out; + + ret_val = phy->ops.read_reg(hw, + E1000_M88E1112_MAC_CTRL_1, + &data); + if (ret_val) + goto out; + + data = (data & E1000_M88E1112_MAC_CTRL_1_MODE_MASK) >> + E1000_M88E1112_MAC_CTRL_1_MODE_SHIFT; + if (data == E1000_M88E1112_AUTO_COPPER_SGMII || + data == E1000_M88E1112_AUTO_COPPER_BASEX) + hw->mac.ops.check_for_link = + igb_check_for_link_media_swap; + } break; case IGP03E1000_E_PHY_ID: phy->type = e1000_phy_igp_3; diff --git a/drivers/net/ethernet/intel/igb/e1000_defines.h b/drivers/net/ethernet/intel/igb/e1000_defines.h index 978eca31ced..378ca21aa64 100644 --- a/drivers/net/ethernet/intel/igb/e1000_defines.h +++ b/drivers/net/ethernet/intel/igb/e1000_defines.h @@ -532,6 +532,17 @@ #define E1000_MDICNFG_PHY_MASK 0x03E00000 #define E1000_MDICNFG_PHY_SHIFT 21 +#define E1000_MEDIA_PORT_COPPER 1 +#define E1000_MEDIA_PORT_OTHER 2 +#define E1000_M88E1112_AUTO_COPPER_SGMII 0x2 +#define E1000_M88E1112_AUTO_COPPER_BASEX 0x3 +#define E1000_M88E1112_STATUS_LINK 0x0004 /* Interface Link Bit */ +#define E1000_M88E1112_MAC_CTRL_1 0x10 +#define E1000_M88E1112_MAC_CTRL_1_MODE_MASK 0x0380 /* Mode Select */ +#define E1000_M88E1112_MAC_CTRL_1_MODE_SHIFT 7 +#define E1000_M88E1112_PAGE_ADDR 0x16 +#define E1000_M88E1112_STATUS 0x01 + /* PCI Express Control */ #define E1000_GCR_CMPL_TMOUT_MASK 0x0000F000 #define E1000_GCR_CMPL_TMOUT_10ms 0x00001000 diff --git a/drivers/net/ethernet/intel/igb/e1000_hw.h b/drivers/net/ethernet/intel/igb/e1000_hw.h index 2e166b22d52..5f9758f3206 100644 --- a/drivers/net/ethernet/intel/igb/e1000_hw.h +++ b/drivers/net/ethernet/intel/igb/e1000_hw.h @@ -533,6 +533,8 @@ struct e1000_dev_spec_82575 { bool clear_semaphore_once; struct e1000_sfp_flags eth_flags; bool module_plugged; + u8 media_port; + bool media_changed; }; struct e1000_hw { diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h index 5e9ed89403a..6c807927171 100644 --- a/drivers/net/ethernet/intel/igb/igb.h +++ b/drivers/net/ethernet/intel/igb/igb.h @@ -462,6 +462,7 @@ struct igb_adapter { #define IGB_FLAG_RSS_FIELD_IPV6_UDP (1 << 7) #define IGB_FLAG_WOL_SUPPORTED (1 << 8) #define IGB_FLAG_NEED_LINK_UPDATE (1 << 9) +#define IGB_FLAG_MEDIA_RESET (1 << 10) /* DMA Coalescing defines */ #define IGB_MIN_TXPBSIZE 20408 diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 025e5f4b748..6da479b365c 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -3946,6 +3946,12 @@ static void igb_watchdog_task(struct work_struct *work) } if (link) { + /* Perform a reset if the media type changed. */ + if (hw->dev_spec._82575.media_changed) { + hw->dev_spec._82575.media_changed = false; + adapter->flags |= IGB_FLAG_MEDIA_RESET; + igb_reset(adapter); + } /* Cancel scheduled suspend requests. */ pm_runtime_resume(netdev->dev.parent); -- cgit v1.2.3-70-g09d2 From 89dbefb213a0b3e53fe1a99ec9c1a230aad5f404 Mon Sep 17 00:00:00 2001 From: Aaron Sierra Date: Thu, 31 Oct 2013 00:32:34 +0000 Subject: igb: Support ports mapped in 64-bit PCI space This patch resolves an issue with 64-bit PCI addresses being truncated because the return values of pci_resource_start() and pci_resource_end() were being cast to unsigned long. Signed-off-by: Aaron Sierra Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb_main.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 6da479b365c..ed129f1c5c3 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -2022,7 +2022,6 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) s32 ret_val; static int global_quad_port_a; /* global quad port a indication */ const struct e1000_info *ei = igb_info_tbl[ent->driver_data]; - unsigned long mmio_start, mmio_len; int err, pci_using_dac; u8 part_str[E1000_PBANUM_LENGTH]; @@ -2079,11 +2078,8 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) hw->back = adapter; adapter->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE); - mmio_start = pci_resource_start(pdev, 0); - mmio_len = pci_resource_len(pdev, 0); - err = -EIO; - hw->hw_addr = ioremap(mmio_start, mmio_len); + hw->hw_addr = pci_iomap(pdev, 0, 0); if (!hw->hw_addr) goto err_ioremap; @@ -2093,8 +2089,8 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); - netdev->mem_start = mmio_start; - netdev->mem_end = mmio_start + mmio_len; + netdev->mem_start = pci_resource_start(pdev, 0); + netdev->mem_end = pci_resource_end(pdev, 0); /* PCI config space info */ hw->vendor_id = pdev->vendor; -- cgit v1.2.3-70-g09d2 From 56cec249167b44ee2ba7a3cbf4431bee937e08e3 Mon Sep 17 00:00:00 2001 From: Carolyn Wyborny Date: Thu, 17 Oct 2013 05:36:26 +0000 Subject: igb: Add new feature Media Auto Sense for 82580 devices only This patch adds support for the hardware feature Media Auto Sense. This feature requires a custom EEPROM image provided by our customer support team. The feature allows hardware designed with dual PHY's, fiber and copper to be used with either media without additional EEPROM changes. Fiber is preferred and driver will swap and configure for fiber media if sensed by the device at any time. Device will swap back to copper if it is the only media detected. Signed-off-by: Carolyn Wyborny Tested-by: Jeff Pieper Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/e1000_82575.c | 13 ++ drivers/net/ethernet/intel/igb/e1000_defines.h | 5 + drivers/net/ethernet/intel/igb/e1000_hw.h | 1 + drivers/net/ethernet/intel/igb/igb.h | 10 ++ drivers/net/ethernet/intel/igb/igb_ethtool.c | 4 + drivers/net/ethernet/intel/igb/igb_main.c | 193 +++++++++++++++++++++++++ 6 files changed, 226 insertions(+) diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c index fe9db48f908..06df6928f44 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.c +++ b/drivers/net/ethernet/intel/igb/e1000_82575.c @@ -441,6 +441,19 @@ static s32 igb_init_mac_params_82575(struct e1000_hw *hw) ? igb_setup_copper_link_82575 : igb_setup_serdes_link_82575; + if (mac->type == e1000_82580) { + switch (hw->device_id) { + /* feature not supported on these id's */ + case E1000_DEV_ID_DH89XXCC_SGMII: + case E1000_DEV_ID_DH89XXCC_SERDES: + case E1000_DEV_ID_DH89XXCC_BACKPLANE: + case E1000_DEV_ID_DH89XXCC_SFP: + break; + default: + hw->dev_spec._82575.mas_capable = true; + break; + } + } return 0; } diff --git a/drivers/net/ethernet/intel/igb/e1000_defines.h b/drivers/net/ethernet/intel/igb/e1000_defines.h index 378ca21aa64..0571b973be8 100644 --- a/drivers/net/ethernet/intel/igb/e1000_defines.h +++ b/drivers/net/ethernet/intel/igb/e1000_defines.h @@ -205,6 +205,11 @@ */ #define E1000_CONNSW_ENRGSRC 0x4 +#define E1000_CONNSW_PHYSD 0x400 +#define E1000_CONNSW_PHY_PDN 0x800 +#define E1000_CONNSW_SERDESD 0x200 +#define E1000_CONNSW_AUTOSENSE_CONF 0x2 +#define E1000_CONNSW_AUTOSENSE_EN 0x1 #define E1000_PCS_CFG_PCS_EN 8 #define E1000_PCS_LCTL_FLV_LINK_UP 1 #define E1000_PCS_LCTL_FSV_100 2 diff --git a/drivers/net/ethernet/intel/igb/e1000_hw.h b/drivers/net/ethernet/intel/igb/e1000_hw.h index 5f9758f3206..ab99e2b582a 100644 --- a/drivers/net/ethernet/intel/igb/e1000_hw.h +++ b/drivers/net/ethernet/intel/igb/e1000_hw.h @@ -535,6 +535,7 @@ struct e1000_dev_spec_82575 { bool module_plugged; u8 media_port; bool media_changed; + bool mas_capable; }; struct e1000_hw { diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h index 6c807927171..11173f46f43 100644 --- a/drivers/net/ethernet/intel/igb/igb.h +++ b/drivers/net/ethernet/intel/igb/igb.h @@ -450,6 +450,8 @@ struct igb_adapter { u8 rss_indir_tbl[IGB_RETA_SIZE]; unsigned long link_check_timeout; + int copper_tries; + struct e1000_info ei; }; #define IGB_FLAG_HAS_MSI (1 << 0) @@ -463,6 +465,14 @@ struct igb_adapter { #define IGB_FLAG_WOL_SUPPORTED (1 << 8) #define IGB_FLAG_NEED_LINK_UPDATE (1 << 9) #define IGB_FLAG_MEDIA_RESET (1 << 10) +#define IGB_FLAG_MAS_CAPABLE (1 << 11) +#define IGB_FLAG_MAS_ENABLE (1 << 12) + +/* Media Auto Sense */ +#define IGB_MAS_ENABLE_0 0X0001 +#define IGB_MAS_ENABLE_1 0X0002 +#define IGB_MAS_ENABLE_2 0X0004 +#define IGB_MAS_ENABLE_3 0X0008 /* DMA Coalescing defines */ #define IGB_MIN_TXPBSIZE 20408 diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index c3143da497c..1c7d2381af8 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c @@ -1983,6 +1983,10 @@ static void igb_diag_test(struct net_device *netdev, bool if_running = netif_running(netdev); set_bit(__IGB_TESTING, &adapter->state); + + /* can't do offline tests on media switching devices */ + if (adapter->hw.dev_spec._82575.mas_capable) + eth_test->flags &= ~ETH_TEST_FL_OFFLINE; if (eth_test->flags == ETH_TEST_FL_OFFLINE) { /* Offline tests */ diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index ed129f1c5c3..3bc10bd5bbc 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -1606,6 +1606,73 @@ static void igb_power_down_link(struct igb_adapter *adapter) igb_shutdown_serdes_link_82575(&adapter->hw); } +/** + * Detect and switch function for Media Auto Sense + * @adapter: address of the board private structure + **/ +static void igb_check_swap_media(struct igb_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 ctrl_ext, connsw; + bool swap_now = false; + + ctrl_ext = rd32(E1000_CTRL_EXT); + connsw = rd32(E1000_CONNSW); + + /* need to live swap if current media is copper and we have fiber/serdes + * to go to. + */ + + if ((hw->phy.media_type == e1000_media_type_copper) && + (!(connsw & E1000_CONNSW_AUTOSENSE_EN))) { + swap_now = true; + } else if (!(connsw & E1000_CONNSW_SERDESD)) { + /* copper signal takes time to appear */ + if (adapter->copper_tries < 4) { + adapter->copper_tries++; + connsw |= E1000_CONNSW_AUTOSENSE_CONF; + wr32(E1000_CONNSW, connsw); + return; + } else { + adapter->copper_tries = 0; + if ((connsw & E1000_CONNSW_PHYSD) && + (!(connsw & E1000_CONNSW_PHY_PDN))) { + swap_now = true; + connsw &= ~E1000_CONNSW_AUTOSENSE_CONF; + wr32(E1000_CONNSW, connsw); + } + } + } + + if (!swap_now) + return; + + switch (hw->phy.media_type) { + case e1000_media_type_copper: + netdev_info(adapter->netdev, + "MAS: changing media to fiber/serdes\n"); + ctrl_ext |= + E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES; + adapter->flags |= IGB_FLAG_MEDIA_RESET; + adapter->copper_tries = 0; + break; + case e1000_media_type_internal_serdes: + case e1000_media_type_fiber: + netdev_info(adapter->netdev, + "MAS: changing media to copper\n"); + ctrl_ext &= + ~E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES; + adapter->flags |= IGB_FLAG_MEDIA_RESET; + break; + default: + /* shouldn't get here during regular operation */ + netdev_err(adapter->netdev, + "AMS: Invalid media type found, returning\n"); + break; + } + wr32(E1000_CTRL_EXT, ctrl_ext); +} + /** * igb_up - Open the interface and prepare it to handle traffic * @adapter: board private structure @@ -1719,6 +1786,37 @@ void igb_reinit_locked(struct igb_adapter *adapter) clear_bit(__IGB_RESETTING, &adapter->state); } +/** igb_enable_mas - Media Autosense re-enable after swap + * + * @adapter: adapter struct + **/ +static s32 igb_enable_mas(struct igb_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 connsw; + s32 ret_val = 0; + + connsw = rd32(E1000_CONNSW); + if (!(hw->phy.media_type == e1000_media_type_copper)) + return ret_val; + + /* configure for SerDes media detect */ + if (!(connsw & E1000_CONNSW_SERDESD)) { + connsw |= E1000_CONNSW_ENRGSRC; + connsw |= E1000_CONNSW_AUTOSENSE_EN; + wr32(E1000_CONNSW, connsw); + wrfl(); + } else if (connsw & E1000_CONNSW_SERDESD) { + /* already SerDes, no need to enable anything */ + return ret_val; + } else { + netdev_info(adapter->netdev, + "MAS: Unable to configure feature, disabling..\n"); + adapter->flags &= ~IGB_FLAG_MAS_ENABLE; + } + return ret_val; +} + void igb_reset(struct igb_adapter *adapter) { struct pci_dev *pdev = adapter->pdev; @@ -1830,6 +1928,16 @@ void igb_reset(struct igb_adapter *adapter) hw->mac.ops.reset_hw(hw); wr32(E1000_WUC, 0); + if (adapter->flags & IGB_FLAG_MEDIA_RESET) { + /* need to resetup here after media swap */ + adapter->ei.get_invariants(hw); + adapter->flags &= ~IGB_FLAG_MEDIA_RESET; + } + if (adapter->flags & IGB_FLAG_MAS_ENABLE) { + if (igb_enable_mas(adapter)) + dev_err(&pdev->dev, + "Error enabling Media Auto Sense\n"); + } if (hw->mac.ops.init_hw(hw)) dev_err(&pdev->dev, "Hardware Error\n"); @@ -1975,6 +2083,58 @@ void igb_set_fw_version(struct igb_adapter *adapter) return; } +/** + * igb_init_mas - init Media Autosense feature if enabled in the NVM + * + * @adapter: adapter struct + **/ +static void igb_init_mas(struct igb_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u16 eeprom_data; + + hw->nvm.ops.read(hw, NVM_COMPAT, 1, &eeprom_data); + switch (hw->bus.func) { + case E1000_FUNC_0: + if (eeprom_data & IGB_MAS_ENABLE_0) { + adapter->flags |= IGB_FLAG_MAS_ENABLE; + netdev_info(adapter->netdev, + "MAS: Enabling Media Autosense for port %d\n", + hw->bus.func); + } + break; + case E1000_FUNC_1: + if (eeprom_data & IGB_MAS_ENABLE_1) { + adapter->flags |= IGB_FLAG_MAS_ENABLE; + netdev_info(adapter->netdev, + "MAS: Enabling Media Autosense for port %d\n", + hw->bus.func); + } + break; + case E1000_FUNC_2: + if (eeprom_data & IGB_MAS_ENABLE_2) { + adapter->flags |= IGB_FLAG_MAS_ENABLE; + netdev_info(adapter->netdev, + "MAS: Enabling Media Autosense for port %d\n", + hw->bus.func); + } + break; + case E1000_FUNC_3: + if (eeprom_data & IGB_MAS_ENABLE_3) { + adapter->flags |= IGB_FLAG_MAS_ENABLE; + netdev_info(adapter->netdev, + "MAS: Enabling Media Autosense for port %d\n", + hw->bus.func); + } + break; + default: + /* Shouldn't get here */ + netdev_err(adapter->netdev, + "MAS: Invalid port configuration, returning\n"); + break; + } +} + /** * igb_init_i2c - Init I2C interface * @adapter: pointer to adapter structure @@ -2346,6 +2506,11 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) adapter->ets = false; } #endif + /* Check if Media Autosense is enabled */ + adapter->ei = *ei; + if (hw->dev_spec._82575.mas_capable) + igb_init_mas(adapter); + /* do hw tstamp init after resetting */ igb_ptp_init(adapter); @@ -3931,6 +4096,7 @@ static void igb_watchdog_task(struct work_struct *work) struct net_device *netdev = adapter->netdev; u32 link; int i; + u32 connsw; link = igb_has_link(adapter); @@ -3941,6 +4107,14 @@ static void igb_watchdog_task(struct work_struct *work) link = false; } + /* Force link down if we have fiber to swap to */ + if (adapter->flags & IGB_FLAG_MAS_ENABLE) { + if (hw->phy.media_type == e1000_media_type_copper) { + connsw = rd32(E1000_CONNSW); + if (!(connsw & E1000_CONNSW_AUTOSENSE_EN)) + link = 0; + } + } if (link) { /* Perform a reset if the media type changed. */ if (hw->dev_spec._82575.media_changed) { @@ -4028,8 +4202,27 @@ static void igb_watchdog_task(struct work_struct *work) mod_timer(&adapter->phy_info_timer, round_jiffies(jiffies + 2 * HZ)); + /* link is down, time to check for alternate media */ + if (adapter->flags & IGB_FLAG_MAS_ENABLE) { + igb_check_swap_media(adapter); + if (adapter->flags & IGB_FLAG_MEDIA_RESET) { + schedule_work(&adapter->reset_task); + /* return immediately */ + return; + } + } pm_schedule_suspend(netdev->dev.parent, MSEC_PER_SEC * 5); + + /* also check for alternate media here */ + } else if (!netif_carrier_ok(netdev) && + (adapter->flags & IGB_FLAG_MAS_ENABLE)) { + igb_check_swap_media(adapter); + if (adapter->flags & IGB_FLAG_MEDIA_RESET) { + schedule_work(&adapter->reset_task); + /* return immediately */ + return; + } } } -- cgit v1.2.3-70-g09d2 From e3670b81954ab1247341a08514aa4df09f0b495e Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 26 Nov 2013 07:15:23 +0000 Subject: igb: Convert to use devm_hwmon_device_register_with_groups Simplify the code. Attach hwmon sysfs attributes to hwmon device instead of pci device. Avoid race conditions caused by attributes being created after registration and provide mandatory 'name' attribute by using new hwmon API. Other cleanup: Instead of allocating memory for hwmon attributes, move attributes and all other hwmon related data into struct hwmon_buff and allocate the entire structure using devm_kzalloc. Check return value from calls to igb_add_hwmon_attr() one by one instead of logically combining them all together. Signed-off-by: Guenter Roeck Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb.h | 8 ++- drivers/net/ethernet/intel/igb/igb_hwmon.c | 100 ++++++++++++++--------------- 2 files changed, 53 insertions(+), 55 deletions(-) diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h index 11173f46f43..8aaca0a1dca 100644 --- a/drivers/net/ethernet/intel/igb/igb.h +++ b/drivers/net/ethernet/intel/igb/igb.h @@ -337,8 +337,10 @@ struct hwmon_attr { }; struct hwmon_buff { - struct device *device; - struct hwmon_attr *hwmon_list; + struct attribute_group group; + const struct attribute_group *groups[2]; + struct attribute *attrs[E1000_MAX_SENSORS * 4 + 1]; + struct hwmon_attr hwmon_list[E1000_MAX_SENSORS * 4]; unsigned int n_hwmon; }; #endif @@ -440,7 +442,7 @@ struct igb_adapter { char fw_version[32]; #ifdef CONFIG_IGB_HWMON - struct hwmon_buff igb_hwmon_buff; + struct hwmon_buff *igb_hwmon_buff; bool ets; #endif struct i2c_algo_bit_data i2c_algo; diff --git a/drivers/net/ethernet/intel/igb/igb_hwmon.c b/drivers/net/ethernet/intel/igb/igb_hwmon.c index 58f1ce967ae..2e7ef2d0711 100644 --- a/drivers/net/ethernet/intel/igb/igb_hwmon.c +++ b/drivers/net/ethernet/intel/igb/igb_hwmon.c @@ -117,8 +117,8 @@ static int igb_add_hwmon_attr(struct igb_adapter *adapter, unsigned int n_attr; struct hwmon_attr *igb_attr; - n_attr = adapter->igb_hwmon_buff.n_hwmon; - igb_attr = &adapter->igb_hwmon_buff.hwmon_list[n_attr]; + n_attr = adapter->igb_hwmon_buff->n_hwmon; + igb_attr = &adapter->igb_hwmon_buff->hwmon_list[n_attr]; switch (type) { case IGB_HWMON_TYPE_LOC: @@ -154,30 +154,16 @@ static int igb_add_hwmon_attr(struct igb_adapter *adapter, igb_attr->dev_attr.attr.mode = S_IRUGO; igb_attr->dev_attr.attr.name = igb_attr->name; sysfs_attr_init(&igb_attr->dev_attr.attr); - rc = device_create_file(&adapter->pdev->dev, - &igb_attr->dev_attr); - if (rc == 0) - ++adapter->igb_hwmon_buff.n_hwmon; - return rc; + adapter->igb_hwmon_buff->attrs[n_attr] = &igb_attr->dev_attr.attr; + + ++adapter->igb_hwmon_buff->n_hwmon; + + return 0; } static void igb_sysfs_del_adapter(struct igb_adapter *adapter) { - int i; - - if (adapter == NULL) - return; - - for (i = 0; i < adapter->igb_hwmon_buff.n_hwmon; i++) { - device_remove_file(&adapter->pdev->dev, - &adapter->igb_hwmon_buff.hwmon_list[i].dev_attr); - } - - kfree(adapter->igb_hwmon_buff.hwmon_list); - - if (adapter->igb_hwmon_buff.device) - hwmon_device_unregister(adapter->igb_hwmon_buff.device); } /* called from igb_main.c */ @@ -189,11 +175,11 @@ void igb_sysfs_exit(struct igb_adapter *adapter) /* called from igb_main.c */ int igb_sysfs_init(struct igb_adapter *adapter) { - struct hwmon_buff *igb_hwmon = &adapter->igb_hwmon_buff; + struct hwmon_buff *igb_hwmon; + struct i2c_client *client; + struct device *hwmon_dev; unsigned int i; - int n_attrs; int rc = 0; - struct i2c_client *client = NULL; /* If this method isn't defined we don't support thermals */ if (adapter->hw.mac.ops.init_thermal_sensor_thresh == NULL) @@ -201,34 +187,16 @@ int igb_sysfs_init(struct igb_adapter *adapter) /* Don't create thermal hwmon interface if no sensors present */ rc = (adapter->hw.mac.ops.init_thermal_sensor_thresh(&adapter->hw)); - if (rc) - goto exit; - - /* init i2c_client */ - client = i2c_new_device(&adapter->i2c_adap, &i350_sensor_info); - if (client == NULL) { - dev_info(&adapter->pdev->dev, - "Failed to create new i2c device..\n"); + if (rc) goto exit; - } - adapter->i2c_client = client; - /* Allocation space for max attributes - * max num sensors * values (loc, temp, max, caution) - */ - n_attrs = E1000_MAX_SENSORS * 4; - igb_hwmon->hwmon_list = kcalloc(n_attrs, sizeof(struct hwmon_attr), - GFP_KERNEL); - if (!igb_hwmon->hwmon_list) { + igb_hwmon = devm_kzalloc(&adapter->pdev->dev, sizeof(*igb_hwmon), + GFP_KERNEL); + if (!igb_hwmon) { rc = -ENOMEM; - goto err; - } - - igb_hwmon->device = hwmon_device_register(&adapter->pdev->dev); - if (IS_ERR(igb_hwmon->device)) { - rc = PTR_ERR(igb_hwmon->device); - goto err; + goto exit; } + adapter->igb_hwmon_buff = igb_hwmon; for (i = 0; i < E1000_MAX_SENSORS; i++) { @@ -240,11 +208,39 @@ int igb_sysfs_init(struct igb_adapter *adapter) /* Bail if any hwmon attr struct fails to initialize */ rc = igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_CAUTION); - rc |= igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_LOC); - rc |= igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_TEMP); - rc |= igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_MAX); if (rc) - goto err; + goto exit; + rc = igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_LOC); + if (rc) + goto exit; + rc = igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_TEMP); + if (rc) + goto exit; + rc = igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_MAX); + if (rc) + goto exit; + } + + /* init i2c_client */ + client = i2c_new_device(&adapter->i2c_adap, &i350_sensor_info); + if (client == NULL) { + dev_info(&adapter->pdev->dev, + "Failed to create new i2c device.\n"); + rc = -ENODEV; + goto exit; + } + adapter->i2c_client = client; + + igb_hwmon->groups[0] = &igb_hwmon->group; + igb_hwmon->group.attrs = igb_hwmon->attrs; + + hwmon_dev = devm_hwmon_device_register_with_groups(&adapter->pdev->dev, + client->name, + igb_hwmon, + igb_hwmon->groups); + if (IS_ERR(hwmon_dev)) { + rc = PTR_ERR(hwmon_dev); + goto err; } goto exit; -- cgit v1.2.3-70-g09d2 From e6e25bba9b8a343af6b5e281a0378d3c8ae52165 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 26 Nov 2013 07:15:34 +0000 Subject: igb: Start temperature sensor attribute index with 1 Per hwmon ABI, temperature sensor attribute index starts with 1, not 0. Signed-off-by: Guenter Roeck Reviewed-by: Jean Delvare Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb_hwmon.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/igb/igb_hwmon.c b/drivers/net/ethernet/intel/igb/igb_hwmon.c index 2e7ef2d0711..e0af5bc6161 100644 --- a/drivers/net/ethernet/intel/igb/igb_hwmon.c +++ b/drivers/net/ethernet/intel/igb/igb_hwmon.c @@ -124,22 +124,22 @@ static int igb_add_hwmon_attr(struct igb_adapter *adapter, case IGB_HWMON_TYPE_LOC: igb_attr->dev_attr.show = igb_hwmon_show_location; snprintf(igb_attr->name, sizeof(igb_attr->name), - "temp%u_label", offset); + "temp%u_label", offset + 1); break; case IGB_HWMON_TYPE_TEMP: igb_attr->dev_attr.show = igb_hwmon_show_temp; snprintf(igb_attr->name, sizeof(igb_attr->name), - "temp%u_input", offset); + "temp%u_input", offset + 1); break; case IGB_HWMON_TYPE_CAUTION: igb_attr->dev_attr.show = igb_hwmon_show_cautionthresh; snprintf(igb_attr->name, sizeof(igb_attr->name), - "temp%u_max", offset); + "temp%u_max", offset + 1); break; case IGB_HWMON_TYPE_MAX: igb_attr->dev_attr.show = igb_hwmon_show_maxopthresh; snprintf(igb_attr->name, sizeof(igb_attr->name), - "temp%u_crit", offset); + "temp%u_crit", offset + 1); break; default: rc = -EPERM; -- cgit v1.2.3-70-g09d2 From 971a351ccbbd2b6eef136a2221da0b80aca50906 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 10 Dec 2013 13:56:29 +0100 Subject: ipv6 addrconf: revert /proc/net/if_inet6 ifa_flag format Turned out that applications like ifconfig do not handle the change. So revert ifa_flag format back to 2-letter hex value. Introduced by: commit 479840ffdbe4242e8a25349218c8e0859223aa35 "ipv6 addrconf: extend ifa_flags to u32" Reported-by: Alexander Aring Signed-off-by: Jiri Pirko Tested-by: FLorent Fourcot Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index be4dbbd17d3..3c3425ee6a2 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -3367,12 +3367,12 @@ static void if6_seq_stop(struct seq_file *seq, void *v) static int if6_seq_show(struct seq_file *seq, void *v) { struct inet6_ifaddr *ifp = (struct inet6_ifaddr *)v; - seq_printf(seq, "%pi6 %02x %02x %02x %03x %8s\n", + seq_printf(seq, "%pi6 %02x %02x %02x %02x %8s\n", &ifp->addr, ifp->idev->dev->ifindex, ifp->prefix_len, ifp->scope, - ifp->flags, + (u8) ifp->flags, ifp->idev->dev->name); return 0; } -- cgit v1.2.3-70-g09d2 From 10ae76faa97cb3e1020dcf2cdae6b1ea8359abab Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Tue, 10 Dec 2013 15:00:50 -0500 Subject: cipso: cleanup cipso_v4_translate() when !CONFIG_NETLABEL Don't needlessly recompute 'opt[opt_iter + 1]' as we already have it stored in 'tag_len'. Signed-off-by: Paul Moore Signed-off-by: David S. Miller --- include/net/cipso_ipv4.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/cipso_ipv4.h b/include/net/cipso_ipv4.h index 2179d071f68..a6fd939f202 100644 --- a/include/net/cipso_ipv4.h +++ b/include/net/cipso_ipv4.h @@ -303,7 +303,7 @@ static inline int cipso_v4_validate(const struct sk_buff *skb, for (opt_iter = 6; opt_iter < opt_len;) { tag_len = opt[opt_iter + 1]; - if ((tag_len == 0) || (opt[opt_iter + 1] > (opt_len - opt_iter))) { + if ((tag_len == 0) || (tag_len > (opt_len - opt_iter))) { err_offset = opt_iter + 1; goto out; } -- cgit v1.2.3-70-g09d2 From 77d47afbf3c58350c3708b609005358bbd33e085 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 10 Dec 2013 23:55:07 +0100 Subject: neigh: use neigh_parms_net() to get struct neigh_parms->net pointer This fixes compile error when CONFIG_NET_NS is not set. Introduced by: commit 1d4c8c29841b9991cdf3c7cc4ba7f96a94f104ca "neigh: restore old behaviour of default parms values" Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- net/core/neighbour.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index ce2b77515a9..8be82a7f0e0 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -2850,7 +2850,7 @@ static void neigh_proc_update(struct ctl_table *ctl, int write) { struct net_device *dev = ctl->extra1; struct neigh_parms *p = ctl->extra2; - struct net *net = p->net; + struct net *net = neigh_parms_net(p); int index = (int *) ctl->data - p->data; if (!write) -- cgit v1.2.3-70-g09d2 From 4e34da4d4252f93a7bc66017a7577afb03c3cb8e Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Tue, 10 Dec 2013 17:19:39 +0100 Subject: bgmac: start/stop PHY on netdev open/stop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I've realized that I need to call ethtool command to get Ethernet working after booting. Ex call: ethtool -s eth0 autoneg on It was fixing Ethernet even if auto-negotiation was already on. Adding calls to phy_start and phy_stop look like a real solution. Signed-off-by: Rafał Miłecki Acked-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bgmac.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c index 0452937227f..fd6a22e3dd7 100644 --- a/drivers/net/ethernet/broadcom/bgmac.c +++ b/drivers/net/ethernet/broadcom/bgmac.c @@ -1141,6 +1141,8 @@ static int bgmac_open(struct net_device *net_dev) } napi_enable(&bgmac->napi); + phy_start(bgmac->phy_dev); + netif_carrier_on(net_dev); err_out: @@ -1153,6 +1155,8 @@ static int bgmac_stop(struct net_device *net_dev) netif_carrier_off(net_dev); + phy_stop(bgmac->phy_dev); + napi_disable(&bgmac->napi); bgmac_chip_intrs_off(bgmac); free_irq(bgmac->core->irq, net_dev); -- cgit v1.2.3-70-g09d2 From 94a12b15e4c575e0aa0ba5e24a4f213163a823d0 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sun, 8 Dec 2013 02:59:18 +0300 Subject: sh_eth: add R8A7791 support Add support for yet another ARM member of the R-Car family, R-Car M2, also known as R8A7791 -- it will share the code and data with previously added R8A7790. Despite the Ether devices in these SoCs are indistinguishable at least from the driver's point of view, we do introduce a new platform device ID "r8a7791-ether" unlike the wildcard ID used for R8A7778/9 SoCs, due to newly established policy for the Renesas SoCs. Signed-off-by: Sergei Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/Kconfig | 2 +- drivers/net/ethernet/renesas/sh_eth.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/renesas/Kconfig b/drivers/net/ethernet/renesas/Kconfig index a30c4395b23..9e757c792d8 100644 --- a/drivers/net/ethernet/renesas/Kconfig +++ b/drivers/net/ethernet/renesas/Kconfig @@ -13,4 +13,4 @@ config SH_ETH Renesas SuperH Ethernet device driver. This driver supporting CPUs are: - SH7619, SH7710, SH7712, SH7724, SH7734, SH7763, SH7757, - R8A7740, R8A777x and R8A7790. + R8A7740, R8A777x and R8A779x. diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 6761dde7007..8601d0c638c 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -395,8 +395,8 @@ static struct sh_eth_cpu_data r8a777x_data = { .hw_swap = 1, }; -/* R8A7790 */ -static struct sh_eth_cpu_data r8a7790_data = { +/* R8A7790/1 */ +static struct sh_eth_cpu_data r8a779x_data = { .set_duplex = sh_eth_set_duplex, .set_rate = sh_eth_set_rate_r8a777x, @@ -2810,7 +2810,8 @@ static struct platform_device_id sh_eth_id_table[] = { { "sh7763-gether", (kernel_ulong_t)&sh7763_data }, { "r8a7740-gether", (kernel_ulong_t)&r8a7740_data }, { "r8a777x-ether", (kernel_ulong_t)&r8a777x_data }, - { "r8a7790-ether", (kernel_ulong_t)&r8a7790_data }, + { "r8a7790-ether", (kernel_ulong_t)&r8a779x_data }, + { "r8a7791-ether", (kernel_ulong_t)&r8a779x_data }, { } }; MODULE_DEVICE_TABLE(platform, sh_eth_id_table); -- cgit v1.2.3-70-g09d2 From 9a32b860431aee0cba50ab2414bfa29f4bb2f0d7 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sun, 8 Dec 2013 12:16:09 +0100 Subject: dn_dev: add support for IFA_FLAGS nl attribute Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- include/net/dn_dev.h | 2 +- net/decnet/dn_dev.c | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/include/net/dn_dev.h b/include/net/dn_dev.h index 20b5ab06032..197886cd7bd 100644 --- a/include/net/dn_dev.h +++ b/include/net/dn_dev.h @@ -9,7 +9,7 @@ struct dn_ifaddr { struct dn_dev *ifa_dev; __le16 ifa_local; __le16 ifa_address; - __u8 ifa_flags; + __u32 ifa_flags; __u8 ifa_scope; char ifa_label[IFNAMSIZ]; struct rcu_head rcu; diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index dd0dfb25f4b..a603823a3e2 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -561,6 +561,7 @@ static const struct nla_policy dn_ifa_policy[IFA_MAX+1] = { [IFA_LOCAL] = { .type = NLA_U16 }, [IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, + [IFA_FLAGS] = { .type = NLA_U32 }, }; static int dn_nl_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh) @@ -648,7 +649,8 @@ static int dn_nl_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh) ifa->ifa_local = nla_get_le16(tb[IFA_LOCAL]); ifa->ifa_address = nla_get_le16(tb[IFA_ADDRESS]); - ifa->ifa_flags = ifm->ifa_flags; + ifa->ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) : + ifm->ifa_flags; ifa->ifa_scope = ifm->ifa_scope; ifa->ifa_dev = dn_db; @@ -669,7 +671,8 @@ static inline size_t dn_ifaddr_nlmsg_size(void) return NLMSG_ALIGN(sizeof(struct ifaddrmsg)) + nla_total_size(IFNAMSIZ) /* IFA_LABEL */ + nla_total_size(2) /* IFA_ADDRESS */ - + nla_total_size(2); /* IFA_LOCAL */ + + nla_total_size(2) /* IFA_LOCAL */ + + nla_total_size(4); /* IFA_FLAGS */ } static int dn_nl_fill_ifaddr(struct sk_buff *skb, struct dn_ifaddr *ifa, @@ -677,6 +680,7 @@ static int dn_nl_fill_ifaddr(struct sk_buff *skb, struct dn_ifaddr *ifa, { struct ifaddrmsg *ifm; struct nlmsghdr *nlh; + u32 ifa_flags = ifa->ifa_flags | IFA_F_PERMANENT; nlh = nlmsg_put(skb, portid, seq, event, sizeof(*ifm), flags); if (nlh == NULL) @@ -685,7 +689,7 @@ static int dn_nl_fill_ifaddr(struct sk_buff *skb, struct dn_ifaddr *ifa, ifm = nlmsg_data(nlh); ifm->ifa_family = AF_DECnet; ifm->ifa_prefixlen = 16; - ifm->ifa_flags = ifa->ifa_flags | IFA_F_PERMANENT; + ifm->ifa_flags = ifa_flags; ifm->ifa_scope = ifa->ifa_scope; ifm->ifa_index = ifa->ifa_dev->dev->ifindex; @@ -694,7 +698,8 @@ static int dn_nl_fill_ifaddr(struct sk_buff *skb, struct dn_ifaddr *ifa, (ifa->ifa_local && nla_put_le16(skb, IFA_LOCAL, ifa->ifa_local)) || (ifa->ifa_label[0] && - nla_put_string(skb, IFA_LABEL, ifa->ifa_label))) + nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) || + nla_put_u32(skb, IFA_FLAGS, ifa_flags)) goto nla_put_failure; return nlmsg_end(skb, nlh); -- cgit v1.2.3-70-g09d2 From ad6c81359fc3e6086d1d6f91acda9d5d0e64b2c3 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sun, 8 Dec 2013 12:16:10 +0100 Subject: ipv4: add support for IFA_FLAGS nl attribute Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- include/linux/inetdevice.h | 2 +- net/ipv4/devinet.c | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h index ae174ca565c..562e5c7c5d3 100644 --- a/include/linux/inetdevice.h +++ b/include/linux/inetdevice.h @@ -136,8 +136,8 @@ struct in_ifaddr { __be32 ifa_mask; __be32 ifa_broadcast; unsigned char ifa_scope; - unsigned char ifa_flags; unsigned char ifa_prefixlen; + __u32 ifa_flags; char ifa_label[IFNAMSIZ]; /* In seconds, relative to tstamp. Expiry is at tstamp + HZ * lft. */ diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 43065be3630..6f49efc9d4b 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -99,6 +99,7 @@ static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = { [IFA_BROADCAST] = { .type = NLA_U32 }, [IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) }, + [IFA_FLAGS] = { .type = NLA_U32 }, }; #define IN4_ADDR_HSIZE_SHIFT 8 @@ -757,7 +758,8 @@ static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh, INIT_HLIST_NODE(&ifa->hash); ifa->ifa_prefixlen = ifm->ifa_prefixlen; ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen); - ifa->ifa_flags = ifm->ifa_flags; + ifa->ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) : + ifm->ifa_flags; ifa->ifa_scope = ifm->ifa_scope; ifa->ifa_dev = in_dev; @@ -1437,7 +1439,8 @@ static size_t inet_nlmsg_size(void) + nla_total_size(4) /* IFA_ADDRESS */ + nla_total_size(4) /* IFA_LOCAL */ + nla_total_size(4) /* IFA_BROADCAST */ - + nla_total_size(IFNAMSIZ); /* IFA_LABEL */ + + nla_total_size(IFNAMSIZ) /* IFA_LABEL */ + + nla_total_size(4); /* IFA_FLAGS */ } static inline u32 cstamp_delta(unsigned long cstamp) @@ -1505,6 +1508,7 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, nla_put_be32(skb, IFA_BROADCAST, ifa->ifa_broadcast)) || (ifa->ifa_label[0] && nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) || + nla_put_u32(skb, IFA_FLAGS, ifa->ifa_flags) || put_cacheinfo(skb, ifa->ifa_cstamp, ifa->ifa_tstamp, preferred, valid)) goto nla_put_failure; -- cgit v1.2.3-70-g09d2 From 8e3bff96afa67369008153f3326fa5ce985cabab Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Sun, 8 Dec 2013 12:15:44 -0800 Subject: net: more spelling fixes Various spelling fixes in networking stack Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/bridge/br_netlink.c | 4 ++-- net/core/net-sysfs.c | 4 ++-- net/core/netprio_cgroup.c | 2 +- net/ipv4/ip_sockglue.c | 2 +- net/ipv4/tcp_output.c | 10 +++++----- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index f75d92e4f96..c2fd6bc5f08 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -373,7 +373,7 @@ int br_setlink(struct net_device *dev, struct nlmsghdr *nlh) p = br_port_get_rtnl(dev); /* We want to accept dev as bridge itself if the AF_SPEC - * is set to see if someone is setting vlan info on the brigde + * is set to see if someone is setting vlan info on the bridge */ if (!p && !afspec) return -EINVAL; @@ -389,7 +389,7 @@ int br_setlink(struct net_device *dev, struct nlmsghdr *nlh) err = br_setport(p, tb); spin_unlock_bh(&p->br->lock); } else { - /* Binary compatability with old RSTP */ + /* Binary compatibility with old RSTP */ if (nla_len(protinfo) < sizeof(u8)) return -EINVAL; diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index f3edf9635e0..1a7b7b1df0d 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -676,8 +676,8 @@ static ssize_t store_rps_dev_flow_table_cnt(struct netdev_rx_queue *queue, while ((mask | (mask >> 1)) != mask) mask |= (mask >> 1); /* On 64 bit arches, must check mask fits in table->mask (u32), - * and on 32bit arches, must check RPS_DEV_FLOW_TABLE_SIZE(mask + 1) - * doesnt overflow. + * and on 32bit arches, must check + * RPS_DEV_FLOW_TABLE_SIZE(mask + 1) doesn't overflow. */ #if BITS_PER_LONG > 32 if (mask > (unsigned long)(u32)mask) diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c index 9b7cf6c85f8..1dda50c2e70 100644 --- a/net/core/netprio_cgroup.c +++ b/net/core/netprio_cgroup.c @@ -30,7 +30,7 @@ #define PRIOMAP_MIN_SZ 128 /* - * Extend @dev->priomap so that it's large enough to accomodate + * Extend @dev->priomap so that it's large enough to accommodate * @target_idx. @dev->priomap.priomap_len > @target_idx after successful * return. Must be called under rtnl lock. */ diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index ddf32a6bc41..a9fc435dc89 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -1051,7 +1051,7 @@ e_inval: * * To support IP_CMSG_PKTINFO option, we store rt_iif and specific * destination in skb->cb[] before dst drop. - * This way, receiver doesnt make cache line misses to read rtable. + * This way, receiver doesn't make cache line misses to read rtable. */ void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb) { diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 993da005e08..2a69f42e51c 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -408,7 +408,7 @@ struct tcp_out_options { * Beware: Something in the Internet is very sensitive to the ordering of * TCP options, we learned this through the hard way, so be careful here. * Luckily we can at least blame others for their non-compliance but from - * inter-operatibility perspective it seems that we're somewhat stuck with + * inter-operability perspective it seems that we're somewhat stuck with * the ordering which we have been using if we want to keep working with * those broken things (not that it currently hurts anybody as there isn't * particular reason why the ordering would need to be changed). @@ -681,7 +681,7 @@ static unsigned int tcp_established_options(struct sock *sk, struct sk_buff *skb * * Its important tcp_wfree() can be replaced by sock_wfree() in the event skb * needs to be reallocated in a driver. - * The invariant being skb->truesize substracted from sk->sk_wmem_alloc + * The invariant being skb->truesize subtracted from sk->sk_wmem_alloc * * Since transmit from skb destructor is forbidden, we use a tasklet * to process all sockets that eventually need to send more skbs. @@ -701,9 +701,9 @@ static void tcp_tsq_handler(struct sock *sk) tcp_write_xmit(sk, tcp_current_mss(sk), 0, 0, GFP_ATOMIC); } /* - * One tasklest per cpu tries to send more skbs. + * One tasklet per cpu tries to send more skbs. * We run in tasklet context but need to disable irqs when - * transfering tsq->head because tcp_wfree() might + * transferring tsq->head because tcp_wfree() might * interrupt us (non NAPI drivers) */ static void tcp_tasklet_func(unsigned long data) @@ -797,7 +797,7 @@ void __init tcp_tasklet_init(void) /* * Write buffer destructor automatically called from kfree_skb. - * We cant xmit new skbs from this context, as we might already + * We can't xmit new skbs from this context, as we might already * hold qdisc lock. */ void tcp_wfree(struct sk_buff *skb) -- cgit v1.2.3-70-g09d2 From 42404c09151029689659818e2196ee2fd97142aa Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 10 Dec 2013 22:05:45 -0500 Subject: Revert "tun: remove useless codes in tun_chr_aio_read() and tun_recvmsg()" This reverts commit 73713357ab58aacda1af715bb5a623528dbbfd79. MSG_TRUNC handling was broken and is going to be fixed in the 'net' tree, so revert this. Signed-off-by: David S. Miller --- drivers/net/tun.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index bbb69351291..3c5a8d8cde5 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1354,6 +1354,7 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv, ret = tun_do_read(tun, tfile, iv, len, file->f_flags & O_NONBLOCK); + ret = min_t(ssize_t, ret, len); if (ret > 0) iocb->ki_pos = ret; out: @@ -1454,6 +1455,10 @@ static int tun_recvmsg(struct kiocb *iocb, struct socket *sock, } ret = tun_do_read(tun, tfile, m->msg_iov, total_len, flags & MSG_DONTWAIT); + if (ret > total_len) { + m->msg_flags |= MSG_TRUNC; + ret = flags & MSG_TRUNC ? ret : total_len; + } out: tun_put(tun); return ret; -- cgit v1.2.3-70-g09d2 From de2aa4760b45262cf25eac6d4c0e461703b7b64b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 10 Dec 2013 22:06:18 -0500 Subject: Revert "macvtap: remove useless codes in macvtap_aio_read() and macvtap_recvmsg()" This reverts commit 41e4af69a5984a3193ba3108fb4e067b0e34dc73. MSG_TRUNC handling was broken and is going to be fixed in the 'net' tree, so revert this. Signed-off-by: David S. Miller --- drivers/net/macvtap.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 2aa5e973ef1..4a34bcb6549 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -871,6 +871,7 @@ static ssize_t macvtap_aio_read(struct kiocb *iocb, const struct iovec *iv, } ret = macvtap_do_read(q, iv, len, file->f_flags & O_NONBLOCK); + ret = min_t(ssize_t, ret, len); /* XXX copied from tun.c. Why? */ if (ret > 0) iocb->ki_pos = ret; out: @@ -1105,6 +1106,10 @@ static int macvtap_recvmsg(struct kiocb *iocb, struct socket *sock, return -EINVAL; ret = macvtap_do_read(q, m->msg_iov, total_len, flags & MSG_DONTWAIT); + if (ret > total_len) { + m->msg_flags |= MSG_TRUNC; + ret = flags & MSG_TRUNC ? ret : total_len; + } return ret; } -- cgit v1.2.3-70-g09d2 From d73aa2867f33582314f098277421ded65f5745a9 Mon Sep 17 00:00:00 2001 From: Yann Droneaud Date: Mon, 9 Dec 2013 22:42:20 +0100 Subject: net: handle error more gracefully in socketpair() This patch makes socketpair() use error paths which do not rely on heavy-weight call to sys_close(): it's better to try to push the file descriptor to userspace before installing the socket file to the file descriptor, so that errors are catched earlier and being easier to handle. Using sys_close() seems to be the exception, while writing the file descriptor before installing it look like it's more or less the norm: eg. except for code used in init/, error handling involve fput() and put_unused_fd(), but not sys_close(). This make socketpair() usage of sys_close() quite unusual. So it deserves to be replaced by the common pattern relying on fput() and put_unused_fd() just like, for example, the one used in pipe(2) or recvmsg(2). Three distinct error paths are still needed since calling fput() on file structure returned by sock_alloc_file() will implicitly call sock_release() on the associated socket structure. Cc: David S. Miller Cc: Al Viro Signed-off-by: Yann Droneaud Link: http://marc.info/?i=1385979146-13825-1-git-send-email-ydroneaud@opteya.com Signed-off-by: David S. Miller --- net/socket.c | 49 +++++++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/net/socket.c b/net/socket.c index cd38a785f7d..879933aaed4 100644 --- a/net/socket.c +++ b/net/socket.c @@ -1445,48 +1445,61 @@ SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol, err = fd1; goto out_release_both; } + fd2 = get_unused_fd_flags(flags); if (unlikely(fd2 < 0)) { err = fd2; - put_unused_fd(fd1); - goto out_release_both; + goto out_put_unused_1; } newfile1 = sock_alloc_file(sock1, flags, NULL); if (unlikely(IS_ERR(newfile1))) { err = PTR_ERR(newfile1); - put_unused_fd(fd1); - put_unused_fd(fd2); - goto out_release_both; + goto out_put_unused_both; } newfile2 = sock_alloc_file(sock2, flags, NULL); if (IS_ERR(newfile2)) { err = PTR_ERR(newfile2); - fput(newfile1); - put_unused_fd(fd1); - put_unused_fd(fd2); - sock_release(sock2); - goto out; + goto out_fput_1; } + err = put_user(fd1, &usockvec[0]); + if (err) + goto out_fput_both; + + err = put_user(fd2, &usockvec[1]); + if (err) + goto out_fput_both; + audit_fd_pair(fd1, fd2); + fd_install(fd1, newfile1); fd_install(fd2, newfile2); /* fd1 and fd2 may be already another descriptors. * Not kernel problem. */ - err = put_user(fd1, &usockvec[0]); - if (!err) - err = put_user(fd2, &usockvec[1]); - if (!err) - return 0; + return 0; - sys_close(fd2); - sys_close(fd1); - return err; +out_fput_both: + fput(newfile2); + fput(newfile1); + put_unused_fd(fd2); + put_unused_fd(fd1); + goto out; + +out_fput_1: + fput(newfile1); + put_unused_fd(fd2); + put_unused_fd(fd1); + sock_release(sock2); + goto out; +out_put_unused_both: + put_unused_fd(fd2); +out_put_unused_1: + put_unused_fd(fd1); out_release_both: sock_release(sock2); out_release_1: -- cgit v1.2.3-70-g09d2 From d24bae32fa9b541eb87edf1b3439f590c3b2dda5 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Mon, 9 Dec 2013 16:17:40 -0800 Subject: virtio_net: remove unused parameter to send_command All the code passes NULL for the last sg list (in). Simplify by just removing it. Signed-off-by: Stephen Hemminger Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 56c2229d28f..d26f695ee64 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -876,13 +876,12 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev) * never fail unless improperly formated. */ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd, - struct scatterlist *out, - struct scatterlist *in) + struct scatterlist *out) { struct scatterlist *sgs[4], hdr, stat; struct virtio_net_ctrl_hdr ctrl; virtio_net_ctrl_ack status = ~0; - unsigned out_num = 0, in_num = 0, tmp; + unsigned out_num = 0, tmp; /* Caller should know better */ BUG_ON(!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)); @@ -895,16 +894,13 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd, if (out) sgs[out_num++] = out; - if (in) - sgs[out_num + in_num++] = in; /* Add return status. */ sg_init_one(&stat, &status, sizeof(status)); - sgs[out_num + in_num++] = &stat; + sgs[out_num] = &stat; - BUG_ON(out_num + in_num > ARRAY_SIZE(sgs)); - BUG_ON(virtqueue_add_sgs(vi->cvq, sgs, out_num, in_num, vi, GFP_ATOMIC) - < 0); + BUG_ON(out_num + 1 > ARRAY_SIZE(sgs)); + BUG_ON(virtqueue_add_sgs(vi->cvq, sgs, out_num, 1, vi, GFP_ATOMIC) < 0); if (unlikely(!virtqueue_kick(vi->cvq))) return status == VIRTIO_NET_OK; @@ -934,8 +930,7 @@ static int virtnet_set_mac_address(struct net_device *dev, void *p) if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR)) { sg_init_one(&sg, addr->sa_data, dev->addr_len); if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MAC, - VIRTIO_NET_CTRL_MAC_ADDR_SET, - &sg, NULL)) { + VIRTIO_NET_CTRL_MAC_ADDR_SET, &sg)) { dev_warn(&vdev->dev, "Failed to set mac address by vq command.\n"); return -EINVAL; @@ -1008,7 +1003,7 @@ static void virtnet_ack_link_announce(struct virtnet_info *vi) { rtnl_lock(); if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_ANNOUNCE, - VIRTIO_NET_CTRL_ANNOUNCE_ACK, NULL, NULL)) + VIRTIO_NET_CTRL_ANNOUNCE_ACK, NULL)) dev_warn(&vi->dev->dev, "Failed to ack link announce.\n"); rtnl_unlock(); } @@ -1026,7 +1021,7 @@ static int virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs) sg_init_one(&sg, &s, sizeof(s)); if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MQ, - VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET, &sg, NULL)) { + VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET, &sg)) { dev_warn(&dev->dev, "Fail to set num of queue pairs to %d\n", queue_pairs); return -EINVAL; @@ -1076,16 +1071,14 @@ static void virtnet_set_rx_mode(struct net_device *dev) sg_init_one(sg, &promisc, sizeof(promisc)); if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_RX, - VIRTIO_NET_CTRL_RX_PROMISC, - sg, NULL)) + VIRTIO_NET_CTRL_RX_PROMISC, sg)) dev_warn(&dev->dev, "Failed to %sable promisc mode.\n", promisc ? "en" : "dis"); sg_init_one(sg, &allmulti, sizeof(allmulti)); if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_RX, - VIRTIO_NET_CTRL_RX_ALLMULTI, - sg, NULL)) + VIRTIO_NET_CTRL_RX_ALLMULTI, sg)) dev_warn(&dev->dev, "Failed to %sable allmulti mode.\n", allmulti ? "en" : "dis"); @@ -1121,8 +1114,7 @@ static void virtnet_set_rx_mode(struct net_device *dev) sizeof(mac_data->entries) + (mc_count * ETH_ALEN)); if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MAC, - VIRTIO_NET_CTRL_MAC_TABLE_SET, - sg, NULL)) + VIRTIO_NET_CTRL_MAC_TABLE_SET, sg)) dev_warn(&dev->dev, "Failed to set MAC filter table.\n"); kfree(buf); @@ -1137,7 +1129,7 @@ static int virtnet_vlan_rx_add_vid(struct net_device *dev, sg_init_one(&sg, &vid, sizeof(vid)); if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_VLAN, - VIRTIO_NET_CTRL_VLAN_ADD, &sg, NULL)) + VIRTIO_NET_CTRL_VLAN_ADD, &sg)) dev_warn(&dev->dev, "Failed to add VLAN ID %d.\n", vid); return 0; } @@ -1151,7 +1143,7 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev, sg_init_one(&sg, &vid, sizeof(vid)); if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_VLAN, - VIRTIO_NET_CTRL_VLAN_DEL, &sg, NULL)) + VIRTIO_NET_CTRL_VLAN_DEL, &sg)) dev_warn(&dev->dev, "Failed to kill VLAN ID %d.\n", vid); return 0; } -- cgit v1.2.3-70-g09d2 From 788a8b6dd3a28e02af5581923a14667f550009b5 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Mon, 9 Dec 2013 16:18:45 -0800 Subject: virtio_net: spelling fixes Signed-off-by: Stephen Hemminger Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index d26f695ee64..c51a98867a4 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -873,7 +873,7 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev) /* * Send command via the control virtqueue and check status. Commands * supported by the hypervisor, as indicated by feature bits, should - * never fail unless improperly formated. + * never fail unless improperly formatted. */ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd, struct scatterlist *out) @@ -1061,7 +1061,7 @@ static void virtnet_set_rx_mode(struct net_device *dev) void *buf; int i; - /* We can't dynamicaly set ndo_set_rx_mode, so return gracefully */ + /* We can't dynamically set ndo_set_rx_mode, so return gracefully */ if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_RX)) return; -- cgit v1.2.3-70-g09d2 From 79ac7c941124866a72f000bb1fbb65dc1d1cf8cb Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 10 Dec 2013 12:48:38 +0900 Subject: net: hippi: remove unnecessary pci_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Signed-off-by: David S. Miller --- drivers/net/hippi/rrunner.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/hippi/rrunner.c b/drivers/net/hippi/rrunner.c index 00ed75155ce..cd85f24637e 100644 --- a/drivers/net/hippi/rrunner.c +++ b/drivers/net/hippi/rrunner.c @@ -213,10 +213,8 @@ static int rr_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) rrpriv->tx_ring_dma); if (rrpriv->regs) pci_iounmap(pdev, rrpriv->regs); - if (pdev) { + if (pdev) pci_release_regions(pdev); - pci_set_drvdata(pdev, NULL); - } out2: free_netdev(dev); out3: @@ -244,7 +242,6 @@ static void rr_remove_one(struct pci_dev *pdev) pci_iounmap(pdev, rr->regs); pci_release_regions(pdev); pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); free_netdev(dev); } -- cgit v1.2.3-70-g09d2 From 49f74ed6da4d70adc81be36f4dde22fa23f28171 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 10 Dec 2013 12:49:34 +0900 Subject: net: fddi: remove unnecessary pci_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Signed-off-by: David S. Miller --- drivers/net/fddi/skfp/skfddi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/fddi/skfp/skfddi.c b/drivers/net/fddi/skfp/skfddi.c index 713d303a06a..d5f58121b2e 100644 --- a/drivers/net/fddi/skfp/skfddi.c +++ b/drivers/net/fddi/skfp/skfddi.c @@ -351,7 +351,6 @@ static void skfp_remove_one(struct pci_dev *pdev) free_netdev(p); pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); } /* -- cgit v1.2.3-70-g09d2 From 5535ec7600ab2fc316512d6fb15e8ec077878934 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 10 Dec 2013 12:50:09 +0900 Subject: net: vmxnet3: remove unnecessary pci_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Signed-off-by: Shreyas N Bhatewara Acked-by: Dmitry Torokhov Signed-off-by: David S. Miller --- drivers/net/vmxnet3/vmxnet3_drv.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index 7e2788c488e..a300a18c550 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -3132,7 +3132,6 @@ err_alloc_queue_desc: err_alloc_shared: dma_unmap_single(&adapter->pdev->dev, adapter->adapter_pa, sizeof(struct vmxnet3_adapter), PCI_DMA_TODEVICE); - pci_set_drvdata(pdev, NULL); free_netdev(netdev); return err; } -- cgit v1.2.3-70-g09d2 From 6d4bebebe20e18c565143b8852c0f5bd50a64f34 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 10 Dec 2013 12:50:42 +0900 Subject: net: phy: spi_ks8995: remove unnecessary spi_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Signed-off-by: David S. Miller --- drivers/net/phy/spi_ks8995.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/phy/spi_ks8995.c b/drivers/net/phy/spi_ks8995.c index f3bea134602..98fb9f360d8 100644 --- a/drivers/net/phy/spi_ks8995.c +++ b/drivers/net/phy/spi_ks8995.c @@ -325,7 +325,6 @@ static int ks8995_probe(struct spi_device *spi) return 0; err_drvdata: - spi_set_drvdata(spi, NULL); kfree(ks); return err; } @@ -337,7 +336,6 @@ static int ks8995_remove(struct spi_device *spi) ks8995 = spi_get_drvdata(spi); sysfs_remove_bin_file(&spi->dev.kobj, &ks8995_registers_attr); - spi_set_drvdata(spi, NULL); kfree(ks8995); return 0; -- cgit v1.2.3-70-g09d2 From 40706af0b246f416a35fc3e12dc695deca8da3ff Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 10 Dec 2013 12:51:09 +0900 Subject: net: ieee802154: remove unnecessary spi_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Signed-off-by: David S. Miller --- drivers/net/ieee802154/at86rf230.c | 2 -- drivers/net/ieee802154/mrf24j40.c | 1 - 2 files changed, 3 deletions(-) diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 2cbe1c24999..ab31544bc25 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -987,7 +987,6 @@ err_gpio_dir: err_slp_tr: gpio_free(lp->rstn); err_rstn: - spi_set_drvdata(spi, NULL); mutex_destroy(&lp->bmux); ieee802154_free_device(lp->dev); return rc; @@ -1006,7 +1005,6 @@ static int at86rf230_remove(struct spi_device *spi) gpio_free(lp->slp_tr); gpio_free(lp->rstn); - spi_set_drvdata(spi, NULL); mutex_destroy(&lp->bmux); ieee802154_free_device(lp->dev); diff --git a/drivers/net/ieee802154/mrf24j40.c b/drivers/net/ieee802154/mrf24j40.c index c6e46d6e9f7..246befa4ba0 100644 --- a/drivers/net/ieee802154/mrf24j40.c +++ b/drivers/net/ieee802154/mrf24j40.c @@ -715,7 +715,6 @@ static int mrf24j40_remove(struct spi_device *spi) * complete? */ /* Clean up the SPI stuff. */ - spi_set_drvdata(spi, NULL); kfree(devrec->buf); kfree(devrec); return 0; -- cgit v1.2.3-70-g09d2 From 57c5bca9f4f8d0be378a115c5ed939bd43932f8e Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 10 Dec 2013 12:51:46 +0900 Subject: atm: he: remove unnecessary pci_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Signed-off-by: David S. Miller --- drivers/atm/he.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/atm/he.c b/drivers/atm/he.c index 8557adcd34e..aa6be269866 100644 --- a/drivers/atm/he.c +++ b/drivers/atm/he.c @@ -419,7 +419,6 @@ static void he_remove_one(struct pci_dev *pci_dev) atm_dev_deregister(atm_dev); kfree(he_dev); - pci_set_drvdata(pci_dev, NULL); pci_disable_device(pci_dev); } -- cgit v1.2.3-70-g09d2 From 109744c7cff0320790f3afa60bebe05994be9ec3 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 10 Dec 2013 12:52:14 +0900 Subject: atm: solos-pci: remove unnecessary pci_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Signed-off-by: David S. Miller --- drivers/atm/solos-pci.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index 32784d18d1f..e3fb496c716 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c @@ -1335,7 +1335,6 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id) out_unmap_both: kfree(card->dma_bounce); - pci_set_drvdata(dev, NULL); pci_iounmap(dev, card->buffers); out_unmap_config: pci_iounmap(dev, card->config_regs); @@ -1457,7 +1456,6 @@ static void fpga_remove(struct pci_dev *dev) pci_release_regions(dev); pci_disable_device(dev); - pci_set_drvdata(dev, NULL); kfree(card); } -- cgit v1.2.3-70-g09d2 From 17569faedf84768e76b204ba6d682022b830a3ed Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 10 Dec 2013 20:55:29 +0800 Subject: net_sched: remove unnecessary parentheses while return return is not a function, parentheses are not required. Signed-off-by: Yang Yingliang Signed-off-by: David S. Miller --- net/sched/act_api.c | 3 ++- net/sched/sch_dsmark.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/net/sched/act_api.c b/net/sched/act_api.c index 69cb848e834..4adbce8f831 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -191,7 +191,8 @@ u32 tcf_hash_new_index(u32 *idx_gen, struct tcf_hashinfo *hinfo) val = 1; } while (tcf_hash_lookup(val, hinfo)); - return (*idx_gen = val); + *idx_gen = val; + return val; } EXPORT_SYMBOL(tcf_hash_new_index); diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c index 3886365cc20..0952fd2684e 100644 --- a/net/sched/sch_dsmark.c +++ b/net/sched/sch_dsmark.c @@ -47,7 +47,7 @@ struct dsmark_qdisc_data { static inline int dsmark_valid_index(struct dsmark_qdisc_data *p, u16 index) { - return (index <= p->indices && index > 0); + return index <= p->indices && index > 0; } /* ------------------------- Class/flow operations ------------------------- */ -- cgit v1.2.3-70-g09d2 From 1fab9abc56036256265f350c700d3d1251a47f0a Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 10 Dec 2013 20:55:30 +0800 Subject: net_sched: cls_bpf: use tabs to do indent Code indent should use tabs where possible Signed-off-by: Yang Yingliang Signed-off-by: David S. Miller --- net/sched/cls_bpf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sched/cls_bpf.c b/net/sched/cls_bpf.c index 1002a822628..d7c72be121f 100644 --- a/net/sched/cls_bpf.c +++ b/net/sched/cls_bpf.c @@ -323,7 +323,7 @@ static int cls_bpf_dump(struct tcf_proto *tp, unsigned long fh, if (nla == NULL) goto nla_put_failure; - memcpy(nla_data(nla), prog->bpf_ops, nla_len(nla)); + memcpy(nla_data(nla), prog->bpf_ops, nla_len(nla)); if (tcf_exts_dump(skb, &prog->exts, &bpf_ext_map) < 0) goto nla_put_failure; -- cgit v1.2.3-70-g09d2 From 82d567c26647aa2e54c6814cd593a32f7799e387 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 10 Dec 2013 20:55:31 +0800 Subject: net_sched: change "foo* bar" to "foo *bar" "foo* bar" or "foo * bar" should be "foo *bar". Signed-off-by: Yang Yingliang Signed-off-by: David S. Miller --- net/sched/cls_u32.c | 2 +- net/sched/sch_generic.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index eb07a1e536e..59e546c2ac9 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -352,7 +352,7 @@ static int u32_destroy_key(struct tcf_proto *tp, struct tc_u_knode *n) return 0; } -static int u32_delete_key(struct tcf_proto *tp, struct tc_u_knode* key) +static int u32_delete_key(struct tcf_proto *tp, struct tc_u_knode *key) { struct tc_u_knode **kp; struct tc_u_hnode *ht = key->ht_up; diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 922a09406ba..6a91d7d48ad 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -338,13 +338,13 @@ EXPORT_SYMBOL(netif_carrier_off); cheaper. */ -static int noop_enqueue(struct sk_buff *skb, struct Qdisc * qdisc) +static int noop_enqueue(struct sk_buff *skb, struct Qdisc *qdisc) { kfree_skb(skb); return NET_XMIT_CN; } -static struct sk_buff *noop_dequeue(struct Qdisc * qdisc) +static struct sk_buff *noop_dequeue(struct Qdisc *qdisc) { return NULL; } -- cgit v1.2.3-70-g09d2 From 833fa7438659d768f0aee862aab4a30cde362bbf Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 10 Dec 2013 20:55:32 +0800 Subject: net_sched: add space around '>' and before '(' Spaces required around that '>' (ctx:VxV) and before the open parenthesis '('. Signed-off-by: Yang Yingliang Signed-off-by: David S. Miller --- net/sched/sch_cbq.c | 3 ++- net/sched/sch_netem.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index 7a42c81a19e..d5a8a4b2454 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -1058,7 +1058,8 @@ static void cbq_normalize_quanta(struct cbq_sched_data *q, int prio) cl->quantum = (cl->weight*cl->allot*q->nclasses[prio])/ q->quanta[prio]; } - if (cl->quantum <= 0 || cl->quantum>32*qdisc_dev(cl->qdisc)->mtu) { + if (cl->quantum <= 0 || + cl->quantum > 32*qdisc_dev(cl->qdisc)->mtu) { pr_warning("CBQ: class %08x has bad quantum==%ld, repaired.\n", cl->common.classid, cl->quantum); cl->quantum = qdisc_dev(cl->qdisc)->mtu/2 + 1; diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index bccd52b36e9..f3befd6b478 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -729,7 +729,7 @@ static int get_loss_clg(struct Qdisc *sch, const struct nlattr *attr) nla_for_each_nested(la, attr, rem) { u16 type = nla_type(la); - switch(type) { + switch (type) { case NETEM_LOSS_GI: { const struct tc_netem_gimodel *gi = nla_data(la); -- cgit v1.2.3-70-g09d2 From fa08943b975c08697e57aff26784970dd0dd926a Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 10 Dec 2013 20:55:33 +0800 Subject: net_sched: sfq: put sfq_unlink in a do - while loop Macros with multiple statements should be enclosed in a do - while loop Signed-off-by: Yang Yingliang Signed-off-by: David S. Miller --- net/sched/sch_sfq.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c index d3a1bc26dbf..76f01e0258d 100644 --- a/net/sched/sch_sfq.c +++ b/net/sched/sch_sfq.c @@ -237,10 +237,12 @@ static inline void sfq_link(struct sfq_sched_data *q, sfq_index x) } #define sfq_unlink(q, x, n, p) \ - n = q->slots[x].dep.next; \ - p = q->slots[x].dep.prev; \ - sfq_dep_head(q, p)->next = n; \ - sfq_dep_head(q, n)->prev = p + do { \ + n = q->slots[x].dep.next; \ + p = q->slots[x].dep.prev; \ + sfq_dep_head(q, p)->next = n; \ + sfq_dep_head(q, n)->prev = p; \ + } while (0) static inline void sfq_dec(struct sfq_sched_data *q, sfq_index x) -- cgit v1.2.3-70-g09d2 From 0dfc3e1862f5e7fe369d7c20c1a1e37633b45573 Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Tue, 10 Dec 2013 16:07:19 -0800 Subject: net: macb: Migrate to dev_pm_ops Migrate the suspend/resume functions to use the dev_pm_ops PM interface. Signed-off-by: Soren Brinkmann Acked-by: Nicolas Ferre Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 92578690f6d..389ccf1362d 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -1946,8 +1946,9 @@ static int __exit macb_remove(struct platform_device *pdev) } #ifdef CONFIG_PM -static int macb_suspend(struct platform_device *pdev, pm_message_t state) +static int macb_suspend(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct net_device *netdev = platform_get_drvdata(pdev); struct macb *bp = netdev_priv(netdev); @@ -1960,8 +1961,9 @@ static int macb_suspend(struct platform_device *pdev, pm_message_t state) return 0; } -static int macb_resume(struct platform_device *pdev) +static int macb_resume(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct net_device *netdev = platform_get_drvdata(pdev); struct macb *bp = netdev_priv(netdev); @@ -1972,19 +1974,17 @@ static int macb_resume(struct platform_device *pdev) return 0; } -#else -#define macb_suspend NULL -#define macb_resume NULL #endif +static SIMPLE_DEV_PM_OPS(macb_pm_ops, macb_suspend, macb_resume); + static struct platform_driver macb_driver = { .remove = __exit_p(macb_remove), - .suspend = macb_suspend, - .resume = macb_resume, .driver = { .name = "macb", .owner = THIS_MODULE, .of_match_table = of_match_ptr(macb_dt_ids), + .pm = &macb_pm_ops, }, }; -- cgit v1.2.3-70-g09d2 From b48e0bab142fdfa16b52fc63f43acf0784c80ee7 Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Tue, 10 Dec 2013 16:07:20 -0800 Subject: net: macb: Migrate to devm clock interface Migrate to using the device managed interface for clocks and clean up the associated error paths. Signed-off-by: Soren Brinkmann Acked-by: Nicolas Ferre Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 389ccf1362d..62aa136889a 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -1790,19 +1790,31 @@ static int __init macb_probe(struct platform_device *pdev) spin_lock_init(&bp->lock); INIT_WORK(&bp->tx_error_task, macb_tx_error_task); - bp->pclk = clk_get(&pdev->dev, "pclk"); + bp->pclk = devm_clk_get(&pdev->dev, "pclk"); if (IS_ERR(bp->pclk)) { - dev_err(&pdev->dev, "failed to get macb_clk\n"); + err = PTR_ERR(bp->pclk); + dev_err(&pdev->dev, "failed to get macb_clk (%u)\n", err); goto err_out_free_dev; } - clk_prepare_enable(bp->pclk); - bp->hclk = clk_get(&pdev->dev, "hclk"); + bp->hclk = devm_clk_get(&pdev->dev, "hclk"); if (IS_ERR(bp->hclk)) { - dev_err(&pdev->dev, "failed to get hclk\n"); - goto err_out_put_pclk; + err = PTR_ERR(bp->hclk); + dev_err(&pdev->dev, "failed to get hclk (%u)\n", err); + goto err_out_free_dev; + } + + err = clk_prepare_enable(bp->pclk); + if (err) { + dev_err(&pdev->dev, "failed to enable pclk (%u)\n", err); + goto err_out_free_dev; + } + + err = clk_prepare_enable(bp->hclk); + if (err) { + dev_err(&pdev->dev, "failed to enable hclk (%u)\n", err); + goto err_out_disable_pclk; } - clk_prepare_enable(bp->hclk); bp->regs = ioremap(regs->start, resource_size(regs)); if (!bp->regs) { @@ -1908,10 +1920,8 @@ err_out_iounmap: iounmap(bp->regs); err_out_disable_clocks: clk_disable_unprepare(bp->hclk); - clk_put(bp->hclk); +err_out_disable_pclk: clk_disable_unprepare(bp->pclk); -err_out_put_pclk: - clk_put(bp->pclk); err_out_free_dev: free_netdev(dev); err_out: @@ -1936,9 +1946,7 @@ static int __exit macb_remove(struct platform_device *pdev) free_irq(dev->irq, dev); iounmap(bp->regs); clk_disable_unprepare(bp->hclk); - clk_put(bp->hclk); clk_disable_unprepare(bp->pclk); - clk_put(bp->pclk); free_netdev(dev); } -- cgit v1.2.3-70-g09d2 From 60fe716f005a0add0447796c38821b22ef379856 Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Tue, 10 Dec 2013 16:07:21 -0800 Subject: net: macb: Use devm_ioremap() Use the device managed version of ioremap to remap IO memory, simplifying error paths. Signed-off-by: Soren Brinkmann Acked-by: Nicolas Ferre Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 62aa136889a..436aecc3173 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -1816,7 +1817,7 @@ static int __init macb_probe(struct platform_device *pdev) goto err_out_disable_pclk; } - bp->regs = ioremap(regs->start, resource_size(regs)); + bp->regs = devm_ioremap(&pdev->dev, regs->start, resource_size(regs)); if (!bp->regs) { dev_err(&pdev->dev, "failed to map registers, aborting.\n"); err = -ENOMEM; @@ -1828,7 +1829,7 @@ static int __init macb_probe(struct platform_device *pdev) if (err) { dev_err(&pdev->dev, "Unable to request IRQ %d (error %d)\n", dev->irq, err); - goto err_out_iounmap; + goto err_out_disable_clocks; } dev->netdev_ops = &macb_netdev_ops; @@ -1916,8 +1917,6 @@ err_out_unregister_netdev: unregister_netdev(dev); err_out_free_irq: free_irq(dev->irq, dev); -err_out_iounmap: - iounmap(bp->regs); err_out_disable_clocks: clk_disable_unprepare(bp->hclk); err_out_disable_pclk: @@ -1944,7 +1943,6 @@ static int __exit macb_remove(struct platform_device *pdev) mdiobus_free(bp->mii_bus); unregister_netdev(dev); free_irq(dev->irq, dev); - iounmap(bp->regs); clk_disable_unprepare(bp->hclk); clk_disable_unprepare(bp->pclk); free_netdev(dev); -- cgit v1.2.3-70-g09d2 From 0a4acf08ea62d8c8a7ed394bb075f0e1f10ac021 Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Tue, 10 Dec 2013 16:07:22 -0800 Subject: net: macb: Use devm_request_irq() Use the device managed interface to request the IRQ, simplifying error paths. Signed-off-by: Soren Brinkmann Acked-by: Nicolas Ferre Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 436aecc3173..603844b1d48 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -1825,7 +1825,8 @@ static int __init macb_probe(struct platform_device *pdev) } dev->irq = platform_get_irq(pdev, 0); - err = request_irq(dev->irq, macb_interrupt, 0, dev->name, dev); + err = devm_request_irq(&pdev->dev, dev->irq, macb_interrupt, 0, + dev->name, dev); if (err) { dev_err(&pdev->dev, "Unable to request IRQ %d (error %d)\n", dev->irq, err); @@ -1892,7 +1893,7 @@ static int __init macb_probe(struct platform_device *pdev) err = register_netdev(dev); if (err) { dev_err(&pdev->dev, "Cannot register net device, aborting.\n"); - goto err_out_free_irq; + goto err_out_disable_clocks; } err = macb_mii_init(bp); @@ -1915,8 +1916,6 @@ static int __init macb_probe(struct platform_device *pdev) err_out_unregister_netdev: unregister_netdev(dev); -err_out_free_irq: - free_irq(dev->irq, dev); err_out_disable_clocks: clk_disable_unprepare(bp->hclk); err_out_disable_pclk: @@ -1942,7 +1941,6 @@ static int __exit macb_remove(struct platform_device *pdev) kfree(bp->mii_bus->irq); mdiobus_free(bp->mii_bus); unregister_netdev(dev); - free_irq(dev->irq, dev); clk_disable_unprepare(bp->hclk); clk_disable_unprepare(bp->pclk); free_netdev(dev); -- cgit v1.2.3-70-g09d2 From e1824dfe0d8e6bae55859eb016ce21b61d1b8c85 Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Tue, 10 Dec 2013 16:07:23 -0800 Subject: net: macb: Adjust tx_clk when link speed changes Adjust the ethernet clock according to the negotiated link speed. Signed-off-by: Soren Brinkmann Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.c | 64 +++++++++++++++++++++++++++++++++++++ drivers/net/ethernet/cadence/macb.h | 1 + 2 files changed, 65 insertions(+) diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 603844b1d48..419529a9309 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -204,6 +204,47 @@ static int macb_mdio_reset(struct mii_bus *bus) return 0; } +/** + * macb_set_tx_clk() - Set a clock to a new frequency + * @clk Pointer to the clock to change + * @rate New frequency in Hz + * @dev Pointer to the struct net_device + */ +static void macb_set_tx_clk(struct clk *clk, int speed, struct net_device *dev) +{ + long ferr, rate, rate_rounded; + + switch (speed) { + case SPEED_10: + rate = 2500000; + break; + case SPEED_100: + rate = 25000000; + break; + case SPEED_1000: + rate = 125000000; + break; + default: + break; + } + + rate_rounded = clk_round_rate(clk, rate); + if (rate_rounded < 0) + return; + + /* RGMII allows 50 ppm frequency error. Test and warn if this limit + * is not satisfied. + */ + ferr = abs(rate_rounded - rate); + ferr = DIV_ROUND_UP(ferr, rate / 100000); + if (ferr > 5) + netdev_warn(dev, "unable to generate target frequency: %ld Hz\n", + rate); + + if (clk_set_rate(clk, rate_rounded)) + netdev_err(dev, "adjusting tx_clk failed.\n"); +} + static void macb_handle_link_change(struct net_device *dev) { struct macb *bp = netdev_priv(dev); @@ -251,6 +292,9 @@ static void macb_handle_link_change(struct net_device *dev) spin_unlock_irqrestore(&bp->lock, flags); + if (!IS_ERR(bp->tx_clk)) + macb_set_tx_clk(bp->tx_clk, phydev->speed, dev); + if (status_change) { if (phydev->link) { netif_carrier_on(dev); @@ -1805,6 +1849,8 @@ static int __init macb_probe(struct platform_device *pdev) goto err_out_free_dev; } + bp->tx_clk = devm_clk_get(&pdev->dev, "tx_clk"); + err = clk_prepare_enable(bp->pclk); if (err) { dev_err(&pdev->dev, "failed to enable pclk (%u)\n", err); @@ -1817,6 +1863,15 @@ static int __init macb_probe(struct platform_device *pdev) goto err_out_disable_pclk; } + if (!IS_ERR(bp->tx_clk)) { + err = clk_prepare_enable(bp->tx_clk); + if (err) { + dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", + err); + goto err_out_disable_hclk; + } + } + bp->regs = devm_ioremap(&pdev->dev, regs->start, resource_size(regs)); if (!bp->regs) { dev_err(&pdev->dev, "failed to map registers, aborting.\n"); @@ -1917,6 +1972,9 @@ static int __init macb_probe(struct platform_device *pdev) err_out_unregister_netdev: unregister_netdev(dev); err_out_disable_clocks: + if (!IS_ERR(bp->tx_clk)) + clk_disable_unprepare(bp->tx_clk); +err_out_disable_hclk: clk_disable_unprepare(bp->hclk); err_out_disable_pclk: clk_disable_unprepare(bp->pclk); @@ -1941,6 +1999,8 @@ static int __exit macb_remove(struct platform_device *pdev) kfree(bp->mii_bus->irq); mdiobus_free(bp->mii_bus); unregister_netdev(dev); + if (!IS_ERR(bp->tx_clk)) + clk_disable_unprepare(bp->tx_clk); clk_disable_unprepare(bp->hclk); clk_disable_unprepare(bp->pclk); free_netdev(dev); @@ -1959,6 +2019,8 @@ static int macb_suspend(struct device *dev) netif_carrier_off(netdev); netif_device_detach(netdev); + if (!IS_ERR(bp->tx_clk)) + clk_disable_unprepare(bp->tx_clk); clk_disable_unprepare(bp->hclk); clk_disable_unprepare(bp->pclk); @@ -1973,6 +2035,8 @@ static int macb_resume(struct device *dev) clk_prepare_enable(bp->pclk); clk_prepare_enable(bp->hclk); + if (!IS_ERR(bp->tx_clk)) + clk_prepare_enable(bp->tx_clk); netif_device_attach(netdev); diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index f4076155bed..51c02442160 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -572,6 +572,7 @@ struct macb { struct platform_device *pdev; struct clk *pclk; struct clk *hclk; + struct clk *tx_clk; struct net_device *dev; struct napi_struct napi; struct work_struct tx_error_task; -- cgit v1.2.3-70-g09d2 From d77b3831f7d59d69aa49d5d1df10bbe56671dc5d Mon Sep 17 00:00:00 2001 From: Ying Xue Date: Tue, 10 Dec 2013 20:45:38 -0800 Subject: tipc: eliminate redundant code with kfree_skb_list routine sk_buff lists are currently relased by looping over the list and explicitly releasing each buffer. We replace all occurrences of this loop with a call to kfree_skb_list(). Signed-off-by: Ying Xue Reviewed-by: Paul Gortmaker Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/link.c | 58 ++++++++------------------------------------------------- net/tipc/node.c | 6 +----- 2 files changed, 9 insertions(+), 55 deletions(-) diff --git a/net/tipc/link.c b/net/tipc/link.c index fd340ad742e..ac26f8a657d 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -386,14 +386,7 @@ exit: */ static void link_release_outqueue(struct tipc_link *l_ptr) { - struct sk_buff *buf = l_ptr->first_out; - struct sk_buff *next; - - while (buf) { - next = buf->next; - kfree_skb(buf); - buf = next; - } + kfree_skb_list(l_ptr->first_out); l_ptr->first_out = NULL; l_ptr->out_queue_size = 0; } @@ -415,32 +408,15 @@ void tipc_link_reset_fragments(struct tipc_link *l_ptr) */ void tipc_link_stop(struct tipc_link *l_ptr) { - struct sk_buff *buf; - struct sk_buff *next; - - buf = l_ptr->oldest_deferred_in; - while (buf) { - next = buf->next; - kfree_skb(buf); - buf = next; - } - - buf = l_ptr->first_out; - while (buf) { - next = buf->next; - kfree_skb(buf); - buf = next; - } - + kfree_skb_list(l_ptr->oldest_deferred_in); + kfree_skb_list(l_ptr->first_out); tipc_link_reset_fragments(l_ptr); - kfree_skb(l_ptr->proto_msg_queue); l_ptr->proto_msg_queue = NULL; } void tipc_link_reset(struct tipc_link *l_ptr) { - struct sk_buff *buf; u32 prev_state = l_ptr->state; u32 checkpoint = l_ptr->next_in_no; int was_active_link = tipc_link_is_active(l_ptr); @@ -471,12 +447,7 @@ void tipc_link_reset(struct tipc_link *l_ptr) link_release_outqueue(l_ptr); kfree_skb(l_ptr->proto_msg_queue); l_ptr->proto_msg_queue = NULL; - buf = l_ptr->oldest_deferred_in; - while (buf) { - struct sk_buff *next = buf->next; - kfree_skb(buf); - buf = next; - } + kfree_skb_list(l_ptr->oldest_deferred_in); if (!list_empty(&l_ptr->waiting_ports)) tipc_link_wakeup_ports(l_ptr, 1); @@ -1124,10 +1095,7 @@ again: if (copy_from_user(buf->data + fragm_crs, sect_crs, sz)) { res = -EFAULT; error: - for (; buf_chain; buf_chain = buf) { - buf = buf_chain->next; - kfree_skb(buf_chain); - } + kfree_skb_list(buf_chain); return res; } sect_crs += sz; @@ -1177,18 +1145,12 @@ error: if (l_ptr->max_pkt < max_pkt) { sender->max_pkt = l_ptr->max_pkt; tipc_node_unlock(node); - for (; buf_chain; buf_chain = buf) { - buf = buf_chain->next; - kfree_skb(buf_chain); - } + kfree_skb_list(buf_chain); goto again; } } else { reject: - for (; buf_chain; buf_chain = buf) { - buf = buf_chain->next; - kfree_skb(buf_chain); - } + kfree_skb_list(buf_chain); return tipc_port_reject_sections(sender, hdr, msg_sect, len, TIPC_ERR_NO_NODE); } @@ -2283,11 +2245,7 @@ static int link_send_long_buf(struct tipc_link *l_ptr, struct sk_buff *buf) fragm = tipc_buf_acquire(fragm_sz + INT_H_SIZE); if (fragm == NULL) { kfree_skb(buf); - while (buf_chain) { - buf = buf_chain; - buf_chain = buf_chain->next; - kfree_skb(buf); - } + kfree_skb_list(buf_chain); return -ENOMEM; } msg_set_size(&fragm_hdr, fragm_sz + INT_H_SIZE); diff --git a/net/tipc/node.c b/net/tipc/node.c index 25100c0a6fe..bf1ac89b480 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -291,11 +291,7 @@ static void node_lost_contact(struct tipc_node *n_ptr) /* Flush broadcast link info associated with lost node */ if (n_ptr->bclink.recv_permitted) { - while (n_ptr->bclink.deferred_head) { - struct sk_buff *buf = n_ptr->bclink.deferred_head; - n_ptr->bclink.deferred_head = buf->next; - kfree_skb(buf); - } + kfree_skb_list(n_ptr->bclink.deferred_head); n_ptr->bclink.deferred_size = 0; if (n_ptr->bclink.reasm_head) { -- cgit v1.2.3-70-g09d2 From 5702dbab687e19792102200b085108f00ab820c9 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Tue, 10 Dec 2013 20:45:39 -0800 Subject: tipc: initiate media type array at compile time Communication media types are abstracted through the struct 'tipc_media', one per media type. These structs are allocated statically inside their respective media file. Furthermore, in order to be able to reach all instances from a central location, we keep a static array with pointers to these structs. This array is currently initialized at runtime, under protection of tipc_net_lock. However, since the contents of the array itself never changes after initialization, we can just as well initialize it at compile time and make it 'const', at the same time making it obvious that no lock protection is needed here. This commit makes the array constant and removes the redundant lock protection. Signed-off-by: Ying Xue Reviewed-by: Paul Gortmaker Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/bearer.c | 63 +++++++++++++--------------------------------------- net/tipc/bearer.h | 5 +++-- net/tipc/eth_media.c | 10 +++------ net/tipc/ib_media.c | 7 +----- 4 files changed, 23 insertions(+), 62 deletions(-) diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index c2101c0bfd6..826aa9fdf45 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -1,7 +1,7 @@ /* * net/tipc/bearer.c: TIPC bearer code * - * Copyright (c) 1996-2006, Ericsson AB + * Copyright (c) 1996-2006, 2013, Ericsson AB * Copyright (c) 2004-2006, 2010-2011, Wind River Systems * All rights reserved. * @@ -41,8 +41,13 @@ #define MAX_ADDR_STR 60 -static struct tipc_media *media_list[MAX_MEDIA]; -static u32 media_count; +static struct tipc_media * const media_list[] = { + ð_media_info, +#ifdef CONFIG_TIPC_MEDIA_IB + &ib_media_info, +#endif + NULL +}; struct tipc_bearer tipc_bearers[MAX_BEARERS]; @@ -55,11 +60,11 @@ struct tipc_media *tipc_media_find(const char *name) { u32 i; - for (i = 0; i < media_count; i++) { + for (i = 0; media_list[i] != NULL; i++) { if (!strcmp(media_list[i]->name, name)) - return media_list[i]; + break; } - return NULL; + return media_list[i]; } /** @@ -69,44 +74,11 @@ static struct tipc_media *media_find_id(u8 type) { u32 i; - for (i = 0; i < media_count; i++) { + for (i = 0; media_list[i] != NULL; i++) { if (media_list[i]->type_id == type) - return media_list[i]; + break; } - return NULL; -} - -/** - * tipc_register_media - register a media type - * - * Bearers for this media type must be activated separately at a later stage. - */ -int tipc_register_media(struct tipc_media *m_ptr) -{ - int res = -EINVAL; - - write_lock_bh(&tipc_net_lock); - - if ((strlen(m_ptr->name) + 1) > TIPC_MAX_MEDIA_NAME) - goto exit; - if (m_ptr->priority > TIPC_MAX_LINK_PRI) - goto exit; - if ((m_ptr->tolerance < TIPC_MIN_LINK_TOL) || - (m_ptr->tolerance > TIPC_MAX_LINK_TOL)) - goto exit; - if (media_count >= MAX_MEDIA) - goto exit; - if (tipc_media_find(m_ptr->name) || media_find_id(m_ptr->type_id)) - goto exit; - - media_list[media_count] = m_ptr; - media_count++; - res = 0; -exit: - write_unlock_bh(&tipc_net_lock); - if (res) - pr_warn("Media <%s> registration error\n", m_ptr->name); - return res; + return media_list[i]; } /** @@ -144,13 +116,11 @@ struct sk_buff *tipc_media_get_names(void) if (!buf) return NULL; - read_lock_bh(&tipc_net_lock); - for (i = 0; i < media_count; i++) { + for (i = 0; media_list[i] != NULL; i++) { tipc_cfg_append_tlv(buf, TIPC_TLV_MEDIA_NAME, media_list[i]->name, strlen(media_list[i]->name) + 1); } - read_unlock_bh(&tipc_net_lock); return buf; } @@ -247,7 +217,7 @@ struct sk_buff *tipc_bearer_get_names(void) return NULL; read_lock_bh(&tipc_net_lock); - for (i = 0; i < media_count; i++) { + for (i = 0; media_list[i] != NULL; i++) { for (j = 0; j < MAX_BEARERS; j++) { b_ptr = &tipc_bearers[j]; if (b_ptr->active && (b_ptr->media == media_list[i])) { @@ -472,5 +442,4 @@ void tipc_bearer_stop(void) if (tipc_bearers[i].active) bearer_disable(&tipc_bearers[i]); } - media_count = 0; } diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h index cc780bbedbb..516af8c0577 100644 --- a/net/tipc/bearer.h +++ b/net/tipc/bearer.h @@ -1,7 +1,7 @@ /* * net/tipc/bearer.h: Include file for TIPC bearer code * - * Copyright (c) 1996-2006, Ericsson AB + * Copyright (c) 1996-2006, 2013, Ericsson AB * Copyright (c) 2005, 2010-2011, Wind River Systems * All rights reserved. * @@ -157,7 +157,6 @@ extern struct tipc_bearer tipc_bearers[]; /* * TIPC routines available to supported media types */ -int tipc_register_media(struct tipc_media *m_ptr); void tipc_recv_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr); @@ -171,10 +170,12 @@ int tipc_disable_bearer(const char *name); */ int tipc_eth_media_start(void); void tipc_eth_media_stop(void); +extern struct tipc_media eth_media_info; #ifdef CONFIG_TIPC_MEDIA_IB int tipc_ib_media_start(void); void tipc_ib_media_stop(void); +extern struct tipc_media ib_media_info; #else static inline int tipc_ib_media_start(void) { return 0; } static inline void tipc_ib_media_stop(void) { return; } diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c index 1e3c33250db..37fb145476e 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c @@ -1,7 +1,7 @@ /* * net/tipc/eth_media.c: Ethernet bearer support for TIPC * - * Copyright (c) 2001-2007, Ericsson AB + * Copyright (c) 2001-2007, 2013, Ericsson AB * Copyright (c) 2005-2008, 2011-2013, Wind River Systems * All rights reserved. * @@ -57,7 +57,7 @@ struct eth_media { struct work_struct cleanup; }; -static struct tipc_media eth_media_info; + static struct eth_media eth_media_array[MAX_ETH_MEDIA]; static int eth_started; @@ -315,7 +315,7 @@ static int eth_msg2addr(const struct tipc_bearer *tb_ptr, /* * Ethernet media registration info */ -static struct tipc_media eth_media_info = { +struct tipc_media eth_media_info = { .send_msg = send_msg, .enable_media = enable_media, .disable_media = disable_media, @@ -342,10 +342,6 @@ int tipc_eth_media_start(void) if (eth_started) return -EINVAL; - res = tipc_register_media(ð_media_info); - if (res) - return res; - res = register_netdevice_notifier(¬ifier); if (!res) eth_started = 1; diff --git a/net/tipc/ib_media.c b/net/tipc/ib_media.c index cbe7fe15cc7..48e1c07842e 100644 --- a/net/tipc/ib_media.c +++ b/net/tipc/ib_media.c @@ -60,7 +60,6 @@ struct ib_media { struct work_struct cleanup; }; -static struct tipc_media ib_media_info; static struct ib_media ib_media_array[MAX_IB_MEDIA]; static int ib_started; @@ -311,7 +310,7 @@ static int ib_msg2addr(const struct tipc_bearer *tb_ptr, /* * InfiniBand media registration info */ -static struct tipc_media ib_media_info = { +struct tipc_media ib_media_info = { .send_msg = send_msg, .enable_media = enable_media, .disable_media = disable_media, @@ -338,10 +337,6 @@ int tipc_ib_media_start(void) if (ib_started) return -EINVAL; - res = tipc_register_media(&ib_media_info); - if (res) - return res; - res = register_netdevice_notifier(¬ifier); if (!res) ib_started = 1; -- cgit v1.2.3-70-g09d2 From ef72a7e02a28adfd9d5d0d1de81c0b75f3823aa5 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Tue, 10 Dec 2013 20:45:40 -0800 Subject: tipc: improve naming and comment consistency in media layer struct 'tipc_media' represents the specific info that the media layer adaptors (eth_media and ib_media) expose to the generic bearer layer. We clarify this by improved commenting, and by giving the 'media_list' array the more appropriate name 'media_info_array'. There are no functional changes in this commit. Signed-off-by: Ying Xue Reviewed-by: Paul Gortmaker Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/bearer.c | 32 ++++++++++++++++---------------- net/tipc/bearer.h | 6 +++--- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 826aa9fdf45..2411bac2b8f 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -41,7 +41,7 @@ #define MAX_ADDR_STR 60 -static struct tipc_media * const media_list[] = { +static struct tipc_media * const media_info_array[] = { ð_media_info, #ifdef CONFIG_TIPC_MEDIA_IB &ib_media_info, @@ -60,11 +60,11 @@ struct tipc_media *tipc_media_find(const char *name) { u32 i; - for (i = 0; media_list[i] != NULL; i++) { - if (!strcmp(media_list[i]->name, name)) + for (i = 0; media_info_array[i] != NULL; i++) { + if (!strcmp(media_info_array[i]->name, name)) break; } - return media_list[i]; + return media_info_array[i]; } /** @@ -74,11 +74,11 @@ static struct tipc_media *media_find_id(u8 type) { u32 i; - for (i = 0; media_list[i] != NULL; i++) { - if (media_list[i]->type_id == type) + for (i = 0; media_info_array[i] != NULL; i++) { + if (media_info_array[i]->type_id == type) break; } - return media_list[i]; + return media_info_array[i]; } /** @@ -116,10 +116,10 @@ struct sk_buff *tipc_media_get_names(void) if (!buf) return NULL; - for (i = 0; media_list[i] != NULL; i++) { + for (i = 0; media_info_array[i] != NULL; i++) { tipc_cfg_append_tlv(buf, TIPC_TLV_MEDIA_NAME, - media_list[i]->name, - strlen(media_list[i]->name) + 1); + media_info_array[i]->name, + strlen(media_info_array[i]->name) + 1); } return buf; } @@ -209,7 +209,7 @@ struct tipc_bearer *tipc_bearer_find_interface(const char *if_name) struct sk_buff *tipc_bearer_get_names(void) { struct sk_buff *buf; - struct tipc_bearer *b_ptr; + struct tipc_bearer *b; int i, j; buf = tipc_cfg_reply_alloc(MAX_BEARERS * TLV_SPACE(TIPC_MAX_BEARER_NAME)); @@ -217,13 +217,13 @@ struct sk_buff *tipc_bearer_get_names(void) return NULL; read_lock_bh(&tipc_net_lock); - for (i = 0; media_list[i] != NULL; i++) { + for (i = 0; media_info_array[i] != NULL; i++) { for (j = 0; j < MAX_BEARERS; j++) { - b_ptr = &tipc_bearers[j]; - if (b_ptr->active && (b_ptr->media == media_list[i])) { + b = &tipc_bearers[j]; + if (b->active && (b->media == media_info_array[i])) { tipc_cfg_append_tlv(buf, TIPC_TLV_BEARER_NAME, - b_ptr->name, - strlen(b_ptr->name) + 1); + b->name, + strlen(b->name) + 1); } } } diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h index 516af8c0577..e50266aa4d1 100644 --- a/net/tipc/bearer.h +++ b/net/tipc/bearer.h @@ -73,14 +73,13 @@ struct tipc_media_addr { struct tipc_bearer; /** - * struct tipc_media - TIPC media information available to internal users + * struct tipc_media - Media specific info exposed to generic bearer layer * @send_msg: routine which handles buffer transmission * @enable_media: routine which enables a media * @disable_media: routine which disables a media * @addr2str: routine which converts media address to string * @addr2msg: routine which converts media address to protocol message area * @msg2addr: routine which converts media address from protocol message area - * @bcast_addr: media address used in broadcasting * @priority: default link (and bearer) priority * @tolerance: default time (in ms) before declaring link failure * @window: default window (in packets) before declaring link congestion @@ -105,13 +104,14 @@ struct tipc_media { }; /** - * struct tipc_bearer - TIPC bearer structure + * struct tipc_bearer - Generic TIPC bearer structure * @usr_handle: pointer to additional media-specific information about bearer * @mtu: max packet size bearer can support * @lock: spinlock for controlling access to bearer * @addr: media-specific address associated with bearer * @name: bearer name (format = media:interface) * @media: ptr to media structure associated with bearer + * @bcast_addr: media address used in broadcasting * @priority: default link priority for bearer * @window: default window size for bearer * @tolerance: default link tolerance for bearer -- cgit v1.2.3-70-g09d2 From 37cb0620073cb64101d9307931c135c70b2e3f04 Mon Sep 17 00:00:00 2001 From: Ying Xue Date: Tue, 10 Dec 2013 20:45:41 -0800 Subject: tipc: remove TIPC usage of field af_packet_priv in struct net_device TIPC is currently using the field 'af_packet_priv' in struct net_device as a handle to find the bearer instance associated to the given network device. But, by doing so it is blocking other networking cleanups, such as the one discussed here: http://patchwork.ozlabs.org/patch/178044/ This commit removes this usage from TIPC. Instead, we introduce a new field, 'tipc_ptr', to the net_device structure, to serve this purpose. When TIPC bearer is enabled, the bearer object is associated to 'tipc_ptr'. When a TIPC packet arrives in the recv_msg() upcall from a networking device, the bearer object can now be obtained from 'tipc_ptr'. When a bearer is disabled, the bearer object is detached from its underlying network device by setting 'tipc_ptr' to NULL. Additionally, an RCU lock is used to protect the new pointer. Henceforth, the existing tipc_net_lock is used in write mode to serialize write accesses to this pointer, while the new RCU lock is applied on the read side to ensure that the pointer is 100% valid within its wrapped area for all readers. Signed-off-by: Ying Xue Cc: Patrick McHardy Reviewed-by: Paul Gortmaker Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- include/linux/netdevice.h | 3 +++ net/tipc/bearer.h | 2 ++ net/tipc/eth_media.c | 55 +++++++++++++++++++++++++++-------------------- net/tipc/ib_media.c | 54 ++++++++++++++++++++++++++-------------------- 4 files changed, 68 insertions(+), 46 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 9d55e5188b9..0ca8100f9fb 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1282,6 +1282,9 @@ struct net_device { #endif #if IS_ENABLED(CONFIG_NET_DSA) struct dsa_switch_tree *dsa_ptr; /* dsa specific data */ +#endif +#if IS_ENABLED(CONFIG_TIPC) + struct tipc_bearer __rcu *tipc_ptr; /* TIPC specific data */ #endif void *atalk_ptr; /* AppleTalk link */ struct in_device __rcu *ip_ptr; /* IPv4 specific data */ diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h index e50266aa4d1..91b8d8b9237 100644 --- a/net/tipc/bearer.h +++ b/net/tipc/bearer.h @@ -105,6 +105,7 @@ struct tipc_media { /** * struct tipc_bearer - Generic TIPC bearer structure + * @dev: ptr to associated network device * @usr_handle: pointer to additional media-specific information about bearer * @mtu: max packet size bearer can support * @lock: spinlock for controlling access to bearer @@ -127,6 +128,7 @@ struct tipc_media { * care of initializing all other fields. */ struct tipc_bearer { + struct net_device *dev; void *usr_handle; /* initalized by media */ u32 mtu; /* initalized by media */ struct tipc_media_addr addr; /* initalized by media */ diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c index 37fb145476e..c5f685dee15 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c @@ -63,6 +63,9 @@ static int eth_started; static int recv_notification(struct notifier_block *nb, unsigned long evt, void *dv); +static int recv_msg(struct sk_buff *buf, struct net_device *dev, + struct packet_type *pt, struct net_device *orig_dev); + /* * Network device notifier info */ @@ -71,6 +74,11 @@ static struct notifier_block notifier = { .priority = 0 }; +static struct packet_type tipc_packet_type __read_mostly = { + .type = __constant_htons(ETH_P_TIPC), + .func = recv_msg, +}; + /** * eth_media_addr_set - initialize Ethernet media address structure * @@ -128,20 +136,25 @@ static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr, static int recv_msg(struct sk_buff *buf, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { - struct eth_media *eb_ptr = (struct eth_media *)pt->af_packet_priv; + struct tipc_bearer *b_ptr; if (!net_eq(dev_net(dev), &init_net)) { kfree_skb(buf); return NET_RX_DROP; } - if (likely(eb_ptr->bearer)) { + rcu_read_lock(); + b_ptr = rcu_dereference(dev->tipc_ptr); + if (likely(b_ptr)) { if (likely(buf->pkt_type <= PACKET_BROADCAST)) { buf->next = NULL; - tipc_recv_msg(buf, eb_ptr->bearer); + tipc_recv_msg(buf, b_ptr); + rcu_read_unlock(); return NET_RX_SUCCESS; } } + rcu_read_unlock(); + kfree_skb(buf); return NET_RX_DROP; } @@ -151,10 +164,7 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev, */ static void setup_media(struct work_struct *work) { - struct eth_media *eb_ptr = - container_of(work, struct eth_media, setup); - - dev_add_pack(&eb_ptr->tipc_packet_type); + dev_add_pack(&tipc_packet_type); } /** @@ -183,15 +193,11 @@ static int enable_media(struct tipc_bearer *tb_ptr) /* Create Ethernet bearer for device */ eb_ptr->dev = dev; - eb_ptr->tipc_packet_type.type = htons(ETH_P_TIPC); - eb_ptr->tipc_packet_type.dev = dev; - eb_ptr->tipc_packet_type.func = recv_msg; - eb_ptr->tipc_packet_type.af_packet_priv = eb_ptr; - INIT_LIST_HEAD(&(eb_ptr->tipc_packet_type.list)); INIT_WORK(&eb_ptr->setup, setup_media); schedule_work(&eb_ptr->setup); /* Associate TIPC bearer with Ethernet bearer */ + tb_ptr->dev = dev; eb_ptr->bearer = tb_ptr; tb_ptr->usr_handle = (void *)eb_ptr; memset(tb_ptr->bcast_addr.value, 0, sizeof(tb_ptr->bcast_addr.value)); @@ -200,6 +206,7 @@ static int enable_media(struct tipc_bearer *tb_ptr) tb_ptr->bcast_addr.broadcast = 1; tb_ptr->mtu = dev->mtu; eth_media_addr_set(tb_ptr, &tb_ptr->addr, (char *)dev->dev_addr); + rcu_assign_pointer(dev->tipc_ptr, tb_ptr); return 0; } @@ -213,7 +220,7 @@ static void cleanup_media(struct work_struct *work) struct eth_media *eb_ptr = container_of(work, struct eth_media, cleanup); - dev_remove_pack(&eb_ptr->tipc_packet_type); + dev_remove_pack(&tipc_packet_type); dev_put(eb_ptr->dev); eb_ptr->dev = NULL; } @@ -232,6 +239,7 @@ static void disable_media(struct tipc_bearer *tb_ptr) eb_ptr->bearer = NULL; INIT_WORK(&eb_ptr->cleanup, cleanup_media); schedule_work(&eb_ptr->cleanup); + RCU_INIT_POINTER(tb_ptr->dev->tipc_ptr, NULL); } /** @@ -243,21 +251,20 @@ static void disable_media(struct tipc_bearer *tb_ptr) static int recv_notification(struct notifier_block *nb, unsigned long evt, void *ptr) { + struct tipc_bearer *b_ptr; struct net_device *dev = netdev_notifier_info_to_dev(ptr); - struct eth_media *eb_ptr = ð_media_array[0]; - struct eth_media *stop = ð_media_array[MAX_ETH_MEDIA]; if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; - while ((eb_ptr->dev != dev)) { - if (++eb_ptr == stop) - return NOTIFY_DONE; /* couldn't find device */ - } - if (!eb_ptr->bearer) + rcu_read_lock(); + b_ptr = rcu_dereference(dev->tipc_ptr); + if (!b_ptr) { + rcu_read_unlock(); return NOTIFY_DONE; /* bearer had been disabled */ + } - eb_ptr->bearer->mtu = dev->mtu; + b_ptr->mtu = dev->mtu; switch (evt) { case NETDEV_CHANGE: @@ -266,13 +273,15 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt, case NETDEV_DOWN: case NETDEV_CHANGEMTU: case NETDEV_CHANGEADDR: - tipc_reset_bearer(eb_ptr->bearer); + tipc_reset_bearer(b_ptr); break; case NETDEV_UNREGISTER: case NETDEV_CHANGENAME: - tipc_disable_bearer(eb_ptr->bearer->name); + tipc_disable_bearer(b_ptr->name); break; } + rcu_read_unlock(); + return NOTIFY_OK; } diff --git a/net/tipc/ib_media.c b/net/tipc/ib_media.c index 48e1c07842e..9fdf03cd672 100644 --- a/net/tipc/ib_media.c +++ b/net/tipc/ib_media.c @@ -62,6 +62,13 @@ struct ib_media { static struct ib_media ib_media_array[MAX_IB_MEDIA]; static int ib_started; +static int recv_msg(struct sk_buff *buf, struct net_device *dev, + struct packet_type *pt, struct net_device *orig_dev); + +static struct packet_type tipc_packet_type __read_mostly = { + .type = __constant_htons(ETH_P_TIPC), + .func = recv_msg, +}; /** * ib_media_addr_set - initialize Infiniband media address structure @@ -120,20 +127,25 @@ static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr, static int recv_msg(struct sk_buff *buf, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { - struct ib_media *ib_ptr = (struct ib_media *)pt->af_packet_priv; + struct tipc_bearer *b_ptr; if (!net_eq(dev_net(dev), &init_net)) { kfree_skb(buf); return NET_RX_DROP; } - if (likely(ib_ptr->bearer)) { + rcu_read_lock(); + b_ptr = rcu_dereference(dev->tipc_ptr); + if (likely(b_ptr)) { if (likely(buf->pkt_type <= PACKET_BROADCAST)) { buf->next = NULL; - tipc_recv_msg(buf, ib_ptr->bearer); + tipc_recv_msg(buf, b_ptr); + rcu_read_unlock(); return NET_RX_SUCCESS; } } + rcu_read_unlock(); + kfree_skb(buf); return NET_RX_DROP; } @@ -143,10 +155,7 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev, */ static void setup_media(struct work_struct *work) { - struct ib_media *ib_ptr = - container_of(work, struct ib_media, setup); - - dev_add_pack(&ib_ptr->tipc_packet_type); + dev_add_pack(&tipc_packet_type); } /** @@ -175,15 +184,11 @@ static int enable_media(struct tipc_bearer *tb_ptr) /* Create InfiniBand bearer for device */ ib_ptr->dev = dev; - ib_ptr->tipc_packet_type.type = htons(ETH_P_TIPC); - ib_ptr->tipc_packet_type.dev = dev; - ib_ptr->tipc_packet_type.func = recv_msg; - ib_ptr->tipc_packet_type.af_packet_priv = ib_ptr; - INIT_LIST_HEAD(&(ib_ptr->tipc_packet_type.list)); INIT_WORK(&ib_ptr->setup, setup_media); schedule_work(&ib_ptr->setup); /* Associate TIPC bearer with InfiniBand bearer */ + tb_ptr->dev = dev; ib_ptr->bearer = tb_ptr; tb_ptr->usr_handle = (void *)ib_ptr; memset(tb_ptr->bcast_addr.value, 0, sizeof(tb_ptr->bcast_addr.value)); @@ -192,6 +197,7 @@ static int enable_media(struct tipc_bearer *tb_ptr) tb_ptr->bcast_addr.broadcast = 1; tb_ptr->mtu = dev->mtu; ib_media_addr_set(tb_ptr, &tb_ptr->addr, (char *)dev->dev_addr); + rcu_assign_pointer(dev->tipc_ptr, tb_ptr); return 0; } @@ -205,7 +211,7 @@ static void cleanup_bearer(struct work_struct *work) struct ib_media *ib_ptr = container_of(work, struct ib_media, cleanup); - dev_remove_pack(&ib_ptr->tipc_packet_type); + dev_remove_pack(&tipc_packet_type); dev_put(ib_ptr->dev); ib_ptr->dev = NULL; } @@ -224,6 +230,7 @@ static void disable_media(struct tipc_bearer *tb_ptr) ib_ptr->bearer = NULL; INIT_WORK(&ib_ptr->cleanup, cleanup_bearer); schedule_work(&ib_ptr->cleanup); + RCU_INIT_POINTER(tb_ptr->dev->tipc_ptr, NULL); } /** @@ -235,21 +242,20 @@ static void disable_media(struct tipc_bearer *tb_ptr) static int recv_notification(struct notifier_block *nb, unsigned long evt, void *ptr) { + struct tipc_bearer *b_ptr; struct net_device *dev = netdev_notifier_info_to_dev(ptr); - struct ib_media *ib_ptr = &ib_media_array[0]; - struct ib_media *stop = &ib_media_array[MAX_IB_MEDIA]; if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; - while ((ib_ptr->dev != dev)) { - if (++ib_ptr == stop) - return NOTIFY_DONE; /* couldn't find device */ - } - if (!ib_ptr->bearer) + rcu_read_lock(); + b_ptr = rcu_dereference(dev->tipc_ptr); + if (!b_ptr) { + rcu_read_unlock(); return NOTIFY_DONE; /* bearer had been disabled */ + } - ib_ptr->bearer->mtu = dev->mtu; + b_ptr->mtu = dev->mtu; switch (evt) { case NETDEV_CHANGE: @@ -258,13 +264,15 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt, case NETDEV_DOWN: case NETDEV_CHANGEMTU: case NETDEV_CHANGEADDR: - tipc_reset_bearer(ib_ptr->bearer); + tipc_reset_bearer(b_ptr); break; case NETDEV_UNREGISTER: case NETDEV_CHANGENAME: - tipc_disable_bearer(ib_ptr->bearer->name); + tipc_disable_bearer(b_ptr->name); break; } + rcu_read_unlock(); + return NOTIFY_OK; } -- cgit v1.2.3-70-g09d2 From 6e967adf798ae5066488fd0c2b2466d06c642f23 Mon Sep 17 00:00:00 2001 From: Ying Xue Date: Tue, 10 Dec 2013 20:45:42 -0800 Subject: tipc: relocate common functions from media to bearer Currently, registering a TIPC stack handler in the network device layer is done twice, once for Ethernet (eth_media) and Infiniband (ib_media) repectively. But, as this registration is not media specific, we can avoid some code duplication by moving the registering function to the generic bearer layer, to the file bearer.c, and call it only once. The same is true for the network device event notifier. As a side effect, the two workqueues we are using for for setting up/ cleaning up media can now be eliminated. Furthermore, the array for storing the specific media type structs, media_array[], can be entirely deleted. Note that the eth_started and ib_started flags were removed during the code relocation. There is now only one call to bearer_setup and bearer_cleanup, and these can logically not race against each other. Despite its size, this cleanup work incurs no functional changes in TIPC. In particular, it should be noted that the sequence ordering of received packets is unaffected by this change, since packet reception never was subject to any work queue handling in the first place. Signed-off-by: Ying Xue Cc: Patrick McHardy Signed-off-by: Jon Maloy Reviewed-by: Paul Gortmaker Signed-off-by: David S. Miller --- net/tipc/bearer.c | 105 ++++++++++++++++++++++++++- net/tipc/bearer.h | 11 +-- net/tipc/core.c | 8 +-- net/tipc/eth_media.c | 199 +-------------------------------------------------- net/tipc/ib_media.c | 192 +------------------------------------------------ 5 files changed, 114 insertions(+), 401 deletions(-) diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 2411bac2b8f..e95e0b91ef3 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -367,7 +367,7 @@ exit: /** * tipc_reset_bearer - Reset all links established over this bearer */ -int tipc_reset_bearer(struct tipc_bearer *b_ptr) +static int tipc_reset_bearer(struct tipc_bearer *b_ptr) { struct tipc_link *l_ptr; struct tipc_link *temp_l_ptr; @@ -432,7 +432,110 @@ int tipc_disable_bearer(const char *name) return res; } +/** + * tipc_l2_rcv_msg - handle incoming TIPC message from an interface + * @buf: the received packet + * @dev: the net device that the packet was received on + * @pt: the packet_type structure which was used to register this handler + * @orig_dev: the original receive net device in case the device is a bond + * + * Accept only packets explicitly sent to this node, or broadcast packets; + * ignores packets sent using interface multicast, and traffic sent to other + * nodes (which can happen if interface is running in promiscuous mode). + */ +static int tipc_l2_rcv_msg(struct sk_buff *buf, struct net_device *dev, + struct packet_type *pt, struct net_device *orig_dev) +{ + struct tipc_bearer *b_ptr; + + if (!net_eq(dev_net(dev), &init_net)) { + kfree_skb(buf); + return NET_RX_DROP; + } + + rcu_read_lock(); + b_ptr = rcu_dereference(dev->tipc_ptr); + if (likely(b_ptr)) { + if (likely(buf->pkt_type <= PACKET_BROADCAST)) { + buf->next = NULL; + tipc_recv_msg(buf, b_ptr); + rcu_read_unlock(); + return NET_RX_SUCCESS; + } + } + rcu_read_unlock(); + + kfree_skb(buf); + return NET_RX_DROP; +} + +/** + * tipc_l2_device_event - handle device events from network device + * @nb: the context of the notification + * @evt: the type of event + * @ptr: the net device that the event was on + * + * This function is called by the Ethernet driver in case of link + * change event. + */ +static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt, + void *ptr) +{ + struct tipc_bearer *b_ptr; + struct net_device *dev = netdev_notifier_info_to_dev(ptr); + if (!net_eq(dev_net(dev), &init_net)) + return NOTIFY_DONE; + + rcu_read_lock(); + b_ptr = rcu_dereference(dev->tipc_ptr); + if (!b_ptr) { + rcu_read_unlock(); + return NOTIFY_DONE; + } + + b_ptr->mtu = dev->mtu; + + switch (evt) { + case NETDEV_CHANGE: + if (netif_carrier_ok(dev)) + break; + case NETDEV_DOWN: + case NETDEV_CHANGEMTU: + case NETDEV_CHANGEADDR: + tipc_reset_bearer(b_ptr); + break; + case NETDEV_UNREGISTER: + case NETDEV_CHANGENAME: + tipc_disable_bearer(b_ptr->name); + break; + } + rcu_read_unlock(); + + return NOTIFY_OK; +} + +static struct packet_type tipc_packet_type __read_mostly = { + .type = __constant_htons(ETH_P_TIPC), + .func = tipc_l2_rcv_msg, +}; + +static struct notifier_block notifier = { + .notifier_call = tipc_l2_device_event, + .priority = 0, +}; + +int tipc_bearer_setup(void) +{ + dev_add_pack(&tipc_packet_type); + return register_netdevice_notifier(¬ifier); +} + +void tipc_bearer_cleanup(void) +{ + unregister_netdevice_notifier(¬ifier); + dev_remove_pack(&tipc_packet_type); +} void tipc_bearer_stop(void) { diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h index 91b8d8b9237..0974c2f2bbe 100644 --- a/net/tipc/bearer.h +++ b/net/tipc/bearer.h @@ -162,25 +162,16 @@ extern struct tipc_bearer tipc_bearers[]; void tipc_recv_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr); -int tipc_reset_bearer(struct tipc_bearer *b_ptr); - int tipc_enable_bearer(const char *bearer_name, u32 disc_domain, u32 priority); int tipc_disable_bearer(const char *name); /* * Routines made available to TIPC by supported media types */ -int tipc_eth_media_start(void); -void tipc_eth_media_stop(void); extern struct tipc_media eth_media_info; #ifdef CONFIG_TIPC_MEDIA_IB -int tipc_ib_media_start(void); -void tipc_ib_media_stop(void); extern struct tipc_media ib_media_info; -#else -static inline int tipc_ib_media_start(void) { return 0; } -static inline void tipc_ib_media_stop(void) { return; } #endif int tipc_media_set_priority(const char *name, u32 new_value); @@ -194,6 +185,8 @@ void tipc_bearer_remove_dest(struct tipc_bearer *b_ptr, u32 dest); struct tipc_bearer *tipc_bearer_find(const char *name); struct tipc_bearer *tipc_bearer_find_interface(const char *if_name); struct tipc_media *tipc_media_find(const char *name); +int tipc_bearer_setup(void); +void tipc_bearer_cleanup(void); void tipc_bearer_stop(void); /** diff --git a/net/tipc/core.c b/net/tipc/core.c index fd4eeeaa972..68977c42302 100644 --- a/net/tipc/core.c +++ b/net/tipc/core.c @@ -82,8 +82,7 @@ struct sk_buff *tipc_buf_acquire(u32 size) static void tipc_core_stop_net(void) { tipc_net_stop(); - tipc_eth_media_stop(); - tipc_ib_media_stop(); + tipc_bearer_cleanup(); } /** @@ -94,10 +93,7 @@ int tipc_core_start_net(unsigned long addr) int res; tipc_net_start(addr); - res = tipc_eth_media_start(); - if (res < 0) - goto err; - res = tipc_ib_media_start(); + res = tipc_bearer_setup(); if (res < 0) goto err; return res; diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c index c5f685dee15..f28f7160adb 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c @@ -37,48 +37,8 @@ #include "core.h" #include "bearer.h" -#define MAX_ETH_MEDIA MAX_BEARERS - #define ETH_ADDR_OFFSET 4 /* message header offset of MAC address */ -/** - * struct eth_media - Ethernet bearer data structure - * @bearer: ptr to associated "generic" bearer structure - * @dev: ptr to associated Ethernet network device - * @tipc_packet_type: used in binding TIPC to Ethernet driver - * @setup: work item used when enabling bearer - * @cleanup: work item used when disabling bearer - */ -struct eth_media { - struct tipc_bearer *bearer; - struct net_device *dev; - struct packet_type tipc_packet_type; - struct work_struct setup; - struct work_struct cleanup; -}; - - -static struct eth_media eth_media_array[MAX_ETH_MEDIA]; -static int eth_started; - -static int recv_notification(struct notifier_block *nb, unsigned long evt, - void *dv); -static int recv_msg(struct sk_buff *buf, struct net_device *dev, - struct packet_type *pt, struct net_device *orig_dev); - -/* - * Network device notifier info - */ -static struct notifier_block notifier = { - .notifier_call = recv_notification, - .priority = 0 -}; - -static struct packet_type tipc_packet_type __read_mostly = { - .type = __constant_htons(ETH_P_TIPC), - .func = recv_msg, -}; - /** * eth_media_addr_set - initialize Ethernet media address structure * @@ -101,16 +61,14 @@ static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr, struct tipc_media_addr *dest) { struct sk_buff *clone; - struct net_device *dev; int delta; + struct net_device *dev = tb_ptr->dev; clone = skb_clone(buf, GFP_ATOMIC); if (!clone) return 0; - dev = ((struct eth_media *)(tb_ptr->usr_handle))->dev; delta = dev->hard_header_len - skb_headroom(buf); - if ((delta > 0) && pskb_expand_head(clone, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC)) { kfree_skb(clone); @@ -126,80 +84,22 @@ static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr, return 0; } -/** - * recv_msg - handle incoming TIPC message from an Ethernet interface - * - * Accept only packets explicitly sent to this node, or broadcast packets; - * ignores packets sent using Ethernet multicast, and traffic sent to other - * nodes (which can happen if interface is running in promiscuous mode). - */ -static int recv_msg(struct sk_buff *buf, struct net_device *dev, - struct packet_type *pt, struct net_device *orig_dev) -{ - struct tipc_bearer *b_ptr; - - if (!net_eq(dev_net(dev), &init_net)) { - kfree_skb(buf); - return NET_RX_DROP; - } - - rcu_read_lock(); - b_ptr = rcu_dereference(dev->tipc_ptr); - if (likely(b_ptr)) { - if (likely(buf->pkt_type <= PACKET_BROADCAST)) { - buf->next = NULL; - tipc_recv_msg(buf, b_ptr); - rcu_read_unlock(); - return NET_RX_SUCCESS; - } - } - rcu_read_unlock(); - - kfree_skb(buf); - return NET_RX_DROP; -} - -/** - * setup_media - setup association between Ethernet bearer and interface - */ -static void setup_media(struct work_struct *work) -{ - dev_add_pack(&tipc_packet_type); -} - /** * enable_media - attach TIPC bearer to an Ethernet interface */ static int enable_media(struct tipc_bearer *tb_ptr) { struct net_device *dev; - struct eth_media *eb_ptr = ð_media_array[0]; - struct eth_media *stop = ð_media_array[MAX_ETH_MEDIA]; char *driver_name = strchr((const char *)tb_ptr->name, ':') + 1; - int pending_dev = 0; - - /* Find unused Ethernet bearer structure */ - while (eb_ptr->dev) { - if (!eb_ptr->bearer) - pending_dev++; - if (++eb_ptr == stop) - return pending_dev ? -EAGAIN : -EDQUOT; - } /* Find device with specified name */ dev = dev_get_by_name(&init_net, driver_name); if (!dev) return -ENODEV; - /* Create Ethernet bearer for device */ - eb_ptr->dev = dev; - INIT_WORK(&eb_ptr->setup, setup_media); - schedule_work(&eb_ptr->setup); - /* Associate TIPC bearer with Ethernet bearer */ tb_ptr->dev = dev; - eb_ptr->bearer = tb_ptr; - tb_ptr->usr_handle = (void *)eb_ptr; + tb_ptr->usr_handle = NULL; memset(tb_ptr->bcast_addr.value, 0, sizeof(tb_ptr->bcast_addr.value)); memcpy(tb_ptr->bcast_addr.value, dev->broadcast, ETH_ALEN); tb_ptr->bcast_addr.media_id = TIPC_MEDIA_TYPE_ETH; @@ -210,21 +110,6 @@ static int enable_media(struct tipc_bearer *tb_ptr) return 0; } -/** - * cleanup_media - break association between Ethernet bearer and interface - * - * This routine must be invoked from a work queue because it can sleep. - */ -static void cleanup_media(struct work_struct *work) -{ - struct eth_media *eb_ptr = - container_of(work, struct eth_media, cleanup); - - dev_remove_pack(&tipc_packet_type); - dev_put(eb_ptr->dev); - eb_ptr->dev = NULL; -} - /** * disable_media - detach TIPC bearer from an Ethernet interface * @@ -234,55 +119,8 @@ static void cleanup_media(struct work_struct *work) */ static void disable_media(struct tipc_bearer *tb_ptr) { - struct eth_media *eb_ptr = (struct eth_media *)tb_ptr->usr_handle; - - eb_ptr->bearer = NULL; - INIT_WORK(&eb_ptr->cleanup, cleanup_media); - schedule_work(&eb_ptr->cleanup); RCU_INIT_POINTER(tb_ptr->dev->tipc_ptr, NULL); -} - -/** - * recv_notification - handle device updates from OS - * - * Change the state of the Ethernet bearer (if any) associated with the - * specified device. - */ -static int recv_notification(struct notifier_block *nb, unsigned long evt, - void *ptr) -{ - struct tipc_bearer *b_ptr; - struct net_device *dev = netdev_notifier_info_to_dev(ptr); - - if (!net_eq(dev_net(dev), &init_net)) - return NOTIFY_DONE; - - rcu_read_lock(); - b_ptr = rcu_dereference(dev->tipc_ptr); - if (!b_ptr) { - rcu_read_unlock(); - return NOTIFY_DONE; /* bearer had been disabled */ - } - - b_ptr->mtu = dev->mtu; - - switch (evt) { - case NETDEV_CHANGE: - if (netif_carrier_ok(dev)) - break; - case NETDEV_DOWN: - case NETDEV_CHANGEMTU: - case NETDEV_CHANGEADDR: - tipc_reset_bearer(b_ptr); - break; - case NETDEV_UNREGISTER: - case NETDEV_CHANGENAME: - tipc_disable_bearer(b_ptr->name); - break; - } - rcu_read_unlock(); - - return NOTIFY_OK; + dev_put(tb_ptr->dev); } /** @@ -338,34 +176,3 @@ struct tipc_media eth_media_info = { .name = "eth" }; -/** - * tipc_eth_media_start - activate Ethernet bearer support - * - * Register Ethernet media type with TIPC bearer code. Also register - * with OS for notifications about device state changes. - */ -int tipc_eth_media_start(void) -{ - int res; - - if (eth_started) - return -EINVAL; - - res = register_netdevice_notifier(¬ifier); - if (!res) - eth_started = 1; - return res; -} - -/** - * tipc_eth_media_stop - deactivate Ethernet bearer support - */ -void tipc_eth_media_stop(void) -{ - if (!eth_started) - return; - - flush_scheduled_work(); - unregister_netdevice_notifier(¬ifier); - eth_started = 0; -} diff --git a/net/tipc/ib_media.c b/net/tipc/ib_media.c index 9fdf03cd672..62d91aeda05 100644 --- a/net/tipc/ib_media.c +++ b/net/tipc/ib_media.c @@ -42,34 +42,6 @@ #include "core.h" #include "bearer.h" -#define MAX_IB_MEDIA MAX_BEARERS - -/** - * struct ib_media - Infiniband media data structure - * @bearer: ptr to associated "generic" bearer structure - * @dev: ptr to associated Infiniband network device - * @tipc_packet_type: used in binding TIPC to Infiniband driver - * @cleanup: work item used when disabling bearer - */ - -struct ib_media { - struct tipc_bearer *bearer; - struct net_device *dev; - struct packet_type tipc_packet_type; - struct work_struct setup; - struct work_struct cleanup; -}; - -static struct ib_media ib_media_array[MAX_IB_MEDIA]; -static int ib_started; -static int recv_msg(struct sk_buff *buf, struct net_device *dev, - struct packet_type *pt, struct net_device *orig_dev); - -static struct packet_type tipc_packet_type __read_mostly = { - .type = __constant_htons(ETH_P_TIPC), - .func = recv_msg, -}; - /** * ib_media_addr_set - initialize Infiniband media address structure * @@ -92,16 +64,14 @@ static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr, struct tipc_media_addr *dest) { struct sk_buff *clone; - struct net_device *dev; int delta; + struct net_device *dev = tb_ptr->dev; clone = skb_clone(buf, GFP_ATOMIC); if (!clone) return 0; - dev = ((struct ib_media *)(tb_ptr->usr_handle))->dev; delta = dev->hard_header_len - skb_headroom(buf); - if ((delta > 0) && pskb_expand_head(clone, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC)) { kfree_skb(clone); @@ -117,80 +87,22 @@ static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr, return 0; } -/** - * recv_msg - handle incoming TIPC message from an InfiniBand interface - * - * Accept only packets explicitly sent to this node, or broadcast packets; - * ignores packets sent using InfiniBand multicast, and traffic sent to other - * nodes (which can happen if interface is running in promiscuous mode). - */ -static int recv_msg(struct sk_buff *buf, struct net_device *dev, - struct packet_type *pt, struct net_device *orig_dev) -{ - struct tipc_bearer *b_ptr; - - if (!net_eq(dev_net(dev), &init_net)) { - kfree_skb(buf); - return NET_RX_DROP; - } - - rcu_read_lock(); - b_ptr = rcu_dereference(dev->tipc_ptr); - if (likely(b_ptr)) { - if (likely(buf->pkt_type <= PACKET_BROADCAST)) { - buf->next = NULL; - tipc_recv_msg(buf, b_ptr); - rcu_read_unlock(); - return NET_RX_SUCCESS; - } - } - rcu_read_unlock(); - - kfree_skb(buf); - return NET_RX_DROP; -} - -/** - * setup_bearer - setup association between InfiniBand bearer and interface - */ -static void setup_media(struct work_struct *work) -{ - dev_add_pack(&tipc_packet_type); -} - /** * enable_media - attach TIPC bearer to an InfiniBand interface */ static int enable_media(struct tipc_bearer *tb_ptr) { struct net_device *dev; - struct ib_media *ib_ptr = &ib_media_array[0]; - struct ib_media *stop = &ib_media_array[MAX_IB_MEDIA]; char *driver_name = strchr((const char *)tb_ptr->name, ':') + 1; - int pending_dev = 0; - - /* Find unused InfiniBand bearer structure */ - while (ib_ptr->dev) { - if (!ib_ptr->bearer) - pending_dev++; - if (++ib_ptr == stop) - return pending_dev ? -EAGAIN : -EDQUOT; - } /* Find device with specified name */ dev = dev_get_by_name(&init_net, driver_name); if (!dev) return -ENODEV; - /* Create InfiniBand bearer for device */ - ib_ptr->dev = dev; - INIT_WORK(&ib_ptr->setup, setup_media); - schedule_work(&ib_ptr->setup); - /* Associate TIPC bearer with InfiniBand bearer */ tb_ptr->dev = dev; - ib_ptr->bearer = tb_ptr; - tb_ptr->usr_handle = (void *)ib_ptr; + tb_ptr->usr_handle = NULL; memset(tb_ptr->bcast_addr.value, 0, sizeof(tb_ptr->bcast_addr.value)); memcpy(tb_ptr->bcast_addr.value, dev->broadcast, INFINIBAND_ALEN); tb_ptr->bcast_addr.media_id = TIPC_MEDIA_TYPE_IB; @@ -201,21 +113,6 @@ static int enable_media(struct tipc_bearer *tb_ptr) return 0; } -/** - * cleanup_bearer - break association between InfiniBand bearer and interface - * - * This routine must be invoked from a work queue because it can sleep. - */ -static void cleanup_bearer(struct work_struct *work) -{ - struct ib_media *ib_ptr = - container_of(work, struct ib_media, cleanup); - - dev_remove_pack(&tipc_packet_type); - dev_put(ib_ptr->dev); - ib_ptr->dev = NULL; -} - /** * disable_media - detach TIPC bearer from an InfiniBand interface * @@ -225,62 +122,10 @@ static void cleanup_bearer(struct work_struct *work) */ static void disable_media(struct tipc_bearer *tb_ptr) { - struct ib_media *ib_ptr = (struct ib_media *)tb_ptr->usr_handle; - - ib_ptr->bearer = NULL; - INIT_WORK(&ib_ptr->cleanup, cleanup_bearer); - schedule_work(&ib_ptr->cleanup); RCU_INIT_POINTER(tb_ptr->dev->tipc_ptr, NULL); + dev_put(tb_ptr->dev); } -/** - * recv_notification - handle device updates from OS - * - * Change the state of the InfiniBand bearer (if any) associated with the - * specified device. - */ -static int recv_notification(struct notifier_block *nb, unsigned long evt, - void *ptr) -{ - struct tipc_bearer *b_ptr; - struct net_device *dev = netdev_notifier_info_to_dev(ptr); - - if (!net_eq(dev_net(dev), &init_net)) - return NOTIFY_DONE; - - rcu_read_lock(); - b_ptr = rcu_dereference(dev->tipc_ptr); - if (!b_ptr) { - rcu_read_unlock(); - return NOTIFY_DONE; /* bearer had been disabled */ - } - - b_ptr->mtu = dev->mtu; - - switch (evt) { - case NETDEV_CHANGE: - if (netif_carrier_ok(dev)) - break; - case NETDEV_DOWN: - case NETDEV_CHANGEMTU: - case NETDEV_CHANGEADDR: - tipc_reset_bearer(b_ptr); - break; - case NETDEV_UNREGISTER: - case NETDEV_CHANGENAME: - tipc_disable_bearer(b_ptr->name); - break; - } - rcu_read_unlock(); - - return NOTIFY_OK; -} - -static struct notifier_block notifier = { - .notifier_call = recv_notification, - .priority = 0, -}; - /** * ib_addr2str - convert InfiniBand address to string */ @@ -332,34 +177,3 @@ struct tipc_media ib_media_info = { .name = "ib" }; -/** - * tipc_ib_media_start - activate InfiniBand bearer support - * - * Register InfiniBand media type with TIPC bearer code. Also register - * with OS for notifications about device state changes. - */ -int tipc_ib_media_start(void) -{ - int res; - - if (ib_started) - return -EINVAL; - - res = register_netdevice_notifier(¬ifier); - if (!res) - ib_started = 1; - return res; -} - -/** - * tipc_ib_media_stop - deactivate InfiniBand bearer support - */ -void tipc_ib_media_stop(void) -{ - if (!ib_started) - return; - - flush_scheduled_work(); - unregister_netdevice_notifier(¬ifier); - ib_started = 0; -} -- cgit v1.2.3-70-g09d2 From e4d050cbf7720d8bcc781f4ef557d37ed148a5c4 Mon Sep 17 00:00:00 2001 From: Ying Xue Date: Tue, 10 Dec 2013 20:45:43 -0800 Subject: tipc: eliminate code duplication in media layer Currently TIPC supports two L2 media types, Ethernet and Infiniband. Because both these media are accessed through the common net_device API, several functions in the two media adaptation files turn out to be fully or almost identical, leading to unnecessary code duplication. In this commit we extract this common code from the two media files and move them to the generic bearer.c. Additionally, we change the function names to reflect their real role: to access L2 media, irrespective of type. Signed-off-by: Ying Xue Cc: Patrick McHardy Reviewed-by: Paul Gortmaker Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/bearer.c | 106 ++++++++++++++++++++++++++++++++++++++++++- net/tipc/bearer.h | 26 +++++------ net/tipc/eth_media.c | 124 +++++++-------------------------------------------- net/tipc/ib_media.c | 124 +++++++-------------------------------------------- 4 files changed, 149 insertions(+), 231 deletions(-) diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index e95e0b91ef3..3bb5f266b0e 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -2,7 +2,7 @@ * net/tipc/bearer.c: TIPC bearer code * * Copyright (c) 1996-2006, 2013, Ericsson AB - * Copyright (c) 2004-2006, 2010-2011, Wind River Systems + * Copyright (c) 2004-2006, 2010-2013, Wind River Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -332,6 +332,7 @@ restart: b_ptr = &tipc_bearers[bearer_id]; strcpy(b_ptr->name, name); + b_ptr->media = m_ptr; res = m_ptr->enable_media(b_ptr); if (res) { pr_warn("Bearer <%s> rejected, enable failure (%d)\n", @@ -340,7 +341,6 @@ restart: } b_ptr->identity = bearer_id; - b_ptr->media = m_ptr; b_ptr->tolerance = m_ptr->tolerance; b_ptr->window = m_ptr->window; b_ptr->net_plane = bearer_id + 'A'; @@ -432,6 +432,108 @@ int tipc_disable_bearer(const char *name) return res; } + +/* tipc_l2_media_addr_set - initialize Ethernet media address structure + * + * Media-dependent "value" field stores MAC address in first 6 bytes + * and zeroes out the remaining bytes. + */ +void tipc_l2_media_addr_set(const struct tipc_bearer *b, + struct tipc_media_addr *a, char *mac) +{ + int len = b->media->hwaddr_len; + + if (unlikely(sizeof(a->value) < len)) { + WARN_ONCE(1, "Media length invalid\n"); + return; + } + + memcpy(a->value, mac, len); + memset(a->value + len, 0, sizeof(a->value) - len); + a->media_id = b->media->type_id; + a->broadcast = !memcmp(mac, b->bcast_addr.value, len); +} + +int tipc_enable_l2_media(struct tipc_bearer *b) +{ + struct net_device *dev; + char *driver_name = strchr((const char *)b->name, ':') + 1; + + /* Find device with specified name */ + dev = dev_get_by_name(&init_net, driver_name); + if (!dev) + return -ENODEV; + + /* Associate TIPC bearer with Ethernet bearer */ + b->media_ptr = dev; + memset(b->bcast_addr.value, 0, sizeof(b->bcast_addr.value)); + memcpy(b->bcast_addr.value, dev->broadcast, b->media->hwaddr_len); + b->bcast_addr.media_id = b->media->type_id; + b->bcast_addr.broadcast = 1; + b->mtu = dev->mtu; + tipc_l2_media_addr_set(b, &b->addr, (char *)dev->dev_addr); + rcu_assign_pointer(dev->tipc_ptr, b); + return 0; +} + +/* tipc_disable_l2_media - detach TIPC bearer from an Ethernet interface + * + * Mark Ethernet bearer as inactive so that incoming buffers are thrown away, + * then get worker thread to complete bearer cleanup. (Can't do cleanup + * here because cleanup code needs to sleep and caller holds spinlocks.) + */ +void tipc_disable_l2_media(struct tipc_bearer *b) +{ + struct net_device *dev = (struct net_device *)b->media_ptr; + RCU_INIT_POINTER(dev->tipc_ptr, NULL); + dev_put(dev); +} + +/** + * tipc_l2_send_msg - send a TIPC packet out over an Ethernet interface + * @buf: the packet to be sent + * @b_ptr: the bearer throught which the packet is to be sent + * @dest: peer destination address + */ +int tipc_l2_send_msg(struct sk_buff *buf, struct tipc_bearer *b, + struct tipc_media_addr *dest) +{ + struct sk_buff *clone; + int delta; + struct net_device *dev = (struct net_device *)b->media_ptr; + + clone = skb_clone(buf, GFP_ATOMIC); + if (!clone) + return 0; + + delta = dev->hard_header_len - skb_headroom(buf); + if ((delta > 0) && + pskb_expand_head(clone, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC)) { + kfree_skb(clone); + return 0; + } + + skb_reset_network_header(clone); + clone->dev = dev; + clone->protocol = htons(ETH_P_TIPC); + dev_hard_header(clone, dev, ETH_P_TIPC, dest->value, + dev->dev_addr, clone->len); + dev_queue_xmit(clone); + return 0; +} + +/* tipc_bearer_send- sends buffer to destination over bearer + * + * IMPORTANT: + * The media send routine must not alter the buffer being passed in + * as it may be needed for later retransmission! + */ +void tipc_bearer_send(struct tipc_bearer *b, struct sk_buff *buf, + struct tipc_media_addr *dest) +{ + b->media->send_msg(buf, b, dest); +} + /** * tipc_l2_rcv_msg - handle incoming TIPC message from an interface * @buf: the received packet diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h index 0974c2f2bbe..fa95c34ca92 100644 --- a/net/tipc/bearer.h +++ b/net/tipc/bearer.h @@ -84,6 +84,7 @@ struct tipc_bearer; * @tolerance: default time (in ms) before declaring link failure * @window: default window (in packets) before declaring link congestion * @type_id: TIPC media identifier + * @hwaddr_len: TIPC media address len * @name: media name */ struct tipc_media { @@ -100,6 +101,7 @@ struct tipc_media { u32 tolerance; u32 window; u32 type_id; + u32 hwaddr_len; char name[TIPC_MAX_MEDIA_NAME]; }; @@ -128,8 +130,7 @@ struct tipc_media { * care of initializing all other fields. */ struct tipc_bearer { - struct net_device *dev; - void *usr_handle; /* initalized by media */ + void *media_ptr; /* initalized by media */ u32 mtu; /* initalized by media */ struct tipc_media_addr addr; /* initalized by media */ char name[TIPC_MAX_BEARER_NAME]; @@ -178,6 +179,12 @@ int tipc_media_set_priority(const char *name, u32 new_value); int tipc_media_set_window(const char *name, u32 new_value); void tipc_media_addr_printf(char *buf, int len, struct tipc_media_addr *a); struct sk_buff *tipc_media_get_names(void); +void tipc_l2_media_addr_set(const struct tipc_bearer *b, + struct tipc_media_addr *a, char *mac); +int tipc_enable_l2_media(struct tipc_bearer *b); +void tipc_disable_l2_media(struct tipc_bearer *b); +int tipc_l2_send_msg(struct sk_buff *buf, struct tipc_bearer *b, + struct tipc_media_addr *dest); struct sk_buff *tipc_bearer_get_names(void); void tipc_bearer_add_dest(struct tipc_bearer *b_ptr, u32 dest); @@ -188,18 +195,7 @@ struct tipc_media *tipc_media_find(const char *name); int tipc_bearer_setup(void); void tipc_bearer_cleanup(void); void tipc_bearer_stop(void); - -/** - * tipc_bearer_send- sends buffer to destination over bearer - * - * IMPORTANT: - * The media send routine must not alter the buffer being passed in - * as it may be needed for later retransmission! - */ -static inline void tipc_bearer_send(struct tipc_bearer *b, struct sk_buff *buf, - struct tipc_media_addr *dest) -{ - b->media->send_msg(buf, b, dest); -} +void tipc_bearer_send(struct tipc_bearer *b, struct sk_buff *buf, + struct tipc_media_addr *dest); #endif /* _TIPC_BEARER_H */ diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c index f28f7160adb..67cf3f935db 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c @@ -39,94 +39,9 @@ #define ETH_ADDR_OFFSET 4 /* message header offset of MAC address */ -/** - * eth_media_addr_set - initialize Ethernet media address structure - * - * Media-dependent "value" field stores MAC address in first 6 bytes - * and zeroes out the remaining bytes. - */ -static void eth_media_addr_set(const struct tipc_bearer *tb_ptr, - struct tipc_media_addr *a, char *mac) -{ - memcpy(a->value, mac, ETH_ALEN); - memset(a->value + ETH_ALEN, 0, sizeof(a->value) - ETH_ALEN); - a->media_id = TIPC_MEDIA_TYPE_ETH; - a->broadcast = !memcmp(mac, tb_ptr->bcast_addr.value, ETH_ALEN); -} - -/** - * send_msg - send a TIPC message out over an Ethernet interface - */ -static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr, - struct tipc_media_addr *dest) -{ - struct sk_buff *clone; - int delta; - struct net_device *dev = tb_ptr->dev; - - clone = skb_clone(buf, GFP_ATOMIC); - if (!clone) - return 0; - - delta = dev->hard_header_len - skb_headroom(buf); - if ((delta > 0) && - pskb_expand_head(clone, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC)) { - kfree_skb(clone); - return 0; - } - - skb_reset_network_header(clone); - clone->dev = dev; - clone->protocol = htons(ETH_P_TIPC); - dev_hard_header(clone, dev, ETH_P_TIPC, dest->value, - dev->dev_addr, clone->len); - dev_queue_xmit(clone); - return 0; -} - -/** - * enable_media - attach TIPC bearer to an Ethernet interface - */ -static int enable_media(struct tipc_bearer *tb_ptr) -{ - struct net_device *dev; - char *driver_name = strchr((const char *)tb_ptr->name, ':') + 1; - - /* Find device with specified name */ - dev = dev_get_by_name(&init_net, driver_name); - if (!dev) - return -ENODEV; - - /* Associate TIPC bearer with Ethernet bearer */ - tb_ptr->dev = dev; - tb_ptr->usr_handle = NULL; - memset(tb_ptr->bcast_addr.value, 0, sizeof(tb_ptr->bcast_addr.value)); - memcpy(tb_ptr->bcast_addr.value, dev->broadcast, ETH_ALEN); - tb_ptr->bcast_addr.media_id = TIPC_MEDIA_TYPE_ETH; - tb_ptr->bcast_addr.broadcast = 1; - tb_ptr->mtu = dev->mtu; - eth_media_addr_set(tb_ptr, &tb_ptr->addr, (char *)dev->dev_addr); - rcu_assign_pointer(dev->tipc_ptr, tb_ptr); - return 0; -} - -/** - * disable_media - detach TIPC bearer from an Ethernet interface - * - * Mark Ethernet bearer as inactive so that incoming buffers are thrown away, - * then get worker thread to complete bearer cleanup. (Can't do cleanup - * here because cleanup code needs to sleep and caller holds spinlocks.) - */ -static void disable_media(struct tipc_bearer *tb_ptr) -{ - RCU_INIT_POINTER(tb_ptr->dev->tipc_ptr, NULL); - dev_put(tb_ptr->dev); -} - -/** - * eth_addr2str - convert Ethernet address to string - */ -static int eth_addr2str(struct tipc_media_addr *a, char *str_buf, int str_size) +/* convert Ethernet address to string */ +static int tipc_eth_addr2str(struct tipc_media_addr *a, char *str_buf, + int str_size) { if (str_size < 18) /* 18 = strlen("aa:bb:cc:dd:ee:ff\0") */ return 1; @@ -135,10 +50,8 @@ static int eth_addr2str(struct tipc_media_addr *a, char *str_buf, int str_size) return 0; } -/** - * eth_str2addr - convert Ethernet address format to message header format - */ -static int eth_addr2msg(struct tipc_media_addr *a, char *msg_area) +/* convert Ethernet address format to message header format */ +static int tipc_eth_addr2msg(struct tipc_media_addr *a, char *msg_area) { memset(msg_area, 0, TIPC_MEDIA_ADDR_SIZE); msg_area[TIPC_MEDIA_TYPE_OFFSET] = TIPC_MEDIA_TYPE_ETH; @@ -146,33 +59,30 @@ static int eth_addr2msg(struct tipc_media_addr *a, char *msg_area) return 0; } -/** - * eth_str2addr - convert message header address format to Ethernet format - */ -static int eth_msg2addr(const struct tipc_bearer *tb_ptr, - struct tipc_media_addr *a, char *msg_area) +/* convert message header address format to Ethernet format */ +static int tipc_eth_msg2addr(const struct tipc_bearer *tb_ptr, + struct tipc_media_addr *a, char *msg_area) { if (msg_area[TIPC_MEDIA_TYPE_OFFSET] != TIPC_MEDIA_TYPE_ETH) return 1; - eth_media_addr_set(tb_ptr, a, msg_area + ETH_ADDR_OFFSET); + tipc_l2_media_addr_set(tb_ptr, a, msg_area + ETH_ADDR_OFFSET); return 0; } -/* - * Ethernet media registration info - */ +/* Ethernet media registration info */ struct tipc_media eth_media_info = { - .send_msg = send_msg, - .enable_media = enable_media, - .disable_media = disable_media, - .addr2str = eth_addr2str, - .addr2msg = eth_addr2msg, - .msg2addr = eth_msg2addr, + .send_msg = tipc_l2_send_msg, + .enable_media = tipc_enable_l2_media, + .disable_media = tipc_disable_l2_media, + .addr2str = tipc_eth_addr2str, + .addr2msg = tipc_eth_addr2msg, + .msg2addr = tipc_eth_msg2addr, .priority = TIPC_DEF_LINK_PRI, .tolerance = TIPC_DEF_LINK_TOL, .window = TIPC_DEF_LINK_WIN, .type_id = TIPC_MEDIA_TYPE_ETH, + .hwaddr_len = ETH_ALEN, .name = "eth" }; diff --git a/net/tipc/ib_media.c b/net/tipc/ib_media.c index 62d91aeda05..844a77e2582 100644 --- a/net/tipc/ib_media.c +++ b/net/tipc/ib_media.c @@ -42,94 +42,9 @@ #include "core.h" #include "bearer.h" -/** - * ib_media_addr_set - initialize Infiniband media address structure - * - * Media-dependent "value" field stores MAC address in first 6 bytes - * and zeroes out the remaining bytes. - */ -static void ib_media_addr_set(const struct tipc_bearer *tb_ptr, - struct tipc_media_addr *a, char *mac) -{ - BUILD_BUG_ON(sizeof(a->value) < INFINIBAND_ALEN); - memcpy(a->value, mac, INFINIBAND_ALEN); - a->media_id = TIPC_MEDIA_TYPE_IB; - a->broadcast = !memcmp(mac, tb_ptr->bcast_addr.value, INFINIBAND_ALEN); -} - -/** - * send_msg - send a TIPC message out over an InfiniBand interface - */ -static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr, - struct tipc_media_addr *dest) -{ - struct sk_buff *clone; - int delta; - struct net_device *dev = tb_ptr->dev; - - clone = skb_clone(buf, GFP_ATOMIC); - if (!clone) - return 0; - - delta = dev->hard_header_len - skb_headroom(buf); - if ((delta > 0) && - pskb_expand_head(clone, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC)) { - kfree_skb(clone); - return 0; - } - - skb_reset_network_header(clone); - clone->dev = dev; - clone->protocol = htons(ETH_P_TIPC); - dev_hard_header(clone, dev, ETH_P_TIPC, dest->value, - dev->dev_addr, clone->len); - dev_queue_xmit(clone); - return 0; -} - -/** - * enable_media - attach TIPC bearer to an InfiniBand interface - */ -static int enable_media(struct tipc_bearer *tb_ptr) -{ - struct net_device *dev; - char *driver_name = strchr((const char *)tb_ptr->name, ':') + 1; - - /* Find device with specified name */ - dev = dev_get_by_name(&init_net, driver_name); - if (!dev) - return -ENODEV; - - /* Associate TIPC bearer with InfiniBand bearer */ - tb_ptr->dev = dev; - tb_ptr->usr_handle = NULL; - memset(tb_ptr->bcast_addr.value, 0, sizeof(tb_ptr->bcast_addr.value)); - memcpy(tb_ptr->bcast_addr.value, dev->broadcast, INFINIBAND_ALEN); - tb_ptr->bcast_addr.media_id = TIPC_MEDIA_TYPE_IB; - tb_ptr->bcast_addr.broadcast = 1; - tb_ptr->mtu = dev->mtu; - ib_media_addr_set(tb_ptr, &tb_ptr->addr, (char *)dev->dev_addr); - rcu_assign_pointer(dev->tipc_ptr, tb_ptr); - return 0; -} - -/** - * disable_media - detach TIPC bearer from an InfiniBand interface - * - * Mark InfiniBand bearer as inactive so that incoming buffers are thrown away, - * then get worker thread to complete bearer cleanup. (Can't do cleanup - * here because cleanup code needs to sleep and caller holds spinlocks.) - */ -static void disable_media(struct tipc_bearer *tb_ptr) -{ - RCU_INIT_POINTER(tb_ptr->dev->tipc_ptr, NULL); - dev_put(tb_ptr->dev); -} - -/** - * ib_addr2str - convert InfiniBand address to string - */ -static int ib_addr2str(struct tipc_media_addr *a, char *str_buf, int str_size) +/* convert InfiniBand address to string */ +static int tipc_ib_addr2str(struct tipc_media_addr *a, char *str_buf, + int str_size) { if (str_size < 60) /* 60 = 19 * strlen("xx:") + strlen("xx\0") */ return 1; @@ -139,10 +54,8 @@ static int ib_addr2str(struct tipc_media_addr *a, char *str_buf, int str_size) return 0; } -/** - * ib_addr2msg - convert InfiniBand address format to message header format - */ -static int ib_addr2msg(struct tipc_media_addr *a, char *msg_area) +/* convert InfiniBand address format to message header format */ +static int tipc_ib_addr2msg(struct tipc_media_addr *a, char *msg_area) { memset(msg_area, 0, TIPC_MEDIA_ADDR_SIZE); msg_area[TIPC_MEDIA_TYPE_OFFSET] = TIPC_MEDIA_TYPE_IB; @@ -150,30 +63,27 @@ static int ib_addr2msg(struct tipc_media_addr *a, char *msg_area) return 0; } -/** - * ib_msg2addr - convert message header address format to InfiniBand format - */ -static int ib_msg2addr(const struct tipc_bearer *tb_ptr, - struct tipc_media_addr *a, char *msg_area) +/* convert message header address format to InfiniBand format */ +static int tipc_ib_msg2addr(const struct tipc_bearer *tb_ptr, + struct tipc_media_addr *a, char *msg_area) { - ib_media_addr_set(tb_ptr, a, msg_area); + tipc_l2_media_addr_set(tb_ptr, a, msg_area); return 0; } -/* - * InfiniBand media registration info - */ +/* InfiniBand media registration info */ struct tipc_media ib_media_info = { - .send_msg = send_msg, - .enable_media = enable_media, - .disable_media = disable_media, - .addr2str = ib_addr2str, - .addr2msg = ib_addr2msg, - .msg2addr = ib_msg2addr, + .send_msg = tipc_l2_send_msg, + .enable_media = tipc_enable_l2_media, + .disable_media = tipc_disable_l2_media, + .addr2str = tipc_ib_addr2str, + .addr2msg = tipc_ib_addr2msg, + .msg2addr = tipc_ib_msg2addr, .priority = TIPC_DEF_LINK_PRI, .tolerance = TIPC_DEF_LINK_TOL, .window = TIPC_DEF_LINK_WIN, .type_id = TIPC_MEDIA_TYPE_IB, + .hwaddr_len = INFINIBAND_ALEN, .name = "ib" }; -- cgit v1.2.3-70-g09d2 From 77a7e07a78a44d6c015fa8447ab84bcdb360e35d Mon Sep 17 00:00:00 2001 From: Ying Xue Date: Tue, 10 Dec 2013 20:45:44 -0800 Subject: tipc: remove unused 'blocked' flag from tipc_link struct In early versions of TIPC it was possible to administratively block individual links through the use of the member flag 'blocked'. This functionality was deemed redundant, and since commit 7368dd ("tipc: clean out all instances of #if 0'd unused code"), this flag has been unused. In the current code, a link only needs to be blocked for sending and reception if it is subject to an ongoing link failover. In that case, it is sufficient to check if the number of expected failover packets is non-zero, something which is done via the funtion 'link_blocked()'. This commit finally removes the redundant 'blocked' flag completely. Signed-off-by: Ying Xue Reviewed-by: Paul Gortmaker Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/link.c | 11 +++++++---- net/tipc/link.h | 7 ------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/net/tipc/link.c b/net/tipc/link.c index ac26f8a657d..3d73144a1cc 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -488,10 +488,11 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event) if (!l_ptr->started && (event != STARTING_EVT)) return; /* Not yet. */ - if (link_blocked(l_ptr)) { + /* Check whether changeover is going on */ + if (l_ptr->exp_msg_count) { if (event == TIMEOUT_EVT) link_set_timer(l_ptr, cont_intv); - return; /* Changeover going on */ + return; } switch (l_ptr->state) { @@ -1731,7 +1732,8 @@ void tipc_link_send_proto_msg(struct tipc_link *l_ptr, u32 msg_typ, l_ptr->proto_msg_queue = NULL; } - if (link_blocked(l_ptr)) + /* Don't send protocol message during link changeover */ + if (l_ptr->exp_msg_count) return; /* Abort non-RESET send if communication with node is prohibited */ @@ -1824,7 +1826,8 @@ static void link_recv_proto_msg(struct tipc_link *l_ptr, struct sk_buff *buf) u32 msg_tol; struct tipc_msg *msg = buf_msg(buf); - if (link_blocked(l_ptr)) + /* Discard protocol message during link changeover */ + if (l_ptr->exp_msg_count) goto exit; /* record unnumbered packet arrival (force mismatch on next timeout) */ diff --git a/net/tipc/link.h b/net/tipc/link.h index 8a6c1026644..424b1dfe436 100644 --- a/net/tipc/link.h +++ b/net/tipc/link.h @@ -112,7 +112,6 @@ struct tipc_stats { * @continuity_interval: link continuity testing interval [in ms] * @abort_limit: # of unacknowledged continuity probes needed to reset link * @state: current state of link FSM - * @blocked: indicates if link has been administratively blocked * @fsm_msg_cnt: # of protocol messages link FSM has sent in current state * @proto_msg: template for control messages generated by link * @pmsg: convenience pointer to "proto_msg" field @@ -162,7 +161,6 @@ struct tipc_link { u32 continuity_interval; u32 abort_limit; int state; - int blocked; u32 fsm_msg_cnt; struct { unchar hdr[INT_H_SIZE]; @@ -312,11 +310,6 @@ static inline int link_reset_reset(struct tipc_link *l_ptr) return l_ptr->state == RESET_RESET; } -static inline int link_blocked(struct tipc_link *l_ptr) -{ - return l_ptr->exp_msg_count || l_ptr->blocked; -} - static inline int link_congested(struct tipc_link *l_ptr) { return l_ptr->out_queue_size >= l_ptr->queue_limit[0]; -- cgit v1.2.3-70-g09d2 From 9319e47c18c41f2748c4140b0ac32097a56f36c1 Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Tue, 10 Dec 2013 20:57:57 -0800 Subject: net: macb: Fix build warning When adjusting the link speed, the target frequency is determined by a 'swith (LINK_SPEED)' statement, that assigns the target rate only for valid and expected LINK_SPEED values. This incomplete switch statement leads to the following build warning: drivers/net/ethernet/cadence/macb.c: In function 'macb_handle_link_change': >> drivers/net/ethernet/cadence/macb.c:241:14: warning: 'rate' may be used uninitialized in this function [-Wmaybe-uninitialized] netdev_warn(dev, "unable to generate target frequency: %ld Hz\n", ^ drivers/net/ethernet/cadence/macb.c:215:13: note: 'rate' was declared here long ferr, rate, rate_rounded; Fixing this by bailing out of that function in the switch's default case before the rate variable is used. Reported-by: kbuild test robot Signed-off-by: Soren Brinkmann Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 419529a9309..3190d38e16f 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -225,7 +225,7 @@ static void macb_set_tx_clk(struct clk *clk, int speed, struct net_device *dev) rate = 125000000; break; default: - break; + return; } rate_rounded = clk_round_rate(clk, rate); -- cgit v1.2.3-70-g09d2 From 2b6a6a90c31c550f839e905484f5253b9d24e33d Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 5 Dec 2013 06:53:41 +0100 Subject: ath10k: fix WEP Shared authentication Frames received from FW were treated incorrectly. This led to stations being unable to associate to WEP Shared ath10k AP. This was indicated by a bizarre hostapd message: Unsupported authentication algorithm (36088) Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 1260a8d15dc..9ea333a7789 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -937,7 +937,11 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) hdr = (struct ieee80211_hdr *)skb->data; fc = le16_to_cpu(hdr->frame_control); - if (fc & IEEE80211_FCTL_PROTECTED) { + /* FW delivers WEP Shared Auth frame with Protected Bit set and + * encrypted payload. However in case of PMF it delivers decrypted + * frames with Protected Bit set. */ + if (ieee80211_has_protected(hdr->frame_control) && + !ieee80211_is_auth(hdr->frame_control)) { status->flag |= RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; hdr->frame_control = __cpu_to_le16(fc & -- cgit v1.2.3-70-g09d2 From f47cdae42aacf24d5632be5fd8eb9ccd7fe59906 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Fri, 6 Dec 2013 03:32:10 -0800 Subject: zd1211rw: Fix FSF address in file headers Several files refer to an old address for the Free Software Foundation in the file header comment. Resolve by replacing the address with the URL so that we do not have to keep updating the header comments anytime the address changes. CC: linux-wireless@vger.kernel.org CC: Daniel Drake CC: Ulrich Kunitz Signed-off-by: Jeff Kirsher Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_chip.c | 3 +-- drivers/net/wireless/zd1211rw/zd_chip.h | 3 +-- drivers/net/wireless/zd1211rw/zd_def.h | 3 +-- drivers/net/wireless/zd1211rw/zd_mac.c | 3 +-- drivers/net/wireless/zd1211rw/zd_mac.h | 3 +-- drivers/net/wireless/zd1211rw/zd_rf.c | 3 +-- drivers/net/wireless/zd1211rw/zd_rf.h | 3 +-- drivers/net/wireless/zd1211rw/zd_rf_al2230.c | 3 +-- drivers/net/wireless/zd1211rw/zd_rf_al7230b.c | 3 +-- drivers/net/wireless/zd1211rw/zd_rf_rf2959.c | 3 +-- drivers/net/wireless/zd1211rw/zd_rf_uw2453.c | 3 +-- drivers/net/wireless/zd1211rw/zd_usb.c | 3 +-- drivers/net/wireless/zd1211rw/zd_usb.h | 3 +-- 13 files changed, 13 insertions(+), 26 deletions(-) diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index 71ab320fae8..73a49b86803 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -14,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ /* This file implements all the hardware specific functions for the ZD1211 diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h index 7ab922209b2..b03786c9f3a 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.h +++ b/drivers/net/wireless/zd1211rw/zd_chip.h @@ -14,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ #ifndef _ZD_CHIP_H diff --git a/drivers/net/wireless/zd1211rw/zd_def.h b/drivers/net/wireless/zd1211rw/zd_def.h index 9a1b013f81b..41bd755bc13 100644 --- a/drivers/net/wireless/zd1211rw/zd_def.h +++ b/drivers/net/wireless/zd1211rw/zd_def.h @@ -14,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ #ifndef _ZD_DEF_H diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index c6208a7988e..eff79a37bc2 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -16,8 +16,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ #include diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h index c01eca859f9..5a484235308 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.h +++ b/drivers/net/wireless/zd1211rw/zd_mac.h @@ -14,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ #ifndef _ZD_MAC_H diff --git a/drivers/net/wireless/zd1211rw/zd_rf.c b/drivers/net/wireless/zd1211rw/zd_rf.c index c875ee05e22..dc179c41451 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf.c +++ b/drivers/net/wireless/zd1211rw/zd_rf.c @@ -14,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ #include diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h index 725b7c99b23..8f14e25e104 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf.h +++ b/drivers/net/wireless/zd1211rw/zd_rf.h @@ -14,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ #ifndef _ZD_RF_H diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c index 12babcb633c..99aed7d7895 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c @@ -14,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ #include diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c index 385c670d129..5fea485be57 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c @@ -14,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ #include diff --git a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c index 784d9ccb8fe..a93f657a41c 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c @@ -14,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ #include diff --git a/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c index c4d324e19c2..61b92402735 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c @@ -14,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ #include diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 84d94f572a4..a912dc05111 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -15,8 +15,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ #include diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h index 45e3bb28a01..a9075f22517 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.h +++ b/drivers/net/wireless/zd1211rw/zd_usb.h @@ -14,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ #ifndef _ZD_USB_H -- cgit v1.2.3-70-g09d2 From a05b8c580c83a7bd4fce81f8d6af044e97e4a7a4 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Fri, 6 Dec 2013 03:32:11 -0800 Subject: rt2x00: Fix FSF address in file headers Several files refer to an old address for the Free Software Foundation in the file header comment. Resolve by replacing the address with the URL so that we do not have to keep updating the header comments anytime the address changes. CC: linux-wireless@vger.kernel.org CC: Ivo van Doorn CC: Gertjan van Wingerde CC: Helmut Schaa Signed-off-by: Jeff Kirsher Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 4 +--- drivers/net/wireless/rt2x00/rt2400pci.h | 4 +--- drivers/net/wireless/rt2x00/rt2500pci.c | 4 +--- drivers/net/wireless/rt2x00/rt2500pci.h | 4 +--- drivers/net/wireless/rt2x00/rt2500usb.c | 4 +--- drivers/net/wireless/rt2x00/rt2500usb.h | 4 +--- drivers/net/wireless/rt2x00/rt2800.h | 4 +--- drivers/net/wireless/rt2x00/rt2800lib.c | 4 +--- drivers/net/wireless/rt2x00/rt2800lib.h | 4 +--- drivers/net/wireless/rt2x00/rt2800mmio.c | 4 +--- drivers/net/wireless/rt2x00/rt2800mmio.h | 4 +--- drivers/net/wireless/rt2x00/rt2800pci.c | 4 +--- drivers/net/wireless/rt2x00/rt2800pci.h | 4 +--- drivers/net/wireless/rt2x00/rt2800soc.c | 4 +--- drivers/net/wireless/rt2x00/rt2800usb.c | 4 +--- drivers/net/wireless/rt2x00/rt2800usb.h | 4 +--- drivers/net/wireless/rt2x00/rt2x00.h | 4 +--- drivers/net/wireless/rt2x00/rt2x00config.c | 4 +--- drivers/net/wireless/rt2x00/rt2x00crypto.c | 4 +--- drivers/net/wireless/rt2x00/rt2x00debug.c | 4 +--- drivers/net/wireless/rt2x00/rt2x00debug.h | 4 +--- drivers/net/wireless/rt2x00/rt2x00dev.c | 4 +--- drivers/net/wireless/rt2x00/rt2x00dump.h | 4 +--- drivers/net/wireless/rt2x00/rt2x00firmware.c | 4 +--- drivers/net/wireless/rt2x00/rt2x00leds.c | 4 +--- drivers/net/wireless/rt2x00/rt2x00leds.h | 4 +--- drivers/net/wireless/rt2x00/rt2x00lib.h | 4 +--- drivers/net/wireless/rt2x00/rt2x00link.c | 4 +--- drivers/net/wireless/rt2x00/rt2x00mac.c | 4 +--- drivers/net/wireless/rt2x00/rt2x00mmio.c | 4 +--- drivers/net/wireless/rt2x00/rt2x00mmio.h | 4 +--- drivers/net/wireless/rt2x00/rt2x00pci.c | 4 +--- drivers/net/wireless/rt2x00/rt2x00pci.h | 4 +--- drivers/net/wireless/rt2x00/rt2x00queue.c | 4 +--- drivers/net/wireless/rt2x00/rt2x00queue.h | 4 +--- drivers/net/wireless/rt2x00/rt2x00reg.h | 4 +--- drivers/net/wireless/rt2x00/rt2x00soc.c | 4 +--- drivers/net/wireless/rt2x00/rt2x00soc.h | 4 +--- drivers/net/wireless/rt2x00/rt2x00usb.c | 4 +--- drivers/net/wireless/rt2x00/rt2x00usb.h | 4 +--- drivers/net/wireless/rt2x00/rt61pci.c | 4 +--- drivers/net/wireless/rt2x00/rt61pci.h | 4 +--- drivers/net/wireless/rt2x00/rt73usb.c | 4 +--- drivers/net/wireless/rt2x00/rt73usb.h | 4 +--- 44 files changed, 44 insertions(+), 132 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 38ed9a3e44c..4ad0de9d1d0 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -13,9 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h index e4b07f0aa3c..0fd3a9d01a6 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.h +++ b/drivers/net/wireless/rt2x00/rt2400pci.h @@ -13,9 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 0ac5c589ddc..4f61ffbcd2f 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -13,9 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h index 9c10068e498..573e87bcc55 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.h +++ b/drivers/net/wireless/rt2x00/rt2500pci.h @@ -13,9 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 85acc79f68b..1bb76935da7 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -13,9 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h index 1b91a4cef96..afba0739c3b 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.h +++ b/drivers/net/wireless/rt2x00/rt2500usb.h @@ -13,9 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index aab6b5e4f5d..a394a9a9591 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -21,9 +21,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 5ee5b296ad2..b8f5b06006c 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -24,9 +24,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index a94ba447e63..3019db637a4 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h @@ -14,9 +14,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ #ifndef RT2800LIB_H diff --git a/drivers/net/wireless/rt2x00/rt2800mmio.c b/drivers/net/wireless/rt2x00/rt2800mmio.c index a8cc736b506..de4790b41be 100644 --- a/drivers/net/wireless/rt2x00/rt2800mmio.c +++ b/drivers/net/wireless/rt2x00/rt2800mmio.c @@ -19,9 +19,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ /* Module: rt2800mmio diff --git a/drivers/net/wireless/rt2x00/rt2800mmio.h b/drivers/net/wireless/rt2x00/rt2800mmio.h index 6a10de3eee3..b63312ce3f2 100644 --- a/drivers/net/wireless/rt2x00/rt2800mmio.h +++ b/drivers/net/wireless/rt2x00/rt2800mmio.h @@ -19,9 +19,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ /* Module: rt2800mmio diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index b504455b4fe..a5b32ca2cf0 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -20,9 +20,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2800pci.h b/drivers/net/wireless/rt2x00/rt2800pci.h index a81c9ee281c..9dfef4607d6 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.h +++ b/drivers/net/wireless/rt2x00/rt2800pci.h @@ -20,9 +20,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2800soc.c b/drivers/net/wireless/rt2x00/rt2800soc.c index 1359227ca41..f6d1bf5be00 100644 --- a/drivers/net/wireless/rt2x00/rt2800soc.c +++ b/drivers/net/wireless/rt2x00/rt2800soc.c @@ -19,9 +19,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ /* Module: rt2800soc diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index a81ceb61d74..49ff178a0b4 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -18,9 +18,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h index 671ea359261..ea7cac09599 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.h +++ b/drivers/net/wireless/rt2x00/rt2800usb.h @@ -17,9 +17,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index e4ba2ce0f21..e3b885d8f7d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -15,9 +15,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 8cb43f8f3ef..1122dc44c9f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -13,9 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c index 3db0d99d9da..a2fd05ba25c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00crypto.c +++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c @@ -13,9 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index 7f7baae5ae0..2e3d1645e68 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -13,9 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.h b/drivers/net/wireless/rt2x00/rt2x00debug.h index e11d39bdfef..e65712c235b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.h +++ b/drivers/net/wireless/rt2x00/rt2x00debug.h @@ -13,9 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 9dd92a70044..00c3fae6fa3 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -14,9 +14,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2x00dump.h b/drivers/net/wireless/rt2x00/rt2x00dump.h index 063ebcce97f..4c0e01b5d51 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dump.h +++ b/drivers/net/wireless/rt2x00/rt2x00dump.h @@ -13,9 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2x00firmware.c b/drivers/net/wireless/rt2x00/rt2x00firmware.c index 1b4254b4272..fbae2799e3e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00firmware.c +++ b/drivers/net/wireless/rt2x00/rt2x00firmware.c @@ -14,9 +14,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2x00leds.c b/drivers/net/wireless/rt2x00/rt2x00leds.c index 997a6c89e66..c681d04b506 100644 --- a/drivers/net/wireless/rt2x00/rt2x00leds.c +++ b/drivers/net/wireless/rt2x00/rt2x00leds.c @@ -13,9 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2x00leds.h b/drivers/net/wireless/rt2x00/rt2x00leds.h index 3b46f0c3332..b2c5269570d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00leds.h +++ b/drivers/net/wireless/rt2x00/rt2x00leds.h @@ -13,9 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 7f40ab8e1bd..fb7c349ccc9 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -14,9 +14,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index c2b3b662918..9b941c0c126 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c @@ -13,9 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 2183e797839..ddeb5a709aa 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -13,9 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2x00mmio.c b/drivers/net/wireless/rt2x00/rt2x00mmio.c index 64b06c6abe5..6f236ea180a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mmio.c +++ b/drivers/net/wireless/rt2x00/rt2x00mmio.c @@ -13,9 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2x00mmio.h b/drivers/net/wireless/rt2x00/rt2x00mmio.h index cda3dbcf7ea..701c3127efb 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mmio.h +++ b/drivers/net/wireless/rt2x00/rt2x00mmio.h @@ -13,9 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index af721831dcb..d93db4b0371 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -13,9 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h index 60d90b20f8b..bc0ca5f58f3 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.h +++ b/drivers/net/wireless/rt2x00/rt2x00pci.h @@ -13,9 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index a5d38e8ad9e..5642ccceca7 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -15,9 +15,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index ebe11722497..c48125be0e3 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -13,9 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h index 6f867eec49c..3cc541d13d6 100644 --- a/drivers/net/wireless/rt2x00/rt2x00reg.h +++ b/drivers/net/wireless/rt2x00/rt2x00reg.h @@ -13,9 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2x00soc.c b/drivers/net/wireless/rt2x00/rt2x00soc.c index 9271a5fce0a..69a0cdadb07 100644 --- a/drivers/net/wireless/rt2x00/rt2x00soc.c +++ b/drivers/net/wireless/rt2x00/rt2x00soc.c @@ -14,9 +14,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2x00soc.h b/drivers/net/wireless/rt2x00/rt2x00soc.h index 474cbfc1efc..9948d355e9a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00soc.h +++ b/drivers/net/wireless/rt2x00/rt2x00soc.h @@ -13,9 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 4e121627925..10572452cc2 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -14,9 +14,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index 323ca7b2b09..e7bcf62347d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -13,9 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index a5b69cb4901..b76f6049ad9 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -13,9 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h index 9bc6b6044e3..1442075a838 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.h +++ b/drivers/net/wireless/rt2x00/rt61pci.h @@ -13,9 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 1baf9c896dc..ade88d7e089 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -13,9 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h index 7577e0ba387..4a4f235466d 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.h +++ b/drivers/net/wireless/rt2x00/rt73usb.h @@ -13,9 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, see . */ /* -- cgit v1.2.3-70-g09d2 From 4280db9d00f96d51789b5b77980173f0491fa594 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Fri, 6 Dec 2013 03:32:12 -0800 Subject: prism54: Fix FSF address in file headers Several files refer to an old address for the Free Software Foundation in the file header comment. Resolve by replacing the address with the URL so that we do not have to keep updating the header comments anytime the address changes. CC: linux-wireless@vger.kernel.org CC: "Luis R. Rodriguez" Signed-off-by: Jeff Kirsher Signed-off-by: John W. Linville --- drivers/net/wireless/prism54/isl_38xx.c | 3 +-- drivers/net/wireless/prism54/isl_38xx.h | 3 +-- drivers/net/wireless/prism54/isl_ioctl.c | 3 +-- drivers/net/wireless/prism54/isl_ioctl.h | 3 +-- drivers/net/wireless/prism54/isl_oid.h | 3 +-- drivers/net/wireless/prism54/islpci_dev.c | 3 +-- drivers/net/wireless/prism54/islpci_dev.h | 3 +-- drivers/net/wireless/prism54/islpci_eth.c | 3 +-- drivers/net/wireless/prism54/islpci_eth.h | 3 +-- drivers/net/wireless/prism54/islpci_hotplug.c | 3 +-- drivers/net/wireless/prism54/islpci_mgt.c | 3 +-- drivers/net/wireless/prism54/islpci_mgt.h | 3 +-- drivers/net/wireless/prism54/oid_mgt.c | 3 +-- drivers/net/wireless/prism54/oid_mgt.h | 3 +-- drivers/net/wireless/prism54/prismcompat.h | 3 +-- 15 files changed, 15 insertions(+), 30 deletions(-) diff --git a/drivers/net/wireless/prism54/isl_38xx.c b/drivers/net/wireless/prism54/isl_38xx.c index 02fc67bccbd..333c1a2f882 100644 --- a/drivers/net/wireless/prism54/isl_38xx.c +++ b/drivers/net/wireless/prism54/isl_38xx.c @@ -12,8 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/drivers/net/wireless/prism54/isl_38xx.h b/drivers/net/wireless/prism54/isl_38xx.h index 19c33d31373..547ab885610 100644 --- a/drivers/net/wireless/prism54/isl_38xx.h +++ b/drivers/net/wireless/prism54/isl_38xx.h @@ -11,8 +11,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c index 8863a6cb238..df784fefb8e 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.c +++ b/drivers/net/wireless/prism54/isl_ioctl.c @@ -14,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/drivers/net/wireless/prism54/isl_ioctl.h b/drivers/net/wireless/prism54/isl_ioctl.h index a34bceb6e3c..842a2549fac 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.h +++ b/drivers/net/wireless/prism54/isl_ioctl.h @@ -13,8 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/drivers/net/wireless/prism54/isl_oid.h b/drivers/net/wireless/prism54/isl_oid.h index 59e31258d45..83fec557997 100644 --- a/drivers/net/wireless/prism54/isl_oid.h +++ b/drivers/net/wireless/prism54/isl_oid.h @@ -13,8 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c index 7fa2898d061..931cf440ff1 100644 --- a/drivers/net/wireless/prism54/islpci_dev.c +++ b/drivers/net/wireless/prism54/islpci_dev.c @@ -13,8 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h index c40403877f9..f6f088e05fe 100644 --- a/drivers/net/wireless/prism54/islpci_dev.h +++ b/drivers/net/wireless/prism54/islpci_dev.h @@ -14,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c index 799e148d037..674658f2e6e 100644 --- a/drivers/net/wireless/prism54/islpci_eth.c +++ b/drivers/net/wireless/prism54/islpci_eth.c @@ -11,8 +11,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/drivers/net/wireless/prism54/islpci_eth.h b/drivers/net/wireless/prism54/islpci_eth.h index 6ca30a5b7bf..80f50f1bc6f 100644 --- a/drivers/net/wireless/prism54/islpci_eth.h +++ b/drivers/net/wireless/prism54/islpci_eth.h @@ -11,8 +11,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c index d7b9e637642..1105a12dbde 100644 --- a/drivers/net/wireless/prism54/islpci_hotplug.c +++ b/drivers/net/wireless/prism54/islpci_hotplug.c @@ -12,8 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/drivers/net/wireless/prism54/islpci_mgt.c b/drivers/net/wireless/prism54/islpci_mgt.c index 9f19cceab48..0de14dfa68c 100644 --- a/drivers/net/wireless/prism54/islpci_mgt.c +++ b/drivers/net/wireless/prism54/islpci_mgt.c @@ -12,8 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/drivers/net/wireless/prism54/islpci_mgt.h b/drivers/net/wireless/prism54/islpci_mgt.h index 0db93db9b67..700c434c880 100644 --- a/drivers/net/wireless/prism54/islpci_mgt.h +++ b/drivers/net/wireless/prism54/islpci_mgt.h @@ -12,8 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/drivers/net/wireless/prism54/oid_mgt.c b/drivers/net/wireless/prism54/oid_mgt.c index 056af38e72e..47b34bfe890 100644 --- a/drivers/net/wireless/prism54/oid_mgt.c +++ b/drivers/net/wireless/prism54/oid_mgt.c @@ -11,8 +11,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/drivers/net/wireless/prism54/oid_mgt.h b/drivers/net/wireless/prism54/oid_mgt.h index 92c8a2d4acd..cf5141df847 100644 --- a/drivers/net/wireless/prism54/oid_mgt.h +++ b/drivers/net/wireless/prism54/oid_mgt.h @@ -11,8 +11,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/drivers/net/wireless/prism54/prismcompat.h b/drivers/net/wireless/prism54/prismcompat.h index aa1d1747784..bc1401eb4b9 100644 --- a/drivers/net/wireless/prism54/prismcompat.h +++ b/drivers/net/wireless/prism54/prismcompat.h @@ -11,8 +11,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ -- cgit v1.2.3-70-g09d2 From 36769159a99063ba4d3cb0a20ed0b3095a334c8c Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Fri, 6 Dec 2013 03:32:13 -0800 Subject: drivers/net/wireless: Fix FSF address in file headers Several files refer to an old address for the Free Software Foundation in the file header comment. Resolve by replacing the address with the URL so that we do not have to keep updating the header comments anytime the address changes. CC: linux-wireless@vger.kernel.org CC: Simon Kelley CC: Christian Lamparter CC: Jussi Kivilinna Signed-off-by: Jeff Kirsher Signed-off-by: John W. Linville --- drivers/net/wireless/atmel.c | 7 +++---- drivers/net/wireless/atmel.h | 4 ++-- drivers/net/wireless/atmel_cs.c | 4 ++-- drivers/net/wireless/atmel_pci.c | 4 ++-- drivers/net/wireless/libertas/README | 5 ++--- drivers/net/wireless/p54/net2280.h | 3 +-- drivers/net/wireless/ray_cs.c | 3 +-- drivers/net/wireless/rndis_wlan.c | 3 +-- 8 files changed, 14 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index 0d950f209da..b73b7e3e219 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -28,8 +28,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Atmel wireless lan drivers; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + along with Atmel wireless lan drivers; if not, see + . For all queries about this code, please contact the current author, Simon Kelley and not Atmel Corporation. @@ -4278,8 +4278,7 @@ static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data) GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with AtmelMACFW; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + along with AtmelMACFW; if not, see . ****************************************************************************/ /* This firmware should work on the 76C502 RFMD, RFMD_D, and RFMD_E */ diff --git a/drivers/net/wireless/atmel.h b/drivers/net/wireless/atmel.h index b9b3e5b7654..96f7318cbb0 100644 --- a/drivers/net/wireless/atmel.h +++ b/drivers/net/wireless/atmel.h @@ -15,8 +15,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Atmel wireless lan drivers; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + along with Atmel wireless lan drivers; if not, see + . ******************************************************************************/ diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c index 52257221921..5e2749dd112 100644 --- a/drivers/net/wireless/atmel_cs.c +++ b/drivers/net/wireless/atmel_cs.c @@ -24,8 +24,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Atmel wireless lan drivers; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + along with Atmel wireless lan drivers; if not, see + . ******************************************************************************/ diff --git a/drivers/net/wireless/atmel_pci.c b/drivers/net/wireless/atmel_pci.c index c1b159ebcff..64d5973ec28 100644 --- a/drivers/net/wireless/atmel_pci.c +++ b/drivers/net/wireless/atmel_pci.c @@ -15,8 +15,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Atmel wireless lan drivers; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + along with Atmel wireless lan drivers; if not, see + . ******************************************************************************/ #include diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README index 91f2ca90c70..1a554a685e9 100644 --- a/drivers/net/wireless/libertas/README +++ b/drivers/net/wireless/libertas/README @@ -8,9 +8,8 @@ Ltd. under the terms of the GNU General Public License Version 2, June 1991 (the "License"). You may use, redistribute and/or modify this File in accordance with the terms and conditions of the License, a copy of which - is available along with the File in the license.txt file or by writing to - the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + is available along with the File in the license.txt file or on the worldwide + web at http://www.gnu.org/licenses/gpl.txt. THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE diff --git a/drivers/net/wireless/p54/net2280.h b/drivers/net/wireless/p54/net2280.h index e3ed893b5aa..aedfaf24f38 100644 --- a/drivers/net/wireless/p54/net2280.h +++ b/drivers/net/wireless/p54/net2280.h @@ -20,8 +20,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ /*-------------------------------------------------------------------------*/ diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 9b557a1bb7f..cbf0a589d32 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -17,8 +17,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * along with this program; if not, see . * * Changes: * Arnaldo Carvalho de Melo - 08/08/2000 diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 8169a85c449..c3cdda1252d 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -15,8 +15,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * * Portions of this file are based on NDISwrapper project, * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani -- cgit v1.2.3-70-g09d2 From 8232f1f3d06cf6f12d64df234f44691a549b8351 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Fri, 6 Dec 2013 03:32:14 -0800 Subject: rfkill: Fix FSF address in file headers Several files refer to an old address for the Free Software Foundation in the file header comment. Resolve by replacing the address with the URL so that we do not have to keep updating the header comments anytime the address changes. CC: linux-wireless@vger.kernel.org Signed-off-by: Jeff Kirsher Signed-off-by: John W. Linville --- net/rfkill/core.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/net/rfkill/core.c b/net/rfkill/core.c index 1bacc107994..ed7e0b4e7f9 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c @@ -14,9 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #include -- cgit v1.2.3-70-g09d2 From 98b32decc83ed3137e3ddbc918b102f8fc406b6d Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Fri, 6 Dec 2013 08:56:16 -0800 Subject: nfc: Fix FSF address in file headers Several files refer to an old address for the Free Software Foundation in the file header comment. Resolve by replacing the address with the URL so that we do not have to keep updating the header comments anytime the address changes. CC: linux-wireless@vger.kernel.org CC: Lauro Ramos Venancio CC: Aloisio Almeida Jr CC: Samuel Ortiz Signed-off-by: Jeff Kirsher Signed-off-by: John W. Linville --- drivers/nfc/mei_phy.c | 4 +--- drivers/nfc/microread/i2c.c | 4 +--- drivers/nfc/microread/mei.c | 4 +--- drivers/nfc/microread/microread.c | 4 +--- drivers/nfc/microread/microread.h | 4 +--- drivers/nfc/nfcwilink.c | 3 +-- drivers/nfc/pn533.c | 4 +--- drivers/nfc/pn544/i2c.c | 4 +--- drivers/nfc/pn544/mei.c | 4 +--- drivers/nfc/pn544/pn544.c | 4 +--- drivers/nfc/pn544/pn544.h | 4 +--- include/linux/platform_data/pn544.h | 3 +-- net/nfc/af_nfc.c | 4 +--- net/nfc/core.c | 4 +--- net/nfc/hci/command.c | 4 +--- net/nfc/hci/core.c | 4 +--- net/nfc/hci/hci.h | 4 +--- net/nfc/hci/hcp.c | 4 +--- net/nfc/hci/llc.c | 4 +--- net/nfc/hci/llc.h | 4 +--- net/nfc/hci/llc_nop.c | 4 +--- net/nfc/hci/llc_shdlc.c | 4 +--- net/nfc/llcp.h | 4 +--- net/nfc/llcp_commands.c | 4 +--- net/nfc/llcp_core.c | 4 +--- net/nfc/llcp_sock.c | 4 +--- net/nfc/nci/core.c | 3 +-- net/nfc/nci/data.c | 3 +-- net/nfc/nci/lib.c | 3 +-- net/nfc/nci/ntf.c | 3 +-- net/nfc/nci/rsp.c | 3 +-- net/nfc/netlink.c | 4 +--- net/nfc/nfc.h | 4 +--- net/nfc/rawsock.c | 4 +--- 34 files changed, 34 insertions(+), 95 deletions(-) diff --git a/drivers/nfc/mei_phy.c b/drivers/nfc/mei_phy.c index 85f90090cc1..1d786055198 100644 --- a/drivers/nfc/mei_phy.c +++ b/drivers/nfc/mei_phy.c @@ -13,9 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/nfc/microread/i2c.c b/drivers/nfc/microread/i2c.c index 696e3467ecc..df85cd3d9db 100644 --- a/drivers/nfc/microread/i2c.c +++ b/drivers/nfc/microread/i2c.c @@ -13,9 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/nfc/microread/mei.c b/drivers/nfc/microread/mei.c index 72fafec3d46..2d1395be64a 100644 --- a/drivers/nfc/microread/mei.c +++ b/drivers/nfc/microread/mei.c @@ -13,9 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/nfc/microread/microread.c b/drivers/nfc/microread/microread.c index 970ded6bfcf..f868333271a 100644 --- a/drivers/nfc/microread/microread.c +++ b/drivers/nfc/microread/microread.c @@ -13,9 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/nfc/microread/microread.h b/drivers/nfc/microread/microread.h index 64b447a1c5b..f538641431a 100644 --- a/drivers/nfc/microread/microread.h +++ b/drivers/nfc/microread/microread.h @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #ifndef __LOCAL_MICROREAD_H_ diff --git a/drivers/nfc/nfcwilink.c b/drivers/nfc/nfcwilink.c index 71308645593..683671a71c7 100644 --- a/drivers/nfc/nfcwilink.c +++ b/drivers/nfc/nfcwilink.c @@ -22,8 +22,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ #include diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index 2daf04c0733..3df19e657bc 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -13,9 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #include diff --git a/drivers/nfc/pn544/i2c.c b/drivers/nfc/pn544/i2c.c index b158ee1c2ac..d6185ff2f87 100644 --- a/drivers/nfc/pn544/i2c.c +++ b/drivers/nfc/pn544/i2c.c @@ -13,9 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/nfc/pn544/mei.c b/drivers/nfc/pn544/mei.c index ee67de50c36..330cd403100 100644 --- a/drivers/nfc/pn544/mei.c +++ b/drivers/nfc/pn544/mei.c @@ -13,9 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #include diff --git a/drivers/nfc/pn544/pn544.c b/drivers/nfc/pn544/pn544.c index 74cfa0a88b9..51e21a87cd8 100644 --- a/drivers/nfc/pn544/pn544.c +++ b/drivers/nfc/pn544/pn544.c @@ -13,9 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/nfc/pn544/pn544.h b/drivers/nfc/pn544/pn544.h index 01020e58544..491bf45da35 100644 --- a/drivers/nfc/pn544/pn544.h +++ b/drivers/nfc/pn544/pn544.h @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #ifndef __LOCAL_PN544_H_ diff --git a/include/linux/platform_data/pn544.h b/include/linux/platform_data/pn544.h index 713bfd70334..5ce1ab983f4 100644 --- a/include/linux/platform_data/pn544.h +++ b/include/linux/platform_data/pn544.h @@ -16,8 +16,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ #ifndef _PN544_H_ diff --git a/net/nfc/af_nfc.c b/net/nfc/af_nfc.c index 9d68441e2a5..2277276f52b 100644 --- a/net/nfc/af_nfc.c +++ b/net/nfc/af_nfc.c @@ -16,9 +16,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #include diff --git a/net/nfc/core.c b/net/nfc/core.c index 872529105ab..02ab3413215 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c @@ -16,9 +16,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__ diff --git a/net/nfc/hci/command.c b/net/nfc/hci/command.c index 64f922be928..a9f4d2e62d8 100644 --- a/net/nfc/hci/command.c +++ b/net/nfc/hci/command.c @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #define pr_fmt(fmt) "hci: %s: " fmt, __func__ diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index d07ca4c5cf8..3b9610031ba 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #define pr_fmt(fmt) "hci: %s: " fmt, __func__ diff --git a/net/nfc/hci/hci.h b/net/nfc/hci/hci.h index b274d12c18a..c3d2e2c1394 100644 --- a/net/nfc/hci/hci.h +++ b/net/nfc/hci/hci.h @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #ifndef __LOCAL_HCI_H diff --git a/net/nfc/hci/hcp.c b/net/nfc/hci/hcp.c index b6b4109f234..e9de1514656 100644 --- a/net/nfc/hci/hcp.c +++ b/net/nfc/hci/hcp.c @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #define pr_fmt(fmt) "hci: %s: " fmt, __func__ diff --git a/net/nfc/hci/llc.c b/net/nfc/hci/llc.c index fe5e966e5b8..a07d2b81848 100644 --- a/net/nfc/hci/llc.c +++ b/net/nfc/hci/llc.c @@ -13,9 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #include diff --git a/net/nfc/hci/llc.h b/net/nfc/hci/llc.h index 7be0b7f3ceb..5dad4c57ffb 100644 --- a/net/nfc/hci/llc.h +++ b/net/nfc/hci/llc.h @@ -13,9 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #ifndef __LOCAL_LLC_H_ diff --git a/net/nfc/hci/llc_nop.c b/net/nfc/hci/llc_nop.c index 87b10291b40..d0435d5a197 100644 --- a/net/nfc/hci/llc_nop.c +++ b/net/nfc/hci/llc_nop.c @@ -13,9 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #include diff --git a/net/nfc/hci/llc_shdlc.c b/net/nfc/hci/llc_shdlc.c index 27b313befc3..719ad0ac40d 100644 --- a/net/nfc/hci/llc_shdlc.c +++ b/net/nfc/hci/llc_shdlc.c @@ -13,9 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #define pr_fmt(fmt) "shdlc: %s: " fmt, __func__ diff --git a/net/nfc/llcp.h b/net/nfc/llcp.h index f4d48b57ea1..de1789e3cc8 100644 --- a/net/nfc/llcp.h +++ b/net/nfc/llcp.h @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ enum llcp_state { diff --git a/net/nfc/llcp_commands.c b/net/nfc/llcp_commands.c index 1017894807c..693cd1aad58 100644 --- a/net/nfc/llcp_commands.c +++ b/net/nfc/llcp_commands.c @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #define pr_fmt(fmt) "llcp: %s: " fmt, __func__ diff --git a/net/nfc/llcp_core.c b/net/nfc/llcp_core.c index 81cd3416c7d..1349074e1ff 100644 --- a/net/nfc/llcp_core.c +++ b/net/nfc/llcp_core.c @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #define pr_fmt(fmt) "llcp: %s: " fmt, __func__ diff --git a/net/nfc/llcp_sock.c b/net/nfc/llcp_sock.c index 824c6056bf8..69fbc8dadba 100644 --- a/net/nfc/llcp_sock.c +++ b/net/nfc/llcp_sock.c @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #define pr_fmt(fmt) "llcp: %s: " fmt, __func__ diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index b943d46a164..f0e955e3a38 100644 --- a/net/nfc/nci/core.c +++ b/net/nfc/nci/core.c @@ -20,8 +20,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/net/nfc/nci/data.c b/net/nfc/nci/data.c index 2a9399dd6c6..6c3aef85287 100644 --- a/net/nfc/nci/data.c +++ b/net/nfc/nci/data.c @@ -16,8 +16,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/net/nfc/nci/lib.c b/net/nfc/nci/lib.c index 6b7fd26c68d..ed774a2e989 100644 --- a/net/nfc/nci/lib.c +++ b/net/nfc/nci/lib.c @@ -20,8 +20,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c index b2aa98ef092..1e905097456 100644 --- a/net/nfc/nci/ntf.c +++ b/net/nfc/nci/ntf.c @@ -20,8 +20,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/net/nfc/nci/rsp.c b/net/nfc/nci/rsp.c index dd072f38ad0..041de51ccdb 100644 --- a/net/nfc/nci/rsp.c +++ b/net/nfc/nci/rsp.c @@ -20,8 +20,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index a9b2342d525..ebbf6fb88b3 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c @@ -16,9 +16,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__ diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h index aaf606fc1fa..9d6e74f7e6b 100644 --- a/net/nfc/nfc.h +++ b/net/nfc/nfc.h @@ -16,9 +16,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #ifndef __LOCAL_NFC_H diff --git a/net/nfc/rawsock.c b/net/nfc/rawsock.c index 66bcd2eb577..c27a6e86cae 100644 --- a/net/nfc/rawsock.c +++ b/net/nfc/rawsock.c @@ -16,9 +16,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__ -- cgit v1.2.3-70-g09d2 From cb161cda634ae5fdb4de797096ba9028171507d2 Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Sat, 7 Dec 2013 02:17:40 +0000 Subject: ath5k: Reset Tx interrupt bits also on PISR Some cards don't update the PISR properly when all SISR bits for Tx interrupts are being cleared and as a result we get interrupt storm. Since we handle all tx queues all together (so we don't really use the SISR bits to do per-queue interrupt handling), we can manualy update PISR by doing a write-to-clear on its Tx interrupt bits. Signed-off-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/dma.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath5k/dma.c b/drivers/net/wireless/ath/ath5k/dma.c index ba200b24be6..e6c52f7c26e 100644 --- a/drivers/net/wireless/ath/ath5k/dma.c +++ b/drivers/net/wireless/ath/ath5k/dma.c @@ -616,7 +616,16 @@ ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) * SISRs will also clear PISR so no need to worry here. */ - pisr_clear = pisr & ~AR5K_ISR_BITS_FROM_SISRS; + /* XXX: There seems to be an issue on some cards + * with tx interrupt flags not being updated + * on PISR despite that all Tx interrupt bits + * are cleared on SISRs. Since we handle all + * Tx queues all together it shouldn't be an + * issue if we clear Tx interrupt flags also + * on PISR to avoid that. + */ + pisr_clear = (pisr & ~AR5K_ISR_BITS_FROM_SISRS) | + (pisr & AR5K_INT_TX_ALL); /* * Write to clear them... -- cgit v1.2.3-70-g09d2 From 22d072f60884edaa68f1665576e8983118f59ead Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Mon, 9 Dec 2013 22:28:32 +0200 Subject: MAINTAINERS: remove myself as maintainer of TI WiLink drivers I don't have the time to maintain the TI WiLink WLAN drivers anymore. Remove my name and mark them as Orphan. Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- MAINTAINERS | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 6d7cf3b5623..bdf13e40045 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8553,12 +8553,11 @@ S: Maintained F: sound/soc/codecs/twl4030* TI WILINK WIRELESS DRIVERS -M: Luciano Coelho L: linux-wireless@vger.kernel.org W: http://wireless.kernel.org/en/users/Drivers/wl12xx W: http://wireless.kernel.org/en/users/Drivers/wl1251 T: git git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx.git -S: Maintained +S: Orphan F: drivers/net/wireless/ti/ F: include/linux/wl12xx.h -- cgit v1.2.3-70-g09d2 From 55957fb7a0b61d8ab6ff3f04e279b8fc22b738fa Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 9 Dec 2013 23:37:49 +0100 Subject: ath9k: initialize retry chain flags in tx99 code Initialize first chain flags in ath9k_build_tx99_skb() according to configured channel mode and channel width Signed-off-by: Lorenzo Bianconi Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/tx99.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c index 57d775783ec..b686a749845 100644 --- a/drivers/net/wireless/ath/ath9k/tx99.c +++ b/drivers/net/wireless/ath/ath9k/tx99.c @@ -48,7 +48,9 @@ static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc) 0x02, 0x23, 0x23, 0xab, 0x63, 0x89, 0x51, 0xb3, 0xe7, 0x8b, 0x72, 0x90, 0x4c, 0xe8, 0xfb, 0xc0}; u32 len = 1200; + struct ieee80211_tx_rate *rate; struct ieee80211_hw *hw = sc->hw; + struct ath_hw *ah = sc->sc_ah; struct ieee80211_hdr *hdr; struct ieee80211_tx_info *tx_info; struct sk_buff *skb; @@ -73,10 +75,16 @@ static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc) tx_info = IEEE80211_SKB_CB(skb); memset(tx_info, 0, sizeof(*tx_info)); + rate = &tx_info->control.rates[0]; tx_info->band = hw->conf.chandef.chan->band; tx_info->flags = IEEE80211_TX_CTL_NO_ACK; tx_info->control.vif = sc->tx99_vif; - tx_info->control.rates[0].count = 1; + rate->count = 1; + if (ah->curchan && IS_CHAN_HT(ah->curchan)) { + rate->flags |= IEEE80211_TX_RC_MCS; + if (IS_CHAN_HT40(ah->curchan)) + rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; + } memcpy(skb->data + sizeof(*hdr), PN9Data, sizeof(PN9Data)); -- cgit v1.2.3-70-g09d2 From 4f8f61eb4341be07b4a8d046f646fcf934a89949 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 11 Dec 2013 15:17:11 +0800 Subject: net_sched: expand control flow of macro SKIP_NONLOCAL SKIP_NONLOCAL hides the control flow. The control flow should be inlined and expanded explicitly in code so that someone who reads it can tell the control flow can be changed by the statement. Signed-off-by: Yang Yingliang Signed-off-by: David S. Miller --- net/sched/em_meta.c | 157 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 122 insertions(+), 35 deletions(-) diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c index e5cef956722..382519a5d7f 100644 --- a/net/sched/em_meta.c +++ b/net/sched/em_meta.c @@ -271,40 +271,52 @@ META_COLLECTOR(int_rtiif) * Socket Attributes **************************************************************************/ -#define SKIP_NONLOCAL(skb) \ - if (unlikely(skb->sk == NULL)) { \ - *err = -1; \ - return; \ - } +#define skip_nonlocal(skb) \ + (unlikely(skb->sk == NULL)) META_COLLECTOR(int_sk_family) { - SKIP_NONLOCAL(skb); + if (skip_nonlocal(skb)) { + *err = -1; + return; + } dst->value = skb->sk->sk_family; } META_COLLECTOR(int_sk_state) { - SKIP_NONLOCAL(skb); + if (skip_nonlocal(skb)) { + *err = -1; + return; + } dst->value = skb->sk->sk_state; } META_COLLECTOR(int_sk_reuse) { - SKIP_NONLOCAL(skb); + if (skip_nonlocal(skb)) { + *err = -1; + return; + } dst->value = skb->sk->sk_reuse; } META_COLLECTOR(int_sk_bound_if) { - SKIP_NONLOCAL(skb); + if (skip_nonlocal(skb)) { + *err = -1; + return; + } /* No error if bound_dev_if is 0, legal userspace check */ dst->value = skb->sk->sk_bound_dev_if; } META_COLLECTOR(var_sk_bound_if) { - SKIP_NONLOCAL(skb); + if (skip_nonlocal(skb)) { + *err = -1; + return; + } if (skb->sk->sk_bound_dev_if == 0) { dst->value = (unsigned long) "any"; @@ -322,151 +334,226 @@ META_COLLECTOR(var_sk_bound_if) META_COLLECTOR(int_sk_refcnt) { - SKIP_NONLOCAL(skb); + if (skip_nonlocal(skb)) { + *err = -1; + return; + } dst->value = atomic_read(&skb->sk->sk_refcnt); } META_COLLECTOR(int_sk_rcvbuf) { - SKIP_NONLOCAL(skb); + if (skip_nonlocal(skb)) { + *err = -1; + return; + } dst->value = skb->sk->sk_rcvbuf; } META_COLLECTOR(int_sk_shutdown) { - SKIP_NONLOCAL(skb); + if (skip_nonlocal(skb)) { + *err = -1; + return; + } dst->value = skb->sk->sk_shutdown; } META_COLLECTOR(int_sk_proto) { - SKIP_NONLOCAL(skb); + if (skip_nonlocal(skb)) { + *err = -1; + return; + } dst->value = skb->sk->sk_protocol; } META_COLLECTOR(int_sk_type) { - SKIP_NONLOCAL(skb); + if (skip_nonlocal(skb)) { + *err = -1; + return; + } dst->value = skb->sk->sk_type; } META_COLLECTOR(int_sk_rmem_alloc) { - SKIP_NONLOCAL(skb); + if (skip_nonlocal(skb)) { + *err = -1; + return; + } dst->value = sk_rmem_alloc_get(skb->sk); } META_COLLECTOR(int_sk_wmem_alloc) { - SKIP_NONLOCAL(skb); + if (skip_nonlocal(skb)) { + *err = -1; + return; + } dst->value = sk_wmem_alloc_get(skb->sk); } META_COLLECTOR(int_sk_omem_alloc) { - SKIP_NONLOCAL(skb); + if (skip_nonlocal(skb)) { + *err = -1; + return; + } dst->value = atomic_read(&skb->sk->sk_omem_alloc); } META_COLLECTOR(int_sk_rcv_qlen) { - SKIP_NONLOCAL(skb); + if (skip_nonlocal(skb)) { + *err = -1; + return; + } dst->value = skb->sk->sk_receive_queue.qlen; } META_COLLECTOR(int_sk_snd_qlen) { - SKIP_NONLOCAL(skb); + if (skip_nonlocal(skb)) { + *err = -1; + return; + } dst->value = skb->sk->sk_write_queue.qlen; } META_COLLECTOR(int_sk_wmem_queued) { - SKIP_NONLOCAL(skb); + if (skip_nonlocal(skb)) { + *err = -1; + return; + } dst->value = skb->sk->sk_wmem_queued; } META_COLLECTOR(int_sk_fwd_alloc) { - SKIP_NONLOCAL(skb); + if (skip_nonlocal(skb)) { + *err = -1; + return; + } dst->value = skb->sk->sk_forward_alloc; } META_COLLECTOR(int_sk_sndbuf) { - SKIP_NONLOCAL(skb); + if (skip_nonlocal(skb)) { + *err = -1; + return; + } dst->value = skb->sk->sk_sndbuf; } META_COLLECTOR(int_sk_alloc) { - SKIP_NONLOCAL(skb); + if (skip_nonlocal(skb)) { + *err = -1; + return; + } dst->value = (__force int) skb->sk->sk_allocation; } META_COLLECTOR(int_sk_hash) { - SKIP_NONLOCAL(skb); + if (skip_nonlocal(skb)) { + *err = -1; + return; + } dst->value = skb->sk->sk_hash; } META_COLLECTOR(int_sk_lingertime) { - SKIP_NONLOCAL(skb); + if (skip_nonlocal(skb)) { + *err = -1; + return; + } dst->value = skb->sk->sk_lingertime / HZ; } META_COLLECTOR(int_sk_err_qlen) { - SKIP_NONLOCAL(skb); + if (skip_nonlocal(skb)) { + *err = -1; + return; + } dst->value = skb->sk->sk_error_queue.qlen; } META_COLLECTOR(int_sk_ack_bl) { - SKIP_NONLOCAL(skb); + if (skip_nonlocal(skb)) { + *err = -1; + return; + } dst->value = skb->sk->sk_ack_backlog; } META_COLLECTOR(int_sk_max_ack_bl) { - SKIP_NONLOCAL(skb); + if (skip_nonlocal(skb)) { + *err = -1; + return; + } dst->value = skb->sk->sk_max_ack_backlog; } META_COLLECTOR(int_sk_prio) { - SKIP_NONLOCAL(skb); + if (skip_nonlocal(skb)) { + *err = -1; + return; + } dst->value = skb->sk->sk_priority; } META_COLLECTOR(int_sk_rcvlowat) { - SKIP_NONLOCAL(skb); + if (skip_nonlocal(skb)) { + *err = -1; + return; + } dst->value = skb->sk->sk_rcvlowat; } META_COLLECTOR(int_sk_rcvtimeo) { - SKIP_NONLOCAL(skb); + if (skip_nonlocal(skb)) { + *err = -1; + return; + } dst->value = skb->sk->sk_rcvtimeo / HZ; } META_COLLECTOR(int_sk_sndtimeo) { - SKIP_NONLOCAL(skb); + if (skip_nonlocal(skb)) { + *err = -1; + return; + } dst->value = skb->sk->sk_sndtimeo / HZ; } META_COLLECTOR(int_sk_sendmsg_off) { - SKIP_NONLOCAL(skb); + if (skip_nonlocal(skb)) { + *err = -1; + return; + } dst->value = skb->sk->sk_frag.offset; } META_COLLECTOR(int_sk_write_pend) { - SKIP_NONLOCAL(skb); + if (skip_nonlocal(skb)) { + *err = -1; + return; + } dst->value = skb->sk->sk_write_pending; } -- cgit v1.2.3-70-g09d2 From d469962f858b71ec43112c256e3df4a60b00beeb Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Wed, 11 Dec 2013 07:44:14 +0100 Subject: bgmac: reset cached MAC state during chip reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without this bgmac_adjust_link didn't know it should re-initialize MAC state. This led to the MAC not working after if down & up routine. Signed-off-by: Rafał Miłecki Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bgmac.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c index fd6a22e3dd7..273b9f97da4 100644 --- a/drivers/net/ethernet/broadcom/bgmac.c +++ b/drivers/net/ethernet/broadcom/bgmac.c @@ -953,6 +953,8 @@ static void bgmac_chip_reset(struct bgmac *bgmac) BGMAC_CMDCFG_CFE | BGMAC_CMDCFG_SR, false); + bgmac->mac_speed = SPEED_UNKNOWN; + bgmac->mac_duplex = DUPLEX_UNKNOWN; bgmac_clear_mib(bgmac); if (core->id.id == BCMA_CORE_4706_MAC_GBIT) -- cgit v1.2.3-70-g09d2 From 1a0ab7675d27542ab30f2fc6af8c3385cc7f708e Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Wed, 11 Dec 2013 08:44:37 +0100 Subject: bgmac: replace some magic values with defines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bgmac.c | 21 +++++++++++++-------- drivers/net/ethernet/broadcom/bgmac.h | 6 +++++- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c index 273b9f97da4..b665a6aa7e1 100644 --- a/drivers/net/ethernet/broadcom/bgmac.c +++ b/drivers/net/ethernet/broadcom/bgmac.c @@ -877,9 +877,9 @@ static void bgmac_chip_reset(struct bgmac *bgmac) } iost = bcma_aread32(core, BCMA_IOST); - if ((ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg == 10) || + if ((ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg == BCMA_PKG_ID_BCM47186) || (ci->id == BCMA_CHIP_ID_BCM4749 && ci->pkg == 10) || - (ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg == 9)) + (ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg == BCMA_PKG_ID_BCM47188)) iost &= ~BGMAC_BCMA_IOST_ATTACHED; if (iost & BGMAC_BCMA_IOST_ATTACHED) { @@ -891,12 +891,16 @@ static void bgmac_chip_reset(struct bgmac *bgmac) bcma_core_enable(core, flags); if (core->id.rev > 2) { - bgmac_set(bgmac, BCMA_CLKCTLST, 1 << 8); - bgmac_wait_value(bgmac->core, BCMA_CLKCTLST, 1 << 24, 1 << 24, + bgmac_set(bgmac, BCMA_CLKCTLST, + BGMAC_BCMA_CLKCTLST_MISC_PLL_REQ); + bgmac_wait_value(bgmac->core, BCMA_CLKCTLST, + BGMAC_BCMA_CLKCTLST_MISC_PLL_ST, + BGMAC_BCMA_CLKCTLST_MISC_PLL_ST, 1000); } - if (ci->id == BCMA_CHIP_ID_BCM5357 || ci->id == BCMA_CHIP_ID_BCM4749 || + if (ci->id == BCMA_CHIP_ID_BCM5357 || + ci->id == BCMA_CHIP_ID_BCM4749 || ci->id == BCMA_CHIP_ID_BCM53572) { struct bcma_drv_cc *cc = &bgmac->core->bus->drv_cc; u8 et_swtype = 0; @@ -911,10 +915,11 @@ static void bgmac_chip_reset(struct bgmac *bgmac) et_swtype &= 0x0f; et_swtype <<= 4; sw_type = et_swtype; - } else if (ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg == 9) { + } else if (ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg == BCMA_PKG_ID_BCM5358) { sw_type = BGMAC_CHIPCTL_1_SW_TYPE_EPHYRMII; - } else if ((ci->id != BCMA_CHIP_ID_BCM53572 && ci->pkg == 10) || - (ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg == 9)) { + } else if ((ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg == BCMA_PKG_ID_BCM47186) || + (ci->id == BCMA_CHIP_ID_BCM4749 && ci->pkg == 10) || + (ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg == BCMA_PKG_ID_BCM47188)) { sw_type = BGMAC_CHIPCTL_1_IF_TYPE_RGMII | BGMAC_CHIPCTL_1_SW_TYPE_RGMII; } diff --git a/drivers/net/ethernet/broadcom/bgmac.h b/drivers/net/ethernet/broadcom/bgmac.h index 550f2a8e85a..2d44119a764 100644 --- a/drivers/net/ethernet/broadcom/bgmac.h +++ b/drivers/net/ethernet/broadcom/bgmac.h @@ -95,7 +95,11 @@ #define BGMAC_RXQ_CTL_MDP_SHIFT 24 #define BGMAC_GPIO_SELECT 0x194 #define BGMAC_GPIO_OUTPUT_EN 0x198 -/* For 0x1e0 see BCMA_CLKCTLST */ + +/* For 0x1e0 see BCMA_CLKCTLST. Below are BGMAC specific bits */ +#define BGMAC_BCMA_CLKCTLST_MISC_PLL_REQ 0x00000100 +#define BGMAC_BCMA_CLKCTLST_MISC_PLL_ST 0x01000000 + #define BGMAC_HW_WAR 0x1e4 #define BGMAC_PWR_CTL 0x1e8 #define BGMAC_DMA_BASE0 0x200 /* Tx and Rx controller */ -- cgit v1.2.3-70-g09d2 From 79d4a94fab0a9cc1b55db45a98277a68ff1febd8 Mon Sep 17 00:00:00 2001 From: Gao feng Date: Tue, 10 Dec 2013 16:37:32 +0800 Subject: vxlan: remove vxlan_group_used in vxlan_open In vxlan_open, vxlan_group_used always returns true, because the state of the vxlan deivces which we want to open has alreay been running. and it has already in vxlan_list. Since ip_mc_join_group takes care of the reference of struct ip_mc_list. removing vxlan_group_used here is safe. Signed-off-by: Gao feng Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 0358c07f766..43dc9ee4758 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1935,7 +1935,6 @@ static void vxlan_uninit(struct net_device *dev) /* Start ageing timer and join group when device is brought up */ static int vxlan_open(struct net_device *dev) { - struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id); struct vxlan_dev *vxlan = netdev_priv(dev); struct vxlan_sock *vs = vxlan->vn_sock; @@ -1943,8 +1942,7 @@ static int vxlan_open(struct net_device *dev) if (!vs) return -ENOTCONN; - if (vxlan_addr_multicast(&vxlan->default_dst.remote_ip) && - vxlan_group_used(vn, &vxlan->default_dst.remote_ip)) { + if (vxlan_addr_multicast(&vxlan->default_dst.remote_ip)) { vxlan_sock_hold(vs); dev_hold(dev); queue_work(vxlan_wq, &vxlan->igmp_join); -- cgit v1.2.3-70-g09d2 From 95ab09917a8187a02b518e22587c7f035edc7465 Mon Sep 17 00:00:00 2001 From: Gao feng Date: Tue, 10 Dec 2013 16:37:33 +0800 Subject: vxlan: leave multicast group when vxlan device down vxlan_group_used only allows device to leave multicast group when the remote_ip of this vxlan device is difference from other vxlan devices' remote_ip. this will cause device not leave multicast group untile the vn_sock of this vxlan deivce being released. The check in vxlan_group_used is not quite precise. since even the remote_ip is same, but these vxlan devices may use different lower devices, and they may use different vn_socks. Only when some vxlan devices use the same vn_sock,same lower device and same remote_ip, the mc_list of the vn_sock should not be changed. Signed-off-by: Gao feng Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 43dc9ee4758..58f6a0c02b1 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -916,17 +916,32 @@ static bool vxlan_snoop(struct net_device *dev, } /* See if multicast group is already in use by other ID */ -static bool vxlan_group_used(struct vxlan_net *vn, union vxlan_addr *remote_ip) +static bool vxlan_group_used(struct vxlan_net *vn, struct vxlan_dev *dev) { struct vxlan_dev *vxlan; + /* The vxlan_sock is only used by dev, leaving group has + * no effect on other vxlan devices. + */ + if (atomic_read(&dev->vn_sock->refcnt) == 1) + return false; + list_for_each_entry(vxlan, &vn->vxlan_list, next) { - if (!netif_running(vxlan->dev)) + if (!netif_running(vxlan->dev) || vxlan == dev) continue; - if (vxlan_addr_equal(&vxlan->default_dst.remote_ip, - remote_ip)) - return true; + if (vxlan->vn_sock != dev->vn_sock) + continue; + + if (!vxlan_addr_equal(&vxlan->default_dst.remote_ip, + &dev->default_dst.remote_ip)) + continue; + + if (vxlan->default_dst.remote_ifindex != + dev->default_dst.remote_ifindex) + continue; + + return true; } return false; @@ -1981,7 +1996,7 @@ static int vxlan_stop(struct net_device *dev) struct vxlan_sock *vs = vxlan->vn_sock; if (vs && vxlan_addr_multicast(&vxlan->default_dst.remote_ip) && - ! vxlan_group_used(vn, &vxlan->default_dst.remote_ip)) { + !vxlan_group_used(vn, vxlan)) { vxlan_sock_hold(vs); dev_hold(dev); queue_work(vxlan_wq, &vxlan->igmp_leave); -- cgit v1.2.3-70-g09d2 From b601fa197fff265bf60eaf6950d4c194da080f4a Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Tue, 10 Dec 2013 15:02:40 +0100 Subject: ipv4: fix wildcard search with inet_confirm_addr() Help of this function says: "in_dev: only on this interface, 0=any interface", but since commit 39a6d0630012 ("[NETNS]: Process inet_confirm_addr in the correct namespace."), the code supposes that it will never be NULL. This function is never called with in_dev == NULL, but it's exported and may be used by an external module. Because this patch restore the ability to call inet_confirm_addr() with in_dev == NULL, I partially revert the above commit, as suggested by Julian. CC: Julian Anastasov Signed-off-by: Nicolas Dichtel Reviewed-by: Julian Anastasov Signed-off-by: David S. Miller --- drivers/net/bonding/bonding.h | 4 ++-- include/linux/inetdevice.h | 5 ++--- net/ipv4/arp.c | 4 +++- net/ipv4/devinet.c | 9 ++++----- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index a9f4f9f4d8c..a74c92c83ea 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -394,8 +394,8 @@ static inline __be32 bond_confirm_addr(struct net_device *dev, __be32 dst, __be3 in_dev = __in_dev_get_rcu(dev); if (in_dev) - addr = inet_confirm_addr(in_dev, dst, local, RT_SCOPE_HOST); - + addr = inet_confirm_addr(dev_net(dev), in_dev, dst, local, + RT_SCOPE_HOST); rcu_read_unlock(); return addr; } diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h index 562e5c7c5d3..0068708161f 100644 --- a/include/linux/inetdevice.h +++ b/include/linux/inetdevice.h @@ -164,11 +164,10 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *); void devinet_init(void); struct in_device *inetdev_by_index(struct net *, int); __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope); -__be32 inet_confirm_addr(struct in_device *in_dev, __be32 dst, __be32 local, - int scope); +__be32 inet_confirm_addr(struct net *net, struct in_device *in_dev, __be32 dst, + __be32 local, int scope); struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix, __be32 mask); - static __inline__ int inet_ifa_match(__be32 addr, struct in_ifaddr *ifa) { return !((addr^ifa->ifa_address)&ifa->ifa_mask); diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index f0418586394..b67cf805910 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -381,6 +381,7 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb) static int arp_ignore(struct in_device *in_dev, __be32 sip, __be32 tip) { + struct net *net = dev_net(in_dev->dev); int scope; switch (IN_DEV_ARP_IGNORE(in_dev)) { @@ -399,6 +400,7 @@ static int arp_ignore(struct in_device *in_dev, __be32 sip, __be32 tip) case 3: /* Do not reply for scope host addresses */ sip = 0; scope = RT_SCOPE_LINK; + in_dev = NULL; break; case 4: /* Reserved */ case 5: @@ -410,7 +412,7 @@ static int arp_ignore(struct in_device *in_dev, __be32 sip, __be32 tip) default: return 0; } - return !inet_confirm_addr(in_dev, sip, tip, scope); + return !inet_confirm_addr(net, in_dev, sip, tip, scope); } static int arp_filter(__be32 sip, __be32 tip, struct net_device *dev) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 6f49efc9d4b..84956f5f013 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1240,22 +1240,21 @@ static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst, /* * Confirm that local IP address exists using wildcards: - * - in_dev: only on this interface, 0=any interface + * - net: netns to check, cannot be NULL + * - in_dev: only on this interface, NULL=any interface * - dst: only in the same subnet as dst, 0=any dst * - local: address, 0=autoselect the local address * - scope: maximum allowed scope value for the local address */ -__be32 inet_confirm_addr(struct in_device *in_dev, +__be32 inet_confirm_addr(struct net *net, struct in_device *in_dev, __be32 dst, __be32 local, int scope) { __be32 addr = 0; struct net_device *dev; - struct net *net; - if (scope != RT_SCOPE_LINK) + if (in_dev != NULL) return confirm_addr_indev(in_dev, dst, local, scope); - net = dev_net(in_dev->dev); rcu_read_lock(); for_each_netdev_rcu(net, dev) { in_dev = __in_dev_get_rcu(dev); -- cgit v1.2.3-70-g09d2 From 6b1dd8560179bd3328a3fb024ce1b63b772464fd Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 11 Dec 2013 15:48:37 +0800 Subject: sch_htb: remove unnecessary NULL pointer judgment It already has a NULL pointer judgment of rtab in qdisc_put_rtab(). Remove the judgment outside of qdisc_put_rtab(). Signed-off-by: Yang Yingliang Signed-off-by: David S. Miller --- net/sched/sch_htb.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 0e1e38b4002..830c64f2553 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -1337,7 +1337,6 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, struct htb_sched *q = qdisc_priv(sch); struct htb_class *cl = (struct htb_class *)*arg, *parent; struct nlattr *opt = tca[TCA_OPTIONS]; - struct qdisc_rate_table *rtab = NULL, *ctab = NULL; struct nlattr *tb[TCA_HTB_MAX + 1]; struct tc_htb_opt *hopt; u64 rate64, ceil64; @@ -1361,16 +1360,11 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, goto failure; /* Keeping backward compatible with rate_table based iproute2 tc */ - if (hopt->rate.linklayer == TC_LINKLAYER_UNAWARE) { - rtab = qdisc_get_rtab(&hopt->rate, tb[TCA_HTB_RTAB]); - if (rtab) - qdisc_put_rtab(rtab); - } - if (hopt->ceil.linklayer == TC_LINKLAYER_UNAWARE) { - ctab = qdisc_get_rtab(&hopt->ceil, tb[TCA_HTB_CTAB]); - if (ctab) - qdisc_put_rtab(ctab); - } + if (hopt->rate.linklayer == TC_LINKLAYER_UNAWARE) + qdisc_put_rtab(qdisc_get_rtab(&hopt->rate, tb[TCA_HTB_RTAB])); + + if (hopt->ceil.linklayer == TC_LINKLAYER_UNAWARE) + qdisc_put_rtab(qdisc_get_rtab(&hopt->ceil, tb[TCA_HTB_CTAB])); if (!cl) { /* new class */ struct Qdisc *new_q; -- cgit v1.2.3-70-g09d2 From e47726683803616c773bc75c88cfb3eb54a8172b Mon Sep 17 00:00:00 2001 From: wangweidong Date: Wed, 11 Dec 2013 16:42:14 +0800 Subject: sctp: remove redundant null check on asoc In sctp_err_lookup, goto out while the asoc is not NULL, so remove the check NULL. Also, in sctp_err_finish which called by sctp_v4_err and sctp_v6_err, they pass asoc to sctp_err_finish while the asoc is not NULL, so remove the check. Signed-off-by: Wang Weidong Acked-by: Neil Horman Acked-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/input.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/net/sctp/input.c b/net/sctp/input.c index 66038533ca5..2a192a7c5d8 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -536,8 +536,7 @@ struct sock *sctp_err_lookup(struct net *net, int family, struct sk_buff *skb, return sk; out: - if (asoc) - sctp_association_put(asoc); + sctp_association_put(asoc); return NULL; } @@ -545,8 +544,7 @@ out: void sctp_err_finish(struct sock *sk, struct sctp_association *asoc) { sctp_bh_unlock_sock(sk); - if (asoc) - sctp_association_put(asoc); + sctp_association_put(asoc); } /* -- cgit v1.2.3-70-g09d2 From 8df8c56a5abc70af5862aa7cac2875aeeb17a42b Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 11 Dec 2013 17:05:34 +0200 Subject: 6lowpan: Moving generic compression code into 6lowpan_iphc.c Because the IEEE 802154 and Bluetooth share the IP header compression and uncompression code, the common code is moved to 6lowpan_iphc.c file. Signed-off-by: Jukka Rissanen Acked-by: Alexander Aring Signed-off-by: Marcel Holtmann --- net/ieee802154/6lowpan.c | 753 ++------------------------------------- net/ieee802154/6lowpan.h | 32 ++ net/ieee802154/6lowpan_iphc.c | 807 ++++++++++++++++++++++++++++++++++++++++++ net/ieee802154/Makefile | 2 +- 4 files changed, 875 insertions(+), 719 deletions(-) create mode 100644 net/ieee802154/6lowpan_iphc.c diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c index 459e200c08a..53d0bd58ed8 100644 --- a/net/ieee802154/6lowpan.c +++ b/net/ieee802154/6lowpan.c @@ -62,9 +62,6 @@ #include "6lowpan.h" -/* TTL uncompression values */ -static const u8 lowpan_ttl_values[] = {0, 1, 64, 255}; - static LIST_HEAD(lowpan_devices); /* private device info */ @@ -135,347 +132,14 @@ static inline void lowpan_raw_dump_table(const char *caller, char *msg, #endif /* DEBUG */ } -static u8 -lowpan_compress_addr_64(u8 **hc06_ptr, u8 shift, const struct in6_addr *ipaddr, - const unsigned char *lladdr) -{ - u8 val = 0; - - if (is_addr_mac_addr_based(ipaddr, lladdr)) - val = 3; /* 0-bits */ - else if (lowpan_is_iid_16_bit_compressable(ipaddr)) { - /* compress IID to 16 bits xxxx::XXXX */ - memcpy(*hc06_ptr, &ipaddr->s6_addr16[7], 2); - *hc06_ptr += 2; - val = 2; /* 16-bits */ - } else { - /* do not compress IID => xxxx::IID */ - memcpy(*hc06_ptr, &ipaddr->s6_addr16[4], 8); - *hc06_ptr += 8; - val = 1; /* 64-bits */ - } - - return rol8(val, shift); -} - -/* - * Uncompress address function for source and - * destination address(non-multicast). - * - * address_mode is sam value or dam value. - */ -static int -lowpan_uncompress_addr(struct sk_buff *skb, - struct in6_addr *ipaddr, - const u8 address_mode, - const struct ieee802154_addr *lladdr) -{ - bool fail; - - switch (address_mode) { - case LOWPAN_IPHC_ADDR_00: - /* for global link addresses */ - fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16); - break; - case LOWPAN_IPHC_ADDR_01: - /* fe:80::XXXX:XXXX:XXXX:XXXX */ - ipaddr->s6_addr[0] = 0xFE; - ipaddr->s6_addr[1] = 0x80; - fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[8], 8); - break; - case LOWPAN_IPHC_ADDR_02: - /* fe:80::ff:fe00:XXXX */ - ipaddr->s6_addr[0] = 0xFE; - ipaddr->s6_addr[1] = 0x80; - ipaddr->s6_addr[11] = 0xFF; - ipaddr->s6_addr[12] = 0xFE; - fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[14], 2); - break; - case LOWPAN_IPHC_ADDR_03: - fail = false; - switch (lladdr->addr_type) { - case IEEE802154_ADDR_LONG: - /* fe:80::XXXX:XXXX:XXXX:XXXX - * \_________________/ - * hwaddr - */ - ipaddr->s6_addr[0] = 0xFE; - ipaddr->s6_addr[1] = 0x80; - memcpy(&ipaddr->s6_addr[8], lladdr->hwaddr, - IEEE802154_ADDR_LEN); - /* second bit-flip (Universe/Local) - * is done according RFC2464 - */ - ipaddr->s6_addr[8] ^= 0x02; - break; - case IEEE802154_ADDR_SHORT: - /* fe:80::ff:fe00:XXXX - * \__/ - * short_addr - * - * Universe/Local bit is zero. - */ - ipaddr->s6_addr[0] = 0xFE; - ipaddr->s6_addr[1] = 0x80; - ipaddr->s6_addr[11] = 0xFF; - ipaddr->s6_addr[12] = 0xFE; - ipaddr->s6_addr16[7] = htons(lladdr->short_addr); - break; - default: - pr_debug("Invalid addr_type set\n"); - return -EINVAL; - } - break; - default: - pr_debug("Invalid address mode value: 0x%x\n", address_mode); - return -EINVAL; - } - - if (fail) { - pr_debug("Failed to fetch skb data\n"); - return -EIO; - } - - lowpan_raw_dump_inline(NULL, "Reconstructed ipv6 addr is:\n", - ipaddr->s6_addr, 16); - - return 0; -} - -/* Uncompress address function for source context - * based address(non-multicast). - */ -static int -lowpan_uncompress_context_based_src_addr(struct sk_buff *skb, - struct in6_addr *ipaddr, - const u8 sam) -{ - switch (sam) { - case LOWPAN_IPHC_ADDR_00: - /* unspec address :: - * Do nothing, address is already :: - */ - break; - case LOWPAN_IPHC_ADDR_01: - /* TODO */ - case LOWPAN_IPHC_ADDR_02: - /* TODO */ - case LOWPAN_IPHC_ADDR_03: - /* TODO */ - netdev_warn(skb->dev, "SAM value 0x%x not supported\n", sam); - return -EINVAL; - default: - pr_debug("Invalid sam value: 0x%x\n", sam); - return -EINVAL; - } - - lowpan_raw_dump_inline(NULL, - "Reconstructed context based ipv6 src addr is:\n", - ipaddr->s6_addr, 16); - - return 0; -} - -/* Uncompress function for multicast destination address, - * when M bit is set. - */ -static int -lowpan_uncompress_multicast_daddr(struct sk_buff *skb, - struct in6_addr *ipaddr, - const u8 dam) -{ - bool fail; - - switch (dam) { - case LOWPAN_IPHC_DAM_00: - /* 00: 128 bits. The full address - * is carried in-line. - */ - fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16); - break; - case LOWPAN_IPHC_DAM_01: - /* 01: 48 bits. The address takes - * the form ffXX::00XX:XXXX:XXXX. - */ - ipaddr->s6_addr[0] = 0xFF; - fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1); - fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[11], 5); - break; - case LOWPAN_IPHC_DAM_10: - /* 10: 32 bits. The address takes - * the form ffXX::00XX:XXXX. - */ - ipaddr->s6_addr[0] = 0xFF; - fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1); - fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[13], 3); - break; - case LOWPAN_IPHC_DAM_11: - /* 11: 8 bits. The address takes - * the form ff02::00XX. - */ - ipaddr->s6_addr[0] = 0xFF; - ipaddr->s6_addr[1] = 0x02; - fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[15], 1); - break; - default: - pr_debug("DAM value has a wrong value: 0x%x\n", dam); - return -EINVAL; - } - - if (fail) { - pr_debug("Failed to fetch skb data\n"); - return -EIO; - } - - lowpan_raw_dump_inline(NULL, "Reconstructed ipv6 multicast addr is:\n", - ipaddr->s6_addr, 16); - - return 0; -} - -static void -lowpan_compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb) -{ - struct udphdr *uh = udp_hdr(skb); - - if (((uh->source & LOWPAN_NHC_UDP_4BIT_MASK) == - LOWPAN_NHC_UDP_4BIT_PORT) && - ((uh->dest & LOWPAN_NHC_UDP_4BIT_MASK) == - LOWPAN_NHC_UDP_4BIT_PORT)) { - pr_debug("UDP header: both ports compression to 4 bits\n"); - **hc06_ptr = LOWPAN_NHC_UDP_CS_P_11; - **(hc06_ptr + 1) = /* subtraction is faster */ - (u8)((uh->dest - LOWPAN_NHC_UDP_4BIT_PORT) + - ((uh->source & LOWPAN_NHC_UDP_4BIT_PORT) << 4)); - *hc06_ptr += 2; - } else if ((uh->dest & LOWPAN_NHC_UDP_8BIT_MASK) == - LOWPAN_NHC_UDP_8BIT_PORT) { - pr_debug("UDP header: remove 8 bits of dest\n"); - **hc06_ptr = LOWPAN_NHC_UDP_CS_P_01; - memcpy(*hc06_ptr + 1, &uh->source, 2); - **(hc06_ptr + 3) = (u8)(uh->dest - LOWPAN_NHC_UDP_8BIT_PORT); - *hc06_ptr += 4; - } else if ((uh->source & LOWPAN_NHC_UDP_8BIT_MASK) == - LOWPAN_NHC_UDP_8BIT_PORT) { - pr_debug("UDP header: remove 8 bits of source\n"); - **hc06_ptr = LOWPAN_NHC_UDP_CS_P_10; - memcpy(*hc06_ptr + 1, &uh->dest, 2); - **(hc06_ptr + 3) = (u8)(uh->source - LOWPAN_NHC_UDP_8BIT_PORT); - *hc06_ptr += 4; - } else { - pr_debug("UDP header: can't compress\n"); - **hc06_ptr = LOWPAN_NHC_UDP_CS_P_00; - memcpy(*hc06_ptr + 1, &uh->source, 2); - memcpy(*hc06_ptr + 3, &uh->dest, 2); - *hc06_ptr += 5; - } - - /* checksum is always inline */ - memcpy(*hc06_ptr, &uh->check, 2); - *hc06_ptr += 2; - - /* skip the UDP header */ - skb_pull(skb, sizeof(struct udphdr)); -} - -static inline int lowpan_fetch_skb_u8(struct sk_buff *skb, u8 *val) -{ - if (unlikely(!pskb_may_pull(skb, 1))) - return -EINVAL; - - *val = skb->data[0]; - skb_pull(skb, 1); - - return 0; -} - -static inline int lowpan_fetch_skb_u16(struct sk_buff *skb, u16 *val) -{ - if (unlikely(!pskb_may_pull(skb, 2))) - return -EINVAL; - - *val = (skb->data[0] << 8) | skb->data[1]; - skb_pull(skb, 2); - - return 0; -} - -static int -lowpan_uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh) -{ - u8 tmp; - - if (!uh) - goto err; - - if (lowpan_fetch_skb_u8(skb, &tmp)) - goto err; - - if ((tmp & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) { - pr_debug("UDP header uncompression\n"); - switch (tmp & LOWPAN_NHC_UDP_CS_P_11) { - case LOWPAN_NHC_UDP_CS_P_00: - memcpy(&uh->source, &skb->data[0], 2); - memcpy(&uh->dest, &skb->data[2], 2); - skb_pull(skb, 4); - break; - case LOWPAN_NHC_UDP_CS_P_01: - memcpy(&uh->source, &skb->data[0], 2); - uh->dest = - skb->data[2] + LOWPAN_NHC_UDP_8BIT_PORT; - skb_pull(skb, 3); - break; - case LOWPAN_NHC_UDP_CS_P_10: - uh->source = skb->data[0] + LOWPAN_NHC_UDP_8BIT_PORT; - memcpy(&uh->dest, &skb->data[1], 2); - skb_pull(skb, 3); - break; - case LOWPAN_NHC_UDP_CS_P_11: - uh->source = - LOWPAN_NHC_UDP_4BIT_PORT + (skb->data[0] >> 4); - uh->dest = - LOWPAN_NHC_UDP_4BIT_PORT + (skb->data[0] & 0x0f); - skb_pull(skb, 1); - break; - default: - pr_debug("ERROR: unknown UDP format\n"); - goto err; - } - - pr_debug("uncompressed UDP ports: src = %d, dst = %d\n", - uh->source, uh->dest); - - /* copy checksum */ - memcpy(&uh->check, &skb->data[0], 2); - skb_pull(skb, 2); - - /* - * UDP lenght needs to be infered from the lower layers - * here, we obtain the hint from the remaining size of the - * frame - */ - uh->len = htons(skb->len + sizeof(struct udphdr)); - pr_debug("uncompressed UDP length: src = %d", uh->len); - } else { - pr_debug("ERROR: unsupported NH format\n"); - goto err; - } - - return 0; -err: - return -EINVAL; -} - static int lowpan_header_create(struct sk_buff *skb, struct net_device *dev, unsigned short type, const void *_daddr, const void *_saddr, unsigned int len) { - u8 tmp, iphc0, iphc1, *hc06_ptr; struct ipv6hdr *hdr; const u8 *saddr = _saddr; const u8 *daddr = _daddr; - u8 head[100]; struct ieee802154_addr sa, da; /* TODO: @@ -485,181 +149,14 @@ static int lowpan_header_create(struct sk_buff *skb, return 0; hdr = ipv6_hdr(skb); - hc06_ptr = head + 2; - - pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength = %d\n" - "\tnexthdr = 0x%02x\n\thop_lim = %d\n", hdr->version, - ntohs(hdr->payload_len), hdr->nexthdr, hdr->hop_limit); - - lowpan_raw_dump_table(__func__, "raw skb network header dump", - skb_network_header(skb), sizeof(struct ipv6hdr)); if (!saddr) saddr = dev->dev_addr; lowpan_raw_dump_inline(__func__, "saddr", (unsigned char *)saddr, 8); - - /* - * As we copy some bit-length fields, in the IPHC encoding bytes, - * we sometimes use |= - * If the field is 0, and the current bit value in memory is 1, - * this does not work. We therefore reset the IPHC encoding here - */ - iphc0 = LOWPAN_DISPATCH_IPHC; - iphc1 = 0; - - /* TODO: context lookup */ - lowpan_raw_dump_inline(__func__, "daddr", (unsigned char *)daddr, 8); - /* - * Traffic class, flow label - * If flow label is 0, compress it. If traffic class is 0, compress it - * We have to process both in the same time as the offset of traffic - * class depends on the presence of version and flow label - */ - - /* hc06 format of TC is ECN | DSCP , original one is DSCP | ECN */ - tmp = (hdr->priority << 4) | (hdr->flow_lbl[0] >> 4); - tmp = ((tmp & 0x03) << 6) | (tmp >> 2); - - if (((hdr->flow_lbl[0] & 0x0F) == 0) && - (hdr->flow_lbl[1] == 0) && (hdr->flow_lbl[2] == 0)) { - /* flow label can be compressed */ - iphc0 |= LOWPAN_IPHC_FL_C; - if ((hdr->priority == 0) && - ((hdr->flow_lbl[0] & 0xF0) == 0)) { - /* compress (elide) all */ - iphc0 |= LOWPAN_IPHC_TC_C; - } else { - /* compress only the flow label */ - *hc06_ptr = tmp; - hc06_ptr += 1; - } - } else { - /* Flow label cannot be compressed */ - if ((hdr->priority == 0) && - ((hdr->flow_lbl[0] & 0xF0) == 0)) { - /* compress only traffic class */ - iphc0 |= LOWPAN_IPHC_TC_C; - *hc06_ptr = (tmp & 0xc0) | (hdr->flow_lbl[0] & 0x0F); - memcpy(hc06_ptr + 1, &hdr->flow_lbl[1], 2); - hc06_ptr += 3; - } else { - /* compress nothing */ - memcpy(hc06_ptr, &hdr, 4); - /* replace the top byte with new ECN | DSCP format */ - *hc06_ptr = tmp; - hc06_ptr += 4; - } - } - - /* NOTE: payload length is always compressed */ - - /* Next Header is compress if UDP */ - if (hdr->nexthdr == UIP_PROTO_UDP) - iphc0 |= LOWPAN_IPHC_NH_C; - - if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) { - *hc06_ptr = hdr->nexthdr; - hc06_ptr += 1; - } - - /* - * Hop limit - * if 1: compress, encoding is 01 - * if 64: compress, encoding is 10 - * if 255: compress, encoding is 11 - * else do not compress - */ - switch (hdr->hop_limit) { - case 1: - iphc0 |= LOWPAN_IPHC_TTL_1; - break; - case 64: - iphc0 |= LOWPAN_IPHC_TTL_64; - break; - case 255: - iphc0 |= LOWPAN_IPHC_TTL_255; - break; - default: - *hc06_ptr = hdr->hop_limit; - hc06_ptr += 1; - break; - } - - /* source address compression */ - if (is_addr_unspecified(&hdr->saddr)) { - pr_debug("source address is unspecified, setting SAC\n"); - iphc1 |= LOWPAN_IPHC_SAC; - /* TODO: context lookup */ - } else if (is_addr_link_local(&hdr->saddr)) { - pr_debug("source address is link-local\n"); - iphc1 |= lowpan_compress_addr_64(&hc06_ptr, - LOWPAN_IPHC_SAM_BIT, &hdr->saddr, saddr); - } else { - pr_debug("send the full source address\n"); - memcpy(hc06_ptr, &hdr->saddr.s6_addr16[0], 16); - hc06_ptr += 16; - } - - /* destination address compression */ - if (is_addr_mcast(&hdr->daddr)) { - pr_debug("destination address is multicast: "); - iphc1 |= LOWPAN_IPHC_M; - if (lowpan_is_mcast_addr_compressable8(&hdr->daddr)) { - pr_debug("compressed to 1 octet\n"); - iphc1 |= LOWPAN_IPHC_DAM_11; - /* use last byte */ - *hc06_ptr = hdr->daddr.s6_addr[15]; - hc06_ptr += 1; - } else if (lowpan_is_mcast_addr_compressable32(&hdr->daddr)) { - pr_debug("compressed to 4 octets\n"); - iphc1 |= LOWPAN_IPHC_DAM_10; - /* second byte + the last three */ - *hc06_ptr = hdr->daddr.s6_addr[1]; - memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[13], 3); - hc06_ptr += 4; - } else if (lowpan_is_mcast_addr_compressable48(&hdr->daddr)) { - pr_debug("compressed to 6 octets\n"); - iphc1 |= LOWPAN_IPHC_DAM_01; - /* second byte + the last five */ - *hc06_ptr = hdr->daddr.s6_addr[1]; - memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[11], 5); - hc06_ptr += 6; - } else { - pr_debug("using full address\n"); - iphc1 |= LOWPAN_IPHC_DAM_00; - memcpy(hc06_ptr, &hdr->daddr.s6_addr[0], 16); - hc06_ptr += 16; - } - } else { - /* TODO: context lookup */ - if (is_addr_link_local(&hdr->daddr)) { - pr_debug("dest address is unicast and link-local\n"); - iphc1 |= lowpan_compress_addr_64(&hc06_ptr, - LOWPAN_IPHC_DAM_BIT, &hdr->daddr, daddr); - } else { - pr_debug("dest address is unicast: using full one\n"); - memcpy(hc06_ptr, &hdr->daddr.s6_addr16[0], 16); - hc06_ptr += 16; - } - } - - /* UDP header compression */ - if (hdr->nexthdr == UIP_PROTO_UDP) - lowpan_compress_udp_header(&hc06_ptr, skb); - - head[0] = iphc0; - head[1] = iphc1; - - skb_pull(skb, sizeof(struct ipv6hdr)); - skb_reset_transport_header(skb); - memcpy(skb_push(skb, hc06_ptr - head), head, hc06_ptr - head); - skb_reset_network_header(skb); - - lowpan_raw_dump_table(__func__, "raw skb data dump", skb->data, - skb->len); + lowpan_header_compress(skb, dev, type, daddr, saddr, len); /* * NOTE1: I'm still unsure about the fact that compression and WPAN @@ -671,39 +168,38 @@ static int lowpan_header_create(struct sk_buff *skb, * from MAC subif of the 'dev' and 'real_dev' network devices, but * this isn't implemented in mainline yet, so currently we assign 0xff */ - { - mac_cb(skb)->flags = IEEE802154_FC_TYPE_DATA; - mac_cb(skb)->seq = ieee802154_mlme_ops(dev)->get_dsn(dev); + mac_cb(skb)->flags = IEEE802154_FC_TYPE_DATA; + mac_cb(skb)->seq = ieee802154_mlme_ops(dev)->get_dsn(dev); - /* prepare wpan address data */ - sa.addr_type = IEEE802154_ADDR_LONG; - sa.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); + /* prepare wpan address data */ + sa.addr_type = IEEE802154_ADDR_LONG; + sa.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); - memcpy(&(sa.hwaddr), saddr, 8); - /* intra-PAN communications */ - da.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); + memcpy(&(sa.hwaddr), saddr, 8); + /* intra-PAN communications */ + da.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); - /* - * if the destination address is the broadcast address, use the - * corresponding short address - */ - if (lowpan_is_addr_broadcast(daddr)) { - da.addr_type = IEEE802154_ADDR_SHORT; - da.short_addr = IEEE802154_ADDR_BROADCAST; - } else { - da.addr_type = IEEE802154_ADDR_LONG; - memcpy(&(da.hwaddr), daddr, IEEE802154_ADDR_LEN); - - /* request acknowledgment */ - mac_cb(skb)->flags |= MAC_CB_FLAG_ACKREQ; - } + /* + * if the destination address is the broadcast address, use the + * corresponding short address + */ + if (lowpan_is_addr_broadcast(daddr)) { + da.addr_type = IEEE802154_ADDR_SHORT; + da.short_addr = IEEE802154_ADDR_BROADCAST; + } else { + da.addr_type = IEEE802154_ADDR_LONG; + memcpy(&(da.hwaddr), daddr, IEEE802154_ADDR_LEN); - return dev_hard_header(skb, lowpan_dev_info(dev)->real_dev, - type, (void *)&da, (void *)&sa, skb->len); + /* request acknowledgment */ + mac_cb(skb)->flags |= MAC_CB_FLAG_ACKREQ; } + + return dev_hard_header(skb, lowpan_dev_info(dev)->real_dev, + type, (void *)&da, (void *)&sa, skb->len); } -static int lowpan_give_skb_to_devices(struct sk_buff *skb) +static int lowpan_give_skb_to_devices(struct sk_buff *skb, + struct net_device *dev) { struct lowpan_dev_record *entry; struct sk_buff *skb_cp; @@ -726,31 +222,6 @@ static int lowpan_give_skb_to_devices(struct sk_buff *skb) return stat; } -static int lowpan_skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr) -{ - struct sk_buff *new; - int stat = NET_RX_SUCCESS; - - new = skb_copy_expand(skb, sizeof(struct ipv6hdr), skb_tailroom(skb), - GFP_ATOMIC); - kfree_skb(skb); - - if (!new) - return -ENOMEM; - - skb_push(new, sizeof(struct ipv6hdr)); - skb_copy_to_linear_data(new, hdr, sizeof(struct ipv6hdr)); - - new->protocol = htons(ETH_P_IPV6); - new->pkt_type = PACKET_HOST; - - stat = lowpan_give_skb_to_devices(new); - - kfree_skb(new); - - return stat; -} - static void lowpan_fragment_timer_expired(unsigned long entry_addr) { struct lowpan_fragment *entry = (struct lowpan_fragment *)entry_addr; @@ -814,13 +285,10 @@ frame_err: return NULL; } -static int -lowpan_process_data(struct sk_buff *skb) +static int process_data(struct sk_buff *skb) { - struct ipv6hdr hdr = {}; - u8 tmp, iphc0, iphc1, num_context = 0; + u8 iphc0, iphc1; const struct ieee802154_addr *_saddr, *_daddr; - int err; lowpan_raw_dump_table(__func__, "raw skb data dump", skb->data, skb->len); @@ -925,162 +393,11 @@ lowpan_process_data(struct sk_buff *skb) _saddr = &mac_cb(skb)->sa; _daddr = &mac_cb(skb)->da; - pr_debug("iphc0 = %02x, iphc1 = %02x\n", iphc0, iphc1); - - /* another if the CID flag is set */ - if (iphc1 & LOWPAN_IPHC_CID) { - pr_debug("CID flag is set, increase header with one\n"); - if (lowpan_fetch_skb_u8(skb, &num_context)) - goto drop; - } - - hdr.version = 6; - - /* Traffic Class and Flow Label */ - switch ((iphc0 & LOWPAN_IPHC_TF) >> 3) { - /* - * Traffic Class and FLow Label carried in-line - * ECN + DSCP + 4-bit Pad + Flow Label (4 bytes) - */ - case 0: /* 00b */ - if (lowpan_fetch_skb_u8(skb, &tmp)) - goto drop; - - memcpy(&hdr.flow_lbl, &skb->data[0], 3); - skb_pull(skb, 3); - hdr.priority = ((tmp >> 2) & 0x0f); - hdr.flow_lbl[0] = ((tmp >> 2) & 0x30) | (tmp << 6) | - (hdr.flow_lbl[0] & 0x0f); - break; - /* - * Traffic class carried in-line - * ECN + DSCP (1 byte), Flow Label is elided - */ - case 2: /* 10b */ - if (lowpan_fetch_skb_u8(skb, &tmp)) - goto drop; - - hdr.priority = ((tmp >> 2) & 0x0f); - hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 0x30); - break; - /* - * Flow Label carried in-line - * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided - */ - case 1: /* 01b */ - if (lowpan_fetch_skb_u8(skb, &tmp)) - goto drop; - - hdr.flow_lbl[0] = (skb->data[0] & 0x0F) | ((tmp >> 2) & 0x30); - memcpy(&hdr.flow_lbl[1], &skb->data[0], 2); - skb_pull(skb, 2); - break; - /* Traffic Class and Flow Label are elided */ - case 3: /* 11b */ - break; - default: - break; - } - - /* Next Header */ - if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) { - /* Next header is carried inline */ - if (lowpan_fetch_skb_u8(skb, &(hdr.nexthdr))) - goto drop; - - pr_debug("NH flag is set, next header carried inline: %02x\n", - hdr.nexthdr); - } - - /* Hop Limit */ - if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I) - hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03]; - else { - if (lowpan_fetch_skb_u8(skb, &(hdr.hop_limit))) - goto drop; - } - - /* Extract SAM to the tmp variable */ - tmp = ((iphc1 & LOWPAN_IPHC_SAM) >> LOWPAN_IPHC_SAM_BIT) & 0x03; - - if (iphc1 & LOWPAN_IPHC_SAC) { - /* Source address context based uncompression */ - pr_debug("SAC bit is set. Handle context based source address.\n"); - err = lowpan_uncompress_context_based_src_addr( - skb, &hdr.saddr, tmp); - } else { - /* Source address uncompression */ - pr_debug("source address stateless compression\n"); - err = lowpan_uncompress_addr(skb, &hdr.saddr, tmp, _saddr); - } - - /* Check on error of previous branch */ - if (err) - goto drop; - - /* Extract DAM to the tmp variable */ - tmp = ((iphc1 & LOWPAN_IPHC_DAM_11) >> LOWPAN_IPHC_DAM_BIT) & 0x03; - - /* check for Multicast Compression */ - if (iphc1 & LOWPAN_IPHC_M) { - if (iphc1 & LOWPAN_IPHC_DAC) { - pr_debug("dest: context-based mcast compression\n"); - /* TODO: implement this */ - } else { - err = lowpan_uncompress_multicast_daddr( - skb, &hdr.daddr, tmp); - if (err) - goto drop; - } - } else { - pr_debug("dest: stateless compression\n"); - err = lowpan_uncompress_addr(skb, &hdr.daddr, tmp, _daddr); - if (err) - goto drop; - } - - /* UDP data uncompression */ - if (iphc0 & LOWPAN_IPHC_NH_C) { - struct udphdr uh; - struct sk_buff *new; - if (lowpan_uncompress_udp_header(skb, &uh)) - goto drop; - - /* - * replace the compressed UDP head by the uncompressed UDP - * header - */ - new = skb_copy_expand(skb, sizeof(struct udphdr), - skb_tailroom(skb), GFP_ATOMIC); - kfree_skb(skb); - - if (!new) - return -ENOMEM; - - skb = new; - - skb_push(skb, sizeof(struct udphdr)); - skb_copy_to_linear_data(skb, &uh, sizeof(struct udphdr)); - - lowpan_raw_dump_table(__func__, "raw UDP header dump", - (u8 *)&uh, sizeof(uh)); - - hdr.nexthdr = UIP_PROTO_UDP; - } - - /* Not fragmented package */ - hdr.payload_len = htons(skb->len); - - pr_debug("skb headroom size = %d, data length = %d\n", - skb_headroom(skb), skb->len); - - pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength = %d\n\t" - "nexthdr = 0x%02x\n\thop_lim = %d\n", hdr.version, - ntohs(hdr.payload_len), hdr.nexthdr, hdr.hop_limit); - - lowpan_raw_dump_table(__func__, "raw header dump", (u8 *)&hdr, - sizeof(hdr)); - return lowpan_skb_deliver(skb, &hdr); + return lowpan_process_data(skb, skb->dev, (u8 *)_saddr->hwaddr, + _saddr->addr_type, IEEE802154_ADDR_LEN, + (u8 *)_daddr->hwaddr, _daddr->addr_type, + IEEE802154_ADDR_LEN, iphc0, iphc1, + lowpan_give_skb_to_devices); unlock_and_drop: spin_unlock_bh(&flist_lock); @@ -1316,7 +633,7 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev, /* Pull off the 1-byte of 6lowpan header. */ skb_pull(local_skb, 1); - lowpan_give_skb_to_devices(local_skb); + lowpan_give_skb_to_devices(local_skb, NULL); kfree_skb(local_skb); kfree_skb(skb); @@ -1328,7 +645,7 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev, local_skb = skb_clone(skb, GFP_ATOMIC); if (!local_skb) goto drop; - lowpan_process_data(local_skb); + process_data(local_skb); kfree_skb(skb); break; diff --git a/net/ieee802154/6lowpan.h b/net/ieee802154/6lowpan.h index 2869c0526da..535606d45c3 100644 --- a/net/ieee802154/6lowpan.h +++ b/net/ieee802154/6lowpan.h @@ -232,6 +232,28 @@ dest = 16 bit inline */ #define LOWPAN_NHC_UDP_CS_P_11 0xF3 /* source & dest = 0xF0B + 4bit inline */ +static inline int lowpan_fetch_skb_u8(struct sk_buff *skb, u8 *val) +{ + if (unlikely(!pskb_may_pull(skb, 1))) + return -EINVAL; + + *val = skb->data[0]; + skb_pull(skb, 1); + + return 0; +} + +static inline int lowpan_fetch_skb_u16(struct sk_buff *skb, u16 *val) +{ + if (unlikely(!pskb_may_pull(skb, 2))) + return -EINVAL; + + *val = (skb->data[0] << 8) | skb->data[1]; + skb_pull(skb, 2); + + return 0; +} + static inline bool lowpan_fetch_skb(struct sk_buff *skb, void *data, const unsigned int len) { @@ -244,4 +266,14 @@ static inline bool lowpan_fetch_skb(struct sk_buff *skb, return false; } +typedef int (*skb_delivery_cb)(struct sk_buff *skb, struct net_device *dev); + +int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, + const u8 *saddr, const u8 saddr_type, const u8 saddr_len, + const u8 *daddr, const u8 daddr_type, const u8 daddr_len, + u8 iphc0, u8 iphc1, skb_delivery_cb skb_deliver); +int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, + unsigned short type, const void *_daddr, + const void *_saddr, unsigned int len); + #endif /* __6LOWPAN_H__ */ diff --git a/net/ieee802154/6lowpan_iphc.c b/net/ieee802154/6lowpan_iphc.c new file mode 100644 index 00000000000..57c0b7ad6b6 --- /dev/null +++ b/net/ieee802154/6lowpan_iphc.c @@ -0,0 +1,807 @@ +/* + * Copyright 2011, Siemens AG + * written by Alexander Smirnov + */ + +/* + * Based on patches from Jon Smirl + * Copyright (c) 2011 Jon Smirl + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* Jon's code is based on 6lowpan implementation for Contiki which is: + * Copyright (c) 2008, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#include "6lowpan.h" + +/* print data in line */ +static inline void raw_dump_inline(const char *caller, char *msg, + unsigned char *buf, int len) +{ + if (msg) + pr_debug("%s():%s: ", caller, msg); + print_hex_dump_debug("", DUMP_PREFIX_NONE, + 16, 1, buf, len, false); +} + +/* + * print data in a table format: + * + * addr: xx xx xx xx xx xx + * addr: xx xx xx xx xx xx + * ... + */ +static inline void raw_dump_table(const char *caller, char *msg, + unsigned char *buf, int len) +{ + if (msg) + pr_debug("%s():%s:\n", caller, msg); + print_hex_dump_debug("\t", DUMP_PREFIX_OFFSET, + 16, 1, buf, len, false); +} + +/* + * Uncompress address function for source and + * destination address(non-multicast). + * + * address_mode is sam value or dam value. + */ +static int uncompress_addr(struct sk_buff *skb, + struct in6_addr *ipaddr, const u8 address_mode, + const u8 *lladdr, const u8 addr_type, + const u8 addr_len) +{ + bool fail; + + switch (address_mode) { + case LOWPAN_IPHC_ADDR_00: + /* for global link addresses */ + fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16); + break; + case LOWPAN_IPHC_ADDR_01: + /* fe:80::XXXX:XXXX:XXXX:XXXX */ + ipaddr->s6_addr[0] = 0xFE; + ipaddr->s6_addr[1] = 0x80; + fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[8], 8); + break; + case LOWPAN_IPHC_ADDR_02: + /* fe:80::ff:fe00:XXXX */ + ipaddr->s6_addr[0] = 0xFE; + ipaddr->s6_addr[1] = 0x80; + ipaddr->s6_addr[11] = 0xFF; + ipaddr->s6_addr[12] = 0xFE; + fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[14], 2); + break; + case LOWPAN_IPHC_ADDR_03: + fail = false; + switch (addr_type) { + case IEEE802154_ADDR_LONG: + /* fe:80::XXXX:XXXX:XXXX:XXXX + * \_________________/ + * hwaddr + */ + ipaddr->s6_addr[0] = 0xFE; + ipaddr->s6_addr[1] = 0x80; + memcpy(&ipaddr->s6_addr[8], lladdr, addr_len); + /* second bit-flip (Universe/Local) + * is done according RFC2464 + */ + ipaddr->s6_addr[8] ^= 0x02; + break; + case IEEE802154_ADDR_SHORT: + /* fe:80::ff:fe00:XXXX + * \__/ + * short_addr + * + * Universe/Local bit is zero. + */ + ipaddr->s6_addr[0] = 0xFE; + ipaddr->s6_addr[1] = 0x80; + ipaddr->s6_addr[11] = 0xFF; + ipaddr->s6_addr[12] = 0xFE; + ipaddr->s6_addr16[7] = htons(*((u16 *)lladdr)); + break; + default: + pr_debug("Invalid addr_type set\n"); + return -EINVAL; + } + break; + default: + pr_debug("Invalid address mode value: 0x%x\n", address_mode); + return -EINVAL; + } + + if (fail) { + pr_debug("Failed to fetch skb data\n"); + return -EIO; + } + + raw_dump_inline(NULL, "Reconstructed ipv6 addr is", + ipaddr->s6_addr, 16); + + return 0; +} + +/* + * Uncompress address function for source context + * based address(non-multicast). + */ +static int uncompress_context_based_src_addr(struct sk_buff *skb, + struct in6_addr *ipaddr, + const u8 sam) +{ + switch (sam) { + case LOWPAN_IPHC_ADDR_00: + /* unspec address :: + * Do nothing, address is already :: + */ + break; + case LOWPAN_IPHC_ADDR_01: + /* TODO */ + case LOWPAN_IPHC_ADDR_02: + /* TODO */ + case LOWPAN_IPHC_ADDR_03: + /* TODO */ + netdev_warn(skb->dev, "SAM value 0x%x not supported\n", sam); + return -EINVAL; + default: + pr_debug("Invalid sam value: 0x%x\n", sam); + return -EINVAL; + } + + raw_dump_inline(NULL, + "Reconstructed context based ipv6 src addr is", + ipaddr->s6_addr, 16); + + return 0; +} + +static int skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr, + struct net_device *dev, skb_delivery_cb deliver_skb) +{ + struct sk_buff *new; + int stat; + + new = skb_copy_expand(skb, sizeof(struct ipv6hdr), skb_tailroom(skb), + GFP_ATOMIC); + kfree_skb(skb); + + if (!new) + return -ENOMEM; + + skb_push(new, sizeof(struct ipv6hdr)); + skb_reset_network_header(new); + skb_copy_to_linear_data(new, hdr, sizeof(struct ipv6hdr)); + + new->protocol = htons(ETH_P_IPV6); + new->pkt_type = PACKET_HOST; + new->dev = dev; + + raw_dump_table(__func__, "raw skb data dump before receiving", + new->data, new->len); + + stat = deliver_skb(new, dev); + + kfree_skb(new); + + return stat; +} + +/* Uncompress function for multicast destination address, + * when M bit is set. + */ +static int +lowpan_uncompress_multicast_daddr(struct sk_buff *skb, + struct in6_addr *ipaddr, + const u8 dam) +{ + bool fail; + + switch (dam) { + case LOWPAN_IPHC_DAM_00: + /* 00: 128 bits. The full address + * is carried in-line. + */ + fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16); + break; + case LOWPAN_IPHC_DAM_01: + /* 01: 48 bits. The address takes + * the form ffXX::00XX:XXXX:XXXX. + */ + ipaddr->s6_addr[0] = 0xFF; + fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1); + fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[11], 5); + break; + case LOWPAN_IPHC_DAM_10: + /* 10: 32 bits. The address takes + * the form ffXX::00XX:XXXX. + */ + ipaddr->s6_addr[0] = 0xFF; + fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1); + fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[13], 3); + break; + case LOWPAN_IPHC_DAM_11: + /* 11: 8 bits. The address takes + * the form ff02::00XX. + */ + ipaddr->s6_addr[0] = 0xFF; + ipaddr->s6_addr[1] = 0x02; + fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[15], 1); + break; + default: + pr_debug("DAM value has a wrong value: 0x%x\n", dam); + return -EINVAL; + } + + if (fail) { + pr_debug("Failed to fetch skb data\n"); + return -EIO; + } + + raw_dump_inline(NULL, "Reconstructed ipv6 multicast addr is", + ipaddr->s6_addr, 16); + + return 0; +} + +static int +uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh) +{ + u8 tmp; + + if (!uh) + goto err; + + if (lowpan_fetch_skb_u8(skb, &tmp)) + goto err; + + if ((tmp & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) { + pr_debug("UDP header uncompression\n"); + switch (tmp & LOWPAN_NHC_UDP_CS_P_11) { + case LOWPAN_NHC_UDP_CS_P_00: + memcpy(&uh->source, &skb->data[0], 2); + memcpy(&uh->dest, &skb->data[2], 2); + skb_pull(skb, 4); + break; + case LOWPAN_NHC_UDP_CS_P_01: + memcpy(&uh->source, &skb->data[0], 2); + uh->dest = + skb->data[2] + LOWPAN_NHC_UDP_8BIT_PORT; + skb_pull(skb, 3); + break; + case LOWPAN_NHC_UDP_CS_P_10: + uh->source = skb->data[0] + LOWPAN_NHC_UDP_8BIT_PORT; + memcpy(&uh->dest, &skb->data[1], 2); + skb_pull(skb, 3); + break; + case LOWPAN_NHC_UDP_CS_P_11: + uh->source = + LOWPAN_NHC_UDP_4BIT_PORT + (skb->data[0] >> 4); + uh->dest = + LOWPAN_NHC_UDP_4BIT_PORT + (skb->data[0] & 0x0f); + skb_pull(skb, 1); + break; + default: + pr_debug("ERROR: unknown UDP format\n"); + goto err; + break; + } + + pr_debug("uncompressed UDP ports: src = %d, dst = %d\n", + uh->source, uh->dest); + + /* copy checksum */ + memcpy(&uh->check, &skb->data[0], 2); + skb_pull(skb, 2); + + /* + * UDP lenght needs to be infered from the lower layers + * here, we obtain the hint from the remaining size of the + * frame + */ + uh->len = htons(skb->len + sizeof(struct udphdr)); + pr_debug("uncompressed UDP length: src = %d", uh->len); + } else { + pr_debug("ERROR: unsupported NH format\n"); + goto err; + } + + return 0; +err: + return -EINVAL; +} + +/* TTL uncompression values */ +static const u8 lowpan_ttl_values[] = { 0, 1, 64, 255 }; + +int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, + const u8 *saddr, const u8 saddr_type, const u8 saddr_len, + const u8 *daddr, const u8 daddr_type, const u8 daddr_len, + u8 iphc0, u8 iphc1, skb_delivery_cb deliver_skb) +{ + struct ipv6hdr hdr = {}; + u8 tmp, num_context = 0; + int err; + + raw_dump_table(__func__, "raw skb data dump uncompressed", + skb->data, skb->len); + + /* another if the CID flag is set */ + if (iphc1 & LOWPAN_IPHC_CID) { + pr_debug("CID flag is set, increase header with one\n"); + if (lowpan_fetch_skb_u8(skb, &num_context)) + goto drop; + } + + hdr.version = 6; + + /* Traffic Class and Flow Label */ + switch ((iphc0 & LOWPAN_IPHC_TF) >> 3) { + /* + * Traffic Class and FLow Label carried in-line + * ECN + DSCP + 4-bit Pad + Flow Label (4 bytes) + */ + case 0: /* 00b */ + if (lowpan_fetch_skb_u8(skb, &tmp)) + goto drop; + + memcpy(&hdr.flow_lbl, &skb->data[0], 3); + skb_pull(skb, 3); + hdr.priority = ((tmp >> 2) & 0x0f); + hdr.flow_lbl[0] = ((tmp >> 2) & 0x30) | (tmp << 6) | + (hdr.flow_lbl[0] & 0x0f); + break; + /* + * Traffic class carried in-line + * ECN + DSCP (1 byte), Flow Label is elided + */ + case 2: /* 10b */ + if (lowpan_fetch_skb_u8(skb, &tmp)) + goto drop; + + hdr.priority = ((tmp >> 2) & 0x0f); + hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 0x30); + break; + /* + * Flow Label carried in-line + * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided + */ + case 1: /* 01b */ + if (lowpan_fetch_skb_u8(skb, &tmp)) + goto drop; + + hdr.flow_lbl[0] = (skb->data[0] & 0x0F) | ((tmp >> 2) & 0x30); + memcpy(&hdr.flow_lbl[1], &skb->data[0], 2); + skb_pull(skb, 2); + break; + /* Traffic Class and Flow Label are elided */ + case 3: /* 11b */ + break; + default: + break; + } + + /* Next Header */ + if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) { + /* Next header is carried inline */ + if (lowpan_fetch_skb_u8(skb, &(hdr.nexthdr))) + goto drop; + + pr_debug("NH flag is set, next header carried inline: %02x\n", + hdr.nexthdr); + } + + /* Hop Limit */ + if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I) + hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03]; + else { + if (lowpan_fetch_skb_u8(skb, &(hdr.hop_limit))) + goto drop; + } + + /* Extract SAM to the tmp variable */ + tmp = ((iphc1 & LOWPAN_IPHC_SAM) >> LOWPAN_IPHC_SAM_BIT) & 0x03; + + if (iphc1 & LOWPAN_IPHC_SAC) { + /* Source address context based uncompression */ + pr_debug("SAC bit is set. Handle context based source address.\n"); + err = uncompress_context_based_src_addr( + skb, &hdr.saddr, tmp); + } else { + /* Source address uncompression */ + pr_debug("source address stateless compression\n"); + err = uncompress_addr(skb, &hdr.saddr, tmp, saddr, + saddr_type, saddr_len); + } + + /* Check on error of previous branch */ + if (err) + goto drop; + + /* Extract DAM to the tmp variable */ + tmp = ((iphc1 & LOWPAN_IPHC_DAM_11) >> LOWPAN_IPHC_DAM_BIT) & 0x03; + + /* check for Multicast Compression */ + if (iphc1 & LOWPAN_IPHC_M) { + if (iphc1 & LOWPAN_IPHC_DAC) { + pr_debug("dest: context-based mcast compression\n"); + /* TODO: implement this */ + } else { + err = lowpan_uncompress_multicast_daddr( + skb, &hdr.daddr, tmp); + if (err) + goto drop; + } + } else { + err = uncompress_addr(skb, &hdr.daddr, tmp, daddr, + daddr_type, daddr_len); + pr_debug("dest: stateless compression mode %d dest %pI6c\n", + tmp, &hdr.daddr); + if (err) + goto drop; + } + + /* UDP data uncompression */ + if (iphc0 & LOWPAN_IPHC_NH_C) { + struct udphdr uh; + struct sk_buff *new; + if (uncompress_udp_header(skb, &uh)) + goto drop; + + /* + * replace the compressed UDP head by the uncompressed UDP + * header + */ + new = skb_copy_expand(skb, sizeof(struct udphdr), + skb_tailroom(skb), GFP_ATOMIC); + kfree_skb(skb); + + if (!new) + return -ENOMEM; + + skb = new; + + skb_push(skb, sizeof(struct udphdr)); + skb_reset_transport_header(skb); + skb_copy_to_linear_data(skb, &uh, sizeof(struct udphdr)); + + raw_dump_table(__func__, "raw UDP header dump", + (u8 *)&uh, sizeof(uh)); + + hdr.nexthdr = UIP_PROTO_UDP; + } + + hdr.payload_len = htons(skb->len); + + pr_debug("skb headroom size = %d, data length = %d\n", + skb_headroom(skb), skb->len); + + pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength = %d\n\t" + "nexthdr = 0x%02x\n\thop_lim = %d\n\tdest = %pI6c\n", + hdr.version, ntohs(hdr.payload_len), hdr.nexthdr, + hdr.hop_limit, &hdr.daddr); + + raw_dump_table(__func__, "raw header dump", (u8 *)&hdr, + sizeof(hdr)); + + return skb_deliver(skb, &hdr, dev, deliver_skb); + +drop: + kfree_skb(skb); + return -EINVAL; +} +EXPORT_SYMBOL_GPL(lowpan_process_data); + +static u8 lowpan_compress_addr_64(u8 **hc06_ptr, u8 shift, + const struct in6_addr *ipaddr, + const unsigned char *lladdr) +{ + u8 val = 0; + + if (is_addr_mac_addr_based(ipaddr, lladdr)) { + val = 3; /* 0-bits */ + pr_debug("address compression 0 bits\n"); + } else if (lowpan_is_iid_16_bit_compressable(ipaddr)) { + /* compress IID to 16 bits xxxx::XXXX */ + memcpy(*hc06_ptr, &ipaddr->s6_addr16[7], 2); + *hc06_ptr += 2; + val = 2; /* 16-bits */ + raw_dump_inline(NULL, "Compressed ipv6 addr is (16 bits)", + *hc06_ptr - 2, 2); + } else { + /* do not compress IID => xxxx::IID */ + memcpy(*hc06_ptr, &ipaddr->s6_addr16[4], 8); + *hc06_ptr += 8; + val = 1; /* 64-bits */ + raw_dump_inline(NULL, "Compressed ipv6 addr is (64 bits)", + *hc06_ptr - 8, 8); + } + + return rol8(val, shift); +} + +static void compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb) +{ + struct udphdr *uh = udp_hdr(skb); + + if (((uh->source & LOWPAN_NHC_UDP_4BIT_MASK) == + LOWPAN_NHC_UDP_4BIT_PORT) && + ((uh->dest & LOWPAN_NHC_UDP_4BIT_MASK) == + LOWPAN_NHC_UDP_4BIT_PORT)) { + pr_debug("UDP header: both ports compression to 4 bits\n"); + **hc06_ptr = LOWPAN_NHC_UDP_CS_P_11; + **(hc06_ptr + 1) = /* subtraction is faster */ + (u8)((uh->dest - LOWPAN_NHC_UDP_4BIT_PORT) + + ((uh->source & LOWPAN_NHC_UDP_4BIT_PORT) << 4)); + *hc06_ptr += 2; + } else if ((uh->dest & LOWPAN_NHC_UDP_8BIT_MASK) == + LOWPAN_NHC_UDP_8BIT_PORT) { + pr_debug("UDP header: remove 8 bits of dest\n"); + **hc06_ptr = LOWPAN_NHC_UDP_CS_P_01; + memcpy(*hc06_ptr + 1, &uh->source, 2); + **(hc06_ptr + 3) = (u8)(uh->dest - LOWPAN_NHC_UDP_8BIT_PORT); + *hc06_ptr += 4; + } else if ((uh->source & LOWPAN_NHC_UDP_8BIT_MASK) == + LOWPAN_NHC_UDP_8BIT_PORT) { + pr_debug("UDP header: remove 8 bits of source\n"); + **hc06_ptr = LOWPAN_NHC_UDP_CS_P_10; + memcpy(*hc06_ptr + 1, &uh->dest, 2); + **(hc06_ptr + 3) = (u8)(uh->source - LOWPAN_NHC_UDP_8BIT_PORT); + *hc06_ptr += 4; + } else { + pr_debug("UDP header: can't compress\n"); + **hc06_ptr = LOWPAN_NHC_UDP_CS_P_00; + memcpy(*hc06_ptr + 1, &uh->source, 2); + memcpy(*hc06_ptr + 3, &uh->dest, 2); + *hc06_ptr += 5; + } + + /* checksum is always inline */ + memcpy(*hc06_ptr, &uh->check, 2); + *hc06_ptr += 2; + + /* skip the UDP header */ + skb_pull(skb, sizeof(struct udphdr)); +} + +int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, + unsigned short type, const void *_daddr, + const void *_saddr, unsigned int len) +{ + u8 tmp, iphc0, iphc1, *hc06_ptr; + struct ipv6hdr *hdr; + u8 head[100] = {}; + + if (type != ETH_P_IPV6) + return -EINVAL; + + hdr = ipv6_hdr(skb); + hc06_ptr = head + 2; + + pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength = %d\n" + "\tnexthdr = 0x%02x\n\thop_lim = %d\n\tdest = %pI6c\n", + hdr->version, ntohs(hdr->payload_len), hdr->nexthdr, + hdr->hop_limit, &hdr->daddr); + + raw_dump_table(__func__, "raw skb network header dump", + skb_network_header(skb), sizeof(struct ipv6hdr)); + + /* + * As we copy some bit-length fields, in the IPHC encoding bytes, + * we sometimes use |= + * If the field is 0, and the current bit value in memory is 1, + * this does not work. We therefore reset the IPHC encoding here + */ + iphc0 = LOWPAN_DISPATCH_IPHC; + iphc1 = 0; + + /* TODO: context lookup */ + + raw_dump_inline(__func__, "saddr", + (unsigned char *)_saddr, IEEE802154_ADDR_LEN); + raw_dump_inline(__func__, "daddr", + (unsigned char *)_daddr, IEEE802154_ADDR_LEN); + + raw_dump_table(__func__, + "sending raw skb network uncompressed packet", + skb->data, skb->len); + + /* + * Traffic class, flow label + * If flow label is 0, compress it. If traffic class is 0, compress it + * We have to process both in the same time as the offset of traffic + * class depends on the presence of version and flow label + */ + + /* hc06 format of TC is ECN | DSCP , original one is DSCP | ECN */ + tmp = (hdr->priority << 4) | (hdr->flow_lbl[0] >> 4); + tmp = ((tmp & 0x03) << 6) | (tmp >> 2); + + if (((hdr->flow_lbl[0] & 0x0F) == 0) && + (hdr->flow_lbl[1] == 0) && (hdr->flow_lbl[2] == 0)) { + /* flow label can be compressed */ + iphc0 |= LOWPAN_IPHC_FL_C; + if ((hdr->priority == 0) && + ((hdr->flow_lbl[0] & 0xF0) == 0)) { + /* compress (elide) all */ + iphc0 |= LOWPAN_IPHC_TC_C; + } else { + /* compress only the flow label */ + *hc06_ptr = tmp; + hc06_ptr += 1; + } + } else { + /* Flow label cannot be compressed */ + if ((hdr->priority == 0) && + ((hdr->flow_lbl[0] & 0xF0) == 0)) { + /* compress only traffic class */ + iphc0 |= LOWPAN_IPHC_TC_C; + *hc06_ptr = (tmp & 0xc0) | (hdr->flow_lbl[0] & 0x0F); + memcpy(hc06_ptr + 1, &hdr->flow_lbl[1], 2); + hc06_ptr += 3; + } else { + /* compress nothing */ + memcpy(hc06_ptr, &hdr, 4); + /* replace the top byte with new ECN | DSCP format */ + *hc06_ptr = tmp; + hc06_ptr += 4; + } + } + + /* NOTE: payload length is always compressed */ + + /* Next Header is compress if UDP */ + if (hdr->nexthdr == UIP_PROTO_UDP) + iphc0 |= LOWPAN_IPHC_NH_C; + + if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) { + *hc06_ptr = hdr->nexthdr; + hc06_ptr += 1; + } + + /* + * Hop limit + * if 1: compress, encoding is 01 + * if 64: compress, encoding is 10 + * if 255: compress, encoding is 11 + * else do not compress + */ + switch (hdr->hop_limit) { + case 1: + iphc0 |= LOWPAN_IPHC_TTL_1; + break; + case 64: + iphc0 |= LOWPAN_IPHC_TTL_64; + break; + case 255: + iphc0 |= LOWPAN_IPHC_TTL_255; + break; + default: + *hc06_ptr = hdr->hop_limit; + hc06_ptr += 1; + break; + } + + /* source address compression */ + if (is_addr_unspecified(&hdr->saddr)) { + pr_debug("source address is unspecified, setting SAC\n"); + iphc1 |= LOWPAN_IPHC_SAC; + /* TODO: context lookup */ + } else if (is_addr_link_local(&hdr->saddr)) { + iphc1 |= lowpan_compress_addr_64(&hc06_ptr, + LOWPAN_IPHC_SAM_BIT, &hdr->saddr, _saddr); + pr_debug("source address unicast link-local %pI6c " + "iphc1 0x%02x\n", &hdr->saddr, iphc1); + } else { + pr_debug("send the full source address\n"); + memcpy(hc06_ptr, &hdr->saddr.s6_addr16[0], 16); + hc06_ptr += 16; + } + + /* destination address compression */ + if (is_addr_mcast(&hdr->daddr)) { + pr_debug("destination address is multicast: "); + iphc1 |= LOWPAN_IPHC_M; + if (lowpan_is_mcast_addr_compressable8(&hdr->daddr)) { + pr_debug("compressed to 1 octet\n"); + iphc1 |= LOWPAN_IPHC_DAM_11; + /* use last byte */ + *hc06_ptr = hdr->daddr.s6_addr[15]; + hc06_ptr += 1; + } else if (lowpan_is_mcast_addr_compressable32(&hdr->daddr)) { + pr_debug("compressed to 4 octets\n"); + iphc1 |= LOWPAN_IPHC_DAM_10; + /* second byte + the last three */ + *hc06_ptr = hdr->daddr.s6_addr[1]; + memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[13], 3); + hc06_ptr += 4; + } else if (lowpan_is_mcast_addr_compressable48(&hdr->daddr)) { + pr_debug("compressed to 6 octets\n"); + iphc1 |= LOWPAN_IPHC_DAM_01; + /* second byte + the last five */ + *hc06_ptr = hdr->daddr.s6_addr[1]; + memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[11], 5); + hc06_ptr += 6; + } else { + pr_debug("using full address\n"); + iphc1 |= LOWPAN_IPHC_DAM_00; + memcpy(hc06_ptr, &hdr->daddr.s6_addr[0], 16); + hc06_ptr += 16; + } + } else { + /* TODO: context lookup */ + if (is_addr_link_local(&hdr->daddr)) { + iphc1 |= lowpan_compress_addr_64(&hc06_ptr, + LOWPAN_IPHC_DAM_BIT, &hdr->daddr, _daddr); + pr_debug("dest address unicast link-local %pI6c " + "iphc1 0x%02x\n", &hdr->daddr, iphc1); + } else { + pr_debug("dest address unicast %pI6c\n", &hdr->daddr); + memcpy(hc06_ptr, &hdr->daddr.s6_addr16[0], 16); + hc06_ptr += 16; + } + } + + /* UDP header compression */ + if (hdr->nexthdr == UIP_PROTO_UDP) + compress_udp_header(&hc06_ptr, skb); + + head[0] = iphc0; + head[1] = iphc1; + + skb_pull(skb, sizeof(struct ipv6hdr)); + skb_reset_transport_header(skb); + memcpy(skb_push(skb, hc06_ptr - head), head, hc06_ptr - head); + skb_reset_network_header(skb); + + pr_debug("header len %d skb %u\n", (int)(hc06_ptr - head), skb->len); + + raw_dump_table(__func__, "raw skb data dump compressed", + skb->data, skb->len); + return 0; +} +EXPORT_SYMBOL_GPL(lowpan_header_compress); diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile index d7716d64c6b..951a83ee8af 100644 --- a/net/ieee802154/Makefile +++ b/net/ieee802154/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_IEEE802154) += ieee802154.o af_802154.o -obj-$(CONFIG_IEEE802154_6LOWPAN) += 6lowpan.o +obj-$(CONFIG_IEEE802154_6LOWPAN) += 6lowpan.o 6lowpan_iphc.o ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o wpan-class.o af_802154-y := af_ieee802154.o raw.o dgram.o -- cgit v1.2.3-70-g09d2 From 0abc652c796dab74d34d60473ec5594cd21620be Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 11 Dec 2013 17:05:35 +0200 Subject: net: if_arp: add ARPHRD_6LOWPAN type Used for IPv6 over LoWPAN networks. Example of this is Bluetooth 6LoWPAN network. Signed-off-by: Jukka Rissanen Acked-by: David S. Miller Signed-off-by: Marcel Holtmann --- include/uapi/linux/if_arp.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/uapi/linux/if_arp.h b/include/uapi/linux/if_arp.h index d7fea3496f3..4d024d75d64 100644 --- a/include/uapi/linux/if_arp.h +++ b/include/uapi/linux/if_arp.h @@ -94,6 +94,7 @@ #define ARPHRD_CAIF 822 /* CAIF media type */ #define ARPHRD_IP6GRE 823 /* GRE over IPv6 */ #define ARPHRD_NETLINK 824 /* Netlink header */ +#define ARPHRD_6LOWPAN 825 /* IPv6 over LoWPAN */ #define ARPHRD_VOID 0xFFFF /* Void type, nothing is known */ #define ARPHRD_NONE 0xFFFE /* zero header length */ -- cgit v1.2.3-70-g09d2 From e74bccb8a598c37840b547a7d606bd8c959cc2e4 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 11 Dec 2013 17:05:36 +0200 Subject: ipv6: Add checks for 6LOWPAN ARP type Signed-off-by: Jukka Rissanen Acked-by: David S. Miller Signed-off-by: Marcel Holtmann --- net/ipv6/addrconf.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 12c97d8aa6b..d125fcdefb7 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1816,6 +1816,7 @@ static int ipv6_generate_eui64(u8 *eui, struct net_device *dev) return addrconf_ifid_sit(eui, dev); case ARPHRD_IPGRE: return addrconf_ifid_gre(eui, dev); + case ARPHRD_6LOWPAN: case ARPHRD_IEEE802154: return addrconf_ifid_eui64(eui, dev); case ARPHRD_IEEE1394: @@ -2658,7 +2659,8 @@ static void addrconf_dev_config(struct net_device *dev) (dev->type != ARPHRD_INFINIBAND) && (dev->type != ARPHRD_IEEE802154) && (dev->type != ARPHRD_IEEE1394) && - (dev->type != ARPHRD_TUNNEL6)) { + (dev->type != ARPHRD_TUNNEL6) && + (dev->type != ARPHRD_6LOWPAN)) { /* Alas, we support only Ethernet autoconfiguration. */ return; } -- cgit v1.2.3-70-g09d2 From 18722c247023035b9e2e2a08a887adec2a9a6e49 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 11 Dec 2013 17:05:37 +0200 Subject: Bluetooth: Enable 6LoWPAN support for BT LE devices This is initial version of http://tools.ietf.org/html/draft-ietf-6lo-btle-00 By default the 6LoWPAN support is not activated and user needs to tweak /sys/kernel/debug/bluetooth/hci0/6lowpan file. The kernel needs IPv6 support before 6LoWPAN is usable. Signed-off-by: Jukka Rissanen Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 1 + include/net/bluetooth/hci_core.h | 1 + include/net/bluetooth/l2cap.h | 1 + net/bluetooth/6lowpan.c | 886 +++++++++++++++++++++++++++++++++++++++ net/bluetooth/6lowpan.h | 26 ++ net/bluetooth/Makefile | 6 +- net/bluetooth/hci_event.c | 3 + net/bluetooth/l2cap_core.c | 12 + 8 files changed, 935 insertions(+), 1 deletion(-) create mode 100644 net/bluetooth/6lowpan.c create mode 100644 net/bluetooth/6lowpan.h diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index cc2da73055f..5dc3d907265 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -131,6 +131,7 @@ enum { HCI_PERIODIC_INQ, HCI_FAST_CONNECTABLE, HCI_BREDR_ENABLED, + HCI_6LOWPAN_ENABLED, }; /* A mask for the flags that are supposed to remain when a reset happens diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index b796161fb04..f2f0cf5865c 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -448,6 +448,7 @@ enum { HCI_CONN_SSP_ENABLED, HCI_CONN_POWER_SAVE, HCI_CONN_REMOTE_OOB, + HCI_CONN_6LOWPAN, }; static inline bool hci_conn_ssp_enabled(struct hci_conn *conn) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index e149e992fda..dbc4a89984c 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -136,6 +136,7 @@ struct l2cap_conninfo { #define L2CAP_FC_L2CAP 0x02 #define L2CAP_FC_CONNLESS 0x04 #define L2CAP_FC_A2MP 0x08 +#define L2CAP_FC_6LOWPAN 0x3e /* reserved and temporary value */ /* L2CAP Control Field bit masks */ #define L2CAP_CTRL_SAR 0xC000 diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c new file mode 100644 index 00000000000..ba840fe2c55 --- /dev/null +++ b/net/bluetooth/6lowpan.c @@ -0,0 +1,886 @@ +/* + Copyright (c) 2013 Intel Corp. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 and + only version 2 as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +*/ + +#include +#include +#include +#include + +#include +#include +#include + +#include /* to get the address type */ + +#include +#include +#include + +#include "../ieee802154/6lowpan.h" /* for the compression support */ + +#define IFACE_NAME_TEMPLATE "bt%d" +#define EUI64_ADDR_LEN 8 + +struct skb_cb { + struct in6_addr addr; + struct l2cap_conn *conn; +}; +#define lowpan_cb(skb) ((struct skb_cb *)((skb)->cb)) + +/* The devices list contains those devices that we are acting + * as a proxy. The BT 6LoWPAN device is a virtual device that + * connects to the Bluetooth LE device. The real connection to + * BT device is done via l2cap layer. There exists one + * virtual device / one BT 6LoWPAN network (=hciX device). + * The list contains struct lowpan_dev elements. + */ +static LIST_HEAD(bt_6lowpan_devices); +static DEFINE_RWLOCK(devices_lock); + +struct lowpan_peer { + struct list_head list; + struct l2cap_conn *conn; + + /* peer addresses in various formats */ + unsigned char eui64_addr[EUI64_ADDR_LEN]; + struct in6_addr peer_addr; +}; + +struct lowpan_dev { + struct list_head list; + + struct hci_dev *hdev; + struct net_device *netdev; + struct list_head peers; + atomic_t peer_count; /* number of items in peers list */ + + struct work_struct delete_netdev; + struct delayed_work notify_peers; +}; + +static inline struct lowpan_dev *lowpan_dev(const struct net_device *netdev) +{ + return netdev_priv(netdev); +} + +static inline void peer_add(struct lowpan_dev *dev, struct lowpan_peer *peer) +{ + list_add(&peer->list, &dev->peers); + atomic_inc(&dev->peer_count); +} + +static inline bool peer_del(struct lowpan_dev *dev, struct lowpan_peer *peer) +{ + list_del(&peer->list); + + if (atomic_dec_and_test(&dev->peer_count)) { + BT_DBG("last peer"); + return true; + } + + return false; +} + +static inline struct lowpan_peer *peer_lookup_ba(struct lowpan_dev *dev, + bdaddr_t *ba, __u8 type) +{ + struct lowpan_peer *peer, *tmp; + + BT_DBG("peers %d addr %pMR type %d", atomic_read(&dev->peer_count), + ba, type); + + list_for_each_entry_safe(peer, tmp, &dev->peers, list) { + BT_DBG("addr %pMR type %d", + &peer->conn->hcon->dst, peer->conn->hcon->dst_type); + + if (bacmp(&peer->conn->hcon->dst, ba)) + continue; + + if (type == peer->conn->hcon->dst_type) + return peer; + } + + return NULL; +} + +static inline struct lowpan_peer *peer_lookup_conn(struct lowpan_dev *dev, + struct l2cap_conn *conn) +{ + struct lowpan_peer *peer, *tmp; + + list_for_each_entry_safe(peer, tmp, &dev->peers, list) { + if (peer->conn == conn) + return peer; + } + + return NULL; +} + +static struct lowpan_peer *lookup_peer(struct l2cap_conn *conn) +{ + struct lowpan_dev *entry, *tmp; + struct lowpan_peer *peer = NULL; + unsigned long flags; + + read_lock_irqsave(&devices_lock, flags); + + list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) { + peer = peer_lookup_conn(entry, conn); + if (peer) + break; + } + + read_unlock_irqrestore(&devices_lock, flags); + + return peer; +} + +static struct lowpan_dev *lookup_dev(struct l2cap_conn *conn) +{ + struct lowpan_dev *entry, *tmp; + struct lowpan_dev *dev = NULL; + unsigned long flags; + + read_lock_irqsave(&devices_lock, flags); + + list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) { + if (conn->hcon->hdev == entry->hdev) { + dev = entry; + break; + } + } + + read_unlock_irqrestore(&devices_lock, flags); + + return dev; +} + +/* print data in line */ +static inline void raw_dump_inline(const char *caller, char *msg, + unsigned char *buf, int len) +{ + if (msg) + pr_debug("%s():%s: ", caller, msg); + + print_hex_dump_debug("", DUMP_PREFIX_NONE, + 16, 1, buf, len, false); +} + +/* print data in a table format: + * + * addr: xx xx xx xx xx xx + * addr: xx xx xx xx xx xx + * ... + */ +static inline void raw_dump_table(const char *caller, char *msg, + unsigned char *buf, int len) +{ + if (msg) + pr_debug("%s():%s:\n", caller, msg); + + print_hex_dump_debug("\t", DUMP_PREFIX_OFFSET, + 16, 1, buf, len, false); +} + +static int give_skb_to_upper(struct sk_buff *skb, struct net_device *dev) +{ + struct sk_buff *skb_cp; + int ret; + + skb_cp = skb_copy(skb, GFP_ATOMIC); + if (!skb_cp) + return -ENOMEM; + + ret = netif_rx(skb_cp); + + BT_DBG("receive skb %d", ret); + if (ret < 0) + return NET_RX_DROP; + + return ret; +} + +static int process_data(struct sk_buff *skb, struct net_device *netdev, + struct l2cap_conn *conn) +{ + const u8 *saddr, *daddr; + u8 iphc0, iphc1; + struct lowpan_dev *dev; + struct lowpan_peer *peer; + unsigned long flags; + + dev = lowpan_dev(netdev); + + read_lock_irqsave(&devices_lock, flags); + peer = peer_lookup_conn(dev, conn); + read_unlock_irqrestore(&devices_lock, flags); + if (!peer) + goto drop; + + saddr = peer->eui64_addr; + daddr = dev->netdev->dev_addr; + + /* at least two bytes will be used for the encoding */ + if (skb->len < 2) + goto drop; + + if (lowpan_fetch_skb_u8(skb, &iphc0)) + goto drop; + + if (lowpan_fetch_skb_u8(skb, &iphc1)) + goto drop; + + return lowpan_process_data(skb, netdev, + saddr, IEEE802154_ADDR_LONG, EUI64_ADDR_LEN, + daddr, IEEE802154_ADDR_LONG, EUI64_ADDR_LEN, + iphc0, iphc1, give_skb_to_upper); + +drop: + kfree_skb(skb); + return -EINVAL; +} + +static int recv_pkt(struct sk_buff *skb, struct net_device *dev, + struct l2cap_conn *conn) +{ + struct sk_buff *local_skb; + int ret; + + if (!netif_running(dev)) + goto drop; + + if (dev->type != ARPHRD_6LOWPAN) + goto drop; + + /* check that it's our buffer */ + if (skb->data[0] == LOWPAN_DISPATCH_IPV6) { + /* Copy the packet so that the IPv6 header is + * properly aligned. + */ + local_skb = skb_copy_expand(skb, NET_SKB_PAD - 1, + skb_tailroom(skb), GFP_ATOMIC); + if (!local_skb) + goto drop; + + local_skb->protocol = htons(ETH_P_IPV6); + local_skb->pkt_type = PACKET_HOST; + + skb_reset_network_header(local_skb); + skb_set_transport_header(local_skb, sizeof(struct ipv6hdr)); + + if (give_skb_to_upper(local_skb, dev) != NET_RX_SUCCESS) { + kfree_skb(local_skb); + goto drop; + } + + dev->stats.rx_bytes += skb->len; + dev->stats.rx_packets++; + + kfree_skb(local_skb); + kfree_skb(skb); + } else { + switch (skb->data[0] & 0xe0) { + case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */ + local_skb = skb_clone(skb, GFP_ATOMIC); + if (!local_skb) + goto drop; + + ret = process_data(local_skb, dev, conn); + if (ret != NET_RX_SUCCESS) + goto drop; + + dev->stats.rx_bytes += skb->len; + dev->stats.rx_packets++; + + kfree_skb(skb); + break; + default: + break; + } + } + + return NET_RX_SUCCESS; + +drop: + kfree_skb(skb); + return NET_RX_DROP; +} + +/* Packet from BT LE device */ +int bt_6lowpan_recv(struct l2cap_conn *conn, struct sk_buff *skb) +{ + struct lowpan_dev *dev; + struct lowpan_peer *peer; + int err; + + peer = lookup_peer(conn); + if (!peer) + return -ENOENT; + + dev = lookup_dev(conn); + if (dev && !dev->netdev) + return -ENOENT; + + err = recv_pkt(skb, dev->netdev, conn); + BT_DBG("recv pkt %d", err); + + return err; +} + +static inline int skbuff_copy(void *msg, int len, int count, int mtu, + struct sk_buff *skb, struct net_device *dev) +{ + struct sk_buff **frag; + int sent = 0; + + memcpy(skb_put(skb, count), msg, count); + + sent += count; + msg += count; + len -= count; + + dev->stats.tx_bytes += count; + dev->stats.tx_packets++; + + raw_dump_table(__func__, "Sending", skb->data, skb->len); + + /* Continuation fragments (no L2CAP header) */ + frag = &skb_shinfo(skb)->frag_list; + while (len > 0) { + struct sk_buff *tmp; + + count = min_t(unsigned int, mtu, len); + + tmp = bt_skb_alloc(count, GFP_ATOMIC); + if (IS_ERR(tmp)) + return PTR_ERR(tmp); + + *frag = tmp; + + memcpy(skb_put(*frag, count), msg, count); + + raw_dump_table(__func__, "Sending fragment", + (*frag)->data, count); + + (*frag)->priority = skb->priority; + + sent += count; + msg += count; + len -= count; + + skb->len += (*frag)->len; + skb->data_len += (*frag)->len; + + frag = &(*frag)->next; + + dev->stats.tx_bytes += count; + dev->stats.tx_packets++; + } + + return sent; +} + +static struct sk_buff *create_pdu(struct l2cap_conn *conn, void *msg, + size_t len, u32 priority, + struct net_device *dev) +{ + struct sk_buff *skb; + int err, count; + struct l2cap_hdr *lh; + + /* FIXME: This mtu check should be not needed and atm is only used for + * testing purposes + */ + if (conn->mtu > (L2CAP_LE_MIN_MTU + L2CAP_HDR_SIZE)) + conn->mtu = L2CAP_LE_MIN_MTU + L2CAP_HDR_SIZE; + + count = min_t(unsigned int, (conn->mtu - L2CAP_HDR_SIZE), len); + + BT_DBG("conn %p len %zu mtu %d count %d", conn, len, conn->mtu, count); + + skb = bt_skb_alloc(count + L2CAP_HDR_SIZE, GFP_ATOMIC); + if (IS_ERR(skb)) + return skb; + + skb->priority = priority; + + lh = (struct l2cap_hdr *)skb_put(skb, L2CAP_HDR_SIZE); + lh->cid = cpu_to_le16(L2CAP_FC_6LOWPAN); + lh->len = cpu_to_le16(len); + + err = skbuff_copy(msg, len, count, conn->mtu, skb, dev); + if (unlikely(err < 0)) { + kfree_skb(skb); + BT_DBG("skbuff copy %d failed", err); + return ERR_PTR(err); + } + + return skb; +} + +static int conn_send(struct l2cap_conn *conn, + void *msg, size_t len, u32 priority, + struct net_device *dev) +{ + struct sk_buff *skb; + + skb = create_pdu(conn, msg, len, priority, dev); + if (IS_ERR(skb)) + return -EINVAL; + + BT_DBG("conn %p skb %p len %d priority %u", conn, skb, skb->len, + skb->priority); + + hci_send_acl(conn->hchan, skb, ACL_START); + + return 0; +} + +static void get_dest_bdaddr(struct in6_addr *ip6_daddr, + bdaddr_t *addr, u8 *addr_type) +{ + u8 *eui64; + + eui64 = ip6_daddr->s6_addr + 8; + + addr->b[0] = eui64[7]; + addr->b[1] = eui64[6]; + addr->b[2] = eui64[5]; + addr->b[3] = eui64[2]; + addr->b[4] = eui64[1]; + addr->b[5] = eui64[0]; + + addr->b[5] ^= 2; + + /* Set universal/local bit to 0 */ + if (addr->b[5] & 1) { + addr->b[5] &= ~1; + *addr_type = BDADDR_LE_PUBLIC; + } else { + *addr_type = BDADDR_LE_RANDOM; + } +} + +static int header_create(struct sk_buff *skb, struct net_device *netdev, + unsigned short type, const void *_daddr, + const void *_saddr, unsigned int len) +{ + struct ipv6hdr *hdr; + struct lowpan_dev *dev; + struct lowpan_peer *peer; + bdaddr_t addr, *any = BDADDR_ANY; + u8 *saddr, *daddr = any->b; + u8 addr_type; + + if (type != ETH_P_IPV6) + return -EINVAL; + + hdr = ipv6_hdr(skb); + + dev = lowpan_dev(netdev); + + if (ipv6_addr_is_multicast(&hdr->daddr)) { + memcpy(&lowpan_cb(skb)->addr, &hdr->daddr, + sizeof(struct in6_addr)); + lowpan_cb(skb)->conn = NULL; + } else { + unsigned long flags; + + /* Get destination BT device from skb. + * If there is no such peer then discard the packet. + */ + get_dest_bdaddr(&hdr->daddr, &addr, &addr_type); + + BT_DBG("dest addr %pMR type %d", &addr, addr_type); + + read_lock_irqsave(&devices_lock, flags); + peer = peer_lookup_ba(dev, &addr, addr_type); + read_unlock_irqrestore(&devices_lock, flags); + + if (!peer) { + BT_DBG("no such peer %pMR found", &addr); + return -ENOENT; + } + + daddr = peer->eui64_addr; + + memcpy(&lowpan_cb(skb)->addr, &hdr->daddr, + sizeof(struct in6_addr)); + lowpan_cb(skb)->conn = peer->conn; + } + + saddr = dev->netdev->dev_addr; + + return lowpan_header_compress(skb, netdev, type, daddr, saddr, len); +} + +/* Packet to BT LE device */ +static int send_pkt(struct l2cap_conn *conn, const void *saddr, + const void *daddr, struct sk_buff *skb, + struct net_device *netdev) +{ + raw_dump_table(__func__, "raw skb data dump before fragmentation", + skb->data, skb->len); + + return conn_send(conn, skb->data, skb->len, 0, netdev); +} + +static void send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev) +{ + struct sk_buff *local_skb; + struct lowpan_dev *entry, *tmp; + unsigned long flags; + + read_lock_irqsave(&devices_lock, flags); + + list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) { + struct lowpan_peer *pentry, *ptmp; + struct lowpan_dev *dev; + + if (entry->netdev != netdev) + continue; + + dev = lowpan_dev(entry->netdev); + + list_for_each_entry_safe(pentry, ptmp, &dev->peers, list) { + local_skb = skb_clone(skb, GFP_ATOMIC); + + send_pkt(pentry->conn, netdev->dev_addr, + pentry->eui64_addr, local_skb, netdev); + + kfree_skb(local_skb); + } + } + + read_unlock_irqrestore(&devices_lock, flags); +} + +static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev) +{ + int err = 0; + unsigned char *eui64_addr; + struct lowpan_dev *dev; + struct lowpan_peer *peer; + bdaddr_t addr; + u8 addr_type; + + if (ipv6_addr_is_multicast(&lowpan_cb(skb)->addr)) { + /* We need to send the packet to every device + * behind this interface. + */ + send_mcast_pkt(skb, netdev); + } else { + unsigned long flags; + + get_dest_bdaddr(&lowpan_cb(skb)->addr, &addr, &addr_type); + eui64_addr = lowpan_cb(skb)->addr.s6_addr + 8; + dev = lowpan_dev(netdev); + + read_lock_irqsave(&devices_lock, flags); + peer = peer_lookup_ba(dev, &addr, addr_type); + read_unlock_irqrestore(&devices_lock, flags); + + BT_DBG("xmit from %s to %pMR (%pI6c) peer %p", netdev->name, + &addr, &lowpan_cb(skb)->addr, peer); + + if (peer && peer->conn) + err = send_pkt(peer->conn, netdev->dev_addr, + eui64_addr, skb, netdev); + } + dev_kfree_skb(skb); + + if (err) + BT_DBG("ERROR: xmit failed (%d)", err); + + return (err < 0) ? NET_XMIT_DROP : err; +} + +static const struct net_device_ops netdev_ops = { + .ndo_start_xmit = bt_xmit, +}; + +static struct header_ops header_ops = { + .create = header_create, +}; + +static void netdev_setup(struct net_device *dev) +{ + dev->addr_len = EUI64_ADDR_LEN; + dev->type = ARPHRD_6LOWPAN; + + dev->hard_header_len = 0; + dev->needed_tailroom = 0; + dev->mtu = IPV6_MIN_MTU; + dev->tx_queue_len = 0; + dev->flags = IFF_RUNNING | IFF_POINTOPOINT; + dev->watchdog_timeo = 0; + + dev->netdev_ops = &netdev_ops; + dev->header_ops = &header_ops; + dev->destructor = free_netdev; +} + +static struct device_type bt_type = { + .name = "bluetooth", +}; + +static void set_addr(u8 *eui, u8 *addr, u8 addr_type) +{ + /* addr is the BT address in little-endian format */ + eui[0] = addr[5]; + eui[1] = addr[4]; + eui[2] = addr[3]; + eui[3] = 0xFF; + eui[4] = 0xFE; + eui[5] = addr[2]; + eui[6] = addr[1]; + eui[7] = addr[0]; + + eui[0] ^= 2; + + /* Universal/local bit set, RFC 4291 */ + if (addr_type == BDADDR_LE_PUBLIC) + eui[0] |= 1; + else + eui[0] &= ~1; +} + +static void set_dev_addr(struct net_device *netdev, bdaddr_t *addr, + u8 addr_type) +{ + netdev->addr_assign_type = NET_ADDR_PERM; + set_addr(netdev->dev_addr, addr->b, addr_type); + netdev->dev_addr[0] ^= 2; +} + +static void ifup(struct net_device *netdev) +{ + int err; + + rtnl_lock(); + err = dev_open(netdev); + if (err < 0) + BT_INFO("iface %s cannot be opened (%d)", netdev->name, err); + rtnl_unlock(); +} + +static void do_notify_peers(struct work_struct *work) +{ + struct lowpan_dev *dev = container_of(work, struct lowpan_dev, + notify_peers.work); + + netdev_notify_peers(dev->netdev); /* send neighbour adv at startup */ +} + +static bool is_bt_6lowpan(struct hci_conn *hcon) +{ + if (hcon->type != LE_LINK) + return false; + + return test_bit(HCI_CONN_6LOWPAN, &hcon->flags); +} + +static int add_peer_conn(struct l2cap_conn *conn, struct lowpan_dev *dev) +{ + struct lowpan_peer *peer; + unsigned long flags; + + peer = kzalloc(sizeof(*peer), GFP_ATOMIC); + if (!peer) + return -ENOMEM; + + peer->conn = conn; + memset(&peer->peer_addr, 0, sizeof(struct in6_addr)); + + /* RFC 2464 ch. 5 */ + peer->peer_addr.s6_addr[0] = 0xFE; + peer->peer_addr.s6_addr[1] = 0x80; + set_addr((u8 *)&peer->peer_addr.s6_addr + 8, conn->hcon->dst.b, + conn->hcon->dst_type); + + memcpy(&peer->eui64_addr, (u8 *)&peer->peer_addr.s6_addr + 8, + EUI64_ADDR_LEN); + peer->eui64_addr[0] ^= 2; /* second bit-flip (Universe/Local) + * is done according RFC2464 + */ + + raw_dump_inline(__func__, "peer IPv6 address", + (unsigned char *)&peer->peer_addr, 16); + raw_dump_inline(__func__, "peer EUI64 address", peer->eui64_addr, 8); + + write_lock_irqsave(&devices_lock, flags); + INIT_LIST_HEAD(&peer->list); + peer_add(dev, peer); + write_unlock_irqrestore(&devices_lock, flags); + + /* Notifying peers about us needs to be done without locks held */ + INIT_DELAYED_WORK(&dev->notify_peers, do_notify_peers); + schedule_delayed_work(&dev->notify_peers, msecs_to_jiffies(100)); + + return 0; +} + +/* This gets called when BT LE 6LoWPAN device is connected. We then + * create network device that acts as a proxy between BT LE device + * and kernel network stack. + */ +int bt_6lowpan_add_conn(struct l2cap_conn *conn) +{ + struct lowpan_peer *peer = NULL; + struct lowpan_dev *dev; + struct net_device *netdev; + int err = 0; + unsigned long flags; + + if (!is_bt_6lowpan(conn->hcon)) + return 0; + + peer = lookup_peer(conn); + if (peer) + return -EEXIST; + + dev = lookup_dev(conn); + if (dev) + return add_peer_conn(conn, dev); + + netdev = alloc_netdev(sizeof(*dev), IFACE_NAME_TEMPLATE, netdev_setup); + if (!netdev) + return -ENOMEM; + + set_dev_addr(netdev, &conn->hcon->src, conn->hcon->src_type); + + netdev->netdev_ops = &netdev_ops; + SET_NETDEV_DEV(netdev, &conn->hcon->dev); + SET_NETDEV_DEVTYPE(netdev, &bt_type); + + err = register_netdev(netdev); + if (err < 0) { + BT_INFO("register_netdev failed %d", err); + free_netdev(netdev); + goto out; + } + + BT_DBG("ifindex %d peer bdaddr %pMR my addr %pMR", + netdev->ifindex, &conn->hcon->dst, &conn->hcon->src); + set_bit(__LINK_STATE_PRESENT, &netdev->state); + + dev = netdev_priv(netdev); + dev->netdev = netdev; + dev->hdev = conn->hcon->hdev; + INIT_LIST_HEAD(&dev->peers); + + write_lock_irqsave(&devices_lock, flags); + INIT_LIST_HEAD(&dev->list); + list_add(&dev->list, &bt_6lowpan_devices); + write_unlock_irqrestore(&devices_lock, flags); + + ifup(netdev); + + return add_peer_conn(conn, dev); + +out: + return err; +} + +static void delete_netdev(struct work_struct *work) +{ + struct lowpan_dev *entry = container_of(work, struct lowpan_dev, + delete_netdev); + + unregister_netdev(entry->netdev); + + /* The entry pointer is deleted in device_event() */ +} + +int bt_6lowpan_del_conn(struct l2cap_conn *conn) +{ + struct lowpan_dev *entry, *tmp; + struct lowpan_dev *dev = NULL; + struct lowpan_peer *peer; + int err = -ENOENT; + unsigned long flags; + bool last = false; + + if (!is_bt_6lowpan(conn->hcon)) + return 0; + + write_lock_irqsave(&devices_lock, flags); + + list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) { + dev = lowpan_dev(entry->netdev); + peer = peer_lookup_conn(dev, conn); + if (peer) { + last = peer_del(dev, peer); + err = 0; + break; + } + } + + if (!err && last && dev && !atomic_read(&dev->peer_count)) { + write_unlock_irqrestore(&devices_lock, flags); + + cancel_delayed_work_sync(&dev->notify_peers); + + /* bt_6lowpan_del_conn() is called with hci dev lock held which + * means that we must delete the netdevice in worker thread. + */ + INIT_WORK(&entry->delete_netdev, delete_netdev); + schedule_work(&entry->delete_netdev); + } else { + write_unlock_irqrestore(&devices_lock, flags); + } + + return err; +} + +static int device_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct net_device *netdev = netdev_notifier_info_to_dev(ptr); + struct lowpan_dev *entry, *tmp; + unsigned long flags; + + if (netdev->type != ARPHRD_6LOWPAN) + return NOTIFY_DONE; + + switch (event) { + case NETDEV_UNREGISTER: + write_lock_irqsave(&devices_lock, flags); + list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, + list) { + if (entry->netdev == netdev) { + list_del(&entry->list); + kfree(entry); + break; + } + } + write_unlock_irqrestore(&devices_lock, flags); + break; + } + + return NOTIFY_DONE; +} + +static struct notifier_block bt_6lowpan_dev_notifier = { + .notifier_call = device_event, +}; + +int bt_6lowpan_init(void) +{ + return register_netdevice_notifier(&bt_6lowpan_dev_notifier); +} + +void bt_6lowpan_cleanup(void) +{ + unregister_netdevice_notifier(&bt_6lowpan_dev_notifier); +} diff --git a/net/bluetooth/6lowpan.h b/net/bluetooth/6lowpan.h new file mode 100644 index 00000000000..680eac808d7 --- /dev/null +++ b/net/bluetooth/6lowpan.h @@ -0,0 +1,26 @@ +/* + Copyright (c) 2013 Intel Corp. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 and + only version 2 as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +*/ + +#ifndef __6LOWPAN_H +#define __6LOWPAN_H + +#include +#include + +int bt_6lowpan_recv(struct l2cap_conn *conn, struct sk_buff *skb); +int bt_6lowpan_add_conn(struct l2cap_conn *conn); +int bt_6lowpan_del_conn(struct l2cap_conn *conn); +int bt_6lowpan_init(void); +void bt_6lowpan_cleanup(void); + +#endif /* __6LOWPAN_H */ diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile index 6a791e73e39..cc6827e2ce6 100644 --- a/net/bluetooth/Makefile +++ b/net/bluetooth/Makefile @@ -10,6 +10,10 @@ obj-$(CONFIG_BT_HIDP) += hidp/ bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \ hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \ - a2mp.o amp.o + a2mp.o amp.o 6lowpan.o + +ifeq ($(CONFIG_IEEE802154_6LOWPAN),) + bluetooth-y += ../ieee802154/6lowpan_iphc.o +endif subdir-ccflags-y += -D__CHECK_ENDIAN__ diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 5fb3df66c2c..5f812455a45 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3533,6 +3533,9 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) conn->handle = __le16_to_cpu(ev->handle); conn->state = BT_CONNECTED; + if (test_bit(HCI_6LOWPAN_ENABLED, &hdev->dev_flags)) + set_bit(HCI_CONN_6LOWPAN, &conn->flags); + hci_conn_add_sysfs(conn); hci_proto_connect_cfm(conn, ev->status); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index b6bca64b320..b0ad2c752d7 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -40,6 +40,7 @@ #include "smp.h" #include "a2mp.h" #include "amp.h" +#include "6lowpan.h" bool disable_ertm; @@ -1468,6 +1469,8 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) BT_DBG(""); + bt_6lowpan_add_conn(conn); + /* Check if we have socket listening on cid */ pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_ATT, &hcon->src, &hcon->dst); @@ -7119,6 +7122,10 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) l2cap_conn_del(conn->hcon, EACCES); break; + case L2CAP_FC_6LOWPAN: + bt_6lowpan_recv(conn, skb); + break; + default: l2cap_data_channel(conn, cid, skb); break; @@ -7186,6 +7193,8 @@ void l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason) { BT_DBG("hcon %p reason %d", hcon, reason); + bt_6lowpan_del_conn(hcon->l2cap_data); + l2cap_conn_del(hcon, bt_to_errno(reason)); } @@ -7467,11 +7476,14 @@ int __init l2cap_init(void) debugfs_create_u16("l2cap_le_default_mps", 0466, bt_debugfs, &le_default_mps); + bt_6lowpan_init(); + return 0; } void l2cap_exit(void) { + bt_6lowpan_cleanup(); debugfs_remove(l2cap_debugfs); l2cap_cleanup_sockets(); } -- cgit v1.2.3-70-g09d2 From 89863109e3dd562529ffd8a559b0de068d1d8502 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 11 Dec 2013 17:05:38 +0200 Subject: Bluetooth: Manually enable or disable 6LoWPAN between devices This is a temporary patch where user can manually enable or disable BT 6LoWPAN functionality between devices. Eventually the connection is established automatically if the devices are advertising suitable capability and this patch can be removed. Before connecting the devices do this echo Y > /sys/kernel/debug/bluetooth/hci0/6lowpan This enables 6LoWPAN support and creates the bt0 interface automatically when devices are finally connected. Rebooting or unloading the bluetooth kernel module will also clear the settings from the kernel. Signed-off-by: Jukka Rissanen Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 8b8b5f80dd8..b23d40385f1 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -636,6 +636,49 @@ static int conn_max_interval_get(void *data, u64 *val) DEFINE_SIMPLE_ATTRIBUTE(conn_max_interval_fops, conn_max_interval_get, conn_max_interval_set, "%llu\n"); +static ssize_t lowpan_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct hci_dev *hdev = file->private_data; + char buf[3]; + + buf[0] = test_bit(HCI_6LOWPAN_ENABLED, &hdev->dev_flags) ? 'Y' : 'N'; + buf[1] = '\n'; + buf[2] = '\0'; + return simple_read_from_buffer(user_buf, count, ppos, buf, 2); +} + +static ssize_t lowpan_write(struct file *fp, const char __user *user_buffer, + size_t count, loff_t *position) +{ + struct hci_dev *hdev = fp->private_data; + bool enable; + char buf[32]; + size_t buf_size = min(count, (sizeof(buf)-1)); + + if (copy_from_user(buf, user_buffer, buf_size)) + return -EFAULT; + + buf[buf_size] = '\0'; + + if (strtobool(buf, &enable) < 0) + return -EINVAL; + + if (enable == test_bit(HCI_6LOWPAN_ENABLED, &hdev->dev_flags)) + return -EALREADY; + + change_bit(HCI_6LOWPAN_ENABLED, &hdev->dev_flags); + + return count; +} + +static const struct file_operations lowpan_debugfs_fops = { + .open = simple_open, + .read = lowpan_read, + .write = lowpan_write, + .llseek = default_llseek, +}; + /* ---- HCI requests ---- */ static void hci_req_sync_complete(struct hci_dev *hdev, u8 result) @@ -1406,6 +1449,8 @@ static int __hci_init(struct hci_dev *hdev) hdev, &conn_min_interval_fops); debugfs_create_file("conn_max_interval", 0644, hdev->debugfs, hdev, &conn_max_interval_fops); + debugfs_create_file("6lowpan", 0644, hdev->debugfs, hdev, + &lowpan_debugfs_fops); } return 0; -- cgit v1.2.3-70-g09d2 From 7e9805696428113e34625a65a30dbc62cb78acc5 Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Wed, 11 Dec 2013 13:48:20 +0100 Subject: ipv6: router reachability probing RFC 4191 states in 3.5: When a host avoids using any non-reachable router X and instead sends a data packet to another router Y, and the host would have used router X if router X were reachable, then the host SHOULD probe each such router X's reachability by sending a single Neighbor Solicitation to that router's address. A host MUST NOT probe a router's reachability in the absence of useful traffic that the host would have sent to the router if it were reachable. In any case, these probes MUST be rate-limited to no more than one per minute per router. Currently, when the neighbour corresponding to a router falls into NUD_FAILED, it's never considered again. Introduce a new rt6_nud_state value, RT6_NUD_FAIL_PROBE, which suggests the route should not be used but should be probed with a single NS. The probe is ratelimited by the existing code. To better distinguish meanings of the failure values, rename RT6_NUD_FAIL_SOFT to RT6_NUD_FAIL_DO_RR. Signed-off-by: Jiri Benc Acked-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- include/net/neighbour.h | 1 + net/core/neighbour.c | 15 +++++++++++++++ net/ipv6/route.c | 16 ++++++++++------ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/include/net/neighbour.h b/include/net/neighbour.h index 41b1ce6c96a..4c09bd23b83 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h @@ -252,6 +252,7 @@ static inline struct neighbour *neigh_create(struct neigh_table *tbl, void neigh_destroy(struct neighbour *neigh); int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb); int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, u32 flags); +void __neigh_set_probe_once(struct neighbour *neigh); void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev); int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev); int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb); diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 8be82a7f0e0..bf6f404c04a 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1238,6 +1238,21 @@ out: } EXPORT_SYMBOL(neigh_update); +/* Update the neigh to listen temporarily for probe responses, even if it is + * in a NUD_FAILED state. The caller has to hold neigh->lock for writing. + */ +void __neigh_set_probe_once(struct neighbour *neigh) +{ + neigh->updated = jiffies; + if (!(neigh->nud_state & NUD_FAILED)) + return; + neigh->nud_state = NUD_PROBE; + atomic_set(&neigh->probes, NEIGH_VAR(neigh->parms, UCAST_PROBES)); + neigh_add_timer(neigh, + jiffies + NEIGH_VAR(neigh->parms, RETRANS_TIME)); +} +EXPORT_SYMBOL(__neigh_set_probe_once); + struct neighbour *neigh_event_ns(struct neigh_table *tbl, u8 *lladdr, void *saddr, struct net_device *dev) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index ddb9d41c8ee..a1a57523b15 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -66,8 +66,9 @@ #endif enum rt6_nud_state { - RT6_NUD_FAIL_HARD = -2, - RT6_NUD_FAIL_SOFT = -1, + RT6_NUD_FAIL_HARD = -3, + RT6_NUD_FAIL_PROBE = -2, + RT6_NUD_FAIL_DO_RR = -1, RT6_NUD_SUCCEED = 1 }; @@ -521,7 +522,7 @@ static void rt6_probe(struct rt6_info *rt) work = kmalloc(sizeof(*work), GFP_ATOMIC); if (neigh && work) - neigh->updated = jiffies; + __neigh_set_probe_once(neigh); if (neigh) write_unlock(&neigh->lock); @@ -577,11 +578,13 @@ static inline enum rt6_nud_state rt6_check_neigh(struct rt6_info *rt) #ifdef CONFIG_IPV6_ROUTER_PREF else if (!(neigh->nud_state & NUD_FAILED)) ret = RT6_NUD_SUCCEED; + else + ret = RT6_NUD_FAIL_PROBE; #endif read_unlock(&neigh->lock); } else { ret = IS_ENABLED(CONFIG_IPV6_ROUTER_PREF) ? - RT6_NUD_SUCCEED : RT6_NUD_FAIL_SOFT; + RT6_NUD_SUCCEED : RT6_NUD_FAIL_DO_RR; } rcu_read_unlock_bh(); @@ -618,16 +621,17 @@ static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict, goto out; m = rt6_score_route(rt, oif, strict); - if (m == RT6_NUD_FAIL_SOFT) { + if (m == RT6_NUD_FAIL_DO_RR) { match_do_rr = true; m = 0; /* lowest valid score */ - } else if (m < 0) { + } else if (m == RT6_NUD_FAIL_HARD) { goto out; } if (strict & RT6_LOOKUP_F_REACHABLE) rt6_probe(rt); + /* note that m can be RT6_NUD_FAIL_PROBE at this point */ if (m > *mpri) { *do_rr = match_do_rr; *mpri = m; -- cgit v1.2.3-70-g09d2 From c45f812f0280c13f1b7992be5e0de512312a9e8f Mon Sep 17 00:00:00 2001 From: Matthew Whitehead Date: Wed, 11 Dec 2013 17:00:59 -0500 Subject: 8390 : Replace ei_debug with msg_enable/NETIF_MSG_* feature Removed the shared ei_debug variable. Replaced it by adding u32 msg_enable to the private struct ei_device. Now each 8390 ethernet instance has a per-device logging variable. Changed older style printk() calls to more canonical forms. Tested on: ne, ne2k-pci, smc-ultra, and wd hardware. V4.0 - Substituted pr_info() and pr_debug() for printk() KERN_INFO and KERN_DEBUG V3.0 - Checked for cases where pr_cont() was most appropriate choice. - Changed module parameter from 'debug' to 'msg_enable' because debug was no longer the best description. V2.0 - Changed netif_msg_(drv|probe|ifdown|rx_err|tx_err|tx_queued|intr|rx_status|hw) to netif_(dbg|info|warn|err) where possible. Signed-off-by: Matthew Whitehead Signed-off-by: David S. Miller --- drivers/net/ethernet/8390/8390.h | 7 +- drivers/net/ethernet/8390/apne.c | 62 ++++++++++-------- drivers/net/ethernet/8390/ax88796.c | 22 ++++++- drivers/net/ethernet/8390/axnet_cs.c | 119 ++++++++++++++++------------------ drivers/net/ethernet/8390/etherh.c | 51 +++++++++------ drivers/net/ethernet/8390/hydra.c | 11 +++- drivers/net/ethernet/8390/lib8390.c | 77 ++++++++++++---------- drivers/net/ethernet/8390/mac8390.c | 19 ++++-- drivers/net/ethernet/8390/mcf8390.c | 8 ++- drivers/net/ethernet/8390/ne.c | 96 +++++++++++++++------------ drivers/net/ethernet/8390/ne2k-pci.c | 54 ++++++++++----- drivers/net/ethernet/8390/pcnet_cs.c | 62 ++++++++++-------- drivers/net/ethernet/8390/smc-ultra.c | 48 ++++++++------ drivers/net/ethernet/8390/stnic.c | 28 +++++--- drivers/net/ethernet/8390/wd.c | 42 +++++++----- drivers/net/ethernet/8390/zorro8390.c | 22 +++++-- 16 files changed, 426 insertions(+), 302 deletions(-) diff --git a/drivers/net/ethernet/8390/8390.h b/drivers/net/ethernet/8390/8390.h index 2923c51bb35..3e2f2c2e7b5 100644 --- a/drivers/net/ethernet/8390/8390.h +++ b/drivers/net/ethernet/8390/8390.h @@ -21,12 +21,6 @@ struct e8390_pkt_hdr { unsigned short count; /* header + packet length in bytes */ }; -#ifdef notdef -extern int ei_debug; -#else -#define ei_debug 1 -#endif - #ifdef CONFIG_NET_POLL_CONTROLLER void ei_poll(struct net_device *dev); void eip_poll(struct net_device *dev); @@ -99,6 +93,7 @@ struct ei_device { u32 *reg_offset; /* Register mapping table */ spinlock_t page_lock; /* Page register locks */ unsigned long priv; /* Private field to store bus IDs etc. */ + u32 msg_enable; /* debug message level */ #ifdef AX88796_PLATFORM unsigned char rxcr_base; /* default value for RXCR */ #endif diff --git a/drivers/net/ethernet/8390/apne.c b/drivers/net/ethernet/8390/apne.c index 912ed7a5f33..811fa5d5c69 100644 --- a/drivers/net/ethernet/8390/apne.c +++ b/drivers/net/ethernet/8390/apne.c @@ -116,9 +116,15 @@ static const char version[] = static int apne_owned; /* signal if card already owned */ +static u32 apne_msg_enable; +module_param_named(msg_enable, apne_msg_enable, uint, (S_IRUSR|S_IRGRP|S_IROTH)); +MODULE_PARM_DESC(msg_enable, "Debug message level (see linux/netdevice.h for bitmap)"); + struct net_device * __init apne_probe(int unit) { struct net_device *dev; + struct ei_device *ei_local; + #ifndef MANUAL_CONFIG char tuple[8]; #endif @@ -133,11 +139,11 @@ struct net_device * __init apne_probe(int unit) if ( !(AMIGAHW_PRESENT(PCMCIA)) ) return ERR_PTR(-ENODEV); - printk("Looking for PCMCIA ethernet card : "); + pr_info("Looking for PCMCIA ethernet card : "); /* check if a card is inserted */ if (!(PCMCIA_INSERTED)) { - printk("NO PCMCIA card inserted\n"); + pr_cont("NO PCMCIA card inserted\n"); return ERR_PTR(-ENODEV); } @@ -148,6 +154,8 @@ struct net_device * __init apne_probe(int unit) sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); } + ei_local = netdev_priv(dev); + ei_local->msg_enable = apne_msg_enable; /* disable pcmcia irq for readtuple */ pcmcia_disable_irq(); @@ -155,14 +163,14 @@ struct net_device * __init apne_probe(int unit) #ifndef MANUAL_CONFIG if ((pcmcia_copy_tuple(CISTPL_FUNCID, tuple, 8) < 3) || (tuple[2] != CISTPL_FUNCID_NETWORK)) { - printk("not an ethernet card\n"); + pr_cont("not an ethernet card\n"); /* XXX: shouldn't we re-enable irq here? */ free_netdev(dev); return ERR_PTR(-ENODEV); } #endif - printk("ethernet PCMCIA card inserted\n"); + pr_cont("ethernet PCMCIA card inserted\n"); if (!init_pcmcia()) { /* XXX: shouldn't we re-enable irq here? */ @@ -204,11 +212,12 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr) int neX000, ctron; #endif static unsigned version_printed; + struct ei_device *ei_local = netdev_priv(dev); - if (ei_debug && version_printed++ == 0) - printk(version); + if ((apne_msg_enable & NETIF_MSG_DRV) && (version_printed++ == 0)) + netdev_info(dev, version); - printk("PCMCIA NE*000 ethercard probe"); + netdev_info(dev, "PCMCIA NE*000 ethercard probe"); /* Reset card. Who knows what dain-bramaged state it was left in. */ { unsigned long reset_start_time = jiffies; @@ -217,7 +226,7 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr) while ((inb(ioaddr + NE_EN0_ISR) & ENISR_RESET) == 0) if (time_after(jiffies, reset_start_time + 2*HZ/100)) { - printk(" not found (no reset ack).\n"); + pr_cont(" not found (no reset ack).\n"); return -ENODEV; } @@ -288,7 +297,7 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr) start_page = 0x01; stop_page = (wordlength == 2) ? 0x40 : 0x20; } else { - printk(" not found.\n"); + pr_cont(" not found.\n"); return -ENXIO; } @@ -320,9 +329,9 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr) for (i = 0; i < ETH_ALEN; i++) dev->dev_addr[i] = SA_prom[i]; - printk(" %pM\n", dev->dev_addr); + pr_cont(" %pM\n", dev->dev_addr); - printk("%s: %s found.\n", dev->name, name); + netdev_info(dev, "%s found.\n", name); ei_status.name = name; ei_status.tx_start_page = start_page; @@ -352,10 +361,11 @@ static void apne_reset_8390(struct net_device *dev) { unsigned long reset_start_time = jiffies; + struct ei_device *ei_local = netdev_priv(dev); init_pcmcia(); - if (ei_debug > 1) printk("resetting the 8390 t=%ld...", jiffies); + netif_dbg(ei_local, hw, dev, "resetting the 8390 t=%ld...\n", jiffies); outb(inb(NE_BASE + NE_RESET), NE_BASE + NE_RESET); @@ -365,8 +375,8 @@ apne_reset_8390(struct net_device *dev) /* This check _should_not_ be necessary, omit eventually. */ while ((inb(NE_BASE+NE_EN0_ISR) & ENISR_RESET) == 0) if (time_after(jiffies, reset_start_time + 2*HZ/100)) { - printk("%s: ne_reset_8390() did not complete.\n", dev->name); - break; + netdev_err(dev, "ne_reset_8390() did not complete.\n"); + break; } outb(ENISR_RESET, NE_BASE + NE_EN0_ISR); /* Ack intr. */ } @@ -386,9 +396,9 @@ apne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_pa /* This *shouldn't* happen. If it does, it's the last thing you'll see */ if (ei_status.dmaing) { - printk("%s: DMAing conflict in ne_get_8390_hdr " - "[DMAstat:%d][irqlock:%d][intr:%d].\n", - dev->name, ei_status.dmaing, ei_status.irqlock, dev->irq); + netdev_err(dev, "DMAing conflict in ne_get_8390_hdr " + "[DMAstat:%d][irqlock:%d][intr:%d].\n", + ei_status.dmaing, ei_status.irqlock, dev->irq); return; } @@ -433,9 +443,9 @@ apne_block_input(struct net_device *dev, int count, struct sk_buff *skb, int rin /* This *shouldn't* happen. If it does, it's the last thing you'll see */ if (ei_status.dmaing) { - printk("%s: DMAing conflict in ne_block_input " - "[DMAstat:%d][irqlock:%d][intr:%d].\n", - dev->name, ei_status.dmaing, ei_status.irqlock, dev->irq); + netdev_err(dev, "DMAing conflict in ne_block_input " + "[DMAstat:%d][irqlock:%d][intr:%d].\n", + ei_status.dmaing, ei_status.irqlock, dev->irq); return; } ei_status.dmaing |= 0x01; @@ -481,9 +491,9 @@ apne_block_output(struct net_device *dev, int count, /* This *shouldn't* happen. If it does, it's the last thing you'll see */ if (ei_status.dmaing) { - printk("%s: DMAing conflict in ne_block_output." - "[DMAstat:%d][irqlock:%d][intr:%d]\n", - dev->name, ei_status.dmaing, ei_status.irqlock, dev->irq); + netdev_err(dev, "DMAing conflict in ne_block_output." + "[DMAstat:%d][irqlock:%d][intr:%d]\n", + ei_status.dmaing, ei_status.irqlock, dev->irq); return; } ei_status.dmaing |= 0x01; @@ -513,7 +523,7 @@ apne_block_output(struct net_device *dev, int count, while ((inb(NE_BASE + NE_EN0_ISR) & ENISR_RDC) == 0) if (time_after(jiffies, dma_start + 2*HZ/100)) { /* 20ms */ - printk("%s: timeout waiting for Tx RDC.\n", dev->name); + netdev_warn(dev, "timeout waiting for Tx RDC.\n"); apne_reset_8390(dev); NS8390_init(dev,1); break; @@ -536,8 +546,8 @@ static irqreturn_t apne_interrupt(int irq, void *dev_id) pcmcia_ack_int(pcmcia_intreq); return IRQ_NONE; } - if (ei_debug > 3) - printk("pcmcia intreq = %x\n", pcmcia_intreq); + if (apne_msg_enable & NETIF_MSG_INTR) + pr_debug("pcmcia intreq = %x\n", pcmcia_intreq); pcmcia_disable_irq(); /* to get rid of the sti() within ei_interrupt */ ei_interrupt(irq, dev_id); pcmcia_ack_int(pcmcia_get_intreq()); diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index 36fa577970b..8ed5b34d755 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -78,6 +78,8 @@ static unsigned char version[] = "ax88796.c: Copyright 2005,2007 Simtec Electron #define AX_GPOC_PPDSET BIT(6) +static u32 ax_msg_enable; + /* device private data */ struct ax_device { @@ -147,8 +149,7 @@ static void ax_reset_8390(struct net_device *dev) unsigned long reset_start_time = jiffies; void __iomem *addr = (void __iomem *)dev->base_addr; - if (ei_debug > 1) - netdev_dbg(dev, "resetting the 8390 t=%ld\n", jiffies); + netif_dbg(ei_local, hw, dev, "resetting the 8390 t=%ld...\n", jiffies); ei_outb(ei_inb(addr + NE_RESET), addr + NE_RESET); @@ -496,12 +497,28 @@ static int ax_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) return phy_ethtool_sset(phy_dev, cmd); } +static u32 ax_get_msglevel(struct net_device *dev) +{ + struct ei_device *ei_local = netdev_priv(dev); + + return ei_local->msg_enable; +} + +static void ax_set_msglevel(struct net_device *dev, u32 v) +{ + struct ei_device *ei_local = netdev_priv(dev); + + ei_local->msg_enable = v; +} + static const struct ethtool_ops ax_ethtool_ops = { .get_drvinfo = ax_get_drvinfo, .get_settings = ax_get_settings, .set_settings = ax_set_settings, .get_link = ethtool_op_get_link, .get_ts_info = ethtool_op_get_ts_info, + .get_msglevel = ax_get_msglevel, + .set_msglevel = ax_set_msglevel, }; #ifdef CONFIG_AX88796_93CX6 @@ -763,6 +780,7 @@ static int ax_init_dev(struct net_device *dev) ei_local->block_output = &ax_block_output; ei_local->get_8390_hdr = &ax_get_8390_hdr; ei_local->priv = 0; + ei_local->msg_enable = ax_msg_enable; dev->netdev_ops = &ax_netdev_ops; dev->ethtool_ops = &ax_ethtool_ops; diff --git a/drivers/net/ethernet/8390/axnet_cs.c b/drivers/net/ethernet/8390/axnet_cs.c index d801c1410fb..5698a4c85d8 100644 --- a/drivers/net/ethernet/8390/axnet_cs.c +++ b/drivers/net/ethernet/8390/axnet_cs.c @@ -105,6 +105,7 @@ static void AX88190_init(struct net_device *dev, int startp); static int ax_open(struct net_device *dev); static int ax_close(struct net_device *dev); static irqreturn_t ax_interrupt(int irq, void *dev_id); +static u32 axnet_msg_enable; /*====================================================================*/ @@ -152,6 +153,7 @@ static int axnet_probe(struct pcmcia_device *link) return -ENOMEM; ei_local = netdev_priv(dev); + ei_local->msg_enable = axnet_msg_enable; spin_lock_init(&ei_local->page_lock); info = PRIV(dev); @@ -650,11 +652,12 @@ static void block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset) { unsigned int nic_base = dev->base_addr; + struct ei_device *ei_local = netdev_priv(dev); int xfer_count = count; char *buf = skb->data; - if ((ei_debug > 4) && (count != 4)) - pr_debug("%s: [bi=%d]\n", dev->name, count+4); + if ((netif_msg_rx_status(ei_local)) && (count != 4)) + netdev_dbg(dev, "[bi=%d]\n", count+4); outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO); outb_p(ring_offset >> 8, nic_base + EN0_RSARHI); outb_p(E8390_RREAD+E8390_START, nic_base + AXNET_CMD); @@ -810,11 +813,6 @@ module_pcmcia_driver(axnet_cs_driver); #define ei_block_input (ei_local->block_input) #define ei_get_8390_hdr (ei_local->get_8390_hdr) -/* use 0 for production, 1 for verification, >2 for debug */ -#ifndef ei_debug -int ei_debug = 1; -#endif - /* Index to functions. */ static void ei_tx_intr(struct net_device *dev); static void ei_tx_err(struct net_device *dev); @@ -925,11 +923,10 @@ static void axnet_tx_timeout(struct net_device *dev) isr = inb(e8390_base+EN0_ISR); spin_unlock_irqrestore(&ei_local->page_lock, flags); - netdev_printk(KERN_DEBUG, dev, - "Tx timed out, %s TSR=%#2x, ISR=%#2x, t=%d.\n", - (txsr & ENTSR_ABT) ? "excess collisions." : - (isr) ? "lost interrupt?" : "cable problem?", - txsr, isr, tickssofar); + netdev_dbg(dev, "Tx timed out, %s TSR=%#2x, ISR=%#2x, t=%d.\n", + (txsr & ENTSR_ABT) ? "excess collisions." : + (isr) ? "lost interrupt?" : "cable problem?", + txsr, isr, tickssofar); if (!isr && !dev->stats.tx_packets) { @@ -998,29 +995,30 @@ static netdev_tx_t axnet_start_xmit(struct sk_buff *skb, { output_page = ei_local->tx_start_page; ei_local->tx1 = send_length; - if (ei_debug && ei_local->tx2 > 0) - netdev_printk(KERN_DEBUG, dev, - "idle transmitter tx2=%d, lasttx=%d, txing=%d\n", - ei_local->tx2, ei_local->lasttx, - ei_local->txing); + if ((netif_msg_tx_queued(ei_local)) && + ei_local->tx2 > 0) + netdev_dbg(dev, + "idle transmitter tx2=%d, lasttx=%d, txing=%d\n", + ei_local->tx2, ei_local->lasttx, + ei_local->txing); } else if (ei_local->tx2 == 0) { output_page = ei_local->tx_start_page + TX_PAGES/2; ei_local->tx2 = send_length; - if (ei_debug && ei_local->tx1 > 0) - netdev_printk(KERN_DEBUG, dev, - "idle transmitter, tx1=%d, lasttx=%d, txing=%d\n", - ei_local->tx1, ei_local->lasttx, - ei_local->txing); + if ((netif_msg_tx_queued(ei_local)) && + ei_local->tx1 > 0) + netdev_dbg(dev, + "idle transmitter, tx1=%d, lasttx=%d, txing=%d\n", + ei_local->tx1, ei_local->lasttx, + ei_local->txing); } else { /* We should never get here. */ - if (ei_debug) - netdev_printk(KERN_DEBUG, dev, - "No Tx buffers free! tx1=%d tx2=%d last=%d\n", - ei_local->tx1, ei_local->tx2, - ei_local->lasttx); + netif_dbg(ei_local, tx_err, dev, + "No Tx buffers free! tx1=%d tx2=%d last=%d\n", + ei_local->tx1, ei_local->tx2, + ei_local->lasttx); ei_local->irqlock = 0; netif_stop_queue(dev); outb_p(ENISR_ALL, e8390_base + EN0_IMR); @@ -1124,10 +1122,9 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id) spin_unlock_irqrestore(&ei_local->page_lock, flags); return IRQ_NONE; } - - if (ei_debug > 3) - netdev_printk(KERN_DEBUG, dev, "interrupt(isr=%#2.2x)\n", - inb_p(e8390_base + EN0_ISR)); + + netif_dbg(ei_local, intr, dev, "interrupt(isr=%#2.2x)\n", + inb_p(e8390_base + EN0_ISR)); outb_p(0x00, e8390_base + EN0_ISR); ei_local->irqlock = 1; @@ -1137,9 +1134,8 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id) ++nr_serviced < MAX_SERVICE) { if (!netif_running(dev) || (interrupts == 0xff)) { - if (ei_debug > 1) - netdev_warn(dev, - "interrupt from stopped card\n"); + netif_warn(ei_local, intr, dev, + "interrupt from stopped card\n"); outb_p(interrupts, e8390_base + EN0_ISR); interrupts = 0; break; @@ -1175,14 +1171,15 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id) } } - if (interrupts && ei_debug > 3) + if (interrupts && (netif_msg_intr(ei_local))) { handled = 1; if (nr_serviced >= MAX_SERVICE) { /* 0xFF is valid for a card removal */ - if(interrupts!=0xFF) - netdev_warn(dev, "Too much work at interrupt, status %#2.2x\n", + if (interrupts != 0xFF) + netdev_warn(dev, + "Too much work at interrupt, status %#2.2x\n", interrupts); outb_p(ENISR_ALL, e8390_base + EN0_ISR); /* Ack. most intrs. */ } else { @@ -1221,8 +1218,7 @@ static void ei_tx_err(struct net_device *dev) unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU); #ifdef VERBOSE_ERROR_DUMP - netdev_printk(KERN_DEBUG, dev, - "transmitter error (%#2x):", txsr); + netdev_dbg(dev, "transmitter error (%#2x):", txsr); if (txsr & ENTSR_ABT) pr_cont(" excess-collisions"); if (txsr & ENTSR_ND) @@ -1287,9 +1283,9 @@ static void ei_tx_intr(struct net_device *dev) else if (ei_local->tx2 < 0) { if (ei_local->lasttx != 2 && ei_local->lasttx != -2) - netdev_info(dev, "%s: bogus last_tx_buffer %d, tx2=%d\n", - ei_local->name, ei_local->lasttx, - ei_local->tx2); + netdev_err(dev, "%s: bogus last_tx_buffer %d, tx2=%d\n", + ei_local->name, ei_local->lasttx, + ei_local->tx2); ei_local->tx2 = 0; if (ei_local->tx1 > 0) { @@ -1366,9 +1362,11 @@ static void ei_receive(struct net_device *dev) Keep quiet if it looks like a card removal. One problem here is that some clones crash in roughly the same way. */ - if (ei_debug > 0 && this_frame != ei_local->current_page && (this_frame!=0x0 || rxing_page!=0xFF)) - netdev_err(dev, "mismatched read page pointers %2x vs %2x\n", - this_frame, ei_local->current_page); + if ((netif_msg_rx_err(ei_local)) && + this_frame != ei_local->current_page && + (this_frame != 0x0 || rxing_page != 0xFF)) + netdev_err(dev, "mismatched read page pointers %2x vs %2x\n", + this_frame, ei_local->current_page); if (this_frame == rxing_page) /* Read all the frames? */ break; /* Done for now */ @@ -1383,11 +1381,10 @@ static void ei_receive(struct net_device *dev) if (pkt_len < 60 || pkt_len > 1518) { - if (ei_debug) - netdev_printk(KERN_DEBUG, dev, - "bogus packet size: %d, status=%#2x nxpg=%#2x\n", - rx_frame.count, rx_frame.status, - rx_frame.next); + netif_err(ei_local, rx_err, dev, + "bogus packet size: %d, status=%#2x nxpg=%#2x\n", + rx_frame.count, rx_frame.status, + rx_frame.next); dev->stats.rx_errors++; dev->stats.rx_length_errors++; } @@ -1398,10 +1395,9 @@ static void ei_receive(struct net_device *dev) skb = netdev_alloc_skb(dev, pkt_len + 2); if (skb == NULL) { - if (ei_debug > 1) - netdev_printk(KERN_DEBUG, dev, - "Couldn't allocate a sk_buff of size %d\n", - pkt_len); + netif_err(ei_local, rx_err, dev, + "Couldn't allocate a sk_buff of size %d\n", + pkt_len); dev->stats.rx_dropped++; break; } @@ -1420,11 +1416,10 @@ static void ei_receive(struct net_device *dev) } else { - if (ei_debug) - netdev_printk(KERN_DEBUG, dev, - "bogus packet: status=%#2x nxpg=%#2x size=%d\n", - rx_frame.status, rx_frame.next, - rx_frame.count); + netif_err(ei_local, rx_err, dev, + "bogus packet: status=%#2x nxpg=%#2x size=%d\n", + rx_frame.status, rx_frame.next, + rx_frame.count); dev->stats.rx_errors++; /* NB: The NIC counts CRC, frame and missed errors. */ if (pkt_stat & ENRSR_FO) @@ -1461,6 +1456,7 @@ static void ei_rx_overrun(struct net_device *dev) axnet_dev_t *info = PRIV(dev); long e8390_base = dev->base_addr; unsigned char was_txing, must_resend = 0; + struct ei_device *ei_local = netdev_priv(dev); /* * Record whether a Tx was in progress and then issue the @@ -1468,9 +1464,8 @@ static void ei_rx_overrun(struct net_device *dev) */ was_txing = inb_p(e8390_base+E8390_CMD) & E8390_TRANS; outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD); - - if (ei_debug > 1) - netdev_printk(KERN_DEBUG, dev, "Receiver overrun\n"); + + netif_dbg(ei_local, rx_err, dev, "Receiver overrun\n"); dev->stats.rx_over_errors++; /* diff --git a/drivers/net/ethernet/8390/etherh.c b/drivers/net/ethernet/8390/etherh.c index 78c6fb4b114..b15e482a7c6 100644 --- a/drivers/net/ethernet/8390/etherh.c +++ b/drivers/net/ethernet/8390/etherh.c @@ -56,9 +56,6 @@ #define ei_inb_p(_p) readb((void __iomem *)_p) #define ei_outb_p(_v,_p) writeb(_v,(void __iomem *)_p) -#define NET_DEBUG 0 -#define DEBUG_INIT 2 - #define DRV_NAME "etherh" #define DRV_VERSION "1.11" @@ -67,7 +64,7 @@ static char version[] __initdata = #include "lib8390.c" -static unsigned int net_debug = NET_DEBUG; +static u32 etherh_msg_enable; struct etherh_priv { void __iomem *ioc_fast; @@ -317,9 +314,9 @@ etherh_block_output (struct net_device *dev, int count, const unsigned char *buf void __iomem *dma_base, *addr; if (ei_local->dmaing) { - printk(KERN_ERR "%s: DMAing conflict in etherh_block_input: " - " DMAstat %d irqlock %d\n", dev->name, - ei_local->dmaing, ei_local->irqlock); + netdev_err(dev, "DMAing conflict in etherh_block_input: " + " DMAstat %d irqlock %d\n", + ei_local->dmaing, ei_local->irqlock); return; } @@ -361,8 +358,7 @@ etherh_block_output (struct net_device *dev, int count, const unsigned char *buf while ((readb (addr + EN0_ISR) & ENISR_RDC) == 0) if (time_after(jiffies, dma_start + 2*HZ/100)) { /* 20ms */ - printk(KERN_ERR "%s: timeout waiting for TX RDC\n", - dev->name); + netdev_warn(dev, "timeout waiting for TX RDC\n"); etherh_reset (dev); __NS8390_init (dev, 1); break; @@ -383,9 +379,9 @@ etherh_block_input (struct net_device *dev, int count, struct sk_buff *skb, int void __iomem *dma_base, *addr; if (ei_local->dmaing) { - printk(KERN_ERR "%s: DMAing conflict in etherh_block_input: " - " DMAstat %d irqlock %d\n", dev->name, - ei_local->dmaing, ei_local->irqlock); + netdev_err(dev, "DMAing conflict in etherh_block_input: " + " DMAstat %d irqlock %d\n", + ei_local->dmaing, ei_local->irqlock); return; } @@ -423,9 +419,9 @@ etherh_get_header (struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_p void __iomem *dma_base, *addr; if (ei_local->dmaing) { - printk(KERN_ERR "%s: DMAing conflict in etherh_get_header: " - " DMAstat %d irqlock %d\n", dev->name, - ei_local->dmaing, ei_local->irqlock); + netdev_err(dev, "DMAing conflict in etherh_get_header: " + " DMAstat %d irqlock %d\n", + ei_local->dmaing, ei_local->irqlock); return; } @@ -513,8 +509,8 @@ static void __init etherh_banner(void) { static int version_printed; - if (net_debug && version_printed++ == 0) - printk(KERN_INFO "%s", version); + if ((etherh_msg_enable & NETIF_MSG_DRV) && (version_printed++ == 0)) + pr_info("%s", version); } /* @@ -625,11 +621,27 @@ static int etherh_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) return 0; } +static u32 etherh_get_msglevel(struct net_device *dev) +{ + struct ei_device *ei_local = netdev_priv(dev); + + return ei_local->msg_enable; +} + +static void etherh_set_msglevel(struct net_device *dev, u32 v) +{ + struct ei_device *ei_local = netdev_priv(dev); + + ei_local->msg_enable = v; +} + static const struct ethtool_ops etherh_ethtool_ops = { .get_settings = etherh_get_settings, .set_settings = etherh_set_settings, .get_drvinfo = etherh_get_drvinfo, .get_ts_info = ethtool_op_get_ts_info, + .get_msglevel = etherh_get_msglevel, + .set_msglevel = etherh_set_msglevel, }; static const struct net_device_ops etherh_netdev_ops = { @@ -746,6 +758,7 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id) ei_local->block_output = etherh_block_output; ei_local->get_8390_hdr = etherh_get_header; ei_local->interface_num = 0; + ei_local->msg_enable = etherh_msg_enable; etherh_reset(dev); __NS8390_init(dev, 0); @@ -754,8 +767,8 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id) if (ret) goto free; - printk(KERN_INFO "%s: %s in slot %d, %pM\n", - dev->name, data->name, ec->slot_no, dev->dev_addr); + netdev_info(dev, "%s in slot %d, %pM\n", + data->name, ec->slot_no, dev->dev_addr); ecard_set_drvdata(ec, dev); diff --git a/drivers/net/ethernet/8390/hydra.c b/drivers/net/ethernet/8390/hydra.c index fb3dd4399cf..d8b86c83dd1 100644 --- a/drivers/net/ethernet/8390/hydra.c +++ b/drivers/net/ethernet/8390/hydra.c @@ -66,6 +66,7 @@ static void hydra_block_input(struct net_device *dev, int count, static void hydra_block_output(struct net_device *dev, int count, const unsigned char *buf, int start_page); static void hydra_remove_one(struct zorro_dev *z); +static u32 hydra_msg_enable; static struct zorro_device_id hydra_zorro_tbl[] = { { ZORRO_PROD_HYDRA_SYSTEMS_AMIGANET }, @@ -119,6 +120,7 @@ static int hydra_init(struct zorro_dev *z) int start_page, stop_page; int j; int err; + struct ei_device *ei_local; static u32 hydra_offsets[16] = { 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, @@ -137,6 +139,8 @@ static int hydra_init(struct zorro_dev *z) start_page = NESM_START_PG; stop_page = NESM_STOP_PG; + ei_local = netdev_priv(dev); + ei_local->msg_enable = hydra_msg_enable; dev->base_addr = ioaddr; dev->irq = IRQ_AMIGA_PORTS; @@ -187,15 +191,16 @@ static int hydra_open(struct net_device *dev) static int hydra_close(struct net_device *dev) { - if (ei_debug > 1) - printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name); + struct ei_device *ei_local = netdev_priv(dev); + + netif_dbg(ei_local, ifdown, dev, "Shutting down ethercard.\n"); __ei_close(dev); return 0; } static void hydra_reset_8390(struct net_device *dev) { - printk(KERN_INFO "Hydra hw reset not there\n"); + netdev_info(dev, "Hydra hw reset not there\n"); } static void hydra_get_8390_hdr(struct net_device *dev, diff --git a/drivers/net/ethernet/8390/lib8390.c b/drivers/net/ethernet/8390/lib8390.c index b329f5c0d62..d2cd80444ad 100644 --- a/drivers/net/ethernet/8390/lib8390.c +++ b/drivers/net/ethernet/8390/lib8390.c @@ -99,11 +99,6 @@ #define ei_block_input (ei_local->block_input) #define ei_get_8390_hdr (ei_local->get_8390_hdr) -/* use 0 for production, 1 for verification, >2 for debug */ -#ifndef ei_debug -int ei_debug = 1; -#endif - /* Index to functions. */ static void ei_tx_intr(struct net_device *dev); static void ei_tx_err(struct net_device *dev); @@ -116,6 +111,11 @@ static void NS8390_trigger_send(struct net_device *dev, unsigned int length, static void do_set_multicast_list(struct net_device *dev); static void __NS8390_init(struct net_device *dev, int startp); +static unsigned version_printed; +static u32 msg_enable; +module_param(msg_enable, uint, (S_IRUSR|S_IRGRP|S_IROTH)); +MODULE_PARM_DESC(msg_enable, "Debug message level (see linux/netdevice.h for bitmap)"); + /* * SMP and the 8390 setup. * @@ -345,19 +345,23 @@ static netdev_tx_t __ei_start_xmit(struct sk_buff *skb, if (ei_local->tx1 == 0) { output_page = ei_local->tx_start_page; ei_local->tx1 = send_length; - if (ei_debug && ei_local->tx2 > 0) - netdev_dbg(dev, "idle transmitter tx2=%d, lasttx=%d, txing=%d\n", + if ((netif_msg_tx_queued(ei_local)) && + ei_local->tx2 > 0) + netdev_dbg(dev, + "idle transmitter tx2=%d, lasttx=%d, txing=%d\n", ei_local->tx2, ei_local->lasttx, ei_local->txing); } else if (ei_local->tx2 == 0) { output_page = ei_local->tx_start_page + TX_PAGES/2; ei_local->tx2 = send_length; - if (ei_debug && ei_local->tx1 > 0) - netdev_dbg(dev, "idle transmitter, tx1=%d, lasttx=%d, txing=%d\n", + if ((netif_msg_tx_queued(ei_local)) && + ei_local->tx1 > 0) + netdev_dbg(dev, + "idle transmitter, tx1=%d, lasttx=%d, txing=%d\n", ei_local->tx1, ei_local->lasttx, ei_local->txing); } else { /* We should never get here. */ - if (ei_debug) - netdev_dbg(dev, "No Tx buffers free! tx1=%d tx2=%d last=%d\n", - ei_local->tx1, ei_local->tx2, ei_local->lasttx); + netif_dbg(ei_local, tx_err, dev, + "No Tx buffers free! tx1=%d tx2=%d last=%d\n", + ei_local->tx1, ei_local->tx2, ei_local->lasttx); ei_local->irqlock = 0; netif_stop_queue(dev); ei_outb_p(ENISR_ALL, e8390_base + EN0_IMR); @@ -388,7 +392,7 @@ static netdev_tx_t __ei_start_xmit(struct sk_buff *skb, } else ei_local->txqueue++; - if (ei_local->tx1 && ei_local->tx2) + if (ei_local->tx1 && ei_local->tx2) netif_stop_queue(dev); else netif_start_queue(dev); @@ -445,9 +449,8 @@ static irqreturn_t __ei_interrupt(int irq, void *dev_id) /* Change to page 0 and read the intr status reg. */ ei_outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD); - if (ei_debug > 3) - netdev_dbg(dev, "interrupt(isr=%#2.2x)\n", - ei_inb_p(e8390_base + EN0_ISR)); + netif_dbg(ei_local, intr, dev, "interrupt(isr=%#2.2x)\n", + ei_inb_p(e8390_base + EN0_ISR)); /* !!Assumption!! -- we stay in page 0. Don't break this. */ while ((interrupts = ei_inb_p(e8390_base + EN0_ISR)) != 0 && @@ -485,7 +488,7 @@ static irqreturn_t __ei_interrupt(int irq, void *dev_id) ei_outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base + E8390_CMD); } - if (interrupts && ei_debug) { + if (interrupts && (netif_msg_intr(ei_local))) { ei_outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base + E8390_CMD); if (nr_serviced >= MAX_SERVICE) { /* 0xFF is valid for a card removal */ @@ -676,10 +679,11 @@ static void ei_receive(struct net_device *dev) Keep quiet if it looks like a card removal. One problem here is that some clones crash in roughly the same way. */ - if (ei_debug > 0 && + if ((netif_msg_rx_status(ei_local)) && this_frame != ei_local->current_page && (this_frame != 0x0 || rxing_page != 0xFF)) - netdev_err(dev, "mismatched read page pointers %2x vs %2x\n", + netdev_err(dev, + "mismatched read page pointers %2x vs %2x\n", this_frame, ei_local->current_page); if (this_frame == rxing_page) /* Read all the frames? */ @@ -707,10 +711,10 @@ static void ei_receive(struct net_device *dev) } if (pkt_len < 60 || pkt_len > 1518) { - if (ei_debug) - netdev_dbg(dev, "bogus packet size: %d, status=%#2x nxpg=%#2x\n", - rx_frame.count, rx_frame.status, - rx_frame.next); + netif_dbg(ei_local, rx_status, dev, + "bogus packet size: %d, status=%#2x nxpg=%#2x\n", + rx_frame.count, rx_frame.status, + rx_frame.next); dev->stats.rx_errors++; dev->stats.rx_length_errors++; } else if ((pkt_stat & 0x0F) == ENRSR_RXOK) { @@ -718,9 +722,9 @@ static void ei_receive(struct net_device *dev) skb = netdev_alloc_skb(dev, pkt_len + 2); if (skb == NULL) { - if (ei_debug > 1) - netdev_dbg(dev, "Couldn't allocate a sk_buff of size %d\n", - pkt_len); + netif_err(ei_local, rx_err, dev, + "Couldn't allocate a sk_buff of size %d\n", + pkt_len); dev->stats.rx_dropped++; break; } else { @@ -736,10 +740,10 @@ static void ei_receive(struct net_device *dev) dev->stats.multicast++; } } else { - if (ei_debug) - netdev_dbg(dev, "bogus packet: status=%#2x nxpg=%#2x size=%d\n", - rx_frame.status, rx_frame.next, - rx_frame.count); + netif_err(ei_local, rx_err, dev, + "bogus packet: status=%#2x nxpg=%#2x size=%d\n", + rx_frame.status, rx_frame.next, + rx_frame.count); dev->stats.rx_errors++; /* NB: The NIC counts CRC, frame and missed errors. */ if (pkt_stat & ENRSR_FO) @@ -789,8 +793,7 @@ static void ei_rx_overrun(struct net_device *dev) was_txing = ei_inb_p(e8390_base+E8390_CMD) & E8390_TRANS; ei_outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD); - if (ei_debug > 1) - netdev_dbg(dev, "Receiver overrun\n"); + netif_dbg(ei_local, rx_err, dev, "Receiver overrun\n"); dev->stats.rx_over_errors++; /* @@ -965,8 +968,9 @@ static void __ei_set_multicast_list(struct net_device *dev) static void ethdev_setup(struct net_device *dev) { struct ei_device *ei_local = netdev_priv(dev); - if (ei_debug > 1) - printk(version); + + if ((msg_enable & NETIF_MSG_DRV) && (version_printed++ == 0)) + pr_info("%s", version); ether_setup(dev); @@ -1035,9 +1039,10 @@ static void __NS8390_init(struct net_device *dev, int startp) ei_outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, e8390_base+E8390_CMD); /* 0x61 */ for (i = 0; i < 6; i++) { ei_outb_p(dev->dev_addr[i], e8390_base + EN1_PHYS_SHIFT(i)); - if (ei_debug > 1 && + if ((netif_msg_probe(ei_local)) && ei_inb_p(e8390_base + EN1_PHYS_SHIFT(i)) != dev->dev_addr[i]) - netdev_err(dev, "Hw. address read/write mismap %d\n", i); + netdev_err(dev, + "Hw. address read/write mismap %d\n", i); } ei_outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG); diff --git a/drivers/net/ethernet/8390/mac8390.c b/drivers/net/ethernet/8390/mac8390.c index 88ccc8b14f0..90e825e8abf 100644 --- a/drivers/net/ethernet/8390/mac8390.c +++ b/drivers/net/ethernet/8390/mac8390.c @@ -167,6 +167,7 @@ static void slow_sane_block_output(struct net_device *dev, int count, const unsigned char *buf, int start_page); static void word_memcpy_tocard(unsigned long tp, const void *fp, int count); static void word_memcpy_fromcard(void *tp, unsigned long fp, int count); +static u32 mac8390_msg_enable; static enum mac8390_type __init mac8390_ident(struct nubus_dev *dev) { @@ -402,6 +403,7 @@ struct net_device * __init mac8390_probe(int unit) struct net_device *dev; struct nubus_dev *ndev = NULL; int err = -ENODEV; + struct ei_device *ei_local; static unsigned int slots; @@ -440,6 +442,10 @@ struct net_device * __init mac8390_probe(int unit) if (!ndev) goto out; + + ei_local = netdev_priv(dev); + ei_local->msg_enable = mac8390_msg_enable; + err = register_netdev(dev); if (err) goto out; @@ -660,19 +666,22 @@ static int mac8390_close(struct net_device *dev) static void mac8390_no_reset(struct net_device *dev) { + struct ei_device *ei_local = netdev_priv(dev); + ei_status.txing = 0; - if (ei_debug > 1) - pr_info("reset not supported\n"); + netif_info(ei_local, hw, dev, "reset not supported\n"); } static void interlan_reset(struct net_device *dev) { unsigned char *target = nubus_slot_addr(IRQ2SLOT(dev->irq)); - if (ei_debug > 1) - pr_info("Need to reset the NS8390 t=%lu...", jiffies); + struct ei_device *ei_local = netdev_priv(dev); + + netif_info(ei_local, hw, dev, "Need to reset the NS8390 t=%lu...", + jiffies); ei_status.txing = 0; target[0xC0000] = 0; - if (ei_debug > 1) + if (netif_msg_hw(ei_local)) pr_cont("reset complete\n"); } diff --git a/drivers/net/ethernet/8390/mcf8390.c b/drivers/net/ethernet/8390/mcf8390.c index 230efd6fa5d..df0ffca91c1 100644 --- a/drivers/net/ethernet/8390/mcf8390.c +++ b/drivers/net/ethernet/8390/mcf8390.c @@ -39,6 +39,7 @@ static const char version[] = #define NESM_START_PG 0x40 /* First page of TX buffer */ #define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */ +static u32 mcf8390_msg_enable; #ifdef NE2000_ODDOFFSET /* @@ -153,9 +154,9 @@ static void mcf8390_reset_8390(struct net_device *dev) { unsigned long reset_start_time = jiffies; u32 addr = dev->base_addr; + struct ei_device *ei_local = netdev_priv(dev); - if (ei_debug > 1) - netdev_dbg(dev, "resetting the 8390 t=%ld...\n", jiffies); + netif_dbg(ei_local, hw, dev, "resetting the 8390 t=%ld...\n", jiffies); ei_outb(ei_inb(addr + NE_RESET), addr + NE_RESET); @@ -288,7 +289,7 @@ static void mcf8390_block_output(struct net_device *dev, int count, dma_start = jiffies; while ((ei_inb(addr + NE_EN0_ISR) & ENISR_RDC) == 0) { if (time_after(jiffies, dma_start + 2 * HZ / 100)) { /* 20ms */ - netdev_err(dev, "timeout waiting for Tx RDC\n"); + netdev_warn(dev, "timeout waiting for Tx RDC\n"); mcf8390_reset_8390(dev); __NS8390_init(dev, 1); break; @@ -437,6 +438,7 @@ static int mcf8390_probe(struct platform_device *pdev) SET_NETDEV_DEV(dev, &pdev->dev); platform_set_drvdata(pdev, dev); ei_local = netdev_priv(dev); + ei_local->msg_enable = mcf8390_msg_enable; dev->irq = irq->start; dev->base_addr = mem->start; diff --git a/drivers/net/ethernet/8390/ne.c b/drivers/net/ethernet/8390/ne.c index b2e84051373..58eaa8f3494 100644 --- a/drivers/net/ethernet/8390/ne.c +++ b/drivers/net/ethernet/8390/ne.c @@ -71,14 +71,17 @@ static struct platform_device *pdev_ne[MAX_NE_CARDS]; static int io[MAX_NE_CARDS]; static int irq[MAX_NE_CARDS]; static int bad[MAX_NE_CARDS]; +static u32 ne_msg_enable; #ifdef MODULE module_param_array(io, int, NULL, 0); module_param_array(irq, int, NULL, 0); module_param_array(bad, int, NULL, 0); +module_param_named(msg_enable, ne_msg_enable, uint, (S_IRUSR|S_IRGRP|S_IROTH)); MODULE_PARM_DESC(io, "I/O base address(es),required"); MODULE_PARM_DESC(irq, "IRQ number(s)"); MODULE_PARM_DESC(bad, "Accept card(s) with bad signatures"); +MODULE_PARM_DESC(msg_enable, "Debug message level (see linux/netdevice.h for bitmap)"); MODULE_DESCRIPTION("NE1000/NE2000 ISA/PnP Ethernet driver"); MODULE_LICENSE("GPL"); #endif /* MODULE */ @@ -214,8 +217,8 @@ static int __init do_ne_probe(struct net_device *dev) if (base_addr > 0x1ff) { /* Check a single specified location. */ int ret = ne_probe1(dev, base_addr); if (ret) - printk(KERN_WARNING "ne.c: No NE*000 card found at " - "i/o = %#lx\n", base_addr); + netdev_warn(dev, "ne.c: No NE*000 card found at " + "i/o = %#lx\n", base_addr); return ret; } else if (base_addr != 0) /* Don't probe at all. */ @@ -264,11 +267,14 @@ static int __init ne_probe_isapnp(struct net_device *dev) /* found it */ dev->base_addr = pnp_port_start(idev, 0); dev->irq = pnp_irq(idev, 0); - printk(KERN_INFO "ne.c: ISAPnP reports %s at i/o %#lx, irq %d.\n", - (char *) isapnp_clone_list[i].driver_data, - dev->base_addr, dev->irq); + netdev_info(dev, + "ne.c: ISAPnP reports %s at i/o %#lx, irq %d.\n", + (char *) isapnp_clone_list[i].driver_data, + dev->base_addr, dev->irq); if (ne_probe1(dev, dev->base_addr) != 0) { /* Shouldn't happen. */ - printk(KERN_ERR "ne.c: Probe of ISAPnP card at %#lx failed.\n", dev->base_addr); + netdev_err(dev, + "ne.c: Probe of ISAPnP card at %#lx failed.\n", + dev->base_addr); pnp_device_detach(idev); return -ENXIO; } @@ -293,6 +299,7 @@ static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr) int neX000, ctron, copam, bad_card; int reg0, ret; static unsigned version_printed; + struct ei_device *ei_local = netdev_priv(dev); if (!request_region(ioaddr, NE_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -319,10 +326,10 @@ static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr) } } - if (ei_debug && version_printed++ == 0) - printk(KERN_INFO "%s%s", version1, version2); + if ((ne_msg_enable & NETIF_MSG_DRV) && (version_printed++ == 0)) + netdev_info(dev, "%s%s", version1, version2); - printk(KERN_INFO "NE*000 ethercard probe at %#3lx:", ioaddr); + netdev_info(dev, "NE*000 ethercard probe at %#3lx:", ioaddr); /* A user with a poor card that fails to ack the reset, or that does not have a valid 0x57,0x57 signature can still use this @@ -343,10 +350,10 @@ static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr) while ((inb_p(ioaddr + EN0_ISR) & ENISR_RESET) == 0) if (time_after(jiffies, reset_start_time + 2*HZ/100)) { if (bad_card) { - printk(" (warning: no reset ack)"); + pr_cont(" (warning: no reset ack)"); break; } else { - printk(" not found (no reset ack).\n"); + pr_cont(" not found (no reset ack).\n"); ret = -ENODEV; goto err_out; } @@ -454,13 +461,13 @@ static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr) } if (bad_clone_list[i].name8 == NULL) { - printk(" not found (invalid signature %2.2x %2.2x).\n", + pr_cont(" not found (invalid signature %2.2x %2.2x).\n", SA_prom[14], SA_prom[15]); ret = -ENXIO; goto err_out; } #else - printk(" not found.\n"); + pr_cont(" not found.\n"); ret = -ENXIO; goto err_out; #endif @@ -476,15 +483,15 @@ static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr) mdelay(10); /* wait 10ms for interrupt to propagate */ outb_p(0x00, ioaddr + EN0_IMR); /* Mask it again. */ dev->irq = probe_irq_off(cookie); - if (ei_debug > 2) - printk(" autoirq is %d\n", dev->irq); + if (netif_msg_probe(ei_local)) + pr_cont(" autoirq is %d", dev->irq); } else if (dev->irq == 2) /* Fixup for users that don't know that IRQ 2 is really IRQ 9, or don't know which one to set. */ dev->irq = 9; if (! dev->irq) { - printk(" failed to detect IRQ line.\n"); + pr_cont(" failed to detect IRQ line.\n"); ret = -EAGAIN; goto err_out; } @@ -493,7 +500,7 @@ static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr) share and the board will usually be enabled. */ ret = request_irq(dev->irq, eip_interrupt, 0, name, dev); if (ret) { - printk (" unable to get IRQ %d (errno=%d).\n", dev->irq, ret); + pr_cont(" unable to get IRQ %d (errno=%d).\n", dev->irq, ret); goto err_out; } @@ -512,7 +519,7 @@ static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr) } #endif - printk("%pM\n", dev->dev_addr); + pr_cont("%pM\n", dev->dev_addr); ei_status.name = name; ei_status.tx_start_page = start_page; @@ -536,11 +543,12 @@ static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr) dev->netdev_ops = &eip_netdev_ops; NS8390p_init(dev, 0); + ei_local->msg_enable = ne_msg_enable; ret = register_netdev(dev); if (ret) goto out_irq; - printk(KERN_INFO "%s: %s found at %#lx, using IRQ %d.\n", - dev->name, name, ioaddr, dev->irq); + netdev_info(dev, "%s found at %#lx, using IRQ %d.\n", + name, ioaddr, dev->irq); return 0; out_irq: @@ -556,9 +564,9 @@ err_out: static void ne_reset_8390(struct net_device *dev) { unsigned long reset_start_time = jiffies; + struct ei_device *ei_local = netdev_priv(dev); - if (ei_debug > 1) - printk(KERN_DEBUG "resetting the 8390 t=%ld...", jiffies); + netif_dbg(ei_local, hw, dev, "resetting the 8390 t=%ld...\n", jiffies); /* DON'T change these to inb_p/outb_p or reset will fail on clones. */ outb(inb(NE_BASE + NE_RESET), NE_BASE + NE_RESET); @@ -569,7 +577,7 @@ static void ne_reset_8390(struct net_device *dev) /* This check _should_not_ be necessary, omit eventually. */ while ((inb_p(NE_BASE+EN0_ISR) & ENISR_RESET) == 0) if (time_after(jiffies, reset_start_time + 2*HZ/100)) { - printk(KERN_WARNING "%s: ne_reset_8390() did not complete.\n", dev->name); + netdev_err(dev, "ne_reset_8390() did not complete.\n"); break; } outb_p(ENISR_RESET, NE_BASE + EN0_ISR); /* Ack intr. */ @@ -587,9 +595,9 @@ static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, i if (ei_status.dmaing) { - printk(KERN_EMERG "%s: DMAing conflict in ne_get_8390_hdr " - "[DMAstat:%d][irqlock:%d].\n", - dev->name, ei_status.dmaing, ei_status.irqlock); + netdev_err(dev, "DMAing conflict in ne_get_8390_hdr " + "[DMAstat:%d][irqlock:%d].\n", + ei_status.dmaing, ei_status.irqlock); return; } @@ -621,6 +629,7 @@ static void ne_block_input(struct net_device *dev, int count, struct sk_buff *sk { #ifdef NE_SANITY_CHECK int xfer_count = count; + struct ei_device *ei_local = netdev_priv(dev); #endif int nic_base = dev->base_addr; char *buf = skb->data; @@ -628,9 +637,9 @@ static void ne_block_input(struct net_device *dev, int count, struct sk_buff *sk /* This *shouldn't* happen. If it does, it's the last thing you'll see */ if (ei_status.dmaing) { - printk(KERN_EMERG "%s: DMAing conflict in ne_block_input " - "[DMAstat:%d][irqlock:%d].\n", - dev->name, ei_status.dmaing, ei_status.irqlock); + netdev_err(dev, "DMAing conflict in ne_block_input " + "[DMAstat:%d][irqlock:%d].\n", + ei_status.dmaing, ei_status.irqlock); return; } ei_status.dmaing |= 0x01; @@ -660,7 +669,7 @@ static void ne_block_input(struct net_device *dev, int count, struct sk_buff *sk this message you either 1) have a slightly incompatible clone or 2) have noise/speed problems with your bus. */ - if (ei_debug > 1) + if (netif_msg_rx_status(ei_local)) { /* DMA termination address check... */ int addr, tries = 20; @@ -674,9 +683,9 @@ static void ne_block_input(struct net_device *dev, int count, struct sk_buff *sk break; } while (--tries > 0); if (tries <= 0) - printk(KERN_WARNING "%s: RX transfer address mismatch," - "%#4.4x (expected) vs. %#4.4x (actual).\n", - dev->name, ring_offset + xfer_count, addr); + netdev_warn(dev, "RX transfer address mismatch," + "%#4.4x (expected) vs. %#4.4x (actual).\n", + ring_offset + xfer_count, addr); } #endif outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ @@ -690,6 +699,7 @@ static void ne_block_output(struct net_device *dev, int count, unsigned long dma_start; #ifdef NE_SANITY_CHECK int retries = 0; + struct ei_device *ei_local = netdev_priv(dev); #endif /* Round the count up for word writes. Do we need to do this? @@ -702,9 +712,9 @@ static void ne_block_output(struct net_device *dev, int count, /* This *shouldn't* happen. If it does, it's the last thing you'll see */ if (ei_status.dmaing) { - printk(KERN_EMERG "%s: DMAing conflict in ne_block_output." - "[DMAstat:%d][irqlock:%d]\n", - dev->name, ei_status.dmaing, ei_status.irqlock); + netdev_err(dev, "DMAing conflict in ne_block_output." + "[DMAstat:%d][irqlock:%d]\n", + ei_status.dmaing, ei_status.irqlock); return; } ei_status.dmaing |= 0x01; @@ -751,7 +761,7 @@ retry: /* This was for the ALPHA version only, but enough people have been encountering problems so it is still here. */ - if (ei_debug > 1) + if (netif_msg_tx_queued(ei_local)) { /* DMA termination address check... */ int addr, tries = 20; @@ -765,9 +775,9 @@ retry: if (tries <= 0) { - printk(KERN_WARNING "%s: Tx packet transfer address mismatch," - "%#4.4x (expected) vs. %#4.4x (actual).\n", - dev->name, (start_page << 8) + count, addr); + netdev_warn(dev, "Tx packet transfer address mismatch," + "%#4.4x (expected) vs. %#4.4x (actual).\n", + (start_page << 8) + count, addr); if (retries++ == 0) goto retry; } @@ -776,7 +786,7 @@ retry: while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0) if (time_after(jiffies, dma_start + 2*HZ/100)) { /* 20ms */ - printk(KERN_WARNING "%s: timeout waiting for Tx RDC.\n", dev->name); + netdev_warn(dev, "timeout waiting for Tx RDC.\n"); ne_reset_8390(dev); NS8390p_init(dev, 1); break; @@ -936,8 +946,8 @@ int __init init_module(void) retval = platform_driver_probe(&ne_driver, ne_drv_probe); if (retval) { if (io[0] == 0) - printk(KERN_NOTICE "ne.c: You must supply \"io=0xNNN\"" - " value(s) for ISA cards.\n"); + pr_notice("ne.c: You must supply \"io=0xNNN\"" + " value(s) for ISA cards.\n"); ne_loop_rm_unreg(1); return retval; } diff --git a/drivers/net/ethernet/8390/ne2k-pci.c b/drivers/net/ethernet/8390/ne2k-pci.c index fc14a85e4d5..f395c967262 100644 --- a/drivers/net/ethernet/8390/ne2k-pci.c +++ b/drivers/net/ethernet/8390/ne2k-pci.c @@ -33,8 +33,6 @@ /* The user-configurable values. These may be modified when a driver module is loaded.*/ -static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ - #define MAX_UNITS 8 /* More are supported, limit only on options */ /* Used to pass the full-duplex flag, etc. */ static int full_duplex[MAX_UNITS]; @@ -60,6 +58,8 @@ static int options[MAX_UNITS]; #include "8390.h" +static u32 ne2k_msg_enable; + /* These identify the driver base version and may not be removed. */ static const char version[] = KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE @@ -76,10 +76,10 @@ MODULE_AUTHOR("Donald Becker / Paul Gortmaker"); MODULE_DESCRIPTION("PCI NE2000 clone driver"); MODULE_LICENSE("GPL"); -module_param(debug, int, 0); +module_param_named(msg_enable, ne2k_msg_enable, uint, (S_IRUSR|S_IRGRP|S_IROTH)); module_param_array(options, int, NULL, 0); module_param_array(full_duplex, int, NULL, 0); -MODULE_PARM_DESC(debug, "debug level (1-2)"); +MODULE_PARM_DESC(msg_enable, "Debug message level (see linux/netdevice.h for bitmap)"); MODULE_PARM_DESC(options, "Bit 5: full duplex"); MODULE_PARM_DESC(full_duplex, "full duplex setting(s) (1)"); @@ -226,6 +226,7 @@ static int ne2k_pci_init_one(struct pci_dev *pdev, static unsigned int fnd_cnt; long ioaddr; int flags = pci_clone_list[chip_idx].flags; + struct ei_device *ei_local; /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -280,6 +281,8 @@ static int ne2k_pci_init_one(struct pci_dev *pdev, goto err_out_free_res; } dev->netdev_ops = &ne2k_netdev_ops; + ei_local = netdev_priv(dev); + ei_local->msg_enable = ne2k_msg_enable; SET_NETDEV_DEV(dev, &pdev->dev); @@ -379,9 +382,9 @@ static int ne2k_pci_init_one(struct pci_dev *pdev, if (i) goto err_out_free_netdev; - printk("%s: %s found at %#lx, IRQ %d, %pM.\n", - dev->name, pci_clone_list[chip_idx].name, ioaddr, dev->irq, - dev->dev_addr); + netdev_info(dev, "%s found at %#lx, IRQ %d, %pM.\n", + pci_clone_list[chip_idx].name, ioaddr, dev->irq, + dev->dev_addr); return 0; @@ -450,9 +453,10 @@ static int ne2k_pci_close(struct net_device *dev) static void ne2k_pci_reset_8390(struct net_device *dev) { unsigned long reset_start_time = jiffies; + struct ei_device *ei_local = netdev_priv(dev); - if (debug > 1) printk("%s: Resetting the 8390 t=%ld...", - dev->name, jiffies); + netif_dbg(ei_local, hw, dev, "resetting the 8390 t=%ld...\n", + jiffies); outb(inb(NE_BASE + NE_RESET), NE_BASE + NE_RESET); @@ -462,7 +466,7 @@ static void ne2k_pci_reset_8390(struct net_device *dev) /* This check _should_not_ be necessary, omit eventually. */ while ((inb(NE_BASE+EN0_ISR) & ENISR_RESET) == 0) if (jiffies - reset_start_time > 2) { - printk("%s: ne2k_pci_reset_8390() did not complete.\n", dev->name); + netdev_err(dev, "ne2k_pci_reset_8390() did not complete.\n"); break; } outb(ENISR_RESET, NE_BASE + EN0_ISR); /* Ack intr. */ @@ -479,9 +483,9 @@ static void ne2k_pci_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr * /* This *shouldn't* happen. If it does, it's the last thing you'll see */ if (ei_status.dmaing) { - printk("%s: DMAing conflict in ne2k_pci_get_8390_hdr " + netdev_err(dev, "DMAing conflict in ne2k_pci_get_8390_hdr " "[DMAstat:%d][irqlock:%d].\n", - dev->name, ei_status.dmaing, ei_status.irqlock); + ei_status.dmaing, ei_status.irqlock); return; } @@ -517,9 +521,9 @@ static void ne2k_pci_block_input(struct net_device *dev, int count, /* This *shouldn't* happen. If it does, it's the last thing you'll see */ if (ei_status.dmaing) { - printk("%s: DMAing conflict in ne2k_pci_block_input " + netdev_err(dev, "DMAing conflict in ne2k_pci_block_input " "[DMAstat:%d][irqlock:%d].\n", - dev->name, ei_status.dmaing, ei_status.irqlock); + ei_status.dmaing, ei_status.irqlock); return; } ei_status.dmaing |= 0x01; @@ -572,9 +576,9 @@ static void ne2k_pci_block_output(struct net_device *dev, int count, /* This *shouldn't* happen. If it does, it's the last thing you'll see */ if (ei_status.dmaing) { - printk("%s: DMAing conflict in ne2k_pci_block_output." + netdev_err(dev, "DMAing conflict in ne2k_pci_block_output." "[DMAstat:%d][irqlock:%d]\n", - dev->name, ei_status.dmaing, ei_status.irqlock); + ei_status.dmaing, ei_status.irqlock); return; } ei_status.dmaing |= 0x01; @@ -619,7 +623,7 @@ static void ne2k_pci_block_output(struct net_device *dev, int count, while ((inb(nic_base + EN0_ISR) & ENISR_RDC) == 0) if (jiffies - dma_start > 2) { /* Avoid clock roll-over. */ - printk(KERN_WARNING "%s: timeout waiting for Tx RDC.\n", dev->name); + netdev_warn(dev, "timeout waiting for Tx RDC.\n"); ne2k_pci_reset_8390(dev); NS8390_init(dev,1); break; @@ -640,8 +644,24 @@ static void ne2k_pci_get_drvinfo(struct net_device *dev, strlcpy(info->bus_info, pci_name(pci_dev), sizeof(info->bus_info)); } +static u32 ne2k_pci_get_msglevel(struct net_device *dev) +{ + struct ei_device *ei_local = netdev_priv(dev); + + return ei_local->msg_enable; +} + +static void ne2k_pci_set_msglevel(struct net_device *dev, u32 v) +{ + struct ei_device *ei_local = netdev_priv(dev); + + ei_local->msg_enable = v; +} + static const struct ethtool_ops ne2k_pci_ethtool_ops = { .get_drvinfo = ne2k_pci_get_drvinfo, + .get_msglevel = ne2k_pci_get_msglevel, + .set_msglevel = ne2k_pci_set_msglevel, }; static void ne2k_pci_remove_one(struct pci_dev *pdev) diff --git a/drivers/net/ethernet/8390/pcnet_cs.c b/drivers/net/ethernet/8390/pcnet_cs.c index 46c5aadaca8..eea33d667fb 100644 --- a/drivers/net/ethernet/8390/pcnet_cs.c +++ b/drivers/net/ethernet/8390/pcnet_cs.c @@ -67,7 +67,7 @@ #define PCNET_RDC_TIMEOUT (2*HZ/100) /* Max wait in jiffies for Tx RDC */ static const char *if_names[] = { "auto", "10baseT", "10base2"}; - +static u32 pcnet_msg_enable; /*====================================================================*/ @@ -558,6 +558,7 @@ static int pcnet_config(struct pcmcia_device *link) int start_pg, stop_pg, cm_offset; int has_shmem = 0; hw_info_t *local_hw_info; + struct ei_device *ei_local; dev_dbg(&link->dev, "pcnet_config\n"); @@ -607,6 +608,8 @@ static int pcnet_config(struct pcmcia_device *link) mii_phy_probe(dev); SET_NETDEV_DEV(dev, &link->dev); + ei_local = netdev_priv(dev); + ei_local->msg_enable = pcnet_msg_enable; if (register_netdev(dev) != 0) { pr_notice("register_netdev() failed\n"); @@ -616,7 +619,7 @@ static int pcnet_config(struct pcmcia_device *link) if (info->flags & (IS_DL10019|IS_DL10022)) { u_char id = inb(dev->base_addr + 0x1a); netdev_info(dev, "NE2000 (DL100%d rev %02x): ", - (info->flags & IS_DL10022) ? 22 : 19, id); + (info->flags & IS_DL10022) ? 22 : 19, id); if (info->pna_phy) pr_cont("PNA, "); } else { @@ -1063,9 +1066,9 @@ static void ei_watchdog(u_long arg) if (info->phy_id == info->eth_phy) { if (p) netdev_info(dev, "autonegotiation complete: " - "%sbaseT-%cD selected\n", - ((p & 0x0180) ? "100" : "10"), - ((p & 0x0140) ? 'F' : 'H')); + "%sbaseT-%cD selected\n", + ((p & 0x0180) ? "100" : "10"), + ((p & 0x0140) ? 'F' : 'H')); else netdev_info(dev, "link partner did not autonegotiate\n"); } @@ -1081,7 +1084,7 @@ static void ei_watchdog(u_long arg) mdio_write(mii_addr, info->phy_id, 0, 0x0400); info->phy_id ^= info->pna_phy ^ info->eth_phy; netdev_info(dev, "switched to %s transceiver\n", - (info->phy_id == info->eth_phy) ? "ethernet" : "PNA"); + (info->phy_id == info->eth_phy) ? "ethernet" : "PNA"); mdio_write(mii_addr, info->phy_id, 0, (info->phy_id == info->eth_phy) ? 0x1000 : 0); info->link_status = 0; @@ -1128,9 +1131,9 @@ static void dma_get_8390_hdr(struct net_device *dev, unsigned int nic_base = dev->base_addr; if (ei_status.dmaing) { - netdev_notice(dev, "DMAing conflict in dma_block_input." - "[DMAstat:%1x][irqlock:%1x]\n", - ei_status.dmaing, ei_status.irqlock); + netdev_err(dev, "DMAing conflict in dma_block_input." + "[DMAstat:%1x][irqlock:%1x]\n", + ei_status.dmaing, ei_status.irqlock); return; } @@ -1159,13 +1162,14 @@ static void dma_block_input(struct net_device *dev, int count, unsigned int nic_base = dev->base_addr; int xfer_count = count; char *buf = skb->data; + struct ei_device *ei_local = netdev_priv(dev); - if ((ei_debug > 4) && (count != 4)) + if ((netif_msg_rx_status(ei_local)) && (count != 4)) netdev_dbg(dev, "[bi=%d]\n", count+4); if (ei_status.dmaing) { - netdev_notice(dev, "DMAing conflict in dma_block_input." - "[DMAstat:%1x][irqlock:%1x]\n", - ei_status.dmaing, ei_status.irqlock); + netdev_err(dev, "DMAing conflict in dma_block_input." + "[DMAstat:%1x][irqlock:%1x]\n", + ei_status.dmaing, ei_status.irqlock); return; } ei_status.dmaing |= 0x01; @@ -1183,7 +1187,8 @@ static void dma_block_input(struct net_device *dev, int count, /* This was for the ALPHA version only, but enough people have been encountering problems that it is still here. */ #ifdef PCMCIA_DEBUG - if (ei_debug > 4) { /* DMA termination address check... */ + /* DMA termination address check... */ + if (netif_msg_rx_status(ei_local)) { int addr, tries = 20; do { /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here @@ -1196,8 +1201,8 @@ static void dma_block_input(struct net_device *dev, int count, } while (--tries > 0); if (tries <= 0) netdev_notice(dev, "RX transfer address mismatch," - "%#4.4x (expected) vs. %#4.4x (actual).\n", - ring_offset + xfer_count, addr); + "%#4.4x (expected) vs. %#4.4x (actual).\n", + ring_offset + xfer_count, addr); } #endif outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ @@ -1213,12 +1218,12 @@ static void dma_block_output(struct net_device *dev, int count, pcnet_dev_t *info = PRIV(dev); #ifdef PCMCIA_DEBUG int retries = 0; + struct ei_device *ei_local = netdev_priv(dev); #endif u_long dma_start; #ifdef PCMCIA_DEBUG - if (ei_debug > 4) - netdev_dbg(dev, "[bo=%d]\n", count); + netif_dbg(ei_local, tx_queued, dev, "[bo=%d]\n", count); #endif /* Round the count up for word writes. Do we need to do this? @@ -1227,9 +1232,9 @@ static void dma_block_output(struct net_device *dev, int count, if (count & 0x01) count++; if (ei_status.dmaing) { - netdev_notice(dev, "DMAing conflict in dma_block_output." - "[DMAstat:%1x][irqlock:%1x]\n", - ei_status.dmaing, ei_status.irqlock); + netdev_err(dev, "DMAing conflict in dma_block_output." + "[DMAstat:%1x][irqlock:%1x]\n", + ei_status.dmaing, ei_status.irqlock); return; } ei_status.dmaing |= 0x01; @@ -1256,7 +1261,8 @@ static void dma_block_output(struct net_device *dev, int count, #ifdef PCMCIA_DEBUG /* This was for the ALPHA version only, but enough people have been encountering problems that it is still here. */ - if (ei_debug > 4) { /* DMA termination address check... */ + /* DMA termination address check... */ + if (netif_msg_tx_queued(ei_local)) { int addr, tries = 20; do { int high = inb_p(nic_base + EN0_RSARHI); @@ -1267,8 +1273,8 @@ static void dma_block_output(struct net_device *dev, int count, } while (--tries > 0); if (tries <= 0) { netdev_notice(dev, "Tx packet transfer address mismatch," - "%#4.4x (expected) vs. %#4.4x (actual).\n", - (start_page << 8) + count, addr); + "%#4.4x (expected) vs. %#4.4x (actual).\n", + (start_page << 8) + count, addr); if (retries++ == 0) goto retry; } @@ -1277,10 +1283,10 @@ static void dma_block_output(struct net_device *dev, int count, while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0) if (time_after(jiffies, dma_start + PCNET_RDC_TIMEOUT)) { - netdev_notice(dev, "timeout waiting for Tx RDC.\n"); - pcnet_reset_8390(dev); - NS8390_init(dev, 1); - break; + netdev_warn(dev, "timeout waiting for Tx RDC.\n"); + pcnet_reset_8390(dev); + NS8390_init(dev, 1); + break; } outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ diff --git a/drivers/net/ethernet/8390/smc-ultra.c b/drivers/net/ethernet/8390/smc-ultra.c index b0fbce39661..139385dcdaa 100644 --- a/drivers/net/ethernet/8390/smc-ultra.c +++ b/drivers/net/ethernet/8390/smc-ultra.c @@ -111,6 +111,7 @@ static struct isapnp_device_id ultra_device_ids[] __initdata = { MODULE_DEVICE_TABLE(isapnp, ultra_device_ids); #endif +static u32 ultra_msg_enable; #define START_PG 0x00 /* First page of TX buffer */ @@ -211,6 +212,7 @@ static int __init ultra_probe1(struct net_device *dev, int ioaddr) unsigned char num_pages, irqreg, addr, piomode; unsigned char idreg = inb(ioaddr + 7); unsigned char reg4 = inb(ioaddr + 4) & 0x7f; + struct ei_device *ei_local = netdev_priv(dev); if (!request_region(ioaddr, ULTRA_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -232,16 +234,16 @@ static int __init ultra_probe1(struct net_device *dev, int ioaddr) goto out; } - if (ei_debug && version_printed++ == 0) - printk(version); + if ((ultra_msg_enable & NETIF_MSG_DRV) && (version_printed++ == 0)) + netdev_info(dev, version); model_name = (idreg & 0xF0) == 0x20 ? "SMC Ultra" : "SMC EtherEZ"; for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(ioaddr + 8 + i); - printk("%s: %s at %#3x, %pM", dev->name, model_name, - ioaddr, dev->dev_addr); + netdev_info(dev, "%s at %#3x, %pM", model_name, + ioaddr, dev->dev_addr); /* Switch from the station address to the alternate register set and read the useful registers there. */ @@ -265,7 +267,7 @@ static int __init ultra_probe1(struct net_device *dev, int ioaddr) irq = irqmap[((irqreg & 0x40) >> 4) + ((irqreg & 0x0c) >> 2)]; if (irq == 0) { - printk(", failed to detect IRQ line.\n"); + pr_cont(", failed to detect IRQ line.\n"); retval = -EAGAIN; goto out; } @@ -296,7 +298,7 @@ static int __init ultra_probe1(struct net_device *dev, int ioaddr) ei_status.mem = ioremap(dev->mem_start, (ei_status.stop_page - START_PG)*256); if (!ei_status.mem) { - printk(", failed to ioremap.\n"); + pr_cont(", failed to ioremap.\n"); retval = -ENOMEM; goto out; } @@ -304,14 +306,15 @@ static int __init ultra_probe1(struct net_device *dev, int ioaddr) dev->mem_end = dev->mem_start + (ei_status.stop_page - START_PG)*256; if (piomode) { - printk(",%s IRQ %d programmed-I/O mode.\n", - eeprom_irq ? "EEPROM" : "assigned ", dev->irq); + pr_cont(", %s IRQ %d programmed-I/O mode.\n", + eeprom_irq ? "EEPROM" : "assigned ", dev->irq); ei_status.block_input = &ultra_pio_input; ei_status.block_output = &ultra_pio_output; ei_status.get_8390_hdr = &ultra_pio_get_hdr; } else { - printk(",%s IRQ %d memory %#lx-%#lx.\n", eeprom_irq ? "" : "assigned ", - dev->irq, dev->mem_start, dev->mem_end-1); + pr_cont(", %s IRQ %d memory %#lx-%#lx.\n", + eeprom_irq ? "" : "assigned ", dev->irq, dev->mem_start, + dev->mem_end-1); ei_status.block_input = &ultra_block_input; ei_status.block_output = &ultra_block_output; ei_status.get_8390_hdr = &ultra_get_8390_hdr; @@ -320,6 +323,7 @@ static int __init ultra_probe1(struct net_device *dev, int ioaddr) dev->netdev_ops = &ultra_netdev_ops; NS8390_init(dev, 0); + ei_local->msg_enable = ultra_msg_enable; retval = register_netdev(dev); if (retval) @@ -356,12 +360,15 @@ static int __init ultra_probe_isapnp(struct net_device *dev) /* found it */ dev->base_addr = pnp_port_start(idev, 0); dev->irq = pnp_irq(idev, 0); - printk(KERN_INFO "smc-ultra.c: ISAPnP reports %s at i/o %#lx, irq %d.\n", - (char *) ultra_device_ids[i].driver_data, - dev->base_addr, dev->irq); + netdev_info(dev, + "smc-ultra.c: ISAPnP reports %s at i/o %#lx, irq %d.\n", + (char *) ultra_device_ids[i].driver_data, + dev->base_addr, dev->irq); if (ultra_probe1(dev, dev->base_addr) != 0) { /* Shouldn't happen. */ - printk(KERN_ERR "smc-ultra.c: Probe of ISAPnP card at %#lx failed.\n", dev->base_addr); - pnp_device_detach(idev); + netdev_err(dev, + "smc-ultra.c: Probe of ISAPnP card at %#lx failed.\n", + dev->base_addr); + pnp_device_detach(idev); return -ENXIO; } ei_status.priv = (unsigned long)idev; @@ -412,9 +419,10 @@ static void ultra_reset_8390(struct net_device *dev) { int cmd_port = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC base addr */ + struct ei_device *ei_local = netdev_priv(dev); outb(ULTRA_RESET, cmd_port); - if (ei_debug > 1) printk("resetting Ultra, t=%ld...", jiffies); + netif_dbg(ei_local, hw, dev, "resetting Ultra, t=%ld...\n", jiffies); ei_status.txing = 0; outb(0x00, cmd_port); /* Disable shared memory for safety. */ @@ -424,7 +432,7 @@ ultra_reset_8390(struct net_device *dev) else outb(0x01, cmd_port + 6); /* Enable interrupts and memory. */ - if (ei_debug > 1) printk("reset done\n"); + netif_dbg(ei_local, hw, dev, "reset done\n"); } /* Grab the 8390 specific header. Similar to the block_input routine, but @@ -530,11 +538,11 @@ static int ultra_close_card(struct net_device *dev) { int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* CMDREG */ + struct ei_device *ei_local = netdev_priv(dev); netif_stop_queue(dev); - if (ei_debug > 1) - printk("%s: Shutting down ethercard.\n", dev->name); + netif_dbg(ei_local, ifdown, dev, "Shutting down ethercard.\n"); outb(0x00, ioaddr + 6); /* Disable interrupts. */ free_irq(dev->irq, dev); @@ -556,8 +564,10 @@ static int irq[MAX_ULTRA_CARDS]; module_param_array(io, int, NULL, 0); module_param_array(irq, int, NULL, 0); +module_param_named(msg_enable, ultra_msg_enable, uint, (S_IRUSR|S_IRGRP|S_IROTH)); MODULE_PARM_DESC(io, "I/O base address(es)"); MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)"); +MODULE_PARM_DESC(msg_enable, "Debug message level (see linux/netdevice.h for bitmap)"); MODULE_DESCRIPTION("SMC Ultra/EtherEZ ISA/PnP Ethernet driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/8390/stnic.c b/drivers/net/ethernet/8390/stnic.c index 8df4c415723..aca957d4e12 100644 --- a/drivers/net/ethernet/8390/stnic.c +++ b/drivers/net/ethernet/8390/stnic.c @@ -69,6 +69,11 @@ static void stnic_block_output (struct net_device *dev, int count, static void stnic_init (struct net_device *dev); +static u32 stnic_msg_enable; + +module_param_named(msg_enable, stnic_msg_enable, uint, (S_IRUSR|S_IRGRP|S_IROTH)); +MODULE_PARM_DESC(msg_enable, "Debug message level (see linux/netdevice.h for bitmap)"); + /* SH7750 specific read/write io. */ static inline void STNIC_DELAY (void) @@ -100,6 +105,7 @@ static int __init stnic_probe(void) { struct net_device *dev; int i, err; + struct ei_device *ei_local; /* If we are not running on a SolutionEngine, give up now */ if (! MACH_SE) @@ -125,10 +131,10 @@ static int __init stnic_probe(void) share and the board will usually be enabled. */ err = request_irq (dev->irq, ei_interrupt, 0, DRV_NAME, dev); if (err) { - printk (KERN_EMERG " unable to get IRQ %d.\n", dev->irq); - free_netdev(dev); - return err; - } + netdev_emerg(dev, " unable to get IRQ %d.\n", dev->irq); + free_netdev(dev); + return err; + } ei_status.name = dev->name; ei_status.word16 = 1; @@ -147,6 +153,8 @@ static int __init stnic_probe(void) ei_status.block_output = &stnic_block_output; stnic_init (dev); + ei_local = netdev_priv(dev); + ei_local->msg_enable = stnic_msg_enable; err = register_netdev(dev); if (err) { @@ -156,7 +164,7 @@ static int __init stnic_probe(void) } stnic_dev = dev; - printk (KERN_INFO "NS ST-NIC 83902A\n"); + netdev_info(dev, "NS ST-NIC 83902A\n"); return 0; } @@ -164,10 +172,11 @@ static int __init stnic_probe(void) static void stnic_reset (struct net_device *dev) { + struct ei_device *ei_local = netdev_priv(dev); + *(vhalf *) PA_83902_RST = 0; udelay (5); - if (ei_debug > 1) - printk (KERN_WARNING "8390 reset done (%ld).\n", jiffies); + netif_warn(ei_local, hw, dev, "8390 reset done (%ld).\n", jiffies); *(vhalf *) PA_83902_RST = ~0; udelay (5); } @@ -176,6 +185,8 @@ static void stnic_get_hdr (struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page) { + struct ei_device *ei_local = netdev_priv(dev); + half buf[2]; STNIC_WRITE (PG0_RSAR0, 0); @@ -196,8 +207,7 @@ stnic_get_hdr (struct net_device *dev, struct e8390_pkt_hdr *hdr, hdr->count = ((buf[1] >> 8) & 0xff) | (buf[1] << 8); #endif - if (ei_debug > 1) - printk (KERN_DEBUG "ring %x status %02x next %02x count %04x.\n", + netif_dbg(ei_local, probe, dev, "ring %x status %02x next %02x count %04x.\n", ring_page, hdr->status, hdr->next, hdr->count); STNIC_WRITE (STNIC_CR, CR_RDMA | CR_PG0 | CR_STA); diff --git a/drivers/net/ethernet/8390/wd.c b/drivers/net/ethernet/8390/wd.c index 03eb3eed49f..dd7d816bde5 100644 --- a/drivers/net/ethernet/8390/wd.c +++ b/drivers/net/ethernet/8390/wd.c @@ -60,6 +60,7 @@ static void wd_block_output(struct net_device *dev, int count, const unsigned char *buf, int start_page); static int wd_close(struct net_device *dev); +static u32 wd_msg_enable; #define WD_START_PG 0x00 /* First page of TX buffer */ #define WD03_STOP_PG 0x20 /* Last page +1 of RX ring */ @@ -170,6 +171,7 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr) int word16 = 0; /* 0 = 8 bit, 1 = 16 bit */ const char *model_name; static unsigned version_printed; + struct ei_device *ei_local = netdev_priv(dev); for (i = 0; i < 8; i++) checksum += inb(ioaddr + 8 + i); @@ -180,19 +182,19 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr) /* Check for semi-valid mem_start/end values if supplied. */ if ((dev->mem_start % 0x2000) || (dev->mem_end % 0x2000)) { - printk(KERN_WARNING "wd.c: user supplied mem_start or mem_end not on 8kB boundary - ignored.\n"); + netdev_warn(dev, + "wd.c: user supplied mem_start or mem_end not on 8kB boundary - ignored.\n"); dev->mem_start = 0; dev->mem_end = 0; } - if (ei_debug && version_printed++ == 0) - printk(version); + if ((wd_msg_enable & NETIF_MSG_DRV) && (version_printed++ == 0)) + netdev_info(dev, version); for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(ioaddr + 8 + i); - printk("%s: WD80x3 at %#3x, %pM", - dev->name, ioaddr, dev->dev_addr); + netdev_info(dev, "WD80x3 at %#3x, %pM", ioaddr, dev->dev_addr); /* The following PureData probe code was contributed by Mike Jagdis . Puredata does software @@ -244,8 +246,9 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr) } #ifndef final_version if ( !ancient && (inb(ioaddr+1) & 0x01) != (word16 & 0x01)) - printk("\nWD80?3: Bus width conflict, %d (probe) != %d (reg report).", - word16 ? 16 : 8, (inb(ioaddr+1) & 0x01) ? 16 : 8); + pr_cont("\nWD80?3: Bus width conflict, %d (probe) != %d (reg report).", + word16 ? 16 : 8, + (inb(ioaddr+1) & 0x01) ? 16 : 8); #endif } @@ -259,7 +262,7 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr) if (reg0 == 0xff || reg0 == 0) { /* Future plan: this could check a few likely locations first. */ dev->mem_start = 0xd0000; - printk(" assigning address %#lx", dev->mem_start); + pr_cont(" assigning address %#lx", dev->mem_start); } else { int high_addr_bits = inb(ioaddr+WD_CMDREG5) & 0x1f; /* Some boards don't have the register 5 -- it returns 0xff. */ @@ -297,8 +300,8 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr) outb_p(0x00, nic_addr+EN0_IMR); /* Mask all intrs. again. */ - if (ei_debug > 2) - printk(" autoirq is %d", dev->irq); + if (netif_msg_drv(ei_local)) + pr_cont(" autoirq is %d", dev->irq); if (dev->irq < 2) dev->irq = word16 ? 10 : 5; } else @@ -310,7 +313,7 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr) share and the board will usually be enabled. */ i = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev); if (i) { - printk (" unable to get IRQ %d.\n", dev->irq); + pr_cont(" unable to get IRQ %d.\n", dev->irq); return i; } @@ -338,8 +341,8 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr) return -ENOMEM; } - printk(" %s, IRQ %d, shared memory at %#lx-%#lx.\n", - model_name, dev->irq, dev->mem_start, dev->mem_end-1); + pr_cont(" %s, IRQ %d, shared memory at %#lx-%#lx.\n", + model_name, dev->irq, dev->mem_start, dev->mem_end-1); ei_status.reset_8390 = wd_reset_8390; ei_status.block_input = wd_block_input; @@ -348,6 +351,7 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr) dev->netdev_ops = &wd_netdev_ops; NS8390_init(dev, 0); + ei_local->msg_enable = wd_msg_enable; #if 1 /* Enable interrupt generation on softconfig cards -- M.U */ @@ -385,9 +389,11 @@ static void wd_reset_8390(struct net_device *dev) { int wd_cmd_port = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */ + struct ei_device *ei_local = netdev_priv(dev); outb(WD_RESET, wd_cmd_port); - if (ei_debug > 1) printk("resetting the WD80x3 t=%lu...", jiffies); + netif_dbg(ei_local, hw, dev, "resetting the WD80x3 t=%lu...\n", + jiffies); ei_status.txing = 0; /* Set up the ASIC registers, just in case something changed them. */ @@ -395,7 +401,7 @@ wd_reset_8390(struct net_device *dev) if (ei_status.word16) outb(NIC16 | ((dev->mem_start>>19) & 0x1f), wd_cmd_port+WD_CMDREG5); - if (ei_debug > 1) printk("reset done\n"); + netif_dbg(ei_local, hw, dev, "reset done\n"); } /* Grab the 8390 specific header. Similar to the block_input routine, but @@ -474,9 +480,9 @@ static int wd_close(struct net_device *dev) { int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */ + struct ei_device *ei_local = netdev_priv(dev); - if (ei_debug > 1) - printk("%s: Shutting down ethercard.\n", dev->name); + netif_dbg(ei_local, ifdown, dev, "Shutting down ethercard.\n"); ei_close(dev); /* Change from 16-bit to 8-bit shared memory so reboot works. */ @@ -502,10 +508,12 @@ module_param_array(io, int, NULL, 0); module_param_array(irq, int, NULL, 0); module_param_array(mem, int, NULL, 0); module_param_array(mem_end, int, NULL, 0); +module_param_named(msg_enable, wd_msg_enable, uint, (S_IRUSR|S_IRGRP|S_IROTH)); MODULE_PARM_DESC(io, "I/O base address(es)"); MODULE_PARM_DESC(irq, "IRQ number(s) (ignored for PureData boards)"); MODULE_PARM_DESC(mem, "memory base address(es)(ignored for PureData boards)"); MODULE_PARM_DESC(mem_end, "memory end address(es)"); +MODULE_PARM_DESC(msg_enable, "Debug message level (see linux/netdevice.h for bitmap)"); MODULE_DESCRIPTION("ISA Western Digital wd8003/wd8013 ; SMC Elite, Elite16 ethernet driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/8390/zorro8390.c b/drivers/net/ethernet/8390/zorro8390.c index 85ec4c2d264..7b373e65f37 100644 --- a/drivers/net/ethernet/8390/zorro8390.c +++ b/drivers/net/ethernet/8390/zorro8390.c @@ -44,6 +44,8 @@ static const char version[] = "8390.c:v1.10cvs 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; +static u32 zorro8390_msg_enable; + #include "lib8390.c" #define DRV_NAME "zorro8390" @@ -86,9 +88,9 @@ static struct card_info { static void zorro8390_reset_8390(struct net_device *dev) { unsigned long reset_start_time = jiffies; + struct ei_device *ei_local = netdev_priv(dev); - if (ei_debug > 1) - netdev_dbg(dev, "resetting - t=%ld...\n", jiffies); + netif_dbg(ei_local, hw, dev, "resetting - t=%ld...\n", jiffies); z_writeb(z_readb(NE_BASE + NE_RESET), NE_BASE + NE_RESET); @@ -119,8 +121,9 @@ static void zorro8390_get_8390_hdr(struct net_device *dev, * If it does, it's the last thing you'll see */ if (ei_status.dmaing) { - netdev_err(dev, "%s: DMAing conflict [DMAstat:%d][irqlock:%d]\n", - __func__, ei_status.dmaing, ei_status.irqlock); + netdev_warn(dev, + "%s: DMAing conflict [DMAstat:%d][irqlock:%d]\n", + __func__, ei_status.dmaing, ei_status.irqlock); return; } @@ -230,7 +233,7 @@ static void zorro8390_block_output(struct net_device *dev, int count, while ((z_readb(NE_BASE + NE_EN0_ISR) & ENISR_RDC) == 0) if (time_after(jiffies, dma_start + 2 * HZ / 100)) { /* 20ms */ - netdev_err(dev, "timeout waiting for Tx RDC\n"); + netdev_warn(dev, "timeout waiting for Tx RDC\n"); zorro8390_reset_8390(dev); __NS8390_init(dev, 1); break; @@ -248,8 +251,9 @@ static int zorro8390_open(struct net_device *dev) static int zorro8390_close(struct net_device *dev) { - if (ei_debug > 1) - netdev_dbg(dev, "Shutting down ethercard\n"); + struct ei_device *ei_local = netdev_priv(dev); + + netif_dbg(ei_local, ifdown, dev, "Shutting down ethercard\n"); __ei_close(dev); return 0; } @@ -293,6 +297,7 @@ static int zorro8390_init(struct net_device *dev, unsigned long board, int err; unsigned char SA_prom[32]; int start_page, stop_page; + struct ei_device *ei_local = netdev_priv(dev); static u32 zorro8390_offsets[16] = { 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, @@ -383,6 +388,9 @@ static int zorro8390_init(struct net_device *dev, unsigned long board, dev->netdev_ops = &zorro8390_netdev_ops; __NS8390_init(dev, 0); + + ei_local->msg_enable = zorro8390_msg_enable; + err = register_netdev(dev); if (err) { free_irq(IRQ_AMIGA_PORTS, dev); -- cgit v1.2.3-70-g09d2 From c767db5147f0f257accbb26639a2b916d5ffb1e6 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 11 Dec 2013 15:51:20 -0800 Subject: net: eth: davinci_cpdma: 64-bit phys/dma_addr_t cleanup Silences the below warnings when building with ARM_LPAE enabled, which gives longer dma_addr_t by default: drivers/net/ethernet/ti/davinci_cpdma.c: In function 'cpdma_desc_pool_create': drivers/net/ethernet/ti/davinci_cpdma.c:182:3: warning: passing argument 3 of 'dma_alloc_attrs' from incompatible pointer type [enabled by default] drivers/net/ethernet/ti/davinci_cpdma.c: In function 'desc_phys': drivers/net/ethernet/ti/davinci_cpdma.c:222:25: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] drivers/net/ethernet/ti/davinci_cpdma.c:223:8: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] Signed-off-by: Olof Johansson Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/davinci_cpdma.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/ti/davinci_cpdma.c b/drivers/net/ethernet/ti/davinci_cpdma.c index 90a79462c86..b041a877fe2 100644 --- a/drivers/net/ethernet/ti/davinci_cpdma.c +++ b/drivers/net/ethernet/ti/davinci_cpdma.c @@ -81,7 +81,7 @@ struct cpdma_desc { }; struct cpdma_desc_pool { - u32 phys; + phys_addr_t phys; u32 hw_addr; void __iomem *iomap; /* ioremap map */ void *cpumap; /* dma_alloc map */ @@ -219,8 +219,7 @@ static inline dma_addr_t desc_phys(struct cpdma_desc_pool *pool, { if (!desc) return 0; - return pool->hw_addr + (__force dma_addr_t)desc - - (__force dma_addr_t)pool->iomap; + return pool->hw_addr + (__force long)desc - (__force long)pool->iomap; } static inline struct cpdma_desc __iomem * -- cgit v1.2.3-70-g09d2 From df7841604394c57289072d15fcd90a2585b701a6 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 11 Dec 2013 15:51:21 -0800 Subject: net: eth: davinci_cpdma: Mark a local variable static Only used locally. Found by sparse. Signed-off-by: Olof Johansson Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/davinci_cpdma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/ti/davinci_cpdma.c b/drivers/net/ethernet/ti/davinci_cpdma.c index b041a877fe2..364d0c7952c 100644 --- a/drivers/net/ethernet/ti/davinci_cpdma.c +++ b/drivers/net/ethernet/ti/davinci_cpdma.c @@ -971,7 +971,7 @@ struct cpdma_control_info { #define ACCESS_RW (ACCESS_RO | ACCESS_WO) }; -struct cpdma_control_info controls[] = { +static struct cpdma_control_info controls[] = { [CPDMA_CMD_IDLE] = {CPDMA_DMACONTROL, 3, 1, ACCESS_WO}, [CPDMA_COPY_ERROR_FRAMES] = {CPDMA_DMACONTROL, 4, 1, ACCESS_RW}, [CPDMA_RX_OFF_LEN_UPDATE] = {CPDMA_DMACONTROL, 2, 1, ACCESS_RW}, -- cgit v1.2.3-70-g09d2 From 1a3b50566f259eb79039b720dbfdbb97a7a1b9c5 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 11 Dec 2013 15:58:07 -0800 Subject: net: eth: cpsw: 64-bit phys_addr_t and sparse cleanup Minor fix for printk format of a phys_addr_t, and the switch of two local functions to static since they're not used outside of the file. Signed-off-by: Olof Johansson Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpsw.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index c8a54f96cf5..915eca91056 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -582,7 +582,7 @@ static void cpsw_intr_disable(struct cpsw_priv *priv) return; } -void cpsw_tx_handler(void *token, int len, int status) +static void cpsw_tx_handler(void *token, int len, int status) { struct sk_buff *skb = token; struct net_device *ndev = skb->dev; @@ -599,7 +599,7 @@ void cpsw_tx_handler(void *token, int len, int status) dev_kfree_skb_any(skb); } -void cpsw_rx_handler(void *token, int len, int status) +static void cpsw_rx_handler(void *token, int len, int status) { struct sk_buff *skb = token; struct sk_buff *new_skb; @@ -2142,8 +2142,8 @@ static int cpsw_probe(struct platform_device *pdev) data->cpts_clock_mult, data->cpts_clock_shift)) dev_err(priv->dev, "error registering cpts device\n"); - cpsw_notice(priv, probe, "initialized device (regs %x, irq %d)\n", - ss_res->start, ndev->irq); + cpsw_notice(priv, probe, "initialized device (regs %pa, irq %d)\n", + &ss_res->start, ndev->irq); if (priv->data.dual_emac) { ret = cpsw_probe_dual_emac(pdev, priv); -- cgit v1.2.3-70-g09d2 From fd981e3c321a7e8661e06fa6077aea89e8228c3a Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Wed, 11 Dec 2013 23:43:43 +0100 Subject: filter: bpf_dbg: add minimal bpf debugger This patch adds a minimal BPF debugger that "emulates" the kernel's BPF engine (w/o extensions) and allows for single stepping (forwards and backwards through BPF code) or running with >=1 breakpoints through selected or all packets from a pcap file with a provided user filter in order to facilitate verification of a BPF program. When a breakpoint is being hit, it dumps all register contents, decoded instructions and in case of branches both decoded branch targets as well as other useful information. Having this facility is in particular useful to verify BPF programs against given test traffic *before* attaching to a live system. With the general availability of cls_bpf, xt_bpf, socket filters, team driver and e.g. PTP code, all BPF users, quite often a single more complex BPF program is being used. Reasons for a more complex BPF program are primarily to optimize execution time for making a verdict when multiple simple BPF programs are combined into one in order to prevent parsing same headers multiple times. In particular, for cls_bpf that can have various return paths for encoding flowids, and xt_bpf to come to a fw verdict this can be the case. Therefore, as this can result in more complex and harder to debug code, it would be very useful to have this minimal tool for testing purposes. It can also be of help for BPF JIT developers as filters are "test attached" to the kernel on a temporary socket thus triggering a JIT image dump when enabled. The tool uses an interactive libreadline shell with auto-completion and history support. Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller --- tools/net/Makefile | 9 +- tools/net/bpf_dbg.c | 1404 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1411 insertions(+), 2 deletions(-) create mode 100644 tools/net/bpf_dbg.c diff --git a/tools/net/Makefile b/tools/net/Makefile index b4444d53b73..0f30d923afa 100644 --- a/tools/net/Makefile +++ b/tools/net/Makefile @@ -2,14 +2,19 @@ prefix = /usr CC = gcc -all : bpf_jit_disasm +all : bpf_jit_disasm bpf_dbg bpf_jit_disasm : CFLAGS = -Wall -O2 bpf_jit_disasm : LDLIBS = -lopcodes -lbfd -ldl bpf_jit_disasm : bpf_jit_disasm.o +bpf_dbg : CFLAGS = -Wall -O2 +bpf_dbg : LDLIBS = -lreadline +bpf_dbg : bpf_dbg.o + clean : - rm -rf *.o bpf_jit_disasm + rm -rf *.o bpf_jit_disasm bpf_dbg install : install bpf_jit_disasm $(prefix)/bin/bpf_jit_disasm + install bpf_dbg $(prefix)/bin/bpf_dbg diff --git a/tools/net/bpf_dbg.c b/tools/net/bpf_dbg.c new file mode 100644 index 00000000000..0fdcb707a2e --- /dev/null +++ b/tools/net/bpf_dbg.c @@ -0,0 +1,1404 @@ +/* + * Minimal BPF debugger + * + * Minimal BPF debugger that mimics the kernel's engine (w/o extensions) + * and allows for single stepping through selected packets from a pcap + * with a provided user filter in order to facilitate verification of a + * BPF program. Besides others, this is useful to verify BPF programs + * before attaching to a live system, and can be used in socket filters, + * cls_bpf, xt_bpf, team driver and e.g. PTP code; in particular when a + * single more complex BPF program is being used. Reasons for a more + * complex BPF program are likely primarily to optimize execution time + * for making a verdict when multiple simple BPF programs are combined + * into one in order to prevent parsing same headers multiple times. + * + * More on how to debug BPF opcodes see Documentation/networking/filter.txt + * which is the main document on BPF. Mini howto for getting started: + * + * 1) `./bpf_dbg` to enter the shell (shell cmds denoted with '>'): + * 2) > load bpf 6,40 0 0 12,21 0 3 20... (output from `bpf_asm` or + * `tcpdump -iem1 -ddd port 22 | tr '\n' ','` to load as filter) + * 3) > load pcap foo.pcap + * 4) > run /disassemble/dump/quit (self-explanatory) + * 5) > breakpoint 2 (sets bp at loaded BPF insns 2, do `run` then; + * multiple bps can be set, of course, a call to `breakpoint` + * w/o args shows currently loaded bps, `breakpoint reset` for + * resetting all breakpoints) + * 6) > select 3 (`run` etc will start from the 3rd packet in the pcap) + * 7) > step [-, +] (performs single stepping through the BPF) + * + * Copyright 2013 Daniel Borkmann + * Licensed under the GNU General Public License, version 2.0 (GPLv2) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TCPDUMP_MAGIC 0xa1b2c3d4 + +#define BPF_LDX_B (BPF_LDX | BPF_B) +#define BPF_LDX_W (BPF_LDX | BPF_W) +#define BPF_JMP_JA (BPF_JMP | BPF_JA) +#define BPF_JMP_JEQ (BPF_JMP | BPF_JEQ) +#define BPF_JMP_JGT (BPF_JMP | BPF_JGT) +#define BPF_JMP_JGE (BPF_JMP | BPF_JGE) +#define BPF_JMP_JSET (BPF_JMP | BPF_JSET) +#define BPF_ALU_ADD (BPF_ALU | BPF_ADD) +#define BPF_ALU_SUB (BPF_ALU | BPF_SUB) +#define BPF_ALU_MUL (BPF_ALU | BPF_MUL) +#define BPF_ALU_DIV (BPF_ALU | BPF_DIV) +#define BPF_ALU_MOD (BPF_ALU | BPF_MOD) +#define BPF_ALU_NEG (BPF_ALU | BPF_NEG) +#define BPF_ALU_AND (BPF_ALU | BPF_AND) +#define BPF_ALU_OR (BPF_ALU | BPF_OR) +#define BPF_ALU_XOR (BPF_ALU | BPF_XOR) +#define BPF_ALU_LSH (BPF_ALU | BPF_LSH) +#define BPF_ALU_RSH (BPF_ALU | BPF_RSH) +#define BPF_MISC_TAX (BPF_MISC | BPF_TAX) +#define BPF_MISC_TXA (BPF_MISC | BPF_TXA) +#define BPF_LD_B (BPF_LD | BPF_B) +#define BPF_LD_H (BPF_LD | BPF_H) +#define BPF_LD_W (BPF_LD | BPF_W) + +#ifndef array_size +# define array_size(x) (sizeof(x) / sizeof((x)[0])) +#endif + +#ifndef __check_format_printf +# define __check_format_printf(pos_fmtstr, pos_fmtargs) \ + __attribute__ ((format (printf, (pos_fmtstr), (pos_fmtargs)))) +#endif + +#define CMD(_name, _func) { .name = _name, .func = _func, } +#define OP(_op, _name) [_op] = _name + +enum { + CMD_OK, + CMD_ERR, + CMD_EX, +}; + +struct shell_cmd { + const char *name; + int (*func)(char *args); +}; + +struct pcap_filehdr { + uint32_t magic; + uint16_t version_major; + uint16_t version_minor; + int32_t thiszone; + uint32_t sigfigs; + uint32_t snaplen; + uint32_t linktype; +}; + +struct pcap_timeval { + int32_t tv_sec; + int32_t tv_usec; +}; + +struct pcap_pkthdr { + struct pcap_timeval ts; + uint32_t caplen; + uint32_t len; +}; + +struct bpf_regs { + uint32_t A; + uint32_t X; + uint32_t M[BPF_MEMWORDS]; + uint32_t R; + bool Rs; + uint16_t Pc; +}; + +static struct sock_filter bpf_image[BPF_MAXINSNS + 1]; +static unsigned int bpf_prog_len = 0; + +static int bpf_breakpoints[64]; +static struct bpf_regs bpf_regs[BPF_MAXINSNS + 1]; +static struct bpf_regs bpf_curr; +static unsigned int bpf_regs_len = 0; + +static int pcap_fd = -1; +static unsigned int pcap_packet = 0; +static size_t pcap_map_size = 0; +static char *pcap_ptr_va_start, *pcap_ptr_va_curr; + +static const char * const op_table[] = { + OP(BPF_ST, "st"), + OP(BPF_STX, "stx"), + OP(BPF_LD_B, "ldb"), + OP(BPF_LD_H, "ldh"), + OP(BPF_LD_W, "ld"), + OP(BPF_LDX, "ldx"), + OP(BPF_LDX_B, "ldxb"), + OP(BPF_JMP_JA, "ja"), + OP(BPF_JMP_JEQ, "jeq"), + OP(BPF_JMP_JGT, "jgt"), + OP(BPF_JMP_JGE, "jge"), + OP(BPF_JMP_JSET, "jset"), + OP(BPF_ALU_ADD, "add"), + OP(BPF_ALU_SUB, "sub"), + OP(BPF_ALU_MUL, "mul"), + OP(BPF_ALU_DIV, "div"), + OP(BPF_ALU_MOD, "mod"), + OP(BPF_ALU_NEG, "neg"), + OP(BPF_ALU_AND, "and"), + OP(BPF_ALU_OR, "or"), + OP(BPF_ALU_XOR, "xor"), + OP(BPF_ALU_LSH, "lsh"), + OP(BPF_ALU_RSH, "rsh"), + OP(BPF_MISC_TAX, "tax"), + OP(BPF_MISC_TXA, "txa"), + OP(BPF_RET, "ret"), +}; + +static __check_format_printf(1, 2) int rl_printf(const char *fmt, ...) +{ + int ret; + va_list vl; + + va_start(vl, fmt); + ret = vfprintf(rl_outstream, fmt, vl); + va_end(vl); + + return ret; +} + +static int matches(const char *cmd, const char *pattern) +{ + int len = strlen(cmd); + + if (len > strlen(pattern)) + return -1; + + return memcmp(pattern, cmd, len); +} + +static void hex_dump(const uint8_t *buf, size_t len) +{ + int i; + + rl_printf("%3u: ", 0); + for (i = 0; i < len; i++) { + if (i && !(i % 16)) + rl_printf("\n%3u: ", i); + rl_printf("%02x ", buf[i]); + } + rl_printf("\n"); +} + +static bool bpf_prog_loaded(void) +{ + if (bpf_prog_len == 0) + rl_printf("no bpf program loaded!\n"); + + return bpf_prog_len > 0; +} + +static void bpf_disasm(const struct sock_filter f, unsigned int i) +{ + const char *op, *fmt; + int val = f.k; + char buf[256]; + + switch (f.code) { + case BPF_RET | BPF_K: + op = op_table[BPF_RET]; + fmt = "#%#x"; + break; + case BPF_RET | BPF_A: + op = op_table[BPF_RET]; + fmt = "a"; + break; + case BPF_RET | BPF_X: + op = op_table[BPF_RET]; + fmt = "x"; + break; + case BPF_MISC_TAX: + op = op_table[BPF_MISC_TAX]; + fmt = ""; + break; + case BPF_MISC_TXA: + op = op_table[BPF_MISC_TXA]; + fmt = ""; + break; + case BPF_ST: + op = op_table[BPF_ST]; + fmt = "M[%d]"; + break; + case BPF_STX: + op = op_table[BPF_STX]; + fmt = "M[%d]"; + break; + case BPF_LD_W | BPF_ABS: + op = op_table[BPF_LD_W]; + fmt = "[%d]"; + break; + case BPF_LD_H | BPF_ABS: + op = op_table[BPF_LD_H]; + fmt = "[%d]"; + break; + case BPF_LD_B | BPF_ABS: + op = op_table[BPF_LD_B]; + fmt = "[%d]"; + break; + case BPF_LD_W | BPF_LEN: + op = op_table[BPF_LD_W]; + fmt = "#len"; + break; + case BPF_LD_W | BPF_IND: + op = op_table[BPF_LD_W]; + fmt = "[x+%d]"; + break; + case BPF_LD_H | BPF_IND: + op = op_table[BPF_LD_H]; + fmt = "[x+%d]"; + break; + case BPF_LD_B | BPF_IND: + op = op_table[BPF_LD_B]; + fmt = "[x+%d]"; + break; + case BPF_LD | BPF_IMM: + op = op_table[BPF_LD_W]; + fmt = "#%#x"; + break; + case BPF_LDX | BPF_IMM: + op = op_table[BPF_LDX]; + fmt = "#%#x"; + break; + case BPF_LDX_B | BPF_MSH: + op = op_table[BPF_LDX_B]; + fmt = "4*([%d]&0xf)"; + break; + case BPF_LD | BPF_MEM: + op = op_table[BPF_LD_W]; + fmt = "M[%d]"; + break; + case BPF_LDX | BPF_MEM: + op = op_table[BPF_LDX]; + fmt = "M[%d]"; + break; + case BPF_JMP_JA: + op = op_table[BPF_JMP_JA]; + fmt = "%d"; + val = i + 1 + f.k; + break; + case BPF_JMP_JGT | BPF_X: + op = op_table[BPF_JMP_JGT]; + fmt = "x"; + break; + case BPF_JMP_JGT | BPF_K: + op = op_table[BPF_JMP_JGT]; + fmt = "#%#x"; + break; + case BPF_JMP_JGE | BPF_X: + op = op_table[BPF_JMP_JGE]; + fmt = "x"; + break; + case BPF_JMP_JGE | BPF_K: + op = op_table[BPF_JMP_JGE]; + fmt = "#%#x"; + break; + case BPF_JMP_JEQ | BPF_X: + op = op_table[BPF_JMP_JEQ]; + fmt = "x"; + break; + case BPF_JMP_JEQ | BPF_K: + op = op_table[BPF_JMP_JEQ]; + fmt = "#%#x"; + break; + case BPF_JMP_JSET | BPF_X: + op = op_table[BPF_JMP_JSET]; + fmt = "x"; + break; + case BPF_JMP_JSET | BPF_K: + op = op_table[BPF_JMP_JSET]; + fmt = "#%#x"; + break; + case BPF_ALU_NEG: + op = op_table[BPF_ALU_NEG]; + fmt = ""; + break; + case BPF_ALU_LSH | BPF_X: + op = op_table[BPF_ALU_LSH]; + fmt = "x"; + break; + case BPF_ALU_LSH | BPF_K: + op = op_table[BPF_ALU_LSH]; + fmt = "#%d"; + break; + case BPF_ALU_RSH | BPF_X: + op = op_table[BPF_ALU_RSH]; + fmt = "x"; + break; + case BPF_ALU_RSH | BPF_K: + op = op_table[BPF_ALU_RSH]; + fmt = "#%d"; + break; + case BPF_ALU_ADD | BPF_X: + op = op_table[BPF_ALU_ADD]; + fmt = "x"; + break; + case BPF_ALU_ADD | BPF_K: + op = op_table[BPF_ALU_ADD]; + fmt = "#%d"; + break; + case BPF_ALU_SUB | BPF_X: + op = op_table[BPF_ALU_SUB]; + fmt = "x"; + break; + case BPF_ALU_SUB | BPF_K: + op = op_table[BPF_ALU_SUB]; + fmt = "#%d"; + break; + case BPF_ALU_MUL | BPF_X: + op = op_table[BPF_ALU_MUL]; + fmt = "x"; + break; + case BPF_ALU_MUL | BPF_K: + op = op_table[BPF_ALU_MUL]; + fmt = "#%d"; + break; + case BPF_ALU_DIV | BPF_X: + op = op_table[BPF_ALU_DIV]; + fmt = "x"; + break; + case BPF_ALU_DIV | BPF_K: + op = op_table[BPF_ALU_DIV]; + fmt = "#%d"; + break; + case BPF_ALU_MOD | BPF_X: + op = op_table[BPF_ALU_MOD]; + fmt = "x"; + break; + case BPF_ALU_MOD | BPF_K: + op = op_table[BPF_ALU_MOD]; + fmt = "#%d"; + break; + case BPF_ALU_AND | BPF_X: + op = op_table[BPF_ALU_AND]; + fmt = "x"; + break; + case BPF_ALU_AND | BPF_K: + op = op_table[BPF_ALU_AND]; + fmt = "#%#x"; + break; + case BPF_ALU_OR | BPF_X: + op = op_table[BPF_ALU_OR]; + fmt = "x"; + break; + case BPF_ALU_OR | BPF_K: + op = op_table[BPF_ALU_OR]; + fmt = "#%#x"; + break; + case BPF_ALU_XOR | BPF_X: + op = op_table[BPF_ALU_XOR]; + fmt = "x"; + break; + case BPF_ALU_XOR | BPF_K: + op = op_table[BPF_ALU_XOR]; + fmt = "#%#x"; + break; + default: + op = "nosup"; + fmt = "%#x"; + val = f.code; + break; + } + + memset(buf, 0, sizeof(buf)); + snprintf(buf, sizeof(buf), fmt, val); + buf[sizeof(buf) - 1] = 0; + + if ((BPF_CLASS(f.code) == BPF_JMP && BPF_OP(f.code) != BPF_JA)) + rl_printf("l%d:\t%s %s, l%d, l%d\n", i, op, buf, + i + 1 + f.jt, i + 1 + f.jf); + else + rl_printf("l%d:\t%s %s\n", i, op, buf); +} + +static void bpf_dump_curr(struct bpf_regs *r, struct sock_filter *f) +{ + int i, m = 0; + + rl_printf("pc: [%u]\n", r->Pc); + rl_printf("code: [%u] jt[%u] jf[%u] k[%u]\n", + f->code, f->jt, f->jf, f->k); + rl_printf("curr: "); + bpf_disasm(*f, r->Pc); + + if (f->jt || f->jf) { + rl_printf("jt: "); + bpf_disasm(*(f + f->jt + 1), r->Pc + f->jt + 1); + rl_printf("jf: "); + bpf_disasm(*(f + f->jf + 1), r->Pc + f->jf + 1); + } + + rl_printf("A: [%#08x][%u]\n", r->A, r->A); + rl_printf("X: [%#08x][%u]\n", r->X, r->X); + if (r->Rs) + rl_printf("ret: [%#08x][%u]!\n", r->R, r->R); + + for (i = 0; i < BPF_MEMWORDS; i++) { + if (r->M[i]) { + m++; + rl_printf("M[%d]: [%#08x][%u]\n", i, r->M[i], r->M[i]); + } + } + if (m == 0) + rl_printf("M[0,%d]: [%#08x][%u]\n", BPF_MEMWORDS - 1, 0, 0); +} + +static void bpf_dump_pkt(uint8_t *pkt, uint32_t pkt_caplen, uint32_t pkt_len) +{ + if (pkt_caplen != pkt_len) + rl_printf("cap: %u, len: %u\n", pkt_caplen, pkt_len); + else + rl_printf("len: %u\n", pkt_len); + + hex_dump(pkt, pkt_caplen); +} + +static void bpf_disasm_all(const struct sock_filter *f, unsigned int len) +{ + unsigned int i; + + for (i = 0; i < len; i++) + bpf_disasm(f[i], i); +} + +static void bpf_dump_all(const struct sock_filter *f, unsigned int len) +{ + unsigned int i; + + rl_printf("/* { op, jt, jf, k }, */\n"); + for (i = 0; i < len; i++) + rl_printf("{ %#04x, %2u, %2u, %#010x },\n", + f[i].code, f[i].jt, f[i].jf, f[i].k); +} + +static bool bpf_runnable(struct sock_filter *f, unsigned int len) +{ + int sock, ret, i; + struct sock_fprog bpf = { + .filter = f, + .len = len, + }; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock < 0) { + rl_printf("cannot open socket!\n"); + return false; + } + ret = setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf)); + if (ret < 0) { + rl_printf("program not allowed to run by kernel!\n"); + return false; + } + close(sock); + for (i = 0; i < len; i++) { + if (BPF_CLASS(f[i].code) == BPF_LD && + f[i].k > SKF_AD_OFF) { + rl_printf("extensions currently not supported!\n"); + return false; + } + } + + return true; +} + +static void bpf_reset_breakpoints(void) +{ + int i; + + for (i = 0; i < array_size(bpf_breakpoints); i++) + bpf_breakpoints[i] = -1; +} + +static void bpf_set_breakpoints(unsigned int where) +{ + int i; + bool set = false; + + for (i = 0; i < array_size(bpf_breakpoints); i++) { + if (bpf_breakpoints[i] == (int) where) { + rl_printf("breakpoint already set!\n"); + set = true; + break; + } + + if (bpf_breakpoints[i] == -1 && set == false) { + bpf_breakpoints[i] = where; + set = true; + } + } + + if (!set) + rl_printf("too many breakpoints set, reset first!\n"); +} + +static void bpf_dump_breakpoints(void) +{ + int i; + + rl_printf("breakpoints: "); + + for (i = 0; i < array_size(bpf_breakpoints); i++) { + if (bpf_breakpoints[i] < 0) + continue; + rl_printf("%d ", bpf_breakpoints[i]); + } + + rl_printf("\n"); +} + +static void bpf_reset(void) +{ + bpf_regs_len = 0; + + memset(bpf_regs, 0, sizeof(bpf_regs)); + memset(&bpf_curr, 0, sizeof(bpf_curr)); +} + +static void bpf_safe_regs(void) +{ + memcpy(&bpf_regs[bpf_regs_len++], &bpf_curr, sizeof(bpf_curr)); +} + +static bool bpf_restore_regs(int off) +{ + unsigned int index = bpf_regs_len - 1 + off; + + if (index == 0) { + bpf_reset(); + return true; + } else if (index < bpf_regs_len) { + memcpy(&bpf_curr, &bpf_regs[index], sizeof(bpf_curr)); + bpf_regs_len = index; + return true; + } else { + rl_printf("reached bottom of register history stack!\n"); + return false; + } +} + +static uint32_t extract_u32(uint8_t *pkt, uint32_t off) +{ + uint32_t r; + + memcpy(&r, &pkt[off], sizeof(r)); + + return ntohl(r); +} + +static uint16_t extract_u16(uint8_t *pkt, uint32_t off) +{ + uint16_t r; + + memcpy(&r, &pkt[off], sizeof(r)); + + return ntohs(r); +} + +static uint8_t extract_u8(uint8_t *pkt, uint32_t off) +{ + return pkt[off]; +} + +static void set_return(struct bpf_regs *r) +{ + r->R = 0; + r->Rs = true; +} + +static void bpf_single_step(struct bpf_regs *r, struct sock_filter *f, + uint8_t *pkt, uint32_t pkt_caplen, + uint32_t pkt_len) +{ + uint32_t K = f->k; + int d; + + switch (f->code) { + case BPF_RET | BPF_K: + r->R = K; + r->Rs = true; + break; + case BPF_RET | BPF_A: + r->R = r->A; + r->Rs = true; + break; + case BPF_RET | BPF_X: + r->R = r->X; + r->Rs = true; + break; + case BPF_MISC_TAX: + r->X = r->A; + break; + case BPF_MISC_TXA: + r->A = r->X; + break; + case BPF_ST: + r->M[K] = r->A; + break; + case BPF_STX: + r->M[K] = r->X; + break; + case BPF_LD_W | BPF_ABS: + d = pkt_caplen - K; + if (d >= sizeof(uint32_t)) + r->A = extract_u32(pkt, K); + else + set_return(r); + break; + case BPF_LD_H | BPF_ABS: + d = pkt_caplen - K; + if (d >= sizeof(uint16_t)) + r->A = extract_u16(pkt, K); + else + set_return(r); + break; + case BPF_LD_B | BPF_ABS: + d = pkt_caplen - K; + if (d >= sizeof(uint8_t)) + r->A = extract_u8(pkt, K); + else + set_return(r); + break; + case BPF_LD_W | BPF_IND: + d = pkt_caplen - (r->X + K); + if (d >= sizeof(uint32_t)) + r->A = extract_u32(pkt, r->X + K); + break; + case BPF_LD_H | BPF_IND: + d = pkt_caplen - (r->X + K); + if (d >= sizeof(uint16_t)) + r->A = extract_u16(pkt, r->X + K); + else + set_return(r); + break; + case BPF_LD_B | BPF_IND: + d = pkt_caplen - (r->X + K); + if (d >= sizeof(uint8_t)) + r->A = extract_u8(pkt, r->X + K); + else + set_return(r); + break; + case BPF_LDX_B | BPF_MSH: + d = pkt_caplen - K; + if (d >= sizeof(uint8_t)) { + r->X = extract_u8(pkt, K); + r->X = (r->X & 0xf) << 2; + } else + set_return(r); + break; + case BPF_LD_W | BPF_LEN: + r->A = pkt_len; + break; + case BPF_LDX_W | BPF_LEN: + r->A = pkt_len; + break; + case BPF_LD | BPF_IMM: + r->A = K; + break; + case BPF_LDX | BPF_IMM: + r->X = K; + break; + case BPF_LD | BPF_MEM: + r->A = r->M[K]; + break; + case BPF_LDX | BPF_MEM: + r->X = r->M[K]; + break; + case BPF_JMP_JA: + r->Pc += K; + break; + case BPF_JMP_JGT | BPF_X: + r->Pc += r->A > r->X ? f->jt : f->jf; + break; + case BPF_JMP_JGT | BPF_K: + r->Pc += r->A > K ? f->jt : f->jf; + break; + case BPF_JMP_JGE | BPF_X: + r->Pc += r->A >= r->X ? f->jt : f->jf; + break; + case BPF_JMP_JGE | BPF_K: + r->Pc += r->A >= K ? f->jt : f->jf; + break; + case BPF_JMP_JEQ | BPF_X: + r->Pc += r->A == r->X ? f->jt : f->jf; + break; + case BPF_JMP_JEQ | BPF_K: + r->Pc += r->A == K ? f->jt : f->jf; + break; + case BPF_JMP_JSET | BPF_X: + r->Pc += r->A & r->X ? f->jt : f->jf; + break; + case BPF_JMP_JSET | BPF_K: + r->Pc += r->A & K ? f->jt : f->jf; + break; + case BPF_ALU_NEG: + r->A = -r->A; + break; + case BPF_ALU_LSH | BPF_X: + r->A <<= r->X; + break; + case BPF_ALU_LSH | BPF_K: + r->A <<= K; + break; + case BPF_ALU_RSH | BPF_X: + r->A >>= r->X; + break; + case BPF_ALU_RSH | BPF_K: + r->A >>= K; + break; + case BPF_ALU_ADD | BPF_X: + r->A += r->X; + break; + case BPF_ALU_ADD | BPF_K: + r->A += K; + break; + case BPF_ALU_SUB | BPF_X: + r->A -= r->X; + break; + case BPF_ALU_SUB | BPF_K: + r->A -= K; + break; + case BPF_ALU_MUL | BPF_X: + r->A *= r->X; + break; + case BPF_ALU_MUL | BPF_K: + r->A *= K; + break; + case BPF_ALU_DIV | BPF_X: + case BPF_ALU_MOD | BPF_X: + if (r->X == 0) { + set_return(r); + break; + } + goto do_div; + case BPF_ALU_DIV | BPF_K: + case BPF_ALU_MOD | BPF_K: + if (K == 0) { + set_return(r); + break; + } +do_div: + switch (f->code) { + case BPF_ALU_DIV | BPF_X: + r->A /= r->X; + break; + case BPF_ALU_DIV | BPF_K: + r->A /= K; + break; + case BPF_ALU_MOD | BPF_X: + r->A %= r->X; + break; + case BPF_ALU_MOD | BPF_K: + r->A %= K; + break; + } + break; + case BPF_ALU_AND | BPF_X: + r->A &= r->X; + break; + case BPF_ALU_AND | BPF_K: + r->A &= r->X; + break; + case BPF_ALU_OR | BPF_X: + r->A |= r->X; + break; + case BPF_ALU_OR | BPF_K: + r->A |= K; + break; + case BPF_ALU_XOR | BPF_X: + r->A ^= r->X; + break; + case BPF_ALU_XOR | BPF_K: + r->A ^= K; + break; + } +} + +static bool bpf_pc_has_breakpoint(uint16_t pc) +{ + int i; + + for (i = 0; i < array_size(bpf_breakpoints); i++) { + if (bpf_breakpoints[i] < 0) + continue; + if (bpf_breakpoints[i] == pc) + return true; + } + + return false; +} + +static bool bpf_handle_breakpoint(struct bpf_regs *r, struct sock_filter *f, + uint8_t *pkt, uint32_t pkt_caplen, + uint32_t pkt_len) +{ + rl_printf("-- register dump --\n"); + bpf_dump_curr(r, &f[r->Pc]); + rl_printf("-- packet dump --\n"); + bpf_dump_pkt(pkt, pkt_caplen, pkt_len); + rl_printf("(breakpoint)\n"); + return true; +} + +static int bpf_run_all(struct sock_filter *f, uint16_t bpf_len, uint8_t *pkt, + uint32_t pkt_caplen, uint32_t pkt_len) +{ + bool stop = false; + + while (bpf_curr.Rs == false && stop == false) { + bpf_safe_regs(); + + if (bpf_pc_has_breakpoint(bpf_curr.Pc)) + stop = bpf_handle_breakpoint(&bpf_curr, f, pkt, + pkt_caplen, pkt_len); + + bpf_single_step(&bpf_curr, &f[bpf_curr.Pc], pkt, pkt_caplen, + pkt_len); + bpf_curr.Pc++; + } + + return stop ? -1 : bpf_curr.R; +} + +static int bpf_run_stepping(struct sock_filter *f, uint16_t bpf_len, + uint8_t *pkt, uint32_t pkt_caplen, + uint32_t pkt_len, int next) +{ + bool stop = false; + int i = 1; + + while (bpf_curr.Rs == false && stop == false) { + bpf_safe_regs(); + + if (i++ == next) + stop = bpf_handle_breakpoint(&bpf_curr, f, pkt, + pkt_caplen, pkt_len); + + bpf_single_step(&bpf_curr, &f[bpf_curr.Pc], pkt, pkt_caplen, + pkt_len); + bpf_curr.Pc++; + } + + return stop ? -1 : bpf_curr.R; +} + +static bool pcap_loaded(void) +{ + if (pcap_fd < 0) + rl_printf("no pcap file loaded!\n"); + + return pcap_fd >= 0; +} + +static struct pcap_pkthdr *pcap_curr_pkt(void) +{ + return (void *) pcap_ptr_va_curr; +} + +static bool pcap_next_pkt(void) +{ + struct pcap_pkthdr *hdr = pcap_curr_pkt(); + + if (pcap_ptr_va_curr + sizeof(*hdr) - + pcap_ptr_va_start >= pcap_map_size) + return false; + if (hdr->caplen == 0 || hdr->len == 0 || hdr->caplen > hdr->len) + return false; + if (pcap_ptr_va_curr + sizeof(*hdr) + hdr->caplen - + pcap_ptr_va_start >= pcap_map_size) + return false; + + pcap_ptr_va_curr += (sizeof(*hdr) + hdr->caplen); + return true; +} + +static void pcap_reset_pkt(void) +{ + pcap_ptr_va_curr = pcap_ptr_va_start + sizeof(struct pcap_filehdr); +} + +static int try_load_pcap(const char *file) +{ + struct pcap_filehdr *hdr; + struct stat sb; + int ret; + + pcap_fd = open(file, O_RDONLY); + if (pcap_fd < 0) { + rl_printf("cannot open pcap [%s]!\n", strerror(errno)); + return CMD_ERR; + } + + ret = fstat(pcap_fd, &sb); + if (ret < 0) { + rl_printf("cannot fstat pcap file!\n"); + return CMD_ERR; + } + + if (!S_ISREG(sb.st_mode)) { + rl_printf("not a regular pcap file, duh!\n"); + return CMD_ERR; + } + + pcap_map_size = sb.st_size; + if (pcap_map_size <= sizeof(struct pcap_filehdr)) { + rl_printf("pcap file too small!\n"); + return CMD_ERR; + } + + pcap_ptr_va_start = mmap(NULL, pcap_map_size, PROT_READ, + MAP_SHARED | MAP_LOCKED, pcap_fd, 0); + if (pcap_ptr_va_start == MAP_FAILED) { + rl_printf("mmap of file failed!"); + return CMD_ERR; + } + + hdr = (void *) pcap_ptr_va_start; + if (hdr->magic != TCPDUMP_MAGIC) { + rl_printf("wrong pcap magic!\n"); + return CMD_ERR; + } + + pcap_reset_pkt(); + + return CMD_OK; + +} + +static void try_close_pcap(void) +{ + if (pcap_fd >= 0) { + munmap(pcap_ptr_va_start, pcap_map_size); + close(pcap_fd); + + pcap_ptr_va_start = pcap_ptr_va_curr = NULL; + pcap_map_size = 0; + pcap_packet = 0; + pcap_fd = -1; + } +} + +static int cmd_load_bpf(char *bpf_string) +{ + char sp, *token, separator = ','; + unsigned short bpf_len, i = 0; + struct sock_filter tmp; + + bpf_prog_len = 0; + memset(bpf_image, 0, sizeof(bpf_image)); + + if (sscanf(bpf_string, "%hu%c", &bpf_len, &sp) != 2 || + sp != separator || bpf_len > BPF_MAXINSNS || bpf_len == 0) { + rl_printf("syntax error in head length encoding!\n"); + return CMD_ERR; + } + + token = bpf_string; + while ((token = strchr(token, separator)) && (++token)[0]) { + if (i >= bpf_len) { + rl_printf("program exceeds encoded length!\n"); + return CMD_ERR; + } + + if (sscanf(token, "%hu %hhu %hhu %u,", + &tmp.code, &tmp.jt, &tmp.jf, &tmp.k) != 4) { + rl_printf("syntax error at instruction %d!\n", i); + return CMD_ERR; + } + + bpf_image[i].code = tmp.code; + bpf_image[i].jt = tmp.jt; + bpf_image[i].jf = tmp.jf; + bpf_image[i].k = tmp.k; + + i++; + } + + if (i != bpf_len) { + rl_printf("syntax error exceeding encoded length!\n"); + return CMD_ERR; + } else + bpf_prog_len = bpf_len; + if (!bpf_runnable(bpf_image, bpf_prog_len)) + bpf_prog_len = 0; + + return CMD_OK; +} + +static int cmd_load_pcap(char *file) +{ + char *file_trim, *tmp; + + file_trim = strtok_r(file, " ", &tmp); + if (file_trim == NULL) + return CMD_ERR; + + try_close_pcap(); + + return try_load_pcap(file_trim); +} + +static int cmd_load(char *arg) +{ + char *subcmd, *cont, *tmp = strdup(arg); + int ret = CMD_OK; + + subcmd = strtok_r(tmp, " ", &cont); + if (subcmd == NULL) + goto out; + if (matches(subcmd, "bpf") == 0) { + bpf_reset(); + bpf_reset_breakpoints(); + + ret = cmd_load_bpf(cont); + } else if (matches(subcmd, "pcap") == 0) { + ret = cmd_load_pcap(cont); + } else { +out: + rl_printf("bpf : load bpf code\n"); + rl_printf("pcap : load pcap file\n"); + ret = CMD_ERR; + } + + free(tmp); + return ret; +} + +static int cmd_step(char *num) +{ + struct pcap_pkthdr *hdr; + int steps, ret; + + if (!bpf_prog_loaded() || !pcap_loaded()) + return CMD_ERR; + + steps = strtol(num, NULL, 10); + if (steps == 0 || strlen(num) == 0) + steps = 1; + if (steps < 0) { + if (!bpf_restore_regs(steps)) + return CMD_ERR; + steps = 1; + } + + hdr = pcap_curr_pkt(); + ret = bpf_run_stepping(bpf_image, bpf_prog_len, + (uint8_t *) hdr + sizeof(*hdr), + hdr->caplen, hdr->len, steps); + if (ret >= 0 || bpf_curr.Rs) { + bpf_reset(); + if (!pcap_next_pkt()) { + rl_printf("(going back to first packet)\n"); + pcap_reset_pkt(); + } else { + rl_printf("(next packet)\n"); + } + } + + return CMD_OK; +} + +static int cmd_select(char *num) +{ + unsigned int which, i; + struct pcap_pkthdr *hdr; + bool have_next = true; + + if (!pcap_loaded() || strlen(num) == 0) + return CMD_ERR; + + which = strtoul(num, NULL, 10); + if (which == 0) { + rl_printf("packet count starts with 1, clamping!\n"); + which = 1; + } + + pcap_reset_pkt(); + bpf_reset(); + + for (i = 0; i < which && (have_next = pcap_next_pkt()); i++) + /* noop */; + if (!have_next || (hdr = pcap_curr_pkt()) == NULL) { + rl_printf("no packet #%u available!\n", which); + pcap_reset_pkt(); + return CMD_ERR; + } + + return CMD_OK; +} + +static int cmd_breakpoint(char *subcmd) +{ + if (!bpf_prog_loaded()) + return CMD_ERR; + if (strlen(subcmd) == 0) + bpf_dump_breakpoints(); + else if (matches(subcmd, "reset") == 0) + bpf_reset_breakpoints(); + else { + unsigned int where = strtoul(subcmd, NULL, 10); + + if (where < bpf_prog_len) { + bpf_set_breakpoints(where); + rl_printf("breakpoint at: "); + bpf_disasm(bpf_image[where], where); + } + } + + return CMD_OK; +} + +static int cmd_run(char *num) +{ + static uint32_t pass = 0, fail = 0; + struct pcap_pkthdr *hdr; + bool has_limit = true; + int ret, pkts = 0, i = 0; + + if (!bpf_prog_loaded() || !pcap_loaded()) + return CMD_ERR; + + pkts = strtol(num, NULL, 10); + if (pkts == 0 || strlen(num) == 0) + has_limit = false; + + do { + hdr = pcap_curr_pkt(); + ret = bpf_run_all(bpf_image, bpf_prog_len, + (uint8_t *) hdr + sizeof(*hdr), + hdr->caplen, hdr->len); + if (ret > 0) + pass++; + else if (ret == 0) + fail++; + else + return CMD_OK; + bpf_reset(); + } while (pcap_next_pkt() && (!has_limit || (has_limit && ++i < pkts))); + + rl_printf("bpf passes:%u fails:%u\n", pass, fail); + + pcap_reset_pkt(); + bpf_reset(); + + pass = fail = 0; + return CMD_OK; +} + +static int cmd_disassemble(char *line_string) +{ + bool single_line = false; + unsigned long line; + + if (!bpf_prog_loaded()) + return CMD_ERR; + if (strlen(line_string) > 0 && + (line = strtoul(line_string, NULL, 10)) < bpf_prog_len) + single_line = true; + if (single_line) + bpf_disasm(bpf_image[line], line); + else + bpf_disasm_all(bpf_image, bpf_prog_len); + + return CMD_OK; +} + +static int cmd_dump(char *dontcare) +{ + if (!bpf_prog_loaded()) + return CMD_ERR; + + bpf_dump_all(bpf_image, bpf_prog_len); + + return CMD_OK; +} + +static int cmd_quit(char *dontcare) +{ + return CMD_EX; +} + +static const struct shell_cmd cmds[] = { + CMD("load", cmd_load), + CMD("select", cmd_select), + CMD("step", cmd_step), + CMD("run", cmd_run), + CMD("breakpoint", cmd_breakpoint), + CMD("disassemble", cmd_disassemble), + CMD("dump", cmd_dump), + CMD("quit", cmd_quit), +}; + +static int execf(char *arg) +{ + char *cmd, *cont, *tmp = strdup(arg); + int i, ret = 0, len; + + cmd = strtok_r(tmp, " ", &cont); + if (cmd == NULL) + goto out; + len = strlen(cmd); + for (i = 0; i < array_size(cmds); i++) { + if (len != strlen(cmds[i].name)) + continue; + if (strncmp(cmds[i].name, cmd, len) == 0) { + ret = cmds[i].func(cont); + break; + } + } +out: + free(tmp); + return ret; +} + +static char *shell_comp_gen(const char *buf, int state) +{ + static int list_index, len; + const char *name; + + if (!state) { + list_index = 0; + len = strlen(buf); + } + + for (; list_index < array_size(cmds); ) { + name = cmds[list_index].name; + list_index++; + + if (strncmp(name, buf, len) == 0) + return strdup(name); + } + + return NULL; +} + +static char **shell_completion(const char *buf, int start, int end) +{ + char **matches = NULL; + + if (start == 0) + matches = rl_completion_matches(buf, shell_comp_gen); + + return matches; +} + +static void intr_shell(int sig) +{ + if (rl_end) + rl_kill_line(-1, 0); + + rl_crlf(); + rl_refresh_line(0, 0); + rl_free_line_state(); +} + +static void init_shell(FILE *fin, FILE *fout) +{ + char file[128]; + + memset(file, 0, sizeof(file)); + snprintf(file, sizeof(file) - 1, + "%s/.bpf_dbg_history", getenv("HOME")); + + read_history(file); + + memset(file, 0, sizeof(file)); + snprintf(file, sizeof(file) - 1, + "%s/.bpf_dbg_init", getenv("HOME")); + + rl_instream = fin; + rl_outstream = fout; + + rl_readline_name = "bpf_dbg"; + rl_terminal_name = getenv("TERM"); + + rl_catch_signals = 0; + rl_catch_sigwinch = 1; + + rl_attempted_completion_function = shell_completion; + + rl_bind_key('\t', rl_complete); + + rl_bind_key_in_map('\t', rl_complete, emacs_meta_keymap); + rl_bind_key_in_map('\033', rl_complete, emacs_meta_keymap); + + rl_read_init_file(file); + rl_prep_terminal(0); + rl_set_signals(); + + signal(SIGINT, intr_shell); +} + +static void exit_shell(void) +{ + char file[128]; + + memset(file, 0, sizeof(file)); + snprintf(file, sizeof(file) - 1, + "%s/.bpf_dbg_history", getenv("HOME")); + + write_history(file); + clear_history(); + rl_deprep_terminal(); + + try_close_pcap(); +} + +static int run_shell_loop(FILE *fin, FILE *fout) +{ + char *buf; + int ret; + + init_shell(fin, fout); + + while ((buf = readline("> ")) != NULL) { + ret = execf(buf); + if (ret == CMD_EX) + break; + if (ret == CMD_OK && strlen(buf) > 0) + add_history(buf); + + free(buf); + } + + exit_shell(); + return 0; +} + +int main(int argc, char **argv) +{ + FILE *fin = NULL, *fout = NULL; + + if (argc >= 2) + fin = fopen(argv[1], "r"); + if (argc >= 3) + fout = fopen(argv[2], "w"); + + return run_shell_loop(fin ? : stdin, fout ? : stdout); +} -- cgit v1.2.3-70-g09d2 From 3f356385e8a449e1d7cfc6b6f8d634ac4f5581a0 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Wed, 11 Dec 2013 23:43:44 +0100 Subject: filter: bpf_asm: add minimal bpf asm tool There are a couple of valid use cases for a minimal low-level bpf asm like tool, for example, using/linking to libpcap is not an option, the required BPF filters use Linux extensions that are not supported by libpcap's compiler, a filter might be more complex and not cleanly implementable with libpcap's compiler, particular filter codes should be optimized differently than libpcap's internal BPF compiler does, or for security audits of emitted BPF JIT code for prepared set of BPF instructions resp. BPF JIT compiler development in general. Then, in such cases writing such a filter in low-level syntax can be an good alternative, for example, xt_bpf and cls_bpf users might have requirements that could result in more complex filter code, or one that cannot be expressed with libpcap (e.g. different return codes in cls_bpf for flowids on various BPF code paths). Moreover, BPF JIT implementors may wish to manually write test cases in order to verify the resulting JIT image, and thus need low-level access to BPF code generation as well. Therefore, complete the available toolchain for BPF with this small bpf_asm helper tool for the tools/net/ directory. These 3 complementary minimal helper tools round up and facilitate BPF development. Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller --- tools/net/Makefile | 18 +- tools/net/bpf_asm.c | 52 ++++ tools/net/bpf_exp.l | 143 ++++++++++ tools/net/bpf_exp.y | 749 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 960 insertions(+), 2 deletions(-) create mode 100644 tools/net/bpf_asm.c create mode 100644 tools/net/bpf_exp.l create mode 100644 tools/net/bpf_exp.y diff --git a/tools/net/Makefile b/tools/net/Makefile index 0f30d923afa..004cd74734b 100644 --- a/tools/net/Makefile +++ b/tools/net/Makefile @@ -1,8 +1,16 @@ prefix = /usr CC = gcc +LEX = flex +YACC = bison -all : bpf_jit_disasm bpf_dbg +%.yacc.c: %.y + $(YACC) -o $@ -d $< + +%.lex.c: %.l + $(LEX) -o $@ $< + +all : bpf_jit_disasm bpf_dbg bpf_asm bpf_jit_disasm : CFLAGS = -Wall -O2 bpf_jit_disasm : LDLIBS = -lopcodes -lbfd -ldl @@ -12,9 +20,15 @@ bpf_dbg : CFLAGS = -Wall -O2 bpf_dbg : LDLIBS = -lreadline bpf_dbg : bpf_dbg.o +bpf_asm : CFLAGS = -Wall -O2 -I. +bpf_asm : LDLIBS = +bpf_asm : bpf_asm.o bpf_exp.yacc.o bpf_exp.lex.o +bpf_exp.lex.o : bpf_exp.yacc.c + clean : - rm -rf *.o bpf_jit_disasm bpf_dbg + rm -rf *.o bpf_jit_disasm bpf_dbg bpf_asm bpf_exp.yacc.* bpf_exp.lex.* install : install bpf_jit_disasm $(prefix)/bin/bpf_jit_disasm install bpf_dbg $(prefix)/bin/bpf_dbg + install bpf_asm $(prefix)/bin/bpf_asm diff --git a/tools/net/bpf_asm.c b/tools/net/bpf_asm.c new file mode 100644 index 00000000000..c15aef097b0 --- /dev/null +++ b/tools/net/bpf_asm.c @@ -0,0 +1,52 @@ +/* + * Minimal BPF assembler + * + * Instead of libpcap high-level filter expressions, it can be quite + * useful to define filters in low-level BPF assembler (that is kept + * close to Steven McCanne and Van Jacobson's original BPF paper). + * In particular for BPF JIT implementors, JIT security auditors, or + * just for defining BPF expressions that contain extensions which are + * not supported by compilers. + * + * How to get into it: + * + * 1) read Documentation/networking/filter.txt + * 2) Run `bpf_asm [-c] ` to translate into binary + * blob that is loadable with xt_bpf, cls_bpf et al. Note: -c will + * pretty print a C-like construct. + * + * Copyright 2013 Daniel Borkmann + * Licensed under the GNU General Public License, version 2.0 (GPLv2) + */ + +#include +#include +#include + +extern void bpf_asm_compile(FILE *fp, bool cstyle); + +int main(int argc, char **argv) +{ + FILE *fp = stdin; + bool cstyle = false; + int i; + + for (i = 1; i < argc; i++) { + if (!strncmp("-c", argv[i], 2)) { + cstyle = true; + continue; + } + + fp = fopen(argv[i], "r"); + if (!fp) { + fp = stdin; + continue; + } + + break; + } + + bpf_asm_compile(fp, cstyle); + + return 0; +} diff --git a/tools/net/bpf_exp.l b/tools/net/bpf_exp.l new file mode 100644 index 00000000000..bf7be77ddd6 --- /dev/null +++ b/tools/net/bpf_exp.l @@ -0,0 +1,143 @@ +/* + * BPF asm code lexer + * + * This program is free software; you can distribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2 of the License, + * or (at your option) any later version. + * + * Syntax kept close to: + * + * Steven McCanne and Van Jacobson. 1993. The BSD packet filter: a new + * architecture for user-level packet capture. In Proceedings of the + * USENIX Winter 1993 Conference Proceedings on USENIX Winter 1993 + * Conference Proceedings (USENIX'93). USENIX Association, Berkeley, + * CA, USA, 2-2. + * + * Copyright 2013 Daniel Borkmann + * Licensed under the GNU General Public License, version 2.0 (GPLv2) + */ + +%{ + +#include +#include +#include + +#include "bpf_exp.yacc.h" + +extern void yyerror(const char *str); + +%} + +%option align +%option ecs + +%option nounput +%option noreject +%option noinput +%option noyywrap + +%option 8bit +%option caseless +%option yylineno + +%% + +"ldb" { return OP_LDB; } +"ldh" { return OP_LDH; } +"ld" { return OP_LD; } +"ldi" { return OP_LDI; } +"ldx" { return OP_LDX; } +"ldxi" { return OP_LDXI; } +"ldxb" { return OP_LDXB; } +"st" { return OP_ST; } +"stx" { return OP_STX; } +"jmp" { return OP_JMP; } +"ja" { return OP_JMP; } +"jeq" { return OP_JEQ; } +"jneq" { return OP_JNEQ; } +"jne" { return OP_JNEQ; } +"jlt" { return OP_JLT; } +"jle" { return OP_JLE; } +"jgt" { return OP_JGT; } +"jge" { return OP_JGE; } +"jset" { return OP_JSET; } +"add" { return OP_ADD; } +"sub" { return OP_SUB; } +"mul" { return OP_MUL; } +"div" { return OP_DIV; } +"mod" { return OP_MOD; } +"neg" { return OP_NEG; } +"and" { return OP_AND; } +"xor" { return OP_XOR; } +"or" { return OP_OR; } +"lsh" { return OP_LSH; } +"rsh" { return OP_RSH; } +"ret" { return OP_RET; } +"tax" { return OP_TAX; } +"txa" { return OP_TXA; } + +"#"?("len") { return K_PKT_LEN; } +"#"?("proto") { return K_PROTO; } +"#"?("type") { return K_TYPE; } +"#"?("poff") { return K_POFF; } +"#"?("ifidx") { return K_IFIDX; } +"#"?("nla") { return K_NLATTR; } +"#"?("nlan") { return K_NLATTR_NEST; } +"#"?("mark") { return K_MARK; } +"#"?("queue") { return K_QUEUE; } +"#"?("hatype") { return K_HATYPE; } +"#"?("rxhash") { return K_RXHASH; } +"#"?("cpu") { return K_CPU; } +"#"?("vlan_tci") { return K_VLANT; } +"#"?("vlan_pr") { return K_VLANP; } + +":" { return ':'; } +"," { return ','; } +"#" { return '#'; } +"%" { return '%'; } +"[" { return '['; } +"]" { return ']'; } +"(" { return '('; } +")" { return ')'; } +"x" { return 'x'; } +"a" { return 'a'; } +"+" { return '+'; } +"M" { return 'M'; } +"*" { return '*'; } +"&" { return '&'; } + +([0][x][a-fA-F0-9]+) { + yylval.number = strtoul(yytext, NULL, 16); + return number; + } +([0][b][0-1]+) { + yylval.number = strtol(yytext + 2, NULL, 2); + return number; + } +(([0])|([-+]?[1-9][0-9]*)) { + yylval.number = strtol(yytext, NULL, 10); + return number; + } +([0][0-9]+) { + yylval.number = strtol(yytext + 1, NULL, 8); + return number; + } +[a-zA-Z_][a-zA-Z0-9_]+ { + yylval.label = strdup(yytext); + return label; + } + +"/*"([^\*]|\*[^/])*"*/" { /* NOP */ } +";"[^\n]* { /* NOP */ } +^#.* { /* NOP */ } +[ \t]+ { /* NOP */ } +[ \n]+ { /* NOP */ } + +. { + printf("unknown character \'%s\'", yytext); + yyerror("lex unknown character"); + } + +%% diff --git a/tools/net/bpf_exp.y b/tools/net/bpf_exp.y new file mode 100644 index 00000000000..f524110643b --- /dev/null +++ b/tools/net/bpf_exp.y @@ -0,0 +1,749 @@ +/* + * BPF asm code parser + * + * This program is free software; you can distribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2 of the License, + * or (at your option) any later version. + * + * Syntax kept close to: + * + * Steven McCanne and Van Jacobson. 1993. The BSD packet filter: a new + * architecture for user-level packet capture. In Proceedings of the + * USENIX Winter 1993 Conference Proceedings on USENIX Winter 1993 + * Conference Proceedings (USENIX'93). USENIX Association, Berkeley, + * CA, USA, 2-2. + * + * Copyright 2013 Daniel Borkmann + * Licensed under the GNU General Public License, version 2.0 (GPLv2) + */ + +%{ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bpf_exp.yacc.h" + +enum jmp_type { JTL, JFL, JKL }; + +extern FILE *yyin; +extern int yylex(void); +extern void yyerror(const char *str); + +extern void bpf_asm_compile(FILE *fp, bool cstyle); +static void bpf_set_curr_instr(uint16_t op, uint8_t jt, uint8_t jf, uint32_t k); +static void bpf_set_curr_label(const char *label); +static void bpf_set_jmp_label(const char *label, enum jmp_type type); + +%} + +%union { + char *label; + uint32_t number; +} + +%token OP_LDB OP_LDH OP_LD OP_LDX OP_ST OP_STX OP_JMP OP_JEQ OP_JGT OP_JGE +%token OP_JSET OP_ADD OP_SUB OP_MUL OP_DIV OP_AND OP_OR OP_XOR OP_LSH OP_RSH +%token OP_RET OP_TAX OP_TXA OP_LDXB OP_MOD OP_NEG OP_JNEQ OP_JLT OP_JLE OP_LDI +%token OP_LDXI + +%token K_PKT_LEN K_PROTO K_TYPE K_NLATTR K_NLATTR_NEST K_MARK K_QUEUE K_HATYPE +%token K_RXHASH K_CPU K_IFIDX K_VLANT K_VLANP K_POFF + +%token ':' ',' '[' ']' '(' ')' 'x' 'a' '+' 'M' '*' '&' '#' '%' + +%token number label + +%type