2017-06-12 15:03:20

by Erik Stromdahl

[permalink] [raw]
Subject: [RFC v2 00/10] ath10k high latency

This is the second version of the high latency patches (stuff common for
usb and sdio). The only difference when compared to the previous version
is that explicit calls to *local_bh_disable* have been added before calling
*ieee80211_rx*.

This is a requirement from mac80211.

Adding these calls should not introduce any problem for pcie since the
*local_bh_enable* and *local_bh_disable* functions will only increment
and decrement the softirq counter by one (if softirq's have already been
disabled before calling *local_bh_disable*, the call to *local_bh_enable*
will not enable them).

Adding these calls removes a warning generated by mac80211.

The previous RFC mentioned a problem related to this warning.
>From Linux 4.12, the warning was not handled correctly and the warning
was turned into an oops (I still don't know the reason for this).

This version fixes this.

Erik Stromdahl (10):
ath10k: high_latency detection
ath10k: htt: RX ring config HL support
ath10k: per target configurablity of various items
ath10k: add start_once support
ath10k: htt: High latency TX support
ath10k: htt: High latency RX support
ath10k: dma fixes for high latency devices
ath10k: add QCA9377 usb hw_param item
ath10k: add QCA9377 sdio hw_param item
ath10k: wmi: disable softirq's while calling ieee80211_rx

drivers/net/wireless/ath/ath10k/core.c | 139 ++++++++++++++++++++++++------
drivers/net/wireless/ath/ath10k/core.h | 16 ++--
drivers/net/wireless/ath/ath10k/htc.c | 13 +--
drivers/net/wireless/ath/ath10k/htt.c | 5 +-
drivers/net/wireless/ath/ath10k/htt.h | 57 +++++++++++-
drivers/net/wireless/ath/ath10k/htt_rx.c | 100 ++++++++++++++++++++-
drivers/net/wireless/ath/ath10k/htt_tx.c | 126 ++++++++++++++++++++++++++-
drivers/net/wireless/ath/ath10k/hw.h | 30 +++++++
drivers/net/wireless/ath/ath10k/mac.c | 5 +-
drivers/net/wireless/ath/ath10k/rx_desc.h | 15 ++++
drivers/net/wireless/ath/ath10k/txrx.c | 5 +-
drivers/net/wireless/ath/ath10k/wmi-tlv.c | 4 +-
drivers/net/wireless/ath/ath10k/wmi.c | 3 +
13 files changed, 464 insertions(+), 54 deletions(-)

--
2.7.4


2017-06-12 15:03:23

by Erik Stromdahl

[permalink] [raw]
Subject: [RFC v2 02/10] ath10k: htt: RX ring config HL support

Special HTT RX ring config message used by high latency
devices.

The main difference between HL and LL is that HL devices
do not use shared memory between device and host and thus,
no host paddr's are added to the RX config message.

Signed-off-by: Erik Stromdahl <[email protected]>
---
drivers/net/wireless/ath/ath10k/htt.c | 5 +++-
drivers/net/wireless/ath/ath10k/htt.h | 1 +
drivers/net/wireless/ath/ath10k/htt_tx.c | 51 ++++++++++++++++++++++++++++++++
3 files changed, 56 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c
index cd160b1..29ed4af 100644
--- a/drivers/net/wireless/ath/ath10k/htt.c
+++ b/drivers/net/wireless/ath/ath10k/htt.c
@@ -258,7 +258,10 @@ int ath10k_htt_setup(struct ath10k_htt *htt)
if (status)
return status;

- status = ath10k_htt_send_rx_ring_cfg_ll(htt);
+ if (ar->is_high_latency)
+ status = ath10k_htt_send_rx_ring_cfg_hl(htt);
+ else
+ status = ath10k_htt_send_rx_ring_cfg_ll(htt);
if (status) {
ath10k_warn(ar, "failed to setup rx ring: %d\n",
status);
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index 6305308..7ffa1d4 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -1805,6 +1805,7 @@ int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt);
int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie);
int ath10k_htt_send_frag_desc_bank_cfg(struct ath10k_htt *htt);
int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt);
+int ath10k_htt_send_rx_ring_cfg_hl(struct ath10k_htt *htt);
int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,
u8 max_subfrms_ampdu,
u8 max_subfrms_amsdu);
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
index 685faac..8d85f82 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -693,6 +693,57 @@ int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt)
return 0;
}

+int ath10k_htt_send_rx_ring_cfg_hl(struct ath10k_htt *htt)
+{
+ struct ath10k *ar = htt->ar;
+ struct sk_buff *skb;
+ struct htt_cmd *cmd;
+ struct htt_rx_ring_setup_ring *ring;
+ const int num_rx_ring = 1;
+ u16 flags;
+ int len;
+ int ret;
+
+ /*
+ * the HW expects the buffer to be an integral number of 4-byte
+ * "words"
+ */
+ BUILD_BUG_ON(!IS_ALIGNED(HTT_RX_BUF_SIZE, 4));
+ BUILD_BUG_ON((HTT_RX_BUF_SIZE & HTT_MAX_CACHE_LINE_SIZE_MASK) != 0);
+
+ len = sizeof(cmd->hdr) + sizeof(cmd->rx_setup.hdr)
+ + (sizeof(*ring) * num_rx_ring);
+ skb = ath10k_htc_alloc_skb(ar, len);
+ if (!skb)
+ return -ENOMEM;
+
+ skb_put(skb, len);
+
+ cmd = (struct htt_cmd *)skb->data;
+ ring = &cmd->rx_setup.rings[0];
+
+ cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_RX_RING_CFG;
+ cmd->rx_setup.hdr.num_rings = 1;
+
+ flags = 0;
+ flags |= HTT_RX_RING_FLAGS_MSDU_PAYLOAD;
+ flags |= HTT_RX_RING_FLAGS_UNICAST_RX;
+ flags |= HTT_RX_RING_FLAGS_MULTICAST_RX;
+
+ memset(ring, 0, sizeof(*ring));
+ ring->rx_ring_len = __cpu_to_le16(HTT_RX_RING_SIZE_MIN);
+ ring->rx_ring_bufsize = __cpu_to_le16(HTT_RX_BUF_SIZE);
+ ring->flags = __cpu_to_le16(flags);
+
+ ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb);
+ if (ret) {
+ dev_kfree_skb_any(skb);
+ return ret;
+ }
+
+ return 0;
+}
+
int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,
u8 max_subfrms_ampdu,
u8 max_subfrms_amsdu)
--
2.7.4

2017-06-12 15:03:30

by Erik Stromdahl

[permalink] [raw]
Subject: [RFC v2 10/10] ath10k: wmi: disable softirq's while calling ieee80211_rx

Signed-off-by: Erik Stromdahl <[email protected]>
---
drivers/net/wireless/ath/ath10k/wmi.c | 3 +++
1 file changed, 3 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index 472b42b..d5d0d5c 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -2383,7 +2383,10 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
status->freq, status->band, status->signal,
status->rate_idx);

+ local_bh_disable();
ieee80211_rx(ar->hw, skb);
+ local_bh_enable();
+
return 0;
}

--
2.7.4

2017-06-12 15:03:26

by Erik Stromdahl

[permalink] [raw]
Subject: [RFC v2 06/10] ath10k: htt: High latency RX support

Special HTT RX handling for high latency interfaces.

Since no DMA physical addresses are used in the RX ring
config message (this is not supported by the high latency
devices), no RX ring is allocated.
All RX skb's are allocated by the driver and passed directly
to mac80211 in the HTT RX indication handler.

A nice side effect of this is that no huge buffer will be
allocated with dma_alloc_coherent. On embedded systems with
limited memory resources, the allocation of the RX ring is
prone to fail.

Some tweaks made to "make it work":

Removal of protected bit in 802.11 header frame control field.
The chipset seems to do hw decryption but the frame_control
protected bit is still set.

This is necessary for mac80211 not to drop the frame.

Signed-off-by: Erik Stromdahl <[email protected]>
---
drivers/net/wireless/ath/ath10k/core.c | 38 +++++++-----
drivers/net/wireless/ath/ath10k/htt.h | 47 +++++++++++++++
drivers/net/wireless/ath/ath10k/htt_rx.c | 97 ++++++++++++++++++++++++++++++-
drivers/net/wireless/ath/ath10k/rx_desc.h | 15 +++++
4 files changed, 179 insertions(+), 18 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index a1a4610..c20b97b 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -2044,10 +2044,12 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
goto err_wmi_detach;
}

- status = ath10k_htt_rx_alloc(&ar->htt);
- if (status) {
- ath10k_err(ar, "failed to alloc htt rx: %d\n", status);
- goto err_htt_tx_detach;
+ if (!ar->is_high_latency) {
+ status = ath10k_htt_rx_alloc(&ar->htt);
+ if (status) {
+ ath10k_err(ar, "failed to alloc htt rx: %d\n", status);
+ goto err_htt_tx_detach;
+ }
}

status = ath10k_hif_start(ar);
@@ -2156,16 +2158,20 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
}
}

- /* If firmware indicates Full Rx Reorder support it must be used in a
- * slightly different manner. Let HTT code know.
- */
- ar->htt.rx_ring.in_ord_rx = !!(test_bit(WMI_SERVICE_RX_FULL_REORDER,
- ar->wmi.svc_map));
+ if (!ar->is_high_latency) {
+ /* If firmware indicates Full Rx Reorder support it must be
+ * used in a slightly different manner. Let HTT code know.
+ */
+ ar->htt.rx_ring.in_ord_rx =
+ !!(test_bit(WMI_SERVICE_RX_FULL_REORDER,
+ ar->wmi.svc_map));

- status = ath10k_htt_rx_ring_refill(ar);
- if (status) {
- ath10k_err(ar, "failed to refill htt rx ring: %d\n", status);
- goto err_hif_stop;
+ status = ath10k_htt_rx_ring_refill(ar);
+ if (status) {
+ ath10k_err(ar, "failed to refill htt rx ring: %d\n",
+ status);
+ goto err_hif_stop;
+ }
}

if (ar->max_num_vdevs >= 64)
@@ -2194,7 +2200,8 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
err_hif_stop:
ath10k_hif_stop(ar);
err_htt_rx_detach:
- ath10k_htt_rx_free(&ar->htt);
+ if (!ar->is_high_latency)
+ ath10k_htt_rx_free(&ar->htt);
err_htt_tx_detach:
ath10k_htt_tx_free(&ar->htt);
err_wmi_detach:
@@ -2239,7 +2246,8 @@ void ath10k_core_stop(struct ath10k *ar)

ath10k_hif_stop(ar);
ath10k_htt_tx_stop(&ar->htt);
- ath10k_htt_rx_free(&ar->htt);
+ if (!ar->is_high_latency)
+ ath10k_htt_rx_free(&ar->htt);
ath10k_wmi_detach(ar);
ar->is_started = false;
}
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index bac453f..ac5603e 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -646,6 +646,15 @@ struct htt_rx_indication {
struct htt_rx_indication_mpdu_range mpdu_ranges[0];
} __packed;

+/* High latency version of the RX indication */
+struct htt_rx_indication_hl {
+ struct htt_rx_indication_hdr hdr;
+ struct htt_rx_indication_ppdu ppdu;
+ struct htt_rx_indication_prefix prefix;
+ struct fw_rx_desc_hl fw_desc;
+ struct htt_rx_indication_mpdu_range mpdu_ranges[0];
+} __packed;
+
static inline struct htt_rx_indication_mpdu_range *
htt_rx_ind_get_mpdu_ranges(struct htt_rx_indication *rx_ind)
{
@@ -658,6 +667,18 @@ static inline struct htt_rx_indication_mpdu_range *
return ptr;
}

+static inline struct htt_rx_indication_mpdu_range *
+ htt_rx_ind_get_mpdu_ranges_hl(struct htt_rx_indication_hl *rx_ind)
+{
+ void *ptr = rx_ind;
+
+ ptr += sizeof(rx_ind->hdr)
+ + sizeof(rx_ind->ppdu)
+ + sizeof(rx_ind->prefix)
+ + sizeof(rx_ind->fw_desc);
+ return ptr;
+}
+
enum htt_rx_flush_mpdu_status {
HTT_RX_FLUSH_MPDU_DISCARD = 0,
HTT_RX_FLUSH_MPDU_REORDER = 1,
@@ -1530,6 +1551,7 @@ struct htt_resp {
struct htt_mgmt_tx_completion mgmt_tx_completion;
struct htt_data_tx_completion data_tx_completion;
struct htt_rx_indication rx_ind;
+ struct htt_rx_indication_hl rx_ind_hl;
struct htt_rx_fragment_indication rx_frag_ind;
struct htt_rx_peer_map peer_map;
struct htt_rx_peer_unmap peer_unmap;
@@ -1754,6 +1776,31 @@ struct htt_rx_desc {
u8 msdu_payload[0];
};

+#define HTT_RX_DESC_HL_INFO_SEQ_NUM_MASK 0x00000fff
+#define HTT_RX_DESC_HL_INFO_SEQ_NUM_LSB 0
+#define HTT_RX_DESC_HL_INFO_ENCRYPTED_MASK 0x00001000
+#define HTT_RX_DESC_HL_INFO_ENCRYPTED_LSB 12
+#define HTT_RX_DESC_HL_INFO_CHAN_INFO_PRESENT_MASK 0x00002000
+#define HTT_RX_DESC_HL_INFO_CHAN_INFO_PRESENT_LSB 13
+#define HTT_RX_DESC_HL_INFO_MCAST_BCAST_MASK 0x00008000
+#define HTT_RX_DESC_HL_INFO_MCAST_BCAST_LSB 15
+#define HTT_RX_DESC_HL_INFO_FRAGMENT_MASK 0x00010000
+#define HTT_RX_DESC_HL_INFO_FRAGMENT_LSB 16
+#define HTT_RX_DESC_HL_INFO_KEY_ID_OCT_MASK 0x01fe0000
+#define HTT_RX_DESC_HL_INFO_KEY_ID_OCT_LSB 17
+
+struct htt_rx_desc_base_hl {
+ __le32 info; /* HTT_RX_DESC_HL_INFO_ */
+};
+
+struct htt_rx_chan_info {
+ __le16 primary_chan_center_freq_mhz;
+ __le16 contig_chan1_center_freq_mhz;
+ __le16 contig_chan2_center_freq_mhz;
+ u8 phy_mode;
+ u8 reserved;
+} __packed;
+
#define HTT_RX_DESC_ALIGN 8

#define HTT_MAC_ADDR_LEN 6
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 6c0a821..5833c08 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -1567,8 +1567,94 @@ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt)
return num_msdus;
}

-static void ath10k_htt_rx_proc_rx_ind(struct ath10k_htt *htt,
- struct htt_rx_indication *rx)
+static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt,
+ struct htt_rx_indication_hl *rx,
+ struct sk_buff *skb)
+{
+ struct ath10k *ar = htt->ar;
+ struct ath10k_peer *peer;
+ struct htt_rx_indication_mpdu_range *mpdu_ranges;
+ struct fw_rx_desc_hl *fw_desc;
+ struct ieee80211_hdr *hdr;
+ struct ieee80211_rx_status *rx_status;
+ u16 peer_id;
+ u8 rx_desc_len;
+ int num_mpdu_ranges;
+ size_t tot_hdr_len;
+
+ peer_id = __le16_to_cpu(rx->hdr.peer_id);
+
+ peer = ath10k_peer_find_by_id(ar, peer_id);
+ if (!peer)
+ ath10k_warn(ar, "Got RX ind from invalid peer: %u\n", peer_id);
+
+ num_mpdu_ranges = MS(__le32_to_cpu(rx->hdr.info1),
+ HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES);
+ mpdu_ranges = htt_rx_ind_get_mpdu_ranges_hl(rx);
+ fw_desc = &rx->fw_desc;
+ rx_desc_len = fw_desc->len;
+
+ /* I have not yet seen any case where num_mpdu_ranges > 1.
+ * qcacld does not seem handle that case either, so we introduce the
+ * same limitiation here as well.
+ */
+ if (num_mpdu_ranges > 1)
+ ath10k_warn(ar,
+ "Unsupported number of MPDU ranges: %d, ignoring all but the first\n",
+ num_mpdu_ranges);
+
+ if (mpdu_ranges->mpdu_range_status !=
+ HTT_RX_IND_MPDU_STATUS_OK) {
+ ath10k_warn(ar, "MPDU range status: %d\n",
+ mpdu_ranges->mpdu_range_status);
+ goto err;
+ }
+
+ /* Strip off all headers before the MAC header before delivery to
+ * mac80211
+ */
+ tot_hdr_len = sizeof(struct htt_resp_hdr) + sizeof(rx->hdr) +
+ sizeof(rx->ppdu) + sizeof(rx->prefix) +
+ sizeof(rx->fw_desc) + sizeof(*mpdu_ranges) + rx_desc_len;
+ skb_pull(skb, tot_hdr_len);
+
+ hdr = (struct ieee80211_hdr *)skb->data;
+ rx_status = IEEE80211_SKB_RXCB(skb);
+ rx_status->signal = ATH10K_DEFAULT_NOISE_FLOOR +
+ rx->ppdu.combined_rssi;
+ rx_status->flag &= ~RX_FLAG_NO_SIGNAL_VAL;
+
+ /* Not entirely sure about this, but all frames from the chipset has
+ * the protected flag set even though they have already been decrypted.
+ * Unmasking this flag is necessary in order for mac80211 not to drop
+ * the frame.
+ * TODO: Verify this is always the case or find out a way to check
+ * if there has been hw decryption.
+ */
+ if (ieee80211_has_protected(hdr->frame_control)) {
+ hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+ rx_status->flag |= RX_FLAG_DECRYPTED |
+ RX_FLAG_IV_STRIPPED |
+ RX_FLAG_MMIC_STRIPPED;
+ }
+
+ local_bh_disable();
+ ieee80211_rx(ar->hw, skb);
+ local_bh_enable();
+
+ /* We have delivered the skb to the upper layers (mac80211) so we
+ * must not free it.
+ */
+ return false;
+err:
+ /* Tell the caller that it must free the skb since we have not
+ * consumed it
+ */
+ return true;
+}
+
+static void ath10k_htt_rx_proc_rx_ind_ll(struct ath10k_htt *htt,
+ struct htt_rx_indication *rx)
{
struct ath10k *ar = htt->ar;
struct htt_rx_indication_mpdu_range *mpdu_ranges;
@@ -2356,7 +2442,12 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
break;
}
case HTT_T2H_MSG_TYPE_RX_IND:
- ath10k_htt_rx_proc_rx_ind(htt, &resp->rx_ind);
+ if (ar->is_high_latency)
+ return ath10k_htt_rx_proc_rx_ind_hl(htt,
+ &resp->rx_ind_hl,
+ skb);
+ else
+ ath10k_htt_rx_proc_rx_ind_ll(htt, &resp->rx_ind);
break;
case HTT_T2H_MSG_TYPE_PEER_MAP: {
struct htt_peer_map_event ev = {
diff --git a/drivers/net/wireless/ath/ath10k/rx_desc.h b/drivers/net/wireless/ath/ath10k/rx_desc.h
index c1022a1..76b2fe5 100644
--- a/drivers/net/wireless/ath/ath10k/rx_desc.h
+++ b/drivers/net/wireless/ath/ath10k/rx_desc.h
@@ -1222,4 +1222,19 @@ struct fw_rx_desc_base {
u8 info0;
} __packed;

+#define FW_RX_DESC_FLAGS_FIRST_MSDU (1 << 0)
+#define FW_RX_DESC_FLAGS_LAST_MSDU (1 << 1)
+#define FW_RX_DESC_C3_FAILED (1 << 2)
+#define FW_RX_DESC_C4_FAILED (1 << 3)
+#define FW_RX_DESC_IPV6 (1 << 4)
+#define FW_RX_DESC_TCP (1 << 5)
+#define FW_RX_DESC_UDP (1 << 6)
+
+struct fw_rx_desc_hl {
+ u8 info0;
+ u8 version;
+ u8 len;
+ u8 flags;
+} __packed;
+
#endif /* _RX_DESC_H_ */
--
2.7.4

2017-06-12 15:03:23

by Erik Stromdahl

[permalink] [raw]
Subject: [RFC v2 03/10] ath10k: per target configurablity of various items

Added ability to set bus type and configure the max number of
peers in the ath10k_hw_params struct.

With this functionality it is possible to have a different
hw configuration depending on bus type for the same radio
chipset.

E.g. SDIO and USB devices using the same chipset as PCIe
devices will potentially use different board files and perhaps
other configuration parameters.

One such parameter is the max number of peers.
Instead of using a default value (suitable for PCIe devices)
derived from the WMI op version, a per target value can be
used instead.

This is needed by the QCA9377 USB device in order to prevent
the target fw to crash after HTT RX ring cfg is issued.

Apparently, the QCA9377 HL device does not seem to handle the
same amount of peers as the LL devices.

Signed-off-by: Erik Stromdahl <[email protected]>
---
drivers/net/wireless/ath/ath10k/core.c | 33 +++++++++++++++++++++++--------
drivers/net/wireless/ath/ath10k/core.h | 7 -------
drivers/net/wireless/ath/ath10k/hw.h | 22 +++++++++++++++++++++
drivers/net/wireless/ath/ath10k/wmi-tlv.c | 4 ++--
4 files changed, 49 insertions(+), 17 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index d3bf5c4..587c013 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -1631,9 +1631,19 @@ static int ath10k_init_hw_params(struct ath10k *ar)
for (i = 0; i < ARRAY_SIZE(ath10k_hw_params_list); i++) {
hw_params = &ath10k_hw_params_list[i];

- if (hw_params->id == ar->target_version &&
- hw_params->dev_id == ar->dev_id)
- break;
+ if (ar->is_high_latency) {
+ /* High latency devices will use different fw depending
+ * on if it is a USB or SDIO device.
+ */
+ if (hw_params->bus == ar->hif.bus &&
+ hw_params->id == ar->target_version &&
+ hw_params->dev_id == ar->dev_id)
+ break;
+ } else {
+ if (hw_params->id == ar->target_version &&
+ hw_params->dev_id == ar->dev_id)
+ break;
+ }
}

if (i == ARRAY_SIZE(ath10k_hw_params_list)) {
@@ -1732,6 +1742,7 @@ static void ath10k_core_set_coverage_class_work(struct work_struct *work)
static int ath10k_core_init_firmware_features(struct ath10k *ar)
{
struct ath10k_fw_file *fw_file = &ar->normal_mode_fw.fw_file;
+ int max_num_peers;

if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, fw_file->fw_features) &&
!test_bit(ATH10K_FW_FEATURE_WMI_10X, fw_file->fw_features)) {
@@ -1811,7 +1822,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)

switch (fw_file->wmi_op_version) {
case ATH10K_FW_WMI_OP_VERSION_MAIN:
- ar->max_num_peers = TARGET_NUM_PEERS;
+ max_num_peers = TARGET_NUM_PEERS;
ar->max_num_stations = TARGET_NUM_STATIONS;
ar->max_num_vdevs = TARGET_NUM_VDEVS;
ar->htt.max_num_pending_tx = TARGET_NUM_MSDU_DESC;
@@ -1823,10 +1834,10 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
case ATH10K_FW_WMI_OP_VERSION_10_2:
case ATH10K_FW_WMI_OP_VERSION_10_2_4:
if (ath10k_peer_stats_enabled(ar)) {
- ar->max_num_peers = TARGET_10X_TX_STATS_NUM_PEERS;
+ max_num_peers = TARGET_10X_TX_STATS_NUM_PEERS;
ar->max_num_stations = TARGET_10X_TX_STATS_NUM_STATIONS;
} else {
- ar->max_num_peers = TARGET_10X_NUM_PEERS;
+ max_num_peers = TARGET_10X_NUM_PEERS;
ar->max_num_stations = TARGET_10X_NUM_STATIONS;
}
ar->max_num_vdevs = TARGET_10X_NUM_VDEVS;
@@ -1835,7 +1846,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM;
break;
case ATH10K_FW_WMI_OP_VERSION_TLV:
- ar->max_num_peers = TARGET_TLV_NUM_PEERS;
+ max_num_peers = TARGET_TLV_NUM_PEERS;
ar->max_num_stations = TARGET_TLV_NUM_STATIONS;
ar->max_num_vdevs = TARGET_TLV_NUM_VDEVS;
ar->max_num_tdls_vdevs = TARGET_TLV_NUM_TDLS_VDEVS;
@@ -1846,7 +1857,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM;
break;
case ATH10K_FW_WMI_OP_VERSION_10_4:
- ar->max_num_peers = TARGET_10_4_NUM_PEERS;
+ max_num_peers = TARGET_10_4_NUM_PEERS;
ar->max_num_stations = TARGET_10_4_NUM_STATIONS;
ar->num_active_peers = TARGET_10_4_ACTIVE_PEERS;
ar->max_num_vdevs = TARGET_10_4_NUM_VDEVS;
@@ -1863,10 +1874,16 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
break;
case ATH10K_FW_WMI_OP_VERSION_UNSET:
case ATH10K_FW_WMI_OP_VERSION_MAX:
+ default:
WARN_ON(1);
return -EINVAL;
}

+ if (ar->hw_params.max_num_peers)
+ ar->max_num_peers = ar->hw_params.max_num_peers;
+ else
+ ar->max_num_peers = max_num_peers;
+
/* Backwards compatibility for firmwares without
* ATH10K_FW_IE_HTT_OP_VERSION.
*/
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 90069b8..cdac923 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -88,13 +88,6 @@

struct ath10k;

-enum ath10k_bus {
- ATH10K_BUS_PCI,
- ATH10K_BUS_AHB,
- ATH10K_BUS_SDIO,
- ATH10K_BUS_USB,
-};
-
static inline const char *ath10k_bus_str(enum ath10k_bus bus)
{
switch (bus) {
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index d342728..160377aa 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -20,6 +20,13 @@

#include "targaddrs.h"

+enum ath10k_bus {
+ ATH10K_BUS_PCI,
+ ATH10K_BUS_AHB,
+ ATH10K_BUS_SDIO,
+ ATH10K_BUS_USB,
+};
+
#define ATH10K_FW_DIR "ath10k"

#define QCA988X_2_0_DEVICE_ID (0x003c)
@@ -454,6 +461,18 @@ struct ath10k_hw_params {

/* Number of bytes to be discarded for each FFT sample */
int spectral_bin_discard;
+
+ /* max_num_peers can be used to override the setting derived from
+ * the WMI op version. If this value is non-zero, it will always
+ * be used instead of the default value derived from the WMI op
+ * version.
+ */
+ int max_num_peers;
+
+ /* Specifies whether or not the device is a high latency device */
+ bool is_high_latency;
+
+ enum ath10k_bus bus;
};

struct htt_rx_desc;
@@ -564,6 +583,9 @@ ath10k_rx_desc_get_l3_pad_bytes(struct ath10k_hw_params *hw,
#define TARGET_TLV_NUM_MSDU_DESC (1024 + 32)
#define TARGET_TLV_NUM_WOW_PATTERNS 22

+/* Target specific defines for QCA9377 high latency firmware */
+#define TARGET_QCA9377_HL_NUM_PEERS 15
+
/* Diagnostic Window */
#define CE_DIAG_PIPE 7

diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index f918802..754d445 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -1406,7 +1406,7 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar)
cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks);

cfg->num_vdevs = __cpu_to_le32(TARGET_TLV_NUM_VDEVS);
- cfg->num_peers = __cpu_to_le32(TARGET_TLV_NUM_PEERS);
+ cfg->num_peers = __cpu_to_le32(ar->max_num_peers);

if (test_bit(WMI_SERVICE_RX_FULL_REORDER, ar->wmi.svc_map)) {
cfg->num_offload_peers = __cpu_to_le32(TARGET_TLV_NUM_VDEVS);
@@ -1417,7 +1417,7 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar)
}

cfg->num_peer_keys = __cpu_to_le32(2);
- cfg->num_tids = __cpu_to_le32(TARGET_TLV_NUM_TIDS);
+ cfg->num_tids = __cpu_to_le32(ar->max_num_peers * 2);
cfg->ast_skid_limit = __cpu_to_le32(0x10);
cfg->tx_chain_mask = __cpu_to_le32(0x7);
cfg->rx_chain_mask = __cpu_to_le32(0x7);
--
2.7.4

2017-06-13 17:39:58

by Peter Oh

[permalink] [raw]
Subject: Re: [RFC v2 06/10] ath10k: htt: High latency RX support


On 06/12/2017 08:03 AM, Erik Stromdahl wrote:
> Special HTT RX handling for high latency interfaces.
>
> Since no DMA physical addresses are used in the RX ring
> config message (this is not supported by the high latency
> devices), no RX ring is allocated.
> All RX skb's are allocated by the driver and passed directly
> to mac80211 in the HTT RX indication handler.
>
> A nice side effect of this is that no huge buffer will be
> allocated with dma_alloc_coherent. On embedded systems with
> limited memory resources, the allocation of the RX ring is
> prone to fail.
>
> Some tweaks made to "make it work":
>
> Removal of protected bit in 802.11 header frame control field.
> The chipset seems to do hw decryption but the frame_control
> protected bit is still set.
>
> This is necessary for mac80211 not to drop the frame.
>
> Signed-off-by: Erik Stromdahl <[email protected]>
> ---
>
> +static void ath10k_htt_rx_proc_rx_ind_ll(struct ath10k_htt *htt,
> + struct htt_rx_indication *rx)
> {
> struct ath10k *ar = htt->ar;
> struct htt_rx_indication_mpdu_range *mpdu_ranges;
> @@ -2356,7 +2442,12 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
> break;
> }
> case HTT_T2H_MSG_TYPE_RX_IND:
> - ath10k_htt_rx_proc_rx_ind(htt, &resp->rx_ind);
> + if (ar->is_high_latency)
Can we use function pointers at initial time to avoid condition check at
hot path?
I'm afraid adding more lines on hot path.
> + return ath10k_htt_rx_proc_rx_ind_hl(htt,
> + &resp->rx_ind_hl,
> + skb);
> + else
> + ath10k_htt_rx_proc_rx_ind_ll(htt, &resp->rx_ind);
> break;
> case HTT_T2H_MSG_TYPE_PEER_MAP: {
> struct htt_peer_map_event ev = {
>

2017-06-19 15:38:00

by Kalle Valo

[permalink] [raw]
Subject: Re: [RFC v2 05/10] ath10k: htt: High latency TX support

Erik Stromdahl <[email protected]> writes:

> On 2017-06-13 19:38, Peter Oh wrote:
>> On 06/12/2017 08:03 AM, Erik Stromdahl wrote:
>>> Add HTT TX function for HL interfaces.
>>> Intended for SDIO and USB.
>>>
>>> Signed-off-by: Erik Stromdahl <[email protected]>
>>> ---
>>>
>>> diff --git a/drivers/net/wireless/ath/ath10k/mac.c
>>> b/drivers/net/wireless/ath/ath10k/mac.c
>>> index 48418f9..c5fd803 100644
>>> --- a/drivers/net/wireless/ath/ath10k/mac.c
>>> +++ b/drivers/net/wireless/ath/ath10k/mac.c
>>> @@ -3572,7 +3572,10 @@ static int ath10k_mac_tx_submit(struct ath10k *a=
r,
>>> switch (txpath) {
>>> case ATH10K_MAC_TX_HTT:
>>> - ret =3D ath10k_htt_tx(htt, txmode, skb);
>>> + if (ar->is_high_latency)
>> Can we use function pointers at initial time to avoid condition check at=
hot path?
>> I'm afraid adding more lines on hot path.
>
> I haven't made any comparison of assembly code between if-paths or
> function pointers, but since most architectures have conditional
> instructions I don't think the penalty is that big (if there is any
> penalty at all). There are plenty of other condition checks in the RX
> path (mac80211 is full of them), so I don't really see this as an
> issue.

Unless we can measure it I wouldn't be that worried either. Without
numbers trying to optimise is hard to get right.

> That being said, any improvement is always welcome (even micro
> optimizations if they are beneficial). I will think about this and see
> if adding function pointers can be done in a nice way.

But are function pointers really that much faster? You have to do a
function call anyway. And maybe use of likely() would be better, we want
to optimise for the low latency case anyway, but I still doubt we could
even measure that.

--=20
Kalle Valo=

2017-06-12 15:03:27

by Erik Stromdahl

[permalink] [raw]
Subject: [RFC v2 07/10] ath10k: dma fixes for high latency devices

Several DMA related functions (such as the dma_map_xxx functions)
are not used with high latency devices and don't need to be invoked
in this case.

Signed-off-by: Erik Stromdahl <[email protected]>
---
drivers/net/wireless/ath/ath10k/htc.c | 13 ++++++++-----
drivers/net/wireless/ath/ath10k/htt_rx.c | 3 ++-
drivers/net/wireless/ath/ath10k/htt_tx.c | 3 +++
drivers/net/wireless/ath/ath10k/txrx.c | 5 +++--
4 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c
index e5c80f5..232740c 100644
--- a/drivers/net/wireless/ath/ath10k/htc.c
+++ b/drivers/net/wireless/ath/ath10k/htc.c
@@ -137,11 +137,14 @@ int ath10k_htc_send(struct ath10k_htc *htc,
ath10k_htc_prepare_tx_skb(ep, skb);

skb_cb->eid = eid;
- skb_cb->paddr = dma_map_single(dev, skb->data, skb->len, DMA_TO_DEVICE);
- ret = dma_mapping_error(dev, skb_cb->paddr);
- if (ret) {
- ret = -EIO;
- goto err_credits;
+ if (!ar->is_high_latency) {
+ skb_cb->paddr = dma_map_single(dev, skb->data, skb->len,
+ DMA_TO_DEVICE);
+ ret = dma_mapping_error(dev, skb_cb->paddr);
+ if (ret) {
+ ret = -EIO;
+ goto err_credits;
+ }
}

sg_item.transfer_id = ep->eid;
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 5833c08..972c21c 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -2492,7 +2492,8 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
break;
}
case HTT_T2H_MSG_TYPE_TX_COMPL_IND:
- ath10k_htt_rx_tx_compl_ind(htt->ar, skb);
+ if (!ar->is_high_latency)
+ ath10k_htt_rx_tx_compl_ind(htt->ar, skb);
break;
case HTT_T2H_MSG_TYPE_SEC_IND: {
struct ath10k *ar = htt->ar;
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
index e3b820d..27bbc3e 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -409,6 +409,9 @@ int ath10k_htt_tx_start(struct ath10k_htt *htt)
if (htt->tx_mem_allocated)
return 0;

+ if (ar->is_high_latency)
+ return 0;
+
ret = ath10k_htt_tx_alloc_buf(htt);
if (ret)
goto free_idr_pending_tx;
diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c
index d4986f6..fae143e 100644
--- a/drivers/net/wireless/ath/ath10k/txrx.c
+++ b/drivers/net/wireless/ath/ath10k/txrx.c
@@ -90,11 +90,12 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt,

ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id);
ath10k_htt_tx_dec_pending(htt);
- if (htt->num_pending_tx == 0)
+ if (!ar->is_high_latency && (htt->num_pending_tx == 0))
wake_up(&htt->empty_tx_wq);
spin_unlock_bh(&htt->tx_lock);

- dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
+ if (!ar->is_high_latency)
+ dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);

ath10k_report_offchan_tx(htt->ar, msdu);

--
2.7.4

2017-06-12 15:03:28

by Erik Stromdahl

[permalink] [raw]
Subject: [RFC v2 08/10] ath10k: add QCA9377 usb hw_param item

Hardware parameters for QCA9377 usb devices.

Signed-off-by: Erik Stromdahl <[email protected]>
---
drivers/net/wireless/ath/ath10k/core.c | 23 +++++++++++++++++++++++
drivers/net/wireless/ath/ath10k/hw.h | 1 +
2 files changed, 24 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index c20b97b..dc8ea5e 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -299,6 +299,29 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.spectral_bin_discard = 0,
},
{
+ .id = QCA9377_HW_1_1_DEV_VERSION,
+ .dev_id = QCA9377_1_0_DEVICE_ID,
+ .name = "qca9377 hw1.1 usb",
+ .patch_load_addr = QCA9377_HW_1_0_PATCH_LOAD_ADDR,
+ .uart_pin = 6,
+ .otp_exe_param = 0,
+ .channel_counters_freq_hz = 88000,
+ .max_probe_resp_desc_thres = 0,
+ .cal_data_len = 8124,
+ .fw = {
+ .dir = QCA9377_HW_1_0_FW_DIR,
+ .board = QCA9377_HW_1_0_BOARD_DATA_FILE_USB,
+ .board_size = QCA9377_BOARD_DATA_SZ,
+ .board_ext_size = QCA9377_BOARD_EXT_DATA_SZ,
+ },
+ .hw_ops = &qca988x_ops,
+ .decap_align_bytes = 4,
+ .max_num_peers = TARGET_QCA9377_HL_NUM_PEERS,
+ .is_high_latency = true,
+ .bus = ATH10K_BUS_USB,
+ .start_once = true,
+ },
+ {
.id = QCA4019_HW_1_0_DEV_VERSION,
.dev_id = 0,
.name = "qca4019 hw1.0",
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index f733e73..cc3d0eb 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -127,6 +127,7 @@ enum qca9377_chip_id_rev {
/* QCA9377 1.0 definitions */
#define QCA9377_HW_1_0_FW_DIR ATH10K_FW_DIR "/QCA9377/hw1.0"
#define QCA9377_HW_1_0_BOARD_DATA_FILE "board.bin"
+#define QCA9377_HW_1_0_BOARD_DATA_FILE_USB "board-usb.bin"
#define QCA9377_HW_1_0_PATCH_LOAD_ADDR 0x1234

/* QCA4019 1.0 definitions */
--
2.7.4

2017-06-17 18:00:03

by Erik Stromdahl

[permalink] [raw]
Subject: Re: [RFC v2 05/10] ath10k: htt: High latency TX support



On 2017-06-13 19:38, Peter Oh wrote:
> On 06/12/2017 08:03 AM, Erik Stromdahl wrote:
>> Add HTT TX function for HL interfaces.
>> Intended for SDIO and USB.
>>
>> Signed-off-by: Erik Stromdahl <[email protected]>
>> ---
>>
>> diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
>> index 48418f9..c5fd803 100644
>> --- a/drivers/net/wireless/ath/ath10k/mac.c
>> +++ b/drivers/net/wireless/ath/ath10k/mac.c
>> @@ -3572,7 +3572,10 @@ static int ath10k_mac_tx_submit(struct ath10k *ar,
>> switch (txpath) {
>> case ATH10K_MAC_TX_HTT:
>> - ret = ath10k_htt_tx(htt, txmode, skb);
>> + if (ar->is_high_latency)
> Can we use function pointers at initial time to avoid condition check at hot path?
> I'm afraid adding more lines on hot path.
I haven't made any comparison of assembly code between if-paths or function pointers,
but since most architectures have conditional instructions I don't think the
penalty is that big (if there is any penalty at all).
There are plenty of other condition checks in the RX path (mac80211 is full of them),
so I don't really see this as an issue.
That being said, any improvement is always welcome (even micro optimizations
if they are beneficial).
I will think about this and see if adding function pointers can be done in a nice way.

2017-06-12 15:03:29

by Erik Stromdahl

[permalink] [raw]
Subject: [RFC v2 09/10] ath10k: add QCA9377 sdio hw_param item

Hardware parameters for QCA9377 sdio devices.

Signed-off-by: Erik Stromdahl <[email protected]>
---
drivers/net/wireless/ath/ath10k/core.c | 25 +++++++++++++++++++++++++
drivers/net/wireless/ath/ath10k/hw.h | 1 +
2 files changed, 26 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index dc8ea5e..675ce08 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -322,6 +322,31 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.start_once = true,
},
{
+ .id = QCA9377_HW_1_1_DEV_VERSION,
+ .dev_id = QCA9377_1_0_DEVICE_ID,
+ .name = "qca9377 hw1.1 sdio",
+ .patch_load_addr = QCA9377_HW_1_0_PATCH_LOAD_ADDR,
+ .uart_pin = 19,
+ .otp_exe_param = 0,
+ .channel_counters_freq_hz = 88000,
+ .max_probe_resp_desc_thres = 0,
+ .cal_data_len = 8124,
+ .fw = {
+ .dir = QCA9377_HW_1_0_FW_DIR,
+ .board = QCA9377_HW_1_0_BOARD_DATA_FILE_SDIO,
+ .board_size = QCA9377_BOARD_DATA_SZ,
+ .board_ext_size = QCA9377_BOARD_EXT_DATA_SZ,
+ },
+ .hw_ops = &qca6174_ops,
+ .hw_clk = qca6174_clk,
+ .target_cpu_freq = 176000000,
+ .decap_align_bytes = 4,
+ .max_num_peers = TARGET_QCA9377_HL_NUM_PEERS,
+ .is_high_latency = true,
+ .bus = ATH10K_BUS_SDIO,
+ .start_once = true,
+ },
+ {
.id = QCA4019_HW_1_0_DEV_VERSION,
.dev_id = 0,
.name = "qca4019 hw1.0",
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index cc3d0eb..676c855 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -128,6 +128,7 @@ enum qca9377_chip_id_rev {
#define QCA9377_HW_1_0_FW_DIR ATH10K_FW_DIR "/QCA9377/hw1.0"
#define QCA9377_HW_1_0_BOARD_DATA_FILE "board.bin"
#define QCA9377_HW_1_0_BOARD_DATA_FILE_USB "board-usb.bin"
+#define QCA9377_HW_1_0_BOARD_DATA_FILE_SDIO "board-sdio.bin"
#define QCA9377_HW_1_0_PATCH_LOAD_ADDR 0x1234

/* QCA4019 1.0 definitions */
--
2.7.4

2017-06-13 17:38:41

by Peter Oh

[permalink] [raw]
Subject: Re: [RFC v2 05/10] ath10k: htt: High latency TX support

On 06/12/2017 08:03 AM, Erik Stromdahl wrote:
> Add HTT TX function for HL interfaces.
> Intended for SDIO and USB.
>
> Signed-off-by: Erik Stromdahl <[email protected]>
> ---
>
> diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
> index 48418f9..c5fd803 100644
> --- a/drivers/net/wireless/ath/ath10k/mac.c
> +++ b/drivers/net/wireless/ath/ath10k/mac.c
> @@ -3572,7 +3572,10 @@ static int ath10k_mac_tx_submit(struct ath10k *ar,
>
> switch (txpath) {
> case ATH10K_MAC_TX_HTT:
> - ret = ath10k_htt_tx(htt, txmode, skb);
> + if (ar->is_high_latency)
Can we use function pointers at initial time to avoid condition check at
hot path?
I'm afraid adding more lines on hot path.
> + ret = ath10k_htt_tx_hl(htt, txmode, skb);
> + else
> + ret = ath10k_htt_tx_ll(htt, txmode, skb);
> break;
> case ATH10K_MAC_TX_HTT_MGMT:
> ret = ath10k_htt_mgmt_tx(htt, skb);

2017-06-12 15:03:21

by Erik Stromdahl

[permalink] [raw]
Subject: [RFC v2 01/10] ath10k: high_latency detection

The setup of high latency chips (USB and SDIO) is
sometimes different than for chips using low latency
interfaces.

The bus type is used to determine if the interface is
a high latency interface.

Signed-off-by: Erik Stromdahl <[email protected]>
---
drivers/net/wireless/ath/ath10k/core.c | 1 +
drivers/net/wireless/ath/ath10k/core.h | 7 +++++++
2 files changed, 8 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 3fb1429..d3bf5c4 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -2455,6 +2455,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
ar->hw_rev = hw_rev;
ar->hif.ops = hif_ops;
ar->hif.bus = bus;
+ ar->is_high_latency = ath10k_is_high_latency(bus);

switch (hw_rev) {
case ATH10K_HW_QCA988X:
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 1efe0a1..90069b8 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -789,6 +789,8 @@ struct ath10k {

bool p2p;

+ bool is_high_latency;
+
struct {
enum ath10k_bus bus;
const struct ath10k_hif_ops *ops;
@@ -1008,6 +1010,11 @@ static inline bool ath10k_peer_stats_enabled(struct ath10k *ar)
return false;
}

+static inline bool ath10k_is_high_latency(enum ath10k_bus bus)
+{
+ return ((bus == ATH10K_BUS_SDIO) || (bus == ATH10K_BUS_USB));
+}
+
struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
enum ath10k_bus bus,
enum ath10k_hw_rev hw_rev,
--
2.7.4

2017-06-12 15:03:25

by Erik Stromdahl

[permalink] [raw]
Subject: [RFC v2 05/10] ath10k: htt: High latency TX support

Add HTT TX function for HL interfaces.
Intended for SDIO and USB.

Signed-off-by: Erik Stromdahl <[email protected]>
---
drivers/net/wireless/ath/ath10k/htt.h | 9 ++--
drivers/net/wireless/ath/ath10k/htt_tx.c | 72 +++++++++++++++++++++++++++++++-
drivers/net/wireless/ath/ath10k/mac.c | 5 ++-
3 files changed, 80 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index 7ffa1d4..bac453f 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -1830,9 +1830,12 @@ int ath10k_htt_tx_mgmt_inc_pending(struct ath10k_htt *htt, bool is_mgmt,
int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb);
void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id);
int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu);
-int ath10k_htt_tx(struct ath10k_htt *htt,
- enum ath10k_hw_txrx_mode txmode,
- struct sk_buff *msdu);
+int ath10k_htt_tx_ll(struct ath10k_htt *htt,
+ enum ath10k_hw_txrx_mode txmode,
+ struct sk_buff *msdu);
+int ath10k_htt_tx_hl(struct ath10k_htt *htt,
+ enum ath10k_hw_txrx_mode txmode,
+ struct sk_buff *msdu);
void ath10k_htt_rx_pktlog_completion_handler(struct ath10k *ar,
struct sk_buff *skb);
int ath10k_htt_txrx_compl_task(struct ath10k *ar, int budget);
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
index 8d85f82..e3b820d 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -946,8 +946,76 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
return res;
}

-int ath10k_htt_tx(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txmode,
- struct sk_buff *msdu)
+#define HTT_TX_HL_NEEDED_HEADROOM \
+ (unsigned int)(sizeof(struct htt_cmd_hdr) + \
+ sizeof(struct htt_data_tx_desc) + \
+ sizeof(struct ath10k_htc_hdr))
+
+int ath10k_htt_tx_hl(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txmode,
+ struct sk_buff *msdu)
+{
+ struct ath10k *ar = htt->ar;
+ int res, data_len;
+ struct htt_cmd_hdr *cmd_hdr;
+ struct htt_data_tx_desc *tx_desc;
+ struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu);
+ u8 flags0;
+ u16 flags1 = 0;
+
+ data_len = msdu->len;
+ flags0 = SM(txmode, HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
+
+ if (skb_cb->flags & ATH10K_SKB_F_NO_HWCRYPT)
+ flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT;
+
+ if (msdu->ip_summed == CHECKSUM_PARTIAL &&
+ !test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) {
+ flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD;
+ flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD;
+ }
+
+ /* Prepend the HTT header and TX desc struct to the data message
+ * and realloc the skb if it does not have enough headroom.
+ */
+ if (skb_headroom(msdu) < HTT_TX_HL_NEEDED_HEADROOM) {
+ struct sk_buff *tmp_skb = msdu;
+
+ ath10k_dbg(htt->ar, ATH10K_DBG_HTT,
+ "Not enough headroom in skb. Current headroom: %u, needed: %u. Reallocating...\n",
+ skb_headroom(msdu), HTT_TX_HL_NEEDED_HEADROOM);
+ msdu = skb_realloc_headroom(msdu, HTT_TX_HL_NEEDED_HEADROOM);
+ kfree_skb(tmp_skb);
+ if (!msdu) {
+ ath10k_warn(htt->ar, "htt hl tx: Unable to realloc skb!\n");
+ res = -ENOMEM;
+ goto out;
+ }
+ }
+
+ skb_push(msdu, sizeof(*cmd_hdr));
+ skb_push(msdu, sizeof(*tx_desc));
+ cmd_hdr = (struct htt_cmd_hdr *)msdu->data;
+ tx_desc = (struct htt_data_tx_desc *)(msdu->data + sizeof(*cmd_hdr));
+
+ cmd_hdr->msg_type = HTT_H2T_MSG_TYPE_TX_FRM;
+ tx_desc->flags0 = flags0;
+ tx_desc->flags1 = __cpu_to_le16(flags1);
+ tx_desc->len = __cpu_to_le16(data_len);
+ tx_desc->id = 0;
+ tx_desc->frags_paddr = 0; /* always zero */
+ /* Initialize peer_id to INVALID_PEER because this is NOT
+ * Reinjection path
+ */
+ tx_desc->peerid = __cpu_to_le32(HTT_INVALID_PEERID);
+
+ res = ath10k_htc_send(&htt->ar->htc, htt->eid, msdu);
+
+out:
+ return res;
+}
+
+int ath10k_htt_tx_ll(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txmode,
+ struct sk_buff *msdu)
{
struct ath10k *ar = htt->ar;
struct device *dev = ar->dev;
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 48418f9..c5fd803 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -3572,7 +3572,10 @@ static int ath10k_mac_tx_submit(struct ath10k *ar,

switch (txpath) {
case ATH10K_MAC_TX_HTT:
- ret = ath10k_htt_tx(htt, txmode, skb);
+ if (ar->is_high_latency)
+ ret = ath10k_htt_tx_hl(htt, txmode, skb);
+ else
+ ret = ath10k_htt_tx_ll(htt, txmode, skb);
break;
case ATH10K_MAC_TX_HTT_MGMT:
ret = ath10k_htt_mgmt_tx(htt, skb);
--
2.7.4

2017-06-12 15:03:24

by Erik Stromdahl

[permalink] [raw]
Subject: [RFC v2 04/10] ath10k: add start_once support

Add possibility to configure the driver to only start target once.
This can reduce startup time of SDIO devices significantly since
loading the firmware can take a substantial amount of time.

The patch is also necessary for high latency devices in general
since it does not seem to be possible to rerun the BMI phase
(fw upload) without power-cycling the device.

Signed-off-by: Erik Stromdahl <[email protected]>
---
drivers/net/wireless/ath/ath10k/core.c | 19 +++++++++++++++----
drivers/net/wireless/ath/ath10k/core.h | 2 ++
drivers/net/wireless/ath/ath10k/hw.h | 6 ++++++
3 files changed, 23 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 587c013..a1a4610 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -1966,6 +1966,9 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
int status;
u32 val;

+ if (ar->is_started && ar->hw_params.start_once)
+ return 0;
+
lockdep_assert_held(&ar->conf_mutex);

clear_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags);
@@ -2185,6 +2188,7 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
if (status)
goto err_hif_stop;

+ ar->is_started = true;
return 0;

err_hif_stop:
@@ -2237,6 +2241,7 @@ void ath10k_core_stop(struct ath10k *ar)
ath10k_htt_tx_stop(&ar->htt);
ath10k_htt_rx_free(&ar->htt);
ath10k_wmi_detach(ar);
+ ar->is_started = false;
}
EXPORT_SYMBOL(ath10k_core_stop);

@@ -2339,12 +2344,18 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
goto err_unlock;
}

- ath10k_debug_print_boot_info(ar);
- ath10k_core_stop(ar);
+ /* Leave target running if hw_params.start_once is set */
+ if (ar->hw_params.start_once) {
+ mutex_unlock(&ar->conf_mutex);
+ } else {
+ ath10k_debug_print_boot_info(ar);
+ ath10k_core_stop(ar);

- mutex_unlock(&ar->conf_mutex);
+ mutex_unlock(&ar->conf_mutex);
+
+ ath10k_hif_power_down(ar);
+ }

- ath10k_hif_power_down(ar);
return 0;

err_unlock:
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index cdac923..0e75441 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -784,6 +784,8 @@ struct ath10k {

bool is_high_latency;

+ bool is_started;
+
struct {
enum ath10k_bus bus;
const struct ath10k_hif_ops *ops;
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index 160377aa..f733e73 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -473,6 +473,12 @@ struct ath10k_hw_params {
bool is_high_latency;

enum ath10k_bus bus;
+
+ /* Specifies whether or not the device should be started once.
+ * If set, the device will be started once by the early fw probe
+ * and it will not be terminated afterwards.
+ */
+ bool start_once;
};

struct htt_rx_desc;
--
2.7.4