summaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/ethernet/msm/msm_rmnet_mhi.c9
-rw-r--r--drivers/net/wireless/ath/ath10k/core.c12
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c107
-rw-r--r--drivers/net/wireless/ath/ath10k/snoc.c4
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-ops.h12
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.c38
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.h1
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.c18
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.h7
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c2
-rw-r--r--drivers/net/wireless/ath/wil6210/sysfs.c3
-rw-r--r--drivers/net/wireless/cnss/cnss_pci.c138
-rw-r--r--drivers/net/wireless/cnss2/debug.c93
-rw-r--r--drivers/net/wireless/cnss2/main.c24
-rw-r--r--drivers/net/wireless/cnss2/pci.c44
-rw-r--r--drivers/net/wireless/cnss2/qmi.c37
-rw-r--r--drivers/net/wireless/wcnss/wcnss_vreg.c32
-rw-r--r--drivers/net/wireless/wcnss/wcnss_wlan.c156
18 files changed, 499 insertions, 238 deletions
diff --git a/drivers/net/ethernet/msm/msm_rmnet_mhi.c b/drivers/net/ethernet/msm/msm_rmnet_mhi.c
index 60b7a64c2edb..de14dcc6f4ed 100644
--- a/drivers/net/ethernet/msm/msm_rmnet_mhi.c
+++ b/drivers/net/ethernet/msm/msm_rmnet_mhi.c
@@ -942,10 +942,13 @@ net_dev_reg_fail:
netif_napi_del(&(rmnet_mhi_ptr->napi));
free_netdev(rmnet_mhi_ptr->dev);
net_dev_alloc_fail:
- mhi_close_channel(rmnet_mhi_ptr->rx_client_handle);
- rmnet_mhi_ptr->dev = NULL;
+ if (rmnet_mhi_ptr->rx_client_handle) {
+ mhi_close_channel(rmnet_mhi_ptr->rx_client_handle);
+ rmnet_mhi_ptr->dev = NULL;
+ }
mhi_rx_chan_start_fail:
- mhi_close_channel(rmnet_mhi_ptr->tx_client_handle);
+ if (rmnet_mhi_ptr->tx_client_handle)
+ mhi_close_channel(rmnet_mhi_ptr->tx_client_handle);
mhi_tx_chan_start_fail:
rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Exited ret %d.\n", ret);
return ret;
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 6906bddb229f..10b33840e5e5 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -1886,6 +1886,12 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
goto err_wmi_detach;
}
+ /* 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_alloc(&ar->htt);
if (status) {
ath10k_err(ar, "failed to alloc htt rx: %d\n", status);
@@ -1997,12 +2003,6 @@ 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));
-
status = ath10k_htt_rx_ring_refill(ar);
if (status) {
ath10k_err(ar, "failed to refill htt rx ring: %d\n", status);
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index e430bab869a8..cce931e51d7e 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -667,6 +667,36 @@ ath10k_mac_get_any_chandef_iter(struct ieee80211_hw *hw,
*def = &conf->def;
}
+static int ath10k_peer_delete(struct ath10k *ar, u32 vdev_id, const u8 *addr)
+{
+ int ret;
+ unsigned long time_left;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ ret = ath10k_wmi_peer_delete(ar, vdev_id, addr);
+ if (ret)
+ return ret;
+
+ ret = ath10k_wait_for_peer_deleted(ar, vdev_id, addr);
+ if (ret)
+ return ret;
+
+ if (QCA_REV_WCN3990(ar)) {
+ time_left = wait_for_completion_timeout(&ar->peer_delete_done,
+ 50 * HZ);
+
+ if (time_left == 0) {
+ ath10k_warn(ar, "Timeout in receiving peer delete response\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ ar->num_peers--;
+
+ return 0;
+}
+
static int ath10k_peer_create(struct ath10k *ar,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
@@ -711,7 +741,7 @@ static int ath10k_peer_create(struct ath10k *ar,
spin_unlock_bh(&ar->data_lock);
ath10k_warn(ar, "failed to find peer %pM on vdev %i after creation\n",
addr, vdev_id);
- ath10k_wmi_peer_delete(ar, vdev_id, addr);
+ ath10k_peer_delete(ar, vdev_id, addr);
return -ENOENT;
}
@@ -779,36 +809,6 @@ static int ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value)
return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, value);
}
-static int ath10k_peer_delete(struct ath10k *ar, u32 vdev_id, const u8 *addr)
-{
- int ret;
- unsigned long time_left;
-
- lockdep_assert_held(&ar->conf_mutex);
-
- ret = ath10k_wmi_peer_delete(ar, vdev_id, addr);
- if (ret)
- return ret;
-
- ret = ath10k_wait_for_peer_deleted(ar, vdev_id, addr);
- if (ret)
- return ret;
-
- if (QCA_REV_WCN3990(ar)) {
- time_left = wait_for_completion_timeout(&ar->peer_delete_done,
- 50 * HZ);
-
- if (time_left == 0) {
- ath10k_warn(ar, "Timeout in receiving peer delete response\n");
- return -ETIMEDOUT;
- }
- }
-
- ar->num_peers--;
-
- return 0;
-}
-
static void ath10k_peer_cleanup(struct ath10k *ar, u32 vdev_id)
{
struct ath10k_peer *peer, *tmp;
@@ -5094,7 +5094,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
err_peer_delete:
if (arvif->vdev_type == WMI_VDEV_TYPE_AP ||
arvif->vdev_type == WMI_VDEV_TYPE_IBSS)
- ath10k_wmi_peer_delete(ar, arvif->vdev_id, vif->addr);
+ ath10k_peer_delete(ar, arvif->vdev_id, vif->addr);
err_vdev_delete:
ath10k_wmi_vdev_delete(ar, arvif->vdev_id);
@@ -5150,8 +5150,8 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
if (arvif->vdev_type == WMI_VDEV_TYPE_AP ||
arvif->vdev_type == WMI_VDEV_TYPE_IBSS) {
- ret = ath10k_wmi_peer_delete(arvif->ar, arvif->vdev_id,
- vif->addr);
+ ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id,
+ vif->addr);
if (ret)
ath10k_warn(ar, "failed to submit AP/IBSS self-peer removal on vdev %i: %d\n",
arvif->vdev_id, ret);
@@ -7168,12 +7168,25 @@ ath10k_mac_update_vif_chan(struct ath10k *ar,
if (WARN_ON(!arvif->is_up))
continue;
+ if (QCA_REV_WCN3990(ar)) {
+ /* In the case of wcn3990 WLAN module we send
+ * vdev restart only, no need to send vdev down.
+ */
- ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
- if (ret) {
- ath10k_warn(ar, "failed to down vdev %d: %d\n",
- arvif->vdev_id, ret);
- continue;
+ ret = ath10k_vdev_restart(arvif, &vifs[i].new_ctx->def);
+ if (ret) {
+ ath10k_warn(ar,
+ "failed to restart vdev %d: %d\n",
+ arvif->vdev_id, ret);
+ continue;
+ }
+ } else {
+ ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
+ if (ret) {
+ ath10k_warn(ar, "failed to down vdev %d: %d\n",
+ arvif->vdev_id, ret);
+ continue;
+ }
}
}
@@ -7204,11 +7217,17 @@ ath10k_mac_update_vif_chan(struct ath10k *ar,
ath10k_warn(ar, "failed to update prb tmpl during csa: %d\n",
ret);
- ret = ath10k_vdev_restart(arvif, &vifs[i].new_ctx->def);
- if (ret) {
- ath10k_warn(ar, "failed to restart vdev %d: %d\n",
- arvif->vdev_id, ret);
- continue;
+ if (!QCA_REV_WCN3990(ar)) {
+ /* In case of other than wcn3990 WLAN module we
+ * send vdev down and vdev restart to the firmware.
+ */
+
+ ret = ath10k_vdev_restart(arvif, &vifs[i].new_ctx->def);
+ if (ret) {
+ ath10k_warn(ar, "failed to restart vdev %d: %d\n",
+ arvif->vdev_id, ret);
+ continue;
+ }
}
ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c
index 59598c990e40..0c60a7baae82 100644
--- a/drivers/net/wireless/ath/ath10k/snoc.c
+++ b/drivers/net/wireless/ath/ath10k/snoc.c
@@ -107,8 +107,8 @@ static struct ce_attr host_ce_config_wlan[] = {
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 0,
- .src_sz_max = 512,
- .dest_nentries = 512,
+ .src_sz_max = 0,
+ .dest_nentries = 0,
.recv_cb = ath10k_snoc_htt_rx_cb,
},
diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h
index 129859255295..c3100fcd80f2 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-ops.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h
@@ -31,6 +31,8 @@ struct wmi_ops {
struct wmi_mgmt_rx_ev_arg *arg);
int (*pull_ch_info)(struct ath10k *ar, struct sk_buff *skb,
struct wmi_ch_info_ev_arg *arg);
+ int (*pull_peer_delete_resp)(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_peer_delete_resp_ev_arg *arg);
int (*pull_vdev_start)(struct ath10k *ar, struct sk_buff *skb,
struct wmi_vdev_start_ev_arg *arg);
int (*pull_peer_kick)(struct ath10k *ar, struct sk_buff *skb,
@@ -246,6 +248,16 @@ ath10k_wmi_pull_mgmt_rx(struct ath10k *ar, struct sk_buff *skb,
}
static inline int
+ath10k_wmi_pull_peer_delete_resp(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_peer_delete_resp_ev_arg *arg)
+{
+ if (!ar->wmi.ops->pull_peer_delete_resp)
+ return -EOPNOTSUPP;
+
+ return ar->wmi.ops->pull_peer_delete_resp(ar, skb, arg);
+}
+
+static inline int
ath10k_wmi_pull_ch_info(struct ath10k *ar, struct sk_buff *skb,
struct wmi_ch_info_ev_arg *arg)
{
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index 888ab5ad37f1..07b15f4c1db4 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -412,15 +412,6 @@ static int ath10k_wmi_tlv_event_tx_pause(struct ath10k *ar,
return 0;
}
-static int ath10k_wmi_tlv_event_peer_delete_resp(struct ath10k *ar,
- struct sk_buff *skb)
-{
- ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TLV_PEER_DELETE_RESP_EVENTID\n");
- complete(&ar->peer_delete_done);
-
- return 0;
-}
-
/***********/
/* TLV ops */
/***********/
@@ -657,6 +648,34 @@ static int ath10k_wmi_tlv_op_pull_mgmt_rx_ev(struct ath10k *ar,
return 0;
}
+static int ath10k_wmi_tlv_op_pull_peer_delete_ev(
+ struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_peer_delete_resp_ev_arg *arg)
+{
+ const void **tb;
+ const struct wmi_peer_delete_resp_ev_arg *ev;
+ int ret;
+
+ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
+ if (IS_ERR(tb)) {
+ ret = PTR_ERR(tb);
+ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
+ return ret;
+ }
+
+ ev = tb[WMI_TLV_TAG_STRUCT_PEER_DELETE_RESP_EVENT];
+ if (!ev) {
+ kfree(tb);
+ return -EPROTO;
+ }
+
+ arg->vdev_id = ev->vdev_id;
+ arg->peer_addr = ev->peer_addr;
+
+ kfree(tb);
+ return 0;
+}
+
static int ath10k_wmi_tlv_op_pull_ch_info_ev(struct ath10k *ar,
struct sk_buff *skb,
struct wmi_ch_info_ev_arg *arg)
@@ -3620,6 +3639,7 @@ static const struct wmi_ops wmi_tlv_ops = {
.pull_scan = ath10k_wmi_tlv_op_pull_scan_ev,
.pull_mgmt_rx = ath10k_wmi_tlv_op_pull_mgmt_rx_ev,
.pull_ch_info = ath10k_wmi_tlv_op_pull_ch_info_ev,
+ .pull_peer_delete_resp = ath10k_wmi_tlv_op_pull_peer_delete_ev,
.pull_vdev_start = ath10k_wmi_tlv_op_pull_vdev_start_ev,
.pull_peer_kick = ath10k_wmi_tlv_op_pull_peer_kick_ev,
.pull_swba = ath10k_wmi_tlv_op_pull_swba_ev,
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
index 86b24c24d9f1..500d1d8f441f 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
@@ -898,6 +898,7 @@ enum wmi_tlv_tag {
WMI_TLV_TAG_STRUCT_HL_1_0_SVC_OFFSET = 176,
WMI_TLV_TAG_STRUCT_MGMT_TX_CMD = 0x1A6,
+ WMI_TLV_TAG_STRUCT_PEER_DELETE_RESP_EVENT = 0x1C3,
WMI_TLV_TAG_MAX
};
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index d60e7fbb7e74..d6ec0de63582 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -2269,6 +2269,24 @@ static bool ath10k_wmi_rx_is_decrypted(struct ath10k *ar,
return true;
}
+int ath10k_wmi_tlv_event_peer_delete_resp(struct ath10k *ar,
+ struct sk_buff *skb)
+{
+ int ret;
+ struct wmi_peer_delete_resp_ev_arg arg = {};
+
+ ret = ath10k_wmi_pull_peer_delete_resp(ar, skb, &arg);
+ if (ret) {
+ ath10k_warn(ar, "failed to parse peer delete resp: %d\n", ret);
+ dev_kfree_skb(skb);
+ return ret;
+ }
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TLV_PEER_DELETE_RESP_EVENTID\n");
+ complete(&ar->peer_delete_done);
+
+ return 0;
+}
+
int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
{
struct wmi_mgmt_rx_ev_arg arg = {};
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index 9bd374910379..7ae07a505c59 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -6234,6 +6234,11 @@ struct wmi_scan_ev_arg {
__le32 vdev_id;
};
+struct wmi_peer_delete_resp_ev_arg {
+ __le32 vdev_id;
+ struct wmi_mac_addr peer_addr;
+};
+
struct wmi_mgmt_rx_ev_arg {
__le32 channel;
__le32 snr;
@@ -6603,6 +6608,8 @@ void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch,
int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg);
int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb);
+int ath10k_wmi_tlv_event_peer_delete_resp(struct ath10k *ar,
+ struct sk_buff *skb);
int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb);
void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb);
void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb);
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 63bb7686b811..94861020af12 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -960,7 +960,7 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
wil_hex_dump_misc("mgmt tx frame ", DUMP_PREFIX_OFFSET, 16, 1, buf,
len, true);
- if (len < sizeof(struct ieee80211_mgmt))
+ if (len < sizeof(struct ieee80211_hdr_3addr))
return -EINVAL;
cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL);
diff --git a/drivers/net/wireless/ath/wil6210/sysfs.c b/drivers/net/wireless/ath/wil6210/sysfs.c
index b4c4d09011b4..b91bf51be767 100644
--- a/drivers/net/wireless/ath/wil6210/sysfs.c
+++ b/drivers/net/wireless/ath/wil6210/sysfs.c
@@ -291,6 +291,8 @@ int wil6210_sysfs_init(struct wil6210_priv *wil)
return err;
}
+ kobject_uevent(&dev->kobj, KOBJ_CHANGE);
+
return 0;
}
@@ -299,4 +301,5 @@ void wil6210_sysfs_remove(struct wil6210_priv *wil)
struct device *dev = wil_to_dev(wil);
sysfs_remove_group(&dev->kobj, &wil6210_attribute_group);
+ kobject_uevent(&dev->kobj, KOBJ_CHANGE);
}
diff --git a/drivers/net/wireless/cnss/cnss_pci.c b/drivers/net/wireless/cnss/cnss_pci.c
index 22c59d8c3c45..d150c2dd0f0f 100644
--- a/drivers/net/wireless/cnss/cnss_pci.c
+++ b/drivers/net/wireless/cnss/cnss_pci.c
@@ -114,6 +114,8 @@
#define WLAN_VREG_SP2T_MIN 2700000
#define POWER_ON_DELAY 2
+#define WLAN_VREG_IO_DELAY_MIN 100
+#define WLAN_VREG_IO_DELAY_MAX 1000
#define WLAN_ENABLE_DELAY 10
#define WLAN_RECOVERY_DELAY 1
#define PCIE_ENABLE_DELAY 100
@@ -134,7 +136,6 @@ static DEFINE_SPINLOCK(pci_link_down_lock);
#define FW_IMAGE_MISSION (0x02)
#define FW_IMAGE_BDATA (0x03)
#define FW_IMAGE_PRINT (0x04)
-#define FW_SETUP_DELAY 2000
#define SEG_METADATA (0x01)
#define SEG_NON_PAGED (0x02)
@@ -274,10 +275,8 @@ static struct cnss_data {
u32 fw_dma_size;
u32 fw_seg_count;
struct segment_memory fw_seg_mem[MAX_NUM_OF_SEGMENTS];
- atomic_t fw_store_in_progress;
/* Firmware setup complete lock */
struct mutex fw_setup_stat_lock;
- struct completion fw_setup_complete;
void *bdata_cpu;
dma_addr_t bdata_dma;
u32 bdata_dma_size;
@@ -307,13 +306,6 @@ static int cnss_wlan_vreg_on(struct cnss_wlan_vreg_info *vreg_info)
}
}
- ret = regulator_enable(vreg_info->wlan_reg);
- if (ret) {
- pr_err("%s: regulator enable failed for WLAN power\n",
- __func__);
- goto error_enable;
- }
-
if (vreg_info->wlan_reg_io) {
ret = regulator_enable(vreg_info->wlan_reg_io);
if (ret) {
@@ -321,6 +313,8 @@ static int cnss_wlan_vreg_on(struct cnss_wlan_vreg_info *vreg_info)
__func__);
goto error_enable_reg_io;
}
+
+ usleep_range(WLAN_VREG_IO_DELAY_MIN, WLAN_VREG_IO_DELAY_MAX);
}
if (vreg_info->wlan_reg_xtal_aon) {
@@ -341,6 +335,13 @@ static int cnss_wlan_vreg_on(struct cnss_wlan_vreg_info *vreg_info)
}
}
+ ret = regulator_enable(vreg_info->wlan_reg);
+ if (ret) {
+ pr_err("%s: regulator enable failed for WLAN power\n",
+ __func__);
+ goto error_enable;
+ }
+
if (vreg_info->wlan_reg_sp2t) {
ret = regulator_enable(vreg_info->wlan_reg_sp2t);
if (ret) {
@@ -377,6 +378,8 @@ error_enable_ant_switch:
if (vreg_info->wlan_reg_sp2t)
regulator_disable(vreg_info->wlan_reg_sp2t);
error_enable_reg_sp2t:
+ regulator_disable(vreg_info->wlan_reg);
+error_enable:
if (vreg_info->wlan_reg_xtal)
regulator_disable(vreg_info->wlan_reg_xtal);
error_enable_reg_xtal:
@@ -386,8 +389,6 @@ error_enable_reg_xtal_aon:
if (vreg_info->wlan_reg_io)
regulator_disable(vreg_info->wlan_reg_io);
error_enable_reg_io:
- regulator_disable(vreg_info->wlan_reg);
-error_enable:
if (vreg_info->wlan_reg_core)
regulator_disable(vreg_info->wlan_reg_core);
error_enable_reg_core:
@@ -425,6 +426,13 @@ static int cnss_wlan_vreg_off(struct cnss_wlan_vreg_info *vreg_info)
}
}
+ ret = regulator_disable(vreg_info->wlan_reg);
+ if (ret) {
+ pr_err("%s: regulator disable failed for WLAN power\n",
+ __func__);
+ goto error_disable;
+ }
+
if (vreg_info->wlan_reg_xtal) {
ret = regulator_disable(vreg_info->wlan_reg_xtal);
if (ret) {
@@ -452,13 +460,6 @@ static int cnss_wlan_vreg_off(struct cnss_wlan_vreg_info *vreg_info)
}
}
- ret = regulator_disable(vreg_info->wlan_reg);
- if (ret) {
- pr_err("%s: regulator disable failed for WLAN power\n",
- __func__);
- goto error_disable;
- }
-
if (vreg_info->wlan_reg_core) {
ret = regulator_disable(vreg_info->wlan_reg_core);
if (ret) {
@@ -718,24 +719,6 @@ static int cnss_wlan_get_resources(struct platform_device *pdev)
}
}
- vreg_info->wlan_reg = regulator_get(&pdev->dev, WLAN_VREG_NAME);
-
- if (IS_ERR(vreg_info->wlan_reg)) {
- if (PTR_ERR(vreg_info->wlan_reg) == -EPROBE_DEFER)
- pr_err("%s: vreg probe defer\n", __func__);
- else
- pr_err("%s: vreg regulator get failed\n", __func__);
- ret = PTR_ERR(vreg_info->wlan_reg);
- goto err_reg_get;
- }
-
- ret = regulator_enable(vreg_info->wlan_reg);
-
- if (ret) {
- pr_err("%s: vreg initial vote failed\n", __func__);
- goto err_reg_enable;
- }
-
if (of_get_property(pdev->dev.of_node,
WLAN_VREG_IO_NAME"-supply", NULL)) {
vreg_info->wlan_reg_io = regulator_get(&pdev->dev,
@@ -755,12 +738,33 @@ static int cnss_wlan_get_resources(struct platform_device *pdev)
__func__);
goto err_reg_io_enable;
}
+
+ usleep_range(WLAN_VREG_IO_DELAY_MIN,
+ WLAN_VREG_IO_DELAY_MAX);
}
}
if (cnss_enable_xtal_ldo(pdev))
goto err_reg_xtal_enable;
+ vreg_info->wlan_reg = regulator_get(&pdev->dev, WLAN_VREG_NAME);
+
+ if (IS_ERR(vreg_info->wlan_reg)) {
+ if (PTR_ERR(vreg_info->wlan_reg) == -EPROBE_DEFER)
+ pr_err("%s: vreg probe defer\n", __func__);
+ else
+ pr_err("%s: vreg regulator get failed\n", __func__);
+ ret = PTR_ERR(vreg_info->wlan_reg);
+ goto err_reg_get;
+ }
+
+ ret = regulator_enable(vreg_info->wlan_reg);
+
+ if (ret) {
+ pr_err("%s: vreg initial vote failed\n", __func__);
+ goto err_reg_enable;
+ }
+
if (of_get_property(pdev->dev.of_node,
WLAN_VREG_SP2T_NAME"-supply", NULL)) {
vreg_info->wlan_reg_sp2t =
@@ -929,7 +933,11 @@ err_reg_sp2t_enable:
err_reg_sp2t_set:
if (vreg_info->wlan_reg_sp2t)
regulator_put(vreg_info->wlan_reg_sp2t);
+ regulator_disable(vreg_info->wlan_reg);
+err_reg_enable:
+ regulator_put(vreg_info->wlan_reg);
+err_reg_get:
cnss_disable_xtal_ldo(pdev);
err_reg_xtal_enable:
@@ -940,12 +948,6 @@ err_reg_io_enable:
err_reg_io_set:
if (vreg_info->wlan_reg_io)
regulator_put(vreg_info->wlan_reg_io);
- regulator_disable(vreg_info->wlan_reg);
-
-err_reg_enable:
- regulator_put(vreg_info->wlan_reg);
-
-err_reg_get:
if (vreg_info->wlan_reg_core)
regulator_disable(vreg_info->wlan_reg_core);
@@ -975,13 +977,13 @@ static void cnss_wlan_release_resources(void)
regulator_put(vreg_info->ant_switch);
if (vreg_info->wlan_reg_sp2t)
regulator_put(vreg_info->wlan_reg_sp2t);
+ regulator_put(vreg_info->wlan_reg);
if (vreg_info->wlan_reg_xtal)
regulator_put(vreg_info->wlan_reg_xtal);
if (vreg_info->wlan_reg_xtal_aon)
regulator_put(vreg_info->wlan_reg_xtal_aon);
if (vreg_info->wlan_reg_io)
regulator_put(vreg_info->wlan_reg_io);
- regulator_put(vreg_info->wlan_reg);
if (vreg_info->wlan_reg_core)
regulator_put(vreg_info->wlan_reg_core);
vreg_info->state = VREG_OFF;
@@ -1374,15 +1376,6 @@ int cnss_get_fw_image(struct image_desc_info *image_desc_info)
!penv->fw_seg_count || !penv->bdata_seg_count)
return -EINVAL;
- /* Check for firmware setup trigger by usersapce is in progress
- * and wait for complition of firmware setup.
- */
-
- if (atomic_read(&penv->fw_store_in_progress)) {
- wait_for_completion_timeout(&penv->fw_setup_complete,
- msecs_to_jiffies(FW_SETUP_DELAY));
- }
-
mutex_lock(&penv->fw_setup_stat_lock);
image_desc_info->fw_addr = penv->fw_dma;
image_desc_info->fw_size = penv->fw_dma_size;
@@ -1627,7 +1620,9 @@ static int cnss_wlan_pci_probe(struct pci_dev *pdev,
goto err_pcie_suspend;
}
+ mutex_lock(&penv->fw_setup_stat_lock);
cnss_wlan_fw_mem_alloc(pdev);
+ mutex_unlock(&penv->fw_setup_stat_lock);
ret = device_create_file(&penv->pldev->dev, &dev_attr_wlan_setup);
@@ -1874,17 +1869,11 @@ static ssize_t fw_image_setup_store(struct device *dev,
if (!penv)
return -ENODEV;
- if (atomic_read(&penv->fw_store_in_progress)) {
- pr_info("%s: Firmware setup in progress\n", __func__);
- return 0;
- }
-
- atomic_set(&penv->fw_store_in_progress, 1);
- init_completion(&penv->fw_setup_complete);
+ mutex_lock(&penv->fw_setup_stat_lock);
+ pr_info("%s: Firmware setup in progress\n", __func__);
if (kstrtoint(buf, 0, &val)) {
- atomic_set(&penv->fw_store_in_progress, 0);
- complete(&penv->fw_setup_complete);
+ mutex_unlock(&penv->fw_setup_stat_lock);
return -EINVAL;
}
@@ -1895,8 +1884,7 @@ static ssize_t fw_image_setup_store(struct device *dev,
if (ret != 0) {
pr_err("%s: Invalid parsing of FW image files %d",
__func__, ret);
- atomic_set(&penv->fw_store_in_progress, 0);
- complete(&penv->fw_setup_complete);
+ mutex_unlock(&penv->fw_setup_stat_lock);
return -EINVAL;
}
penv->fw_image_setup = val;
@@ -1906,9 +1894,8 @@ static ssize_t fw_image_setup_store(struct device *dev,
penv->bmi_test = val;
}
- atomic_set(&penv->fw_store_in_progress, 0);
- complete(&penv->fw_setup_complete);
-
+ pr_info("%s: Firmware setup completed\n", __func__);
+ mutex_unlock(&penv->fw_setup_stat_lock);
return count;
}
@@ -2007,16 +1994,21 @@ int cnss_get_codeswap_struct(struct codeswap_codeseg_info *swap_seg)
{
struct codeswap_codeseg_info *cnss_seg_info = penv->cnss_seg_info;
+ mutex_lock(&penv->fw_setup_stat_lock);
if (!cnss_seg_info) {
swap_seg = NULL;
+ mutex_unlock(&penv->fw_setup_stat_lock);
return -ENOENT;
}
+
if (!atomic_read(&penv->fw_available)) {
pr_debug("%s: fw is not available\n", __func__);
+ mutex_unlock(&penv->fw_setup_stat_lock);
return -ENOENT;
}
*swap_seg = *cnss_seg_info;
+ mutex_unlock(&penv->fw_setup_stat_lock);
return 0;
}
@@ -2035,15 +2027,6 @@ static void cnss_wlan_memory_expansion(void)
u_int32_t total_length = 0;
struct pci_dev *pdev;
- /* Check for firmware setup trigger by usersapce is in progress
- * and wait for complition of firmware setup.
- */
-
- if (atomic_read(&penv->fw_store_in_progress)) {
- wait_for_completion_timeout(&penv->fw_setup_complete,
- msecs_to_jiffies(FW_SETUP_DELAY));
- }
-
mutex_lock(&penv->fw_setup_stat_lock);
filename = cnss_wlan_get_evicted_data_file();
pdev = penv->pdev;
@@ -2859,6 +2842,7 @@ static int cnss_probe(struct platform_device *pdev)
penv->vreg_info.wlan_reg = NULL;
penv->vreg_info.state = VREG_OFF;
penv->pci_register_again = false;
+ mutex_init(&penv->fw_setup_stat_lock);
ret = cnss_wlan_get_resources(pdev);
if (ret)
@@ -3016,8 +3000,6 @@ skip_ramdump:
memset(phys_to_virt(0), 0, SZ_4K);
#endif
- atomic_set(&penv->fw_store_in_progress, 0);
- mutex_init(&penv->fw_setup_stat_lock);
ret = device_create_file(dev, &dev_attr_fw_image_setup);
if (ret) {
pr_err("cnss: fw_image_setup sys file creation failed\n");
diff --git a/drivers/net/wireless/cnss2/debug.c b/drivers/net/wireless/cnss2/debug.c
index 360ab31c61dd..c3bcb38f428f 100644
--- a/drivers/net/wireless/cnss2/debug.c
+++ b/drivers/net/wireless/cnss2/debug.c
@@ -15,6 +15,7 @@
#include <linux/debugfs.h>
#include "main.h"
#include "debug.h"
+#include "pci.h"
#define CNSS_IPC_LOG_PAGES 32
@@ -121,13 +122,90 @@ static int cnss_stats_open(struct inode *inode, struct file *file)
}
static const struct file_operations cnss_stats_fops = {
- .read = seq_read,
- .release = single_release,
- .open = cnss_stats_open,
- .owner = THIS_MODULE,
- .llseek = seq_lseek,
+ .read = seq_read,
+ .release = single_release,
+ .open = cnss_stats_open,
+ .owner = THIS_MODULE,
+ .llseek = seq_lseek,
};
+static ssize_t cnss_dev_boot_debug_write(struct file *fp,
+ const char __user *user_buf,
+ size_t count, loff_t *off)
+{
+ struct cnss_plat_data *plat_priv =
+ ((struct seq_file *)fp->private_data)->private;
+ char buf[64];
+ char *cmd;
+ unsigned int len = 0;
+ int ret = 0;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+
+ buf[len] = '\0';
+ cmd = buf;
+
+ if (sysfs_streq(cmd, "on")) {
+ ret = cnss_power_on_device(plat_priv);
+ } else if (sysfs_streq(cmd, "enumerate")) {
+ ret = cnss_pci_init(plat_priv);
+ } else if (sysfs_streq(cmd, "download")) {
+ ret = cnss_pci_start_mhi(plat_priv->bus_priv);
+ } else {
+ cnss_pr_err("Device boot debugfs command is invalid\n");
+ ret = -EINVAL;
+ }
+
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static int cnss_dev_boot_debug_show(struct seq_file *s, void *data)
+{
+ seq_puts(s, "\nUsage: echo <action> > <debugfs_path>/cnss/dev_boot\n");
+ seq_puts(s, "<action> can be one of below:\n");
+ seq_puts(s, "on: turn on device power, assert WLAN_EN\n");
+ seq_puts(s, "enumerate: de-assert PERST, enumerate PCIe\n");
+ seq_puts(s, "download: download FW and do QMI handshake with FW\n");
+
+ return 0;
+}
+
+static int cnss_dev_boot_debug_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, cnss_dev_boot_debug_show, inode->i_private);
+}
+
+static const struct file_operations cnss_dev_boot_debug_fops = {
+ .read = seq_read,
+ .write = cnss_dev_boot_debug_write,
+ .release = single_release,
+ .open = cnss_dev_boot_debug_open,
+ .owner = THIS_MODULE,
+ .llseek = seq_lseek,
+};
+
+#ifdef CONFIG_CNSS2_DEBUG
+static int cnss_create_debug_only_node(struct cnss_plat_data *plat_priv)
+{
+ struct dentry *root_dentry = plat_priv->root_dentry;
+
+ debugfs_create_file("dev_boot", 0600, root_dentry, plat_priv,
+ &cnss_dev_boot_debug_fops);
+
+ return 0;
+}
+#else
+static int cnss_create_debug_only_node(struct cnss_plat_data *plat_priv)
+{
+ return 0;
+}
+#endif
+
int cnss_debugfs_create(struct cnss_plat_data *plat_priv)
{
int ret = 0;
@@ -139,11 +217,16 @@ int cnss_debugfs_create(struct cnss_plat_data *plat_priv)
cnss_pr_err("Unable to create debugfs %d\n", ret);
goto out;
}
+
plat_priv->root_dentry = root_dentry;
+
debugfs_create_file("pin_connect_result", 0644, root_dentry, plat_priv,
&cnss_pin_connect_fops);
debugfs_create_file("stats", 0644, root_dentry, plat_priv,
&cnss_stats_fops);
+
+ cnss_create_debug_only_node(plat_priv);
+
out:
return ret;
}
diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c
index 432960afe09a..8838a1319629 100644
--- a/drivers/net/wireless/cnss2/main.c
+++ b/drivers/net/wireless/cnss2/main.c
@@ -57,6 +57,7 @@ MODULE_PARM_DESC(enable_waltest, "Enable to handle firmware waltest");
enum cnss_debug_quirks {
LINK_DOWN_SELF_RECOVERY,
+ SKIP_DEVICE_BOOT,
};
unsigned long quirks;
@@ -1100,7 +1101,8 @@ static int cnss_qca6290_powerup(struct cnss_plat_data *plat_priv)
return -ENODEV;
}
- if (plat_priv->ramdump_info_v2.dump_data_valid) {
+ if (plat_priv->ramdump_info_v2.dump_data_valid ||
+ test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_DEINIT);
cnss_pci_clear_dump_info(pci_priv);
}
@@ -2231,13 +2233,15 @@ static int cnss_probe(struct platform_device *plat_dev)
if (ret)
goto reset_ctx;
- ret = cnss_power_on_device(plat_priv);
- if (ret)
- goto free_res;
+ if (!test_bit(SKIP_DEVICE_BOOT, &quirks)) {
+ ret = cnss_power_on_device(plat_priv);
+ if (ret)
+ goto free_res;
- ret = cnss_pci_init(plat_priv);
- if (ret)
- goto power_off;
+ ret = cnss_pci_init(plat_priv);
+ if (ret)
+ goto power_off;
+ }
ret = cnss_register_esoc(plat_priv);
if (ret)
@@ -2290,9 +2294,11 @@ unreg_bus_scale:
unreg_esoc:
cnss_unregister_esoc(plat_priv);
deinit_pci:
- cnss_pci_deinit(plat_priv);
+ if (!test_bit(SKIP_DEVICE_BOOT, &quirks))
+ cnss_pci_deinit(plat_priv);
power_off:
- cnss_power_off_device(plat_priv);
+ if (!test_bit(SKIP_DEVICE_BOOT, &quirks))
+ cnss_power_off_device(plat_priv);
free_res:
cnss_put_resources(plat_priv);
reset_ctx:
diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c
index a17b72ce03ba..ce5a7b2bc88e 100644
--- a/drivers/net/wireless/cnss2/pci.c
+++ b/drivers/net/wireless/cnss2/pci.c
@@ -787,36 +787,6 @@ int cnss_pci_get_bar_info(struct cnss_pci_data *pci_priv, void __iomem **va,
return 0;
}
-#ifdef CONFIG_CNSS_QCA6290
-#define PCI_MAX_BAR_SIZE 0xD00000
-
-static void __iomem *cnss_pci_iomap(struct pci_dev *dev, int bar,
- unsigned long maxlen)
-{
- resource_size_t start = pci_resource_start(dev, bar);
- resource_size_t len = PCI_MAX_BAR_SIZE;
- unsigned long flags = pci_resource_flags(dev, bar);
-
- if (!len || !start)
- return NULL;
-
- if ((flags & IORESOURCE_IO) || (flags & IORESOURCE_MEM)) {
- if (flags & IORESOURCE_CACHEABLE && !(flags & IORESOURCE_IO))
- return ioremap(start, len);
- else
- return ioremap_nocache(start, len);
- }
-
- return NULL;
-}
-#else
-static void __iomem *cnss_pci_iomap(struct pci_dev *dev, int bar,
- unsigned long maxlen)
-{
- return pci_iomap(dev, bar, maxlen);
-}
-#endif
-
static struct cnss_msi_config msi_config = {
.total_vectors = 32,
.total_users = 4,
@@ -1003,7 +973,7 @@ static int cnss_pci_enable_bus(struct cnss_pci_data *pci_priv)
pci_set_master(pci_dev);
- pci_priv->bar = cnss_pci_iomap(pci_dev, PCI_BAR_NUM, 0);
+ pci_priv->bar = pci_iomap(pci_dev, PCI_BAR_NUM, 0);
if (!pci_priv->bar) {
cnss_pr_err("Failed to do PCI IO map!\n");
ret = -EIO;
@@ -1366,12 +1336,10 @@ int cnss_pci_start_mhi(struct cnss_pci_data *pci_priv)
ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_POWER_ON);
if (ret)
- goto deinit_mhi;
+ goto out;
return 0;
-deinit_mhi:
- cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_DEINIT);
out:
return ret;
}
@@ -1392,8 +1360,12 @@ void cnss_pci_stop_mhi(struct cnss_pci_data *pci_priv)
cnss_pci_set_mhi_state_bit(pci_priv, CNSS_MHI_RESUME);
cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_POWER_OFF);
- if (!plat_priv->ramdump_info_v2.dump_data_valid)
- cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_DEINIT);
+
+ if (plat_priv->ramdump_info_v2.dump_data_valid ||
+ test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state))
+ return;
+
+ cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_DEINIT);
}
static int cnss_pci_probe(struct pci_dev *pci_dev,
diff --git a/drivers/net/wireless/cnss2/qmi.c b/drivers/net/wireless/cnss2/qmi.c
index 99163d51a497..d1c0423b4517 100644
--- a/drivers/net/wireless/cnss2/qmi.c
+++ b/drivers/net/wireless/cnss2/qmi.c
@@ -50,6 +50,30 @@ enum cnss_bdf_type {
CNSS_BDF_ELF,
};
+static char *cnss_qmi_mode_to_str(enum wlfw_driver_mode_enum_v01 mode)
+{
+ switch (mode) {
+ case QMI_WLFW_MISSION_V01:
+ return "MISSION";
+ case QMI_WLFW_FTM_V01:
+ return "FTM";
+ case QMI_WLFW_EPPING_V01:
+ return "EPPING";
+ case QMI_WLFW_WALTEST_V01:
+ return "WALTEST";
+ case QMI_WLFW_OFF_V01:
+ return "OFF";
+ case QMI_WLFW_CCPM_V01:
+ return "CCPM";
+ case QMI_WLFW_QVIT_V01:
+ return "QVIT";
+ case QMI_WLFW_CALIBRATION_V01:
+ return "CALIBRATION";
+ default:
+ return "UNKNOWN";
+ }
+};
+
static void cnss_wlfw_clnt_notifier_work(struct work_struct *work)
{
struct cnss_plat_data *plat_priv =
@@ -585,8 +609,8 @@ int cnss_wlfw_wlan_mode_send_sync(struct cnss_plat_data *plat_priv,
if (!plat_priv)
return -ENODEV;
- cnss_pr_dbg("Sending mode message, state: 0x%lx, mode: %d\n",
- plat_priv->driver_state, mode);
+ cnss_pr_dbg("Sending mode message, mode: %s(%d), state: 0x%lx\n",
+ cnss_qmi_mode_to_str(mode), mode, plat_priv->driver_state);
if (mode == QMI_WLFW_OFF_V01 &&
test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
@@ -617,14 +641,15 @@ int cnss_wlfw_wlan_mode_send_sync(struct cnss_plat_data *plat_priv,
cnss_pr_dbg("WLFW service is disconnected while sending mode off request.\n");
return 0;
}
- cnss_pr_err("Failed to send mode request, mode: %d, err = %d\n",
- mode, ret);
+ cnss_pr_err("Failed to send mode request, mode: %s(%d), err: %d\n",
+ cnss_qmi_mode_to_str(mode), mode, ret);
goto out;
}
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
- cnss_pr_err("Mode request failed, mode: %d, result: %d err: %d\n",
- mode, resp.resp.result, resp.resp.error);
+ cnss_pr_err("Mode request failed, mode: %s(%d), result: %d, err: %d\n",
+ cnss_qmi_mode_to_str(mode), mode, resp.resp.result,
+ resp.resp.error);
ret = resp.resp.result;
goto out;
}
diff --git a/drivers/net/wireless/wcnss/wcnss_vreg.c b/drivers/net/wireless/wcnss/wcnss_vreg.c
index 82b90ad00f8b..d0a74744f70a 100644
--- a/drivers/net/wireless/wcnss/wcnss_vreg.c
+++ b/drivers/net/wireless/wcnss/wcnss_vreg.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2015, 2017 The Linux Foundation. All rights reserved.
*
* 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
@@ -417,13 +417,18 @@ static void wcnss_vregs_off(struct vregs_info regulators[], uint size,
if (regulators[i].state == VREG_NULL_CONFIG)
continue;
+ if (cfg->wcn_external_gpio_support) {
+ if (!memcmp(regulators[i].name, VDD_PA, sizeof(VDD_PA)))
+ continue;
+ }
+
/* Remove PWM mode */
if (regulators[i].state & VREG_OPTIMUM_MODE_MASK) {
- rc = regulator_set_optimum_mode(
- regulators[i].regulator, 0);
- if (rc < 0)
- pr_err("regulator_set_optimum_mode(%s) failed (%d)\n",
- regulators[i].name, rc);
+ rc = regulator_set_load(regulators[i].regulator, 0);
+ if (rc < 0) {
+ pr_err("regulator set load(%s) failed (%d)\n",
+ regulators[i].name, rc);
+ }
}
/* Set voltage to lowest level */
@@ -478,7 +483,12 @@ static int wcnss_vregs_on(struct device *dev,
}
for (i = 0; i < size; i++) {
- /* Get regulator source */
+ if (cfg->wcn_external_gpio_support) {
+ if (!memcmp(regulators[i].name, VDD_PA, sizeof(VDD_PA)))
+ continue;
+ }
+
+ /* Get regulator source */
regulators[i].regulator =
regulator_get(dev, regulators[i].name);
if (IS_ERR(regulators[i].regulator)) {
@@ -518,11 +528,11 @@ static int wcnss_vregs_on(struct device *dev,
/* Vote for PWM/PFM mode if needed */
if (voltage_level[i].uA_load && (reg_cnt > 0)) {
- rc = regulator_set_optimum_mode(regulators[i].regulator,
- voltage_level[i].uA_load);
+ rc = regulator_set_load(regulators[i].regulator,
+ voltage_level[i].uA_load);
if (rc < 0) {
- pr_err("regulator_set_optimum_mode(%s) failed (%d)\n",
- regulators[i].name, rc);
+ pr_err("regulator set load(%s) failed (%d)\n",
+ regulators[i].name, rc);
goto fail;
}
regulators[i].state |= VREG_OPTIMUM_MODE_MASK;
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 505a9e016777..e99d46ca51b0 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -36,6 +36,7 @@
#include <linux/qpnp/qpnp-adc.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_qos.h>
+#include <linux/bitops.h>
#include <soc/qcom/subsystem_restart.h>
#include <soc/qcom/subsystem_notif.h>
@@ -56,6 +57,7 @@
#define WCNSS_PM_QOS_TIMEOUT 15000
#define IS_CAL_DATA_PRESENT 0
#define WAIT_FOR_CBC_IND 2
+#define WCNSS_DUAL_BAND_CAPABILITY_OFFSET BIT(8)
/* module params */
#define WCNSS_CONFIG_UNSPECIFIED (-1)
@@ -119,6 +121,8 @@ static DEFINE_SPINLOCK(reg_spinlock);
#define PRONTO_PMU_COM_CSR_OFFSET 0x1040
#define PRONTO_PMU_SOFT_RESET_OFFSET 0x104C
+#define PRONTO_QFUSE_DUAL_BAND_OFFSET 0x0018
+
#define A2XB_CFG_OFFSET 0x00
#define A2XB_INT_SRC_OFFSET 0x0c
#define A2XB_TSTBUS_CTRL_OFFSET 0x14
@@ -381,6 +385,7 @@ static struct {
void __iomem *pronto_saw2_base;
void __iomem *pronto_pll_base;
void __iomem *pronto_mcu_base;
+ void __iomem *pronto_qfuse;
void __iomem *wlan_tx_status;
void __iomem *wlan_tx_phy_aborts;
void __iomem *wlan_brdg_err_source;
@@ -397,7 +402,7 @@ static struct {
int user_cal_read;
int user_cal_available;
u32 user_cal_rcvd;
- int user_cal_exp_size;
+ u32 user_cal_exp_size;
int iris_xo_mode_set;
int fw_vbatt_state;
char wlan_nv_macAddr[WLAN_MAC_ADDR_SIZE];
@@ -423,6 +428,9 @@ static struct {
int pc_disabled;
struct delayed_work wcnss_pm_qos_del_req;
struct mutex pm_qos_mutex;
+ struct clk *snoc_wcnss;
+ unsigned int snoc_wcnss_clock_freq;
+ bool is_dual_band_disabled;
} *penv = NULL;
static ssize_t wcnss_wlan_macaddr_store(struct device *dev,
@@ -595,7 +603,31 @@ void wcnss_pronto_is_a2xb_bus_stall(void *tst_addr, u32 fifo_mask, char *type)
}
}
-/* Log pronto debug registers before sending reset interrupt */
+int wcnss_get_dual_band_capability_info(struct platform_device *pdev)
+{
+ u32 reg = 0;
+ struct resource *res;
+
+ res = platform_get_resource_byname(
+ pdev, IORESOURCE_MEM, "pronto_qfuse");
+ if (!res)
+ return -EINVAL;
+
+ penv->pronto_qfuse = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(penv->pronto_qfuse))
+ return -ENOMEM;
+
+ reg = readl_relaxed(penv->pronto_qfuse +
+ PRONTO_QFUSE_DUAL_BAND_OFFSET);
+ if (reg & WCNSS_DUAL_BAND_CAPABILITY_OFFSET)
+ penv->is_dual_band_disabled = true;
+ else
+ penv->is_dual_band_disabled = false;
+
+ return 0;
+}
+
+/* Log pronto debug registers during SSR Timeout CB */
void wcnss_pronto_log_debug_regs(void)
{
void __iomem *reg_addr, *tst_addr, *tst_ctrl_addr;
@@ -1683,6 +1715,14 @@ int wcnss_wlan_iris_xo_mode(void)
}
EXPORT_SYMBOL(wcnss_wlan_iris_xo_mode);
+int wcnss_wlan_dual_band_disabled(void)
+{
+ if (penv && penv->pdev)
+ return penv->is_dual_band_disabled;
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL(wcnss_wlan_dual_band_disabled);
void wcnss_suspend_notify(void)
{
@@ -2717,23 +2757,23 @@ wcnss_trigger_config(struct platform_device *pdev)
int is_pronto_vadc;
int is_pronto_v3;
int pil_retry = 0;
- int has_pronto_hw = of_property_read_bool(pdev->dev.of_node,
- "qcom,has-pronto-hw");
-
- is_pronto_vadc = of_property_read_bool(pdev->dev.of_node,
- "qcom,is-pronto-vadc");
+ struct wcnss_wlan_config *wlan_cfg = &penv->wlan_config;
+ struct device_node *node = (&pdev->dev)->of_node;
+ int has_pronto_hw = of_property_read_bool(node, "qcom,has-pronto-hw");
- is_pronto_v3 = of_property_read_bool(pdev->dev.of_node,
- "qcom,is-pronto-v3");
+ is_pronto_vadc = of_property_read_bool(node, "qcom,is-pronto-vadc");
+ is_pronto_v3 = of_property_read_bool(node, "qcom,is-pronto-v3");
- penv->is_vsys_adc_channel = of_property_read_bool(pdev->dev.of_node,
- "qcom,has-vsys-adc-channel");
+ penv->is_vsys_adc_channel =
+ of_property_read_bool(node, "qcom,has-vsys-adc-channel");
+ penv->is_a2xb_split_reg =
+ of_property_read_bool(node, "qcom,has-a2xb-split-reg");
- penv->is_a2xb_split_reg = of_property_read_bool(pdev->dev.of_node,
- "qcom,has-a2xb-split-reg");
+ wlan_cfg->wcn_external_gpio_support =
+ of_property_read_bool(node, "qcom,wcn-external-gpio-support");
- if (of_property_read_u32(pdev->dev.of_node,
- "qcom,wlan-rx-buff-count", &penv->wlan_rx_buff_count)) {
+ if (of_property_read_u32(node, "qcom,wlan-rx-buff-count",
+ &penv->wlan_rx_buff_count)) {
penv->wlan_rx_buff_count = WCNSS_DEF_WLAN_RX_BUFF_COUNT;
}
@@ -2794,15 +2834,18 @@ wcnss_trigger_config(struct platform_device *pdev)
goto fail;
}
- index++;
- ret = wcnss_dt_parse_vreg_level(&pdev->dev, index,
- "qcom,iris-vddpa-current",
- "qcom,iris-vddpa-voltage-level",
- penv->wlan_config.iris_vlevel);
-
- if (ret) {
- dev_err(&pdev->dev, "error reading voltage-level property\n");
- goto fail;
+ if (!wlan_cfg->wcn_external_gpio_support) {
+ index++;
+ ret = wcnss_dt_parse_vreg_level(
+ &pdev->dev, index,
+ "qcom,iris-vddpa-current",
+ "qcom,iris-vddpa-voltage-level",
+ penv->wlan_config.iris_vlevel);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "error reading voltage-level property\n");
+ goto fail;
+ }
}
index++;
@@ -2825,8 +2868,8 @@ wcnss_trigger_config(struct platform_device *pdev)
pdata = pdev->dev.platform_data;
if (WCNSS_CONFIG_UNSPECIFIED == has_48mhz_xo) {
if (has_pronto_hw) {
- has_48mhz_xo = of_property_read_bool(pdev->dev.of_node,
- "qcom,has-48mhz-xo");
+ has_48mhz_xo =
+ of_property_read_bool(node, "qcom,has-48mhz-xo");
} else {
has_48mhz_xo = pdata->has_48mhz_xo;
}
@@ -2837,8 +2880,8 @@ wcnss_trigger_config(struct platform_device *pdev)
penv->wlan_config.is_pronto_v3 = is_pronto_v3;
if (WCNSS_CONFIG_UNSPECIFIED == has_autodetect_xo && has_pronto_hw) {
- has_autodetect_xo = of_property_read_bool(pdev->dev.of_node,
- "qcom,has-autodetect-xo");
+ has_autodetect_xo =
+ of_property_read_bool(node, "qcom,has-autodetect-xo");
}
penv->thermal_mitigation = 0;
@@ -3118,6 +3161,16 @@ wcnss_trigger_config(struct platform_device *pdev)
__func__);
goto fail_ioremap2;
}
+
+ if (of_property_read_bool(node,
+ "qcom,is-dual-band-disabled")) {
+ ret = wcnss_get_dual_band_capability_info(pdev);
+ if (ret) {
+ pr_err(
+ "%s: failed to get dual band info\n", __func__);
+ goto fail_ioremap2;
+ }
+ }
}
penv->adc_tm_dev = qpnp_get_adc_tm(&penv->pdev->dev, "wcnss");
@@ -3129,6 +3182,21 @@ wcnss_trigger_config(struct platform_device *pdev)
penv->fw_vbatt_state = WCNSS_CONFIG_UNSPECIFIED;
}
+ penv->snoc_wcnss = devm_clk_get(&penv->pdev->dev, "snoc_wcnss");
+ if (IS_ERR(penv->snoc_wcnss)) {
+ pr_err("%s: couldn't get snoc_wcnss\n", __func__);
+ penv->snoc_wcnss = NULL;
+ } else {
+ if (of_property_read_u32(pdev->dev.of_node,
+ "qcom,snoc-wcnss-clock-freq",
+ &penv->snoc_wcnss_clock_freq)) {
+ pr_debug("%s: wcnss snoc clock frequency is not defined\n",
+ __func__);
+ devm_clk_put(&penv->pdev->dev, penv->snoc_wcnss);
+ penv->snoc_wcnss = NULL;
+ }
+ }
+
if (penv->wlan_config.is_pronto_vadc) {
penv->vadc_dev = qpnp_get_vadc(&penv->pdev->dev, "wcnss");
@@ -3191,6 +3259,38 @@ fail:
return ret;
}
+/* Driver requires to directly vote the snoc clocks
+ * To enable and disable snoc clock, it call
+ * wcnss_snoc_vote function
+ */
+void wcnss_snoc_vote(bool clk_chk_en)
+{
+ int rc;
+
+ if (!penv->snoc_wcnss) {
+ pr_err("%s: couldn't get clk snoc_wcnss\n", __func__);
+ return;
+ }
+
+ if (clk_chk_en) {
+ rc = clk_set_rate(penv->snoc_wcnss,
+ penv->snoc_wcnss_clock_freq);
+ if (rc) {
+ pr_err("%s: snoc_wcnss_clk-clk_set_rate failed =%d\n",
+ __func__, rc);
+ return;
+ }
+
+ if (clk_prepare_enable(penv->snoc_wcnss)) {
+ pr_err("%s: snoc_wcnss clk enable failed\n", __func__);
+ return;
+ }
+ } else {
+ clk_disable_unprepare(penv->snoc_wcnss);
+ }
+}
+EXPORT_SYMBOL(wcnss_snoc_vote);
+
/* wlan prop driver cannot invoke cancel_work_sync
* function directly, so to invoke this function it
* call wcnss_flush_work function