qcacld-3.0: Add IPA WDI Unified API support
Support for WDI2 in the Unified IPA WDI APIs.
Change-Id: Ife42a6a96ce80070de51f994e29ded252b3dd980
CRs-Fixed: 2183498
diff --git a/Kbuild b/Kbuild
index 432177e..1de5ab7 100644
--- a/Kbuild
+++ b/Kbuild
@@ -2219,7 +2219,7 @@
endif
#Stats & Quota Metering feature
-ifeq ($(CONFIG_IPA),y)
+ifeq ($(CONFIG_IPA_OFFLOAD),1)
ifeq ($(CONFIG_QCACLD_FEATURE_METERING),y)
CDEFINES += -DFEATURE_METERING
endif
diff --git a/core/dp/txrx/ol_txrx_ipa.c b/core/dp/txrx/ol_txrx_ipa.c
index 2565fca..e13a92b 100644
--- a/core/dp/txrx/ol_txrx_ipa.c
+++ b/core/dp/txrx/ol_txrx_ipa.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -280,6 +280,354 @@
return QDF_STATUS_SUCCESS;
}
+#ifdef CONFIG_IPA_WDI_UNIFIED_API
+
+#ifndef QCA_LL_TX_FLOW_CONTROL_V2
+static inline void ol_txrx_setup_mcc_sys_pipes(
+ qdf_ipa_sys_connect_params_t *sys_in,
+ qdf_ipa_wdi_conn_in_params_t *pipe_in)
+{
+ /* Setup MCC sys pipe */
+ QDF_IPA_WDI_CONN_IN_PARAMS_NUM_SYS_PIPE_NEEDED(pipe_in) =
+ OL_TXRX_IPA_MAX_IFACE;
+ for (int i = 0; i < OL_TXRX_IPA_MAX_IFACE; i++)
+ memcpy(&QDF_IPA_WDI_CONN_IN_PARAMS_SYS_IN(pipe_in)[i],
+ &sys_in[i], sizeof(qdf_ipa_sys_connect_params_t));
+}
+#else
+static inline void ol_txrx_setup_mcc_sys_pipes(
+ qdf_ipa_sys_connect_params_t *sys_in,
+ qdf_ipa_wdi_conn_in_params_t *pipe_in)
+{
+ QDF_IPA_WDI_CONN_IN_PARAMS_NUM_SYS_PIPE_NEEDED(pipe_in) = 0;
+}
+#endif
+
+/**
+ * ol_txrx_ipa_setup() - Setup and connect IPA pipes
+ * @pdev: handle to the device instance
+ * @ipa_i2w_cb: IPA to WLAN callback
+ * @ipa_w2i_cb: WLAN to IPA callback
+ * @ipa_wdi_meter_notifier_cb: IPA WDI metering callback
+ * @ipa_desc_size: IPA descriptor size
+ * @ipa_priv: handle to the HTT instance
+ * @is_rm_enabled: Is IPA RM enabled or not
+ * @p_tx_pipe_handle: pointer to Tx pipe handle
+ * @p_rx_pipe_handle: pointer to Rx pipe handle
+ * @is_smmu_enabled: Is SMMU enabled or not
+ * @sys_in: parameters to setup sys pipe in mcc mode
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ol_txrx_ipa_setup(struct cdp_pdev *ppdev, void *ipa_i2w_cb,
+ void *ipa_w2i_cb, void *ipa_wdi_meter_notifier_cb,
+ uint32_t ipa_desc_size, void *ipa_priv,
+ bool is_rm_enabled, uint32_t *p_tx_pipe_handle,
+ uint32_t *p_rx_pipe_handle, bool is_smmu_enabled,
+ qdf_ipa_sys_connect_params_t *sys_in)
+{
+ ol_txrx_pdev_handle pdev = (ol_txrx_pdev_handle)ppdev;
+ struct ol_txrx_ipa_resources *ipa_res = &pdev->ipa_resource;
+ qdf_ipa_ep_cfg_t *tx_cfg;
+ qdf_ipa_ep_cfg_t *rx_cfg;
+ qdf_ipa_wdi_pipe_setup_info_t *tx;
+ qdf_ipa_wdi_pipe_setup_info_t *rx;
+ qdf_ipa_wdi_pipe_setup_info_smmu_t *tx_smmu;
+ qdf_ipa_wdi_pipe_setup_info_smmu_t *rx_smmu;
+ qdf_ipa_wdi_conn_in_params_t pipe_in;
+ qdf_ipa_wdi_conn_out_params_t pipe_out;
+ int ret;
+
+ qdf_mem_zero(&tx, sizeof(qdf_ipa_wdi_pipe_setup_info_t));
+ qdf_mem_zero(&rx, sizeof(qdf_ipa_wdi_pipe_setup_info_t));
+ qdf_mem_zero(&pipe_in, sizeof(pipe_in));
+ qdf_mem_zero(&pipe_out, sizeof(pipe_out));
+
+ if (is_smmu_enabled)
+ QDF_IPA_WDI_CONN_IN_PARAMS_SMMU_ENABLED(&pipe_in) = true;
+ else
+ QDF_IPA_WDI_CONN_IN_PARAMS_SMMU_ENABLED(&pipe_in) = false;
+
+ ol_txrx_setup_mcc_sys_pipes(sys_in, &pipe_in);
+
+ /* TX PIPE */
+ if (QDF_IPA_WDI_CONN_IN_PARAMS_SMMU_ENABLED(&pipe_in)) {
+ tx_smmu = &QDF_IPA_WDI_CONN_IN_PARAMS_TX_SMMU(&pipe_in);
+ tx_cfg = &QDF_IPA_WDI_SETUP_INFO_SMMU_EP_CFG(tx_smmu);
+ } else {
+ tx = &QDF_IPA_WDI_CONN_IN_PARAMS_TX(&pipe_in);
+ tx_cfg = &QDF_IPA_WDI_SETUP_INFO_EP_CFG(tx);
+ }
+
+ QDF_IPA_EP_CFG_NAT_EN(tx_cfg) = IPA_BYPASS_NAT;
+ QDF_IPA_EP_CFG_HDR_LEN(tx_cfg) = OL_TXRX_IPA_UC_WLAN_TX_HDR_LEN;
+ QDF_IPA_EP_CFG_HDR_OFST_PKT_SIZE_VALID(tx_cfg) = 1;
+ QDF_IPA_EP_CFG_HDR_OFST_PKT_SIZE(tx_cfg) = 0;
+ QDF_IPA_EP_CFG_HDR_ADDITIONAL_CONST_LEN(tx_cfg) =
+ OL_TXRX_IPA_UC_WLAN_8023_HDR_SIZE;
+ QDF_IPA_EP_CFG_MODE(tx_cfg) = IPA_BASIC;
+ QDF_IPA_EP_CFG_HDR_LITTLE_ENDIAN(tx_cfg) = true;
+
+ if (QDF_IPA_WDI_CONN_IN_PARAMS_SMMU_ENABLED(&pipe_in)) {
+ /* TODO: SMMU implementation on CLD_3.2 */
+ QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
+ "%s: SMMU is not implementation on host", __func__);
+ return QDF_STATUS_E_FAILURE;
+ } else {
+ QDF_IPA_WDI_SETUP_INFO_CLIENT(tx) = IPA_CLIENT_WLAN1_CONS;
+ QDF_IPA_WDI_SETUP_INFO_TRANSFER_RING_BASE_PA(tx) =
+ ipa_res->tx_comp_ring_base_paddr;
+ QDF_IPA_WDI_SETUP_INFO_TRANSFER_RING_SIZE(tx) =
+ ipa_res->tx_comp_ring_size * sizeof(qdf_dma_addr_t);
+
+ QDF_IPA_WDI_SETUP_INFO_EVENT_RING_BASE_PA(tx) =
+ ipa_res->ce_sr_base_paddr;
+ QDF_IPA_WDI_SETUP_INFO_EVENT_RING_SIZE(tx) =
+ ipa_res->ce_sr_ring_size;
+ QDF_IPA_WDI_SETUP_INFO_EVENT_RING_DOORBELL_PA(tx) =
+ ipa_res->ce_reg_paddr;
+ QDF_IPA_WDI_SETUP_INFO_NUM_PKT_BUFFERS(tx) =
+ ipa_res->tx_num_alloc_buffer;
+ QDF_IPA_WDI_SETUP_INFO_PKT_OFFSET(tx) = 0;
+ }
+
+ /* RX PIPE */
+ if (QDF_IPA_WDI_CONN_IN_PARAMS_SMMU_ENABLED(&pipe_in)) {
+ rx_smmu = &QDF_IPA_WDI_CONN_IN_PARAMS_RX_SMMU(&pipe_in);
+ rx_cfg = &QDF_IPA_WDI_SETUP_INFO_SMMU_EP_CFG(rx_smmu);
+ } else {
+ rx = &QDF_IPA_WDI_CONN_IN_PARAMS_RX(&pipe_in);
+ rx_cfg = &QDF_IPA_WDI_SETUP_INFO_EP_CFG(rx);
+ }
+
+ QDF_IPA_EP_CFG_NAT_EN(rx_cfg) = IPA_BYPASS_NAT;
+ QDF_IPA_EP_CFG_HDR_LEN(rx_cfg) = OL_TXRX_IPA_UC_WLAN_RX_HDR_LEN;
+ QDF_IPA_EP_CFG_HDR_OFST_PKT_SIZE_VALID(rx_cfg) = 1;
+ QDF_IPA_EP_CFG_HDR_OFST_PKT_SIZE(rx_cfg) = 0;
+ QDF_IPA_EP_CFG_HDR_ADDITIONAL_CONST_LEN(rx_cfg) =
+ OL_TXRX_IPA_UC_WLAN_8023_HDR_SIZE;
+ QDF_IPA_EP_CFG_HDR_OFST_METADATA_VALID(rx_cfg) = 0;
+ QDF_IPA_EP_CFG_HDR_METADATA_REG_VALID(rx_cfg) = 1;
+ QDF_IPA_EP_CFG_MODE(rx_cfg) = IPA_BASIC;
+ QDF_IPA_EP_CFG_HDR_LITTLE_ENDIAN(rx_cfg) = true;
+
+ if (QDF_IPA_WDI_CONN_IN_PARAMS_SMMU_ENABLED(&pipe_in)) {
+ /* TODO: SMMU implementation on CLD_3.2 */
+ QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
+ "%s: SMMU is not implementation on host", __func__);
+ return QDF_STATUS_E_FAILURE;
+ } else {
+ QDF_IPA_WDI_SETUP_INFO_CLIENT(rx) = IPA_CLIENT_WLAN1_PROD;
+ QDF_IPA_WDI_SETUP_INFO_TRANSFER_RING_BASE_PA(rx) =
+ ipa_res->rx_rdy_ring_base_paddr;
+ QDF_IPA_WDI_SETUP_INFO_TRANSFER_RING_SIZE(rx) =
+ ipa_res->rx_rdy_ring_size;
+ QDF_IPA_WDI_SETUP_INFO_TRANSFER_RING_DOORBELL_PA(rx) =
+ ipa_res->rx_proc_done_idx_paddr;
+ QDF_IPA_WDI_SETUP_INFO_EVENT_RING_BASE_PA(rx) =
+ ipa_res->rx2_rdy_ring_base_paddr;
+ QDF_IPA_WDI_SETUP_INFO_EVENT_RING_SIZE(rx) =
+ ipa_res->rx2_rdy_ring_size;
+ QDF_IPA_WDI_SETUP_INFO_EVENT_RING_DOORBELL_PA(rx) =
+ ipa_res->rx2_proc_done_idx_paddr;
+ QDF_IPA_WDI_SETUP_INFO_PKT_OFFSET(rx) = 0;
+ }
+
+ QDF_IPA_WDI_CONN_IN_PARAMS_NOTIFY(&pipe_in) = ipa_w2i_cb;
+ QDF_IPA_WDI_CONN_IN_PARAMS_PRIV(&pipe_in) = ipa_priv;
+
+ /* Connect WDI IPA PIPE */
+ ret = qdf_ipa_wdi_conn_pipes(&pipe_in, &pipe_out);
+ if (ret) {
+ QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
+ "%s: ipa_wdi_conn_pipes: IPA pipe setup failed: ret=%d",
+ __func__, ret);
+ return QDF_STATUS_E_FAILURE;
+ }
+
+ /* IPA uC Doorbell registers */
+ QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG,
+ "%s: Tx DB PA=0x%x, Rx DB PA=0x%x",
+ __func__,
+ (unsigned int)QDF_IPA_WDI_CONN_OUT_PARAMS_TX_UC_DB_PA(&pipe_out),
+ (unsigned int)QDF_IPA_WDI_CONN_OUT_PARAMS_RX_UC_DB_PA(&pipe_out));
+
+ ipa_res->tx_comp_doorbell_paddr =
+ QDF_IPA_WDI_CONN_OUT_PARAMS_TX_UC_DB_PA(&pipe_out);
+ ipa_res->rx_ready_doorbell_paddr =
+ QDF_IPA_WDI_CONN_OUT_PARAMS_RX_UC_DB_PA(&pipe_out);
+
+ return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * ol_txrx_ipa_cleanup() - Disconnect IPA pipes
+ * @tx_pipe_handle: Tx pipe handle
+ * @rx_pipe_handle: Rx pipe handle
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ol_txrx_ipa_cleanup(uint32_t tx_pipe_handle, uint32_t rx_pipe_handle)
+{
+ int ret;
+
+ QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG,
+ "%s: Disconnect IPA pipe", __func__);
+ ret = qdf_ipa_wdi_disconn_pipes();
+ if (ret) {
+ QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
+ "ipa_wdi_disconn_pipes failed: ret=%d", ret);
+ return QDF_STATUS_E_FAILURE;
+ }
+
+ return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * ol_txrx_ipa_setup_iface() - Setup IPA header and register interface
+ * @ifname: Interface name
+ * @mac_addr: Interface MAC address
+ * @prod_client: IPA prod client type
+ * @cons_client: IPA cons client type
+ * @session_id: Session ID
+ * @is_ipv6_enabled: Is IPV6 enabled or not
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ol_txrx_ipa_setup_iface(char *ifname, uint8_t *mac_addr,
+ qdf_ipa_client_type_t prod_client,
+ qdf_ipa_client_type_t cons_client,
+ uint8_t session_id, bool is_ipv6_enabled)
+{
+ qdf_ipa_wdi_reg_intf_in_params_t in;
+ qdf_ipa_wdi_hdr_info_t hdr_info;
+ struct ol_txrx_ipa_uc_tx_hdr uc_tx_hdr;
+ struct ol_txrx_ipa_uc_tx_hdr uc_tx_hdr_v6;
+ int ret = -EINVAL;
+
+ QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG,
+ "%s: Add Partial hdr: %s, %pM",
+ __func__, ifname, mac_addr);
+
+ qdf_mem_zero(&hdr_info, sizeof(qdf_ipa_wdi_hdr_info_t));
+ memcpy(&uc_tx_hdr, &ipa_uc_tx_hdr, OL_TXRX_IPA_UC_WLAN_TX_HDR_LEN);
+ qdf_ether_addr_copy(uc_tx_hdr.eth.h_source, mac_addr);
+ uc_tx_hdr.ipa_hd.vdev_id = session_id;
+
+ /* IPV4 header */
+ uc_tx_hdr.eth.h_proto = qdf_htons(ETH_P_IP);
+
+ QDF_IPA_WDI_HDR_INFO_HDR(&hdr_info) = (uint8_t *)&uc_tx_hdr;
+ QDF_IPA_WDI_HDR_INFO_HDR_LEN(&hdr_info) =
+ OL_TXRX_IPA_UC_WLAN_TX_HDR_LEN;
+ QDF_IPA_WDI_HDR_INFO_HDR_TYPE(&hdr_info) = IPA_HDR_L2_ETHERNET_II;
+ QDF_IPA_WDI_HDR_INFO_DST_MAC_ADDR_OFFSET(&hdr_info) =
+ OL_TXRX_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
+
+ QDF_IPA_WDI_REG_INTF_IN_PARAMS_NETDEV_NAME(&in) = ifname;
+ memcpy(&(QDF_IPA_WDI_REG_INTF_IN_PARAMS_HDR_INFO(&in)[IPA_IP_v4]),
+ &hdr_info, sizeof(qdf_ipa_wdi_hdr_info_t));
+ QDF_IPA_WDI_REG_INTF_IN_PARAMS_ALT_DST_PIPE(&in) = cons_client;
+ QDF_IPA_WDI_REG_INTF_IN_PARAMS_IS_META_DATA_VALID(&in) = 1;
+ QDF_IPA_WDI_REG_INTF_IN_PARAMS_META_DATA(&in) =
+ htonl(session_id << 16);
+ QDF_IPA_WDI_REG_INTF_IN_PARAMS_META_DATA_MASK(&in) = htonl(0x00FF0000);
+
+ /* IPV6 header */
+ if (is_ipv6_enabled) {
+ memcpy(&uc_tx_hdr_v6, &uc_tx_hdr,
+ OL_TXRX_IPA_UC_WLAN_TX_HDR_LEN);
+ uc_tx_hdr_v6.eth.h_proto = qdf_htons(ETH_P_IPV6);
+ QDF_IPA_WDI_HDR_INFO_HDR(&hdr_info) = (uint8_t *)&uc_tx_hdr_v6;
+ memcpy(&(QDF_IPA_WDI_REG_INTF_IN_PARAMS_HDR_INFO(&in)[IPA_IP_v6]),
+ &hdr_info, sizeof(qdf_ipa_wdi_hdr_info_t));
+ }
+
+ ret = qdf_ipa_wdi_reg_intf(&in);
+ if (ret) {
+ QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
+ "%s: ipa_wdi_reg_intf falied: ret=%d", __func__, ret);
+ }
+
+ return ret;
+}
+
+/**
+ * ol_txrx_ipa_cleanup_iface() - Cleanup IPA header and deregister interface
+ * @ifname: Interface name
+ * @is_ipv6_enabled: Is IPV6 enabled or not
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ol_txrx_ipa_cleanup_iface(char *ifname, bool is_ipv6_enabled)
+{
+ int ret;
+
+ /* unregister the interface with IPA */
+ ret = qdf_ipa_wdi_dereg_intf(ifname);
+ if (ret) {
+ QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG,
+ "%s: ipa_wdi_dereg_intf failed: devname=%s, ret=%d",
+ __func__, ifname, ret);
+ return QDF_STATUS_E_FAILURE;
+ }
+
+ return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * ol_txrx_ipa_uc_enable_pipes() - Enable and resume traffic on Tx/Rx pipes
+ * @pdev: handle to the device instance
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ol_txrx_ipa_enable_pipes(struct cdp_pdev *ppdev)
+{
+ ol_txrx_pdev_handle pdev = (ol_txrx_pdev_handle)ppdev;
+ int ret;
+
+ /* ACTIVATE TX PIPE */
+ QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG,
+ "%s: Enable IPA pipes", __func__);
+ ret = qdf_ipa_wdi_enable_pipes();
+ if (ret) {
+ QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
+ "%s: ipa_wdi_enable_pipes failed: ret=%d",
+ __func__, ret);
+ return QDF_STATUS_E_FAILURE;
+ }
+
+ ol_txrx_ipa_uc_set_active((struct cdp_pdev *)pdev, true, true);
+ ol_txrx_ipa_uc_set_active((struct cdp_pdev *)pdev, true, false);
+
+ return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * ol_txrx_ipa_uc_disable_pipes() – Suspend traffic and disable Tx/Rx pipes
+ * @pdev: handle to the device instance
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ol_txrx_ipa_disable_pipes(struct cdp_pdev *ppdev)
+{
+ int ret;
+
+ QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG,
+ "%s: Disable IPA pipes", __func__);
+ ret = qdf_ipa_wdi_disable_pipes();
+ if (ret) {
+ QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
+ "%s: ipa_wdi_disable_pipes failed: ret=%d",
+ __func__, ret);
+ return QDF_STATUS_E_FAILURE;
+ }
+
+ return QDF_STATUS_SUCCESS;
+}
+
+#else /* CONFIG_IPA_WDI_UNIFIED_API */
+
/**
* ol_txrx_ipa_setup() - Setup and connect IPA pipes
* @pdev: handle to the device instance
@@ -299,7 +647,6 @@
uint32_t ipa_desc_size, void *ipa_priv,
bool is_rm_enabled, uint32_t *p_tx_pipe_handle,
uint32_t *p_rx_pipe_handle)
-
{
ol_txrx_pdev_handle pdev = (ol_txrx_pdev_handle)ppdev;
struct ol_txrx_ipa_resources *ipa_res = &pdev->ipa_resource;
@@ -344,7 +691,7 @@
ipa_res->tx_num_alloc_buffer;
/* Connect WDI IPA PIPE */
- ret = ipa_connect_wdi_pipe(&pipe_in, &pipe_out);
+ ret = qdf_ipa_connect_wdi_pipe(&pipe_in, &pipe_out);
if (ret) {
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
"ipa_connect_wdi_pipe: Tx pipe setup failed: ret=%d", ret);
@@ -405,7 +752,7 @@
QDF_IPA_PIPE_IN_WDI_NOTIFY(&pipe_in) = ipa_wdi_meter_notifier_cb;
#endif
- ret = ipa_connect_wdi_pipe(&pipe_in, &pipe_out);
+ ret = qdf_ipa_connect_wdi_pipe(&pipe_in, &pipe_out);
if (ret) {
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
"ipa_connect_wdi_pipe: Rx pipe setup failed: ret=%d", ret);
@@ -443,7 +790,7 @@
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG,
"%s: Disconnect TX PIPE tx_pipe_handle=0x%x",
__func__, tx_pipe_handle);
- ret = ipa_disconnect_wdi_pipe(tx_pipe_handle);
+ ret = qdf_ipa_disconnect_wdi_pipe(tx_pipe_handle);
if (ret) {
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
"ipa_disconnect_wdi_pipe: Tx pipe cleanup failed: ret=%d",
@@ -454,7 +801,7 @@
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG,
"%s: Disconnect RX PIPE rx_pipe_handle=0x%x",
__func__, rx_pipe_handle);
- ret = ipa_disconnect_wdi_pipe(rx_pipe_handle);
+ ret = qdf_ipa_disconnect_wdi_pipe(rx_pipe_handle);
if (ret) {
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
"ipa_disconnect_wdi_pipe: Rx pipe cleanup failed: ret=%d",
@@ -726,7 +1073,7 @@
QDF_IPA_RX_INTF_PROP(&rx_intf) = rx_prop;
/* Call the ipa api to register interface */
- ret = ipa_register_intf(ifname, &tx_intf, &rx_intf);
+ ret = qdf_ipa_register_intf(ifname, &tx_intf, &rx_intf);
register_interface_fail:
qdf_mem_free(tx_prop);
@@ -802,7 +1149,7 @@
return QDF_STATUS_SUCCESS;
}
- /**
+/**
* ol_txrx_ipa_uc_enable_pipes() - Enable and resume traffic on Tx/Rx pipes
* @pdev: handle to the device instance
*
@@ -818,14 +1165,14 @@
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG,
"%s: Enable TX PIPE(tx_pipe_handle=%d)",
__func__, ipa_res->tx_pipe_handle);
- result = ipa_enable_wdi_pipe(ipa_res->tx_pipe_handle);
+ result = qdf_ipa_enable_wdi_pipe(ipa_res->tx_pipe_handle);
if (result) {
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
"%s: Enable TX PIPE fail, code %d",
__func__, result);
return QDF_STATUS_E_FAILURE;
}
- result = ipa_resume_wdi_pipe(ipa_res->tx_pipe_handle);
+ result = qdf_ipa_resume_wdi_pipe(ipa_res->tx_pipe_handle);
if (result) {
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
"%s: Resume TX PIPE fail, code %d",
@@ -838,14 +1185,14 @@
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG,
"%s: Enable RX PIPE(rx_pipe_handle=%d)",
__func__, ipa_res->rx_pipe_handle);
- result = ipa_enable_wdi_pipe(ipa_res->rx_pipe_handle);
+ result = qdf_ipa_enable_wdi_pipe(ipa_res->rx_pipe_handle);
if (result) {
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
"%s: Enable RX PIPE fail, code %d",
__func__, result);
return QDF_STATUS_E_FAILURE;
}
- result = ipa_resume_wdi_pipe(ipa_res->rx_pipe_handle);
+ result = qdf_ipa_resume_wdi_pipe(ipa_res->rx_pipe_handle);
if (result) {
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
"%s: Resume RX PIPE fail, code %d",
@@ -871,7 +1218,7 @@
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG,
"%s: Disable RX PIPE", __func__);
- result = ipa_suspend_wdi_pipe(ipa_res->rx_pipe_handle);
+ result = qdf_ipa_suspend_wdi_pipe(ipa_res->rx_pipe_handle);
if (result) {
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
"%s: Suspend RX PIPE fail, code %d",
@@ -879,7 +1226,7 @@
return QDF_STATUS_E_FAILURE;
}
- result = ipa_disable_wdi_pipe(ipa_res->rx_pipe_handle);
+ result = qdf_ipa_disable_wdi_pipe(ipa_res->rx_pipe_handle);
if (result) {
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
"%s: Disable RX PIPE fail, code %d",
@@ -889,14 +1236,14 @@
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG,
"%s: Disable TX PIPE", __func__);
- result = ipa_suspend_wdi_pipe(ipa_res->tx_pipe_handle);
+ result = qdf_ipa_suspend_wdi_pipe(ipa_res->tx_pipe_handle);
if (result) {
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
"%s: Suspend TX PIPE fail, code %d",
__func__, result);
return QDF_STATUS_E_FAILURE;
}
- result = ipa_disable_wdi_pipe(ipa_res->tx_pipe_handle);
+ result = qdf_ipa_disable_wdi_pipe(ipa_res->tx_pipe_handle);
if (result) {
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
"%s: Disable TX PIPE fail, code %d",
@@ -907,6 +1254,8 @@
return QDF_STATUS_SUCCESS;
}
+#endif /* CONFIG_IPA_WDI_UNIFIED_API */
+
/**
* ol_txrx_ipa_set_perf_level() - Set IPA clock bandwidth based on data rates
* @client: Client type
diff --git a/core/dp/txrx/ol_txrx_ipa.h b/core/dp/txrx/ol_txrx_ipa.h
index c846a26..206ab0b 100644
--- a/core/dp/txrx/ol_txrx_ipa.h
+++ b/core/dp/txrx/ol_txrx_ipa.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -74,6 +74,8 @@
#define OL_TXRX_IPA_IPV4_NAME_EXT "_ipv4"
#define OL_TXRX_IPA_IPV6_NAME_EXT "_ipv6"
+#define OL_TXRX_IPA_MAX_IFACE 3
+
#define OL_TXRX_IPA_WLAN_FRAG_HEADER sizeof(struct frag_header)
#define OL_TXRX_IPA_WLAN_IPA_HEADER sizeof(struct ipa_header)
#define OL_TXRX_IPA_UC_WLAN_TX_HDR_LEN sizeof(struct ol_txrx_ipa_uc_tx_hdr)
@@ -110,10 +112,18 @@
QDF_STATUS ol_txrx_ipa_uc_get_stat(struct cdp_pdev *pdev);
QDF_STATUS ol_txrx_ipa_enable_autonomy(struct cdp_pdev *pdev);
QDF_STATUS ol_txrx_ipa_disable_autonomy(struct cdp_pdev *pdev);
+#ifdef CONFIG_IPA_WDI_UNIFIED_API
+QDF_STATUS ol_txrx_ipa_setup(struct cdp_pdev *pdev, void *ipa_i2w_cb,
+ void *ipa_w2i_cb, void *ipa_wdi_meter_notifier_cb,
+ uint32_t ipa_desc_size, void *ipa_priv, bool is_rm_enabled,
+ uint32_t *tx_pipe_handle, uint32_t *rx_pipe_handle,
+ bool is_smmu_enabled, qdf_ipa_sys_connect_params_t *sys_in);
+#else /* CONFIG_IPA_WDI_UNIFIED_API */
QDF_STATUS ol_txrx_ipa_setup(struct cdp_pdev *pdev, void *ipa_i2w_cb,
void *ipa_w2i_cb, void *ipa_wdi_meter_notifier_cb,
uint32_t ipa_desc_size, void *ipa_priv, bool is_rm_enabled,
uint32_t *tx_pipe_handle, uint32_t *rx_pipe_handle);
+#endif /* CONFIG_IPA_WDI_UNIFIED_API */
QDF_STATUS ol_txrx_ipa_cleanup(uint32_t tx_pipe_handle,
uint32_t rx_pipe_handle);
QDF_STATUS ol_txrx_ipa_setup_iface(char *ifname, uint8_t *mac_addr,
diff --git a/core/hdd/src/wlan_hdd_ipa.c b/core/hdd/src/wlan_hdd_ipa.c
index 48c67d6..2481ef5 100644
--- a/core/hdd/src/wlan_hdd_ipa.c
+++ b/core/hdd/src/wlan_hdd_ipa.c
@@ -35,7 +35,11 @@
#ifdef IPA_OFFLOAD
/* Include Files */
+#ifdef CONFIG_IPA_WDI_UNIFIED_API
+#include <qdf_ipa_wdi3.h>
+#else
#include <qdf_ipa.h>
+#endif
#include <wlan_hdd_includes.h>
#include <wlan_hdd_ipa.h>
@@ -78,6 +82,8 @@
#define HDD_IPA_UC_STA_ENABLE_MASK BIT(6)
#define HDD_IPA_REAL_TIME_DEBUGGING BIT(8)
+#define HDD_IPA_MAX_BANDWIDTH 800
+
#define HDD_IPA_MAX_PENDING_EVENT_COUNT 20
#define IPA_WLAN_RX_SOFTIRQ_THRESH 16
@@ -471,6 +477,9 @@
struct completion ipa_uc_set_quota_comp;
#endif
struct completion ipa_resource_comp;
+
+ uint32_t wdi_version;
+ bool is_smmu_enabled; /* IPA caps returned from ipa_wdi_init */
};
#define HDD_IPA_WLAN_FRAG_HEADER sizeof(struct frag_header)
@@ -547,8 +556,9 @@
static void hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa,
bool is_loading);
-#if ((defined(QCA_WIFI_3_0) && defined(CONFIG_IPA3)) || \
- defined(IPA_CLIENT_IS_MHI_CONS))
+static int hdd_ipa_uc_enable_pipes(struct hdd_ipa_priv *hdd_ipa);
+static int hdd_ipa_wdi_init(struct hdd_ipa_priv *hdd_ipa);
+
/**
* hdd_ipa_uc_loaded_uc_cb() - IPA UC loaded event callback
* @priv_ctxt: hdd ipa local context
@@ -641,53 +651,6 @@
}
/**
- * hdd_ipa_uc_register_uc_ready() - Register UC ready callback function to IPA
- * @hdd_ipa: HDD IPA local context
- *
- * Register IPA UC ready callback function to IPA kernel driver
- * Even IPA UC loaded later than WLAN kernel driver, WLAN kernel driver will
- * open WDI pipe after WLAN driver loading finished
- *
- * Return: 0 Success
- * -EPERM Registration fail
- */
-static int hdd_ipa_uc_register_uc_ready(struct hdd_ipa_priv *hdd_ipa)
-{
- qdf_ipa_wdi_uc_ready_params_t uc_ready_param;
- int ret = 0;
-
- hdd_ipa->uc_loaded = false;
- QDF_IPA_UC_READY_PARAMS_PRIV(&uc_ready_param) = (void *)hdd_ipa;
- QDF_IPA_UC_READY_PARAMS_NOTIFY(&uc_ready_param) =
- hdd_ipa_uc_loaded_uc_cb;
- if (ipa_uc_reg_rdyCB(&uc_ready_param)) {
- HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
- "UC Ready CB register fail");
- return -EPERM;
- }
- if (false != QDF_IPA_UC_READY_PARAMS_IS_UC_READY(&uc_ready_param)) {
- HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "UC Ready");
- hdd_ipa->uc_loaded = true;
- } else {
- ret = hdd_ipa_uc_send_wdi_control_msg(false);
- }
-
- return ret;
-}
-#else
-static int hdd_ipa_uc_register_uc_ready(struct hdd_ipa_priv *hdd_ipa)
-{
- hdd_ipa->uc_loaded = true;
- return 0;
-}
-
-static int hdd_ipa_uc_send_wdi_control_msg(bool ctrl)
-{
- return 0;
-}
-#endif
-
-/**
* hdd_ipa_is_enabled() - Is IPA enabled?
* @hdd_ctx: Global HDD context
*
@@ -792,6 +755,891 @@
HDD_IPA_RM_ENABLE_MASK);
}
+#ifdef FEATURE_METERING
+/**
+ * __hdd_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler.
+ * IPA calls to get WLAN stats or set quota limit.
+ * @priv: pointer to private data registered with IPA (we register a
+ *» pointer to the global IPA context)
+ * @evt: the IPA event which triggered the callback
+ * @data: data associated with the event
+ *
+ * Return: None
+ */
+static void __hdd_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt,
+ void *data)
+{
+ struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
+ struct hdd_adapter *adapter = NULL;
+ qdf_ipa_get_wdi_sap_stats_t *wdi_sap_stats;
+ qdf_ipa_set_wifi_quota_t *ipa_set_quota;
+ int ret = 0;
+
+ if (wlan_hdd_validate_context(hdd_ipa->hdd_ctx))
+ return;
+
+ adapter = hdd_get_adapter(hdd_ipa->hdd_ctx, QDF_STA_MODE);
+
+ HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "event=%d", evt);
+
+ switch (evt) {
+ case IPA_GET_WDI_SAP_STATS:
+ /* fill-up ipa_get_wdi_sap_stats structure after getting
+ * ipa_uc_fw_stats from FW
+ */
+ wdi_sap_stats = data;
+
+ if (!adapter) {
+ HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
+ "IPA uC share stats failed - no adapter");
+ QDF_IPA_GET_WDI_SAP_STATS_STATS_VALID(wdi_sap_stats) =
+ 0;
+ return;
+ }
+
+ INIT_COMPLETION(hdd_ipa->ipa_uc_sharing_stats_comp);
+ hdd_ipa_uc_sharing_stats_request(
+ adapter,
+ QDF_IPA_GET_WDI_SAP_STATS_RESET_STATS(wdi_sap_stats));
+ ret = wait_for_completion_timeout(
+ &hdd_ipa->ipa_uc_sharing_stats_comp,
+ msecs_to_jiffies(IPA_UC_SHARING_STATES_WAIT_TIME));
+ if (!ret) {
+ HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
+ "IPA uC share stats request timed out");
+ QDF_IPA_GET_WDI_SAP_STATS_STATS_VALID(wdi_sap_stats)
+ = 0;
+ } else {
+ QDF_IPA_GET_WDI_SAP_STATS_STATS_VALID(wdi_sap_stats)
+ = 1;
+
+ QDF_IPA_GET_WDI_SAP_STATS_IPV4_RX_PACKETS(wdi_sap_stats)
+ = hdd_ipa->ipa_sharing_stats.ipv4_rx_packets;
+ QDF_IPA_GET_WDI_SAP_STATS_IPV4_RX_BYTES(wdi_sap_stats)
+ = hdd_ipa->ipa_sharing_stats.ipv4_rx_bytes;
+ QDF_IPA_GET_WDI_SAP_STATS_IPV6_RX_PACKETS(wdi_sap_stats)
+ = hdd_ipa->ipa_sharing_stats.ipv6_rx_packets;
+ QDF_IPA_GET_WDI_SAP_STATS_IPV6_RX_BYTES(wdi_sap_stats)
+ = hdd_ipa->ipa_sharing_stats.ipv6_rx_bytes;
+ QDF_IPA_GET_WDI_SAP_STATS_IPV4_TX_PACKETS(wdi_sap_stats)
+ = hdd_ipa->ipa_sharing_stats.ipv4_tx_packets;
+ QDF_IPA_GET_WDI_SAP_STATS_IPV4_TX_BYTES(wdi_sap_stats)
+ = hdd_ipa->ipa_sharing_stats.ipv4_tx_bytes;
+ QDF_IPA_GET_WDI_SAP_STATS_IPV6_TX_PACKETS(wdi_sap_stats)
+ = hdd_ipa->ipa_sharing_stats.ipv6_tx_packets;
+ QDF_IPA_GET_WDI_SAP_STATS_IPV6_TX_BYTES(wdi_sap_stats)
+ = hdd_ipa->ipa_sharing_stats.ipv6_tx_bytes;
+ HDD_IPA_DP_LOG(
+ QDF_TRACE_LEVEL_DEBUG,
+ "%s:%d,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu",
+ "IPA_GET_WDI_SAP_STATS",
+ QDF_IPA_GET_WDI_SAP_STATS_STATS_VALID(
+ wdi_sap_stats),
+ QDF_IPA_GET_WDI_SAP_STATS_IPV4_RX_PACKETS(
+ wdi_sap_stats),
+ QDF_IPA_GET_WDI_SAP_STATS_IPV4_RX_BYTES(
+ wdi_sap_stats),
+ QDF_IPA_GET_WDI_SAP_STATS_IPV6_RX_PACKETS(
+ wdi_sap_stats),
+ QDF_IPA_GET_WDI_SAP_STATS_IPV6_RX_BYTES(
+ wdi_sap_stats),
+ QDF_IPA_GET_WDI_SAP_STATS_IPV4_TX_PACKETS(
+ wdi_sap_stats),
+ QDF_IPA_GET_WDI_SAP_STATS_IPV4_TX_BYTES(
+ wdi_sap_stats),
+ QDF_IPA_GET_WDI_SAP_STATS_IPV6_TX_PACKETS(
+ wdi_sap_stats),
+ QDF_IPA_GET_WDI_SAP_STATS_IPV6_TX_BYTES(
+ wdi_sap_stats));
+ }
+ break;
+ case IPA_SET_WIFI_QUOTA:
+ /* get ipa_set_wifi_quota structure from IPA and pass to FW
+ * through quota_exceeded field in ipa_uc_fw_stats
+ */
+ ipa_set_quota = data;
+
+ if (!adapter) {
+ HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
+ "IPA uC set quota failed - no adapter");
+ ipa_set_quota->set_valid = 0;
+ return;
+ }
+
+ INIT_COMPLETION(hdd_ipa->ipa_uc_set_quota_comp);
+ hdd_ipa_uc_set_quota(adapter, ipa_set_quota->set_quota,
+ ipa_set_quota->quota_bytes);
+
+ ret = wait_for_completion_timeout(
+ &hdd_ipa->ipa_uc_set_quota_comp,
+ msecs_to_jiffies(IPA_UC_SET_QUOTA_WAIT_TIME));
+ if (!ret) {
+ HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
+ "IPA uC set quota request timed out");
+ QDF_IPA_SET_WIFI_QUOTA_SET_VALID(ipa_set_quota) = 0;
+ } else {
+ QDF_IPA_SET_WIFI_QUOTA_BYTES(ipa_set_quota) =
+ ((uint64_t)(hdd_ipa->ipa_quota_rsp.quota_hi)
+ << 32) | hdd_ipa->ipa_quota_rsp.quota_lo;
+ QDF_IPA_SET_WIFI_QUOTA_SET_VALID(ipa_set_quota) =
+ hdd_ipa->ipa_quota_rsp.success;
+ }
+
+ HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, "SET_QUOTA: %llu, %d",
+ ipa_set_quota->quota_bytes,
+ ipa_set_quota->set_valid);
+ break;
+ }
+}
+
+/**
+ * hdd_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler.
+ * IPA calls to get WLAN stats or set quota limit.
+ * @priv: pointer to private data registered with IPA (we register a
+ * pointer to the global IPA context)
+ * @evt: the IPA event which triggered the callback
+ * @data: data associated with the event
+ *
+ * Return: None
+ */
+static void hdd_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt,
+ void *data)
+{
+ cds_ssr_protect(__func__);
+ __hdd_ipa_wdi_meter_notifier_cb(evt, data);
+ cds_ssr_unprotect(__func__);
+}
+
+static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt)
+{
+ init_completion(&ipa_ctxt->ipa_uc_sharing_stats_comp);
+ init_completion(&ipa_ctxt->ipa_uc_set_quota_comp);
+}
+#else /* FEATURE_METERING */
+static void hdd_ipa_wdi_meter_notifier_cb(void)
+{
+}
+
+static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt)
+{
+}
+#endif /* FEATURE_METERING */
+
+#ifdef CONFIG_IPA_WDI_UNIFIED_API
+
+/*
+ * TODO: Get WDI version through FW capabilities
+ */
+#ifdef CONFIG_LITHIUM
+static inline void hdd_ipa_wdi_get_wdi_version(struct hdd_ipa_priv *hdd_ipa)
+{
+ hdd_ipa->wdi_version = IPA_WDI_3;
+}
+#elif defined(QCA_WIFI_3_0)
+static inline void hdd_ipa_wdi_get_wdi_version(struct hdd_ipa_priv *hdd_ipa)
+{
+ hdd_ipa->wdi_version = IPA_WDI_2;
+}
+#else
+static inline void hdd_ipa_wdi_get_wdi_version(struct hdd_ipa_priv *hdd_ipa)
+{
+ hdd_ipa->wdi_version = IPA_WDI_1;
+}
+#endif
+
+static inline bool hdd_ipa_wdi_is_smmu_enabled(struct hdd_ipa_priv *hdd_ipa,
+ qdf_device_t osdev)
+{
+ /* TODO: Need to check if SMMU is supported on cld_3.2 */
+ /* return hdd_ipa->is_smmu_enabled && qdf_mem_smmu_s1_enabled(osdev); */
+ return 0;
+}
+
+static inline QDF_STATUS hdd_ipa_wdi_setup(struct hdd_ipa_priv *hdd_ipa)
+{
+ void *soc = cds_get_context(QDF_MODULE_ID_SOC);
+ void *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
+ qdf_device_t osdev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
+ struct hdd_context *hdd_ctx = hdd_ipa->hdd_ctx;
+ qdf_ipa_sys_connect_params_t sys_in[HDD_IPA_MAX_IFACE];
+ int i;
+
+ for (i = 0; i < HDD_IPA_MAX_IFACE; i++)
+ memcpy(&sys_in[i],
+ &hdd_ipa->sys_pipe[i].ipa_sys_params,
+ sizeof(qdf_ipa_sys_connect_params_t));
+
+ return cdp_ipa_setup(soc, (struct cdp_pdev *)pdev,
+ hdd_ipa_i2w_cb, hdd_ipa_w2i_cb,
+ hdd_ipa_wdi_meter_notifier_cb,
+ hdd_ctx->config->IpaDescSize,
+ hdd_ipa, hdd_ipa_is_rm_enabled(hdd_ctx),
+ &hdd_ipa->tx_pipe_handle,
+ &hdd_ipa->rx_pipe_handle,
+ hdd_ipa_wdi_is_smmu_enabled(hdd_ipa, osdev),
+ sys_in);
+}
+
+#ifdef FEATURE_METERING
+static inline void hdd_ipa_wdi_init_metering(struct hdd_ipa_priv *ipa_ctxt, void *in)
+{
+ qdf_ipa_wdi_init_in_params_t *wdi3_in;
+
+ wdi3_in = (qdf_ipa_wdi_init_in_params_t *)in;
+ QDF_IPA_WDI_INIT_IN_PARAMS_WDI_NOTIFY(wdi3_in) =
+ hdd_ipa_wdi_meter_notifier_cb;
+}
+#else
+static inline void hdd_ipa_wdi_init_metering(struct hdd_ipa_priv *ipa_ctxt, void *in)
+{
+}
+#endif
+
+static inline int hdd_ipa_wdi_init(struct hdd_ipa_priv *hdd_ipa)
+{
+ qdf_ipa_wdi_init_in_params_t in;
+ qdf_ipa_wdi_init_out_params_t out;
+ int ret;
+
+ hdd_ipa->uc_loaded = false;
+
+ QDF_IPA_WDI_INIT_IN_PARAMS_WDI_VERSION(&in) = hdd_ipa->wdi_version;
+ QDF_IPA_WDI_INIT_IN_PARAMS_NOTIFY(&in) = hdd_ipa_uc_loaded_uc_cb;
+ QDF_IPA_WDI_INIT_IN_PARAMS_PRIV(&in) = (void *)hdd_ipa;
+ hdd_ipa_wdi_init_metering(hdd_ipa, (void *)&in);
+
+ ret = qdf_ipa_wdi_init(&in, &out);
+ if (ret) {
+ HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
+ "ipa_wdi_init failed with ret=%d", ret);
+ return -EPERM;
+ }
+
+ if (QDF_IPA_WDI_INIT_OUT_PARAMS_IS_UC_READY(&out)) {
+ HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "IPA uC READY");
+ hdd_ipa->uc_loaded = true;
+ hdd_ipa->is_smmu_enabled =
+ QDF_IPA_WDI_INIT_OUT_PARAMS_IS_SMMU_ENABLED(&out);
+ HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "is_smmu_enabled=%d",
+ hdd_ipa->is_smmu_enabled);
+ } else {
+ ret = -EACCES;
+ }
+
+ return ret;
+}
+
+static inline int hdd_ipa_wdi_cleanup(void)
+{
+ int ret;
+
+ ret = qdf_ipa_wdi_cleanup();
+ if (ret)
+ HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
+ "ipa_wdi_cleanup failed ret=%d", ret);
+ return ret;
+}
+
+static inline int hdd_ipa_wdi_setup_sys_pipe(struct hdd_ipa_priv *hdd_ipa,
+ struct ipa_sys_connect_params *sys,
+ uint32_t *handle)
+{
+ return 0;
+}
+
+static inline int hdd_ipa_wdi_teardown_sys_pipe(struct hdd_ipa_priv *hdd_ipa,
+ uint32_t handle)
+{
+ return 0;
+}
+
+static inline int hdd_ipa_wdi_rm_request_resource(
+ struct hdd_ipa_priv *hdd_ipa,
+ enum ipa_rm_resource_name res_name)
+{
+ return 0;
+}
+
+static inline int hdd_ipa_wdi_rm_release_resource(
+ struct hdd_ipa_priv *hdd_ipa,
+ enum ipa_rm_resource_name res_name)
+{
+ return 0;
+}
+
+static inline int hdd_ipa_wdi_setup_rm(struct hdd_ipa_priv *hdd_ipa)
+{
+ return 0;
+}
+
+static inline int hdd_ipa_wdi_destroy_rm(struct hdd_ipa_priv *hdd_ipa)
+{
+ return 0;
+}
+
+static inline int hdd_ipa_wdi_rm_request(struct hdd_ipa_priv *hdd_ipa)
+{
+ return 0;
+}
+
+static inline int hdd_ipa_wdi_rm_try_release(struct hdd_ipa_priv *hdd_ipa)
+{
+ return 0;
+}
+
+static inline int hdd_ipa_wdi_rm_notify_completion(
+ enum ipa_rm_event event,
+ enum ipa_rm_resource_name resource_name)
+{
+ return 0;
+}
+
+#else /* CONFIG_IPA_WDI_UNIFIED_API */
+
+static inline void hdd_ipa_wdi_get_wdi_version(struct hdd_ipa_priv *hdd_ipa)
+{
+}
+
+static inline int hdd_ipa_wdi_is_smmu_enabled(struct hdd_ipa_priv *hdd_ipa,
+ qdf_device_t osdev)
+{
+ /* TODO: Need to check if SMMU is supported on cld_3.2 */
+ /* return qdf_mem_smmu_s1_enabled(osdev); */
+ return 0;
+}
+
+static inline QDF_STATUS hdd_ipa_wdi_setup(struct hdd_ipa_priv *hdd_ipa)
+{
+ void *soc = cds_get_context(QDF_MODULE_ID_SOC);
+ void *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
+ struct hdd_context *hdd_ctx = hdd_ipa->hdd_ctx;
+
+ return cdp_ipa_setup(soc, (struct cdp_pdev *)pdev,
+ hdd_ipa_i2w_cb, hdd_ipa_w2i_cb,
+ hdd_ipa_wdi_meter_notifier_cb,
+ hdd_ctx->config->IpaDescSize,
+ hdd_ipa, hdd_ipa_is_rm_enabled(hdd_ctx),
+ &hdd_ipa->tx_pipe_handle,
+ &hdd_ipa->rx_pipe_handle);
+}
+
+static inline int hdd_ipa_wdi_init(struct hdd_ipa_priv *hdd_ipa)
+{
+ struct ipa_wdi_uc_ready_params uc_ready_param;
+ int ret = 0;
+
+ hdd_ipa->uc_loaded = false;
+ uc_ready_param.priv = (void *)hdd_ipa;
+ uc_ready_param.notify = hdd_ipa_uc_loaded_uc_cb;
+ if (ipa_uc_reg_rdyCB(&uc_ready_param)) {
+ HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
+ "UC Ready CB register fail");
+ return -EPERM;
+ }
+
+ if (true == uc_ready_param.is_uC_ready) {
+ HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "UC Ready");
+ hdd_ipa->uc_loaded = true;
+ } else {
+ ret = -EACCES;
+ }
+
+ return ret;
+}
+
+static inline int hdd_ipa_wdi_cleanup(void)
+{
+ int ret;
+
+ ret = ipa_uc_dereg_rdyCB();
+ if (ret)
+ HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
+ "UC Ready CB deregister fail");
+ return ret;
+}
+
+static inline int hdd_ipa_wdi_setup_sys_pipe(
+ struct hdd_ipa_priv *hdd_ipa,
+ struct ipa_sys_connect_params *sys, uint32_t *handle)
+{
+ return qdf_ipa_setup_sys_pipe(sys, handle);
+}
+
+static inline int hdd_ipa_wdi_teardown_sys_pipe(
+ struct hdd_ipa_priv *hdd_ipa,
+ uint32_t handle)
+{
+ return qdf_ipa_teardown_sys_pipe(handle);
+}
+
+static inline int hdd_ipa_wdi_rm_request_resource(
+ struct hdd_ipa_priv *hdd_ipa,
+ enum ipa_rm_resource_name res_name)
+{
+ return qdf_ipa_rm_request_resource(res_name);
+}
+
+static inline int hdd_ipa_wdi_rm_release_resource(
+ struct hdd_ipa_priv *hdd_ipa,
+ enum ipa_rm_resource_name res_name)
+{
+ return qdf_ipa_rm_release_resource(res_name);
+}
+
+/**
+ * hdd_ipa_init_uc_rm_work - init ipa uc resource manager work
+ * @work: struct work_struct
+ * @work_handler: work_handler
+ *
+ * Return: none
+ */
+static void hdd_ipa_init_uc_rm_work(struct work_struct *work,
+ work_func_t work_handler)
+{
+ INIT_WORK(work, work_handler);
+}
+
+/**
+ * hdd_ipa_wake_lock_timer_func() - Wake lock work handler
+ * @work: scheduled work
+ *
+ * When IPA resources are released in hdd_ipa_wdi_rm_try_release() we do
+ * not want to immediately release the wake lock since the system
+ * would then potentially try to suspend when there is a healthy data
+ * rate. Deferred work is scheduled and this function handles the
+ * work. When this function is called, if the IPA resource is still
+ * released then we release the wake lock.
+ *
+ * Return: None
+ */
+static void hdd_ipa_wake_lock_timer_func(struct work_struct *work)
+{
+ struct hdd_ipa_priv *hdd_ipa = container_of(to_delayed_work(work),
+ struct hdd_ipa_priv,
+ wake_lock_work);
+
+ qdf_spin_lock_bh(&hdd_ipa->rm_lock);
+
+ if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED)
+ goto end;
+
+ hdd_ipa->wake_lock_released = true;
+ qdf_wake_lock_release(&hdd_ipa->wake_lock,
+ WIFI_POWER_EVENT_WAKELOCK_IPA);
+
+end:
+ qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
+}
+
+/**
+ * hdd_ipa_wdi_rm_request() - Request resource from IPA
+ * @hdd_ipa: Global HDD IPA context
+ *
+ * Return: 0 on success, negative errno on error
+ */
+static int hdd_ipa_wdi_rm_request(struct hdd_ipa_priv *hdd_ipa)
+{
+ int ret = 0;
+
+ if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
+ return 0;
+
+ qdf_spin_lock_bh(&hdd_ipa->rm_lock);
+
+ switch (hdd_ipa->rm_state) {
+ case HDD_IPA_RM_GRANTED:
+ qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
+ return 0;
+ case HDD_IPA_RM_GRANT_PENDING:
+ qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
+ return -EINPROGRESS;
+ case HDD_IPA_RM_RELEASED:
+ hdd_ipa->rm_state = HDD_IPA_RM_GRANT_PENDING;
+ break;
+ }
+
+ qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
+
+ ret = qdf_ipa_rm_inactivity_timer_request_resource(
+ IPA_RM_RESOURCE_WLAN_PROD);
+
+ qdf_spin_lock_bh(&hdd_ipa->rm_lock);
+ if (ret == 0) {
+ hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
+ hdd_ipa->stats.num_rm_grant_imm++;
+ }
+
+ cancel_delayed_work(&hdd_ipa->wake_lock_work);
+ if (hdd_ipa->wake_lock_released) {
+ qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
+ WIFI_POWER_EVENT_WAKELOCK_IPA);
+ hdd_ipa->wake_lock_released = false;
+ }
+ qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
+
+ return ret;
+}
+
+/**
+ * hdd_ipa_wdi_rm_try_release() - Attempt to release IPA resource
+ * @hdd_ipa: Global HDD IPA context
+ *
+ * Return: 0 if resources released, negative errno otherwise
+ */
+static int hdd_ipa_wdi_rm_try_release(struct hdd_ipa_priv *hdd_ipa)
+{
+ int ret = 0;
+
+ if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
+ return 0;
+
+ if (atomic_read(&hdd_ipa->tx_ref_cnt))
+ return -EAGAIN;
+
+ qdf_spin_lock_bh(&hdd_ipa->pm_lock);
+
+ if (!qdf_nbuf_is_queue_empty(&hdd_ipa->pm_queue_head)) {
+ qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
+ return -EAGAIN;
+ }
+ qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
+
+ qdf_spin_lock_bh(&hdd_ipa->rm_lock);
+ switch (hdd_ipa->rm_state) {
+ case HDD_IPA_RM_GRANTED:
+ break;
+ case HDD_IPA_RM_GRANT_PENDING:
+ qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
+ return -EINPROGRESS;
+ case HDD_IPA_RM_RELEASED:
+ qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
+ return 0;
+ }
+
+ /* IPA driver returns immediately so set the state here to avoid any
+ * race condition.
+ */
+ hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
+ hdd_ipa->stats.num_rm_release++;
+ qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
+
+ ret = qdf_ipa_rm_inactivity_timer_release_resource(
+ IPA_RM_RESOURCE_WLAN_PROD);
+
+ qdf_spin_lock_bh(&hdd_ipa->rm_lock);
+ if (unlikely(ret != 0)) {
+ hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
+ WARN_ON(1);
+ HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN,
+ "ipa_rm_inactivity_timer_release_resource returnied fail");
+ }
+
+ /*
+ * If wake_lock is released immediately, kernel would try to suspend
+ * immediately as well, Just avoid ping-pong between suspend-resume
+ * while there is healthy amount of data transfer going on by
+ * releasing the wake_lock after some delay.
+ */
+ schedule_delayed_work(&hdd_ipa->wake_lock_work,
+ msecs_to_jiffies
+ (HDD_IPA_RX_INACTIVITY_MSEC_DELAY));
+
+ qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
+
+ return ret;
+}
+
+/**
+ * hdd_ipa_rm_notify() - IPA resource manager notifier callback
+ * @user_data: user data registered with IPA
+ * @event: the IPA resource manager event that occurred
+ * @data: the data associated with the event
+ *
+ * Return: None
+ */
+static void hdd_ipa_rm_notify(void *user_data, enum ipa_rm_event event,
+ unsigned long data)
+{
+ struct hdd_ipa_priv *hdd_ipa = user_data;
+
+ if (unlikely(!hdd_ipa))
+ return;
+
+ if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
+ return;
+
+ HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Evt: %d", event);
+
+ switch (event) {
+ case IPA_RM_RESOURCE_GRANTED:
+ if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
+ /* RM Notification comes with ISR context
+ * it should be serialized into work queue to avoid
+ * ISR sleep problem
+ */
+ hdd_ipa->uc_rm_work.event = event;
+ schedule_work(&hdd_ipa->uc_rm_work.work);
+ break;
+ }
+ qdf_spin_lock_bh(&hdd_ipa->rm_lock);
+ hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
+ qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
+ hdd_ipa->stats.num_rm_grant++;
+ break;
+
+ case IPA_RM_RESOURCE_RELEASED:
+ HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "RM Release");
+ hdd_ipa->resource_unloading = false;
+ break;
+
+ default:
+ HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Unknown RM Evt: %d", event);
+ break;
+ }
+}
+
+/**
+ * hdd_ipa_rm_cons_release() - WLAN consumer resource release handler
+ *
+ * Callback function registered with IPA that is called when IPA wants
+ * to release the WLAN consumer resource
+ *
+ * Return: 0 if the request is granted, negative errno otherwise
+ */
+static int hdd_ipa_rm_cons_release(void)
+{
+ return 0;
+}
+
+/**
+ * hdd_ipa_rm_cons_request() - WLAN consumer resource request handler
+ *
+ * Callback function registered with IPA that is called when IPA wants
+ * to access the WLAN consumer resource
+ *
+ * Return: 0 if the request is granted, negative errno otherwise
+ */
+static int hdd_ipa_rm_cons_request(void)
+{
+ int ret = 0;
+
+ if (ghdd_ipa->resource_loading) {
+ HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
+ "IPA resource loading in progress");
+ ghdd_ipa->pending_cons_req = true;
+ ret = -EINPROGRESS;
+ } else if (ghdd_ipa->resource_unloading) {
+ HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
+ "IPA resource unloading in progress");
+ ghdd_ipa->pending_cons_req = true;
+ ret = -EPERM;
+ }
+
+ return ret;
+}
+
+/**
+ * hdd_ipa_uc_rm_notify_handler() - IPA uC resource notification handler
+ * @context: User context registered with TL (the IPA Global context is
+ * registered
+ * @rxpkt: Packet containing the notification
+ * @staid: ID of the station associated with the packet
+ *
+ * Return: None
+ */
+static void
+hdd_ipa_uc_rm_notify_handler(void *context, enum ipa_rm_event event)
+{
+ struct hdd_ipa_priv *hdd_ipa = context;
+ QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+ /*
+ * When SSR is going on or driver is unloading, just return.
+ */
+ status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
+ if (status)
+ return;
+
+ if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
+ return;
+
+ HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "event code %d", event);
+
+ switch (event) {
+ case IPA_RM_RESOURCE_GRANTED:
+ /* Differed RM Granted */
+ qdf_mutex_acquire(&hdd_ipa->ipa_lock);
+ if ((false == hdd_ipa->resource_unloading) &&
+ (!hdd_ipa->activated_fw_pipe)) {
+ hdd_ipa_uc_enable_pipes(hdd_ipa);
+ }
+ qdf_mutex_release(&hdd_ipa->ipa_lock);
+ break;
+
+ case IPA_RM_RESOURCE_RELEASED:
+ /* Differed RM Released */
+ hdd_ipa->resource_unloading = false;
+ break;
+
+ default:
+ HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
+ "invalid event code %d", event);
+ break;
+ }
+}
+
+/**
+ * hdd_ipa_uc_rm_notify_defer() - Defer IPA uC notification
+ * @hdd_ipa: Global HDD IPA context
+ * @event: IPA resource manager event to be deferred
+ *
+ * This function is called when a resource manager event is received
+ * from firmware in interrupt context. This function will defer the
+ * handling to the OL RX thread
+ *
+ * Return: None
+ */
+static void hdd_ipa_uc_rm_notify_defer(struct work_struct *work)
+{
+ enum ipa_rm_event event;
+ struct uc_rm_work_struct *uc_rm_work = container_of(work,
+ struct uc_rm_work_struct, work);
+ struct hdd_ipa_priv *hdd_ipa = container_of(uc_rm_work,
+ struct hdd_ipa_priv, uc_rm_work);
+
+ cds_ssr_protect(__func__);
+ event = uc_rm_work->event;
+ HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "posted event %d", event);
+
+ hdd_ipa_uc_rm_notify_handler(hdd_ipa, event);
+ cds_ssr_unprotect(__func__);
+}
+
+/**
+ * hdd_ipa_wdi_setup_rm() - Setup IPA resource management
+ * @hdd_ipa: Global HDD IPA context
+ *
+ * Return: 0 on success, negative errno on error
+ */
+static int hdd_ipa_wdi_setup_rm(struct hdd_ipa_priv *hdd_ipa)
+{
+ struct ipa_rm_create_params create_params = { 0 };
+ int ret;
+
+ if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
+ return 0;
+
+ hdd_ipa_init_uc_rm_work(&hdd_ipa->uc_rm_work.work,
+ hdd_ipa_uc_rm_notify_defer);
+ memset(&create_params, 0, sizeof(create_params));
+ create_params.name = IPA_RM_RESOURCE_WLAN_PROD;
+ create_params.reg_params.user_data = hdd_ipa;
+ create_params.reg_params.notify_cb = hdd_ipa_rm_notify;
+ create_params.floor_voltage = IPA_VOLTAGE_SVS;
+
+ ret = qdf_ipa_rm_create_resource(&create_params);
+ if (ret) {
+ HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
+ "Create RM resource failed: %d", ret);
+ goto setup_rm_fail;
+ }
+
+ memset(&create_params, 0, sizeof(create_params));
+ create_params.name = IPA_RM_RESOURCE_WLAN_CONS;
+ create_params.request_resource = hdd_ipa_rm_cons_request;
+ create_params.release_resource = hdd_ipa_rm_cons_release;
+ create_params.floor_voltage = IPA_VOLTAGE_SVS;
+
+ ret = qdf_ipa_rm_create_resource(&create_params);
+ if (ret) {
+ HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
+ "Create RM CONS resource failed: %d", ret);
+ goto delete_prod;
+ }
+
+ ipa_rm_add_dependency(IPA_RM_RESOURCE_WLAN_PROD,
+ IPA_RM_RESOURCE_APPS_CONS);
+
+ ret = qdf_ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_WLAN_PROD,
+ HDD_IPA_RX_INACTIVITY_MSEC_DELAY);
+ if (ret) {
+ HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Timer init failed: %d",
+ ret);
+ goto timer_init_failed;
+ }
+
+ /* Set the lowest bandwidth to start with */
+ ret = hdd_ipa_set_perf_level(hdd_ipa->hdd_ctx, 0, 0);
+
+ if (ret) {
+ HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
+ "Set perf level failed: %d", ret);
+ goto set_perf_failed;
+ }
+
+ qdf_wake_lock_create(&hdd_ipa->wake_lock, "wlan_ipa");
+ INIT_DELAYED_WORK(&hdd_ipa->wake_lock_work,
+ hdd_ipa_wake_lock_timer_func);
+ qdf_spinlock_create(&hdd_ipa->rm_lock);
+ hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
+ hdd_ipa->wake_lock_released = true;
+ atomic_set(&hdd_ipa->tx_ref_cnt, 0);
+
+ return ret;
+
+set_perf_failed:
+ ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
+
+timer_init_failed:
+ ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
+
+delete_prod:
+ ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
+
+setup_rm_fail:
+ return ret;
+}
+
+/**
+ * hdd_ipa_wdi_destroy_rm() - Destroy IPA resources
+ * @hdd_ipa: Global HDD IPA context
+ *
+ * Destroys all resources associated with the IPA resource manager
+ *
+ * Return: None
+ */
+static void hdd_ipa_wdi_destroy_rm(struct hdd_ipa_priv *hdd_ipa)
+{
+ int ret;
+
+ if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
+ return;
+
+ cancel_delayed_work_sync(&hdd_ipa->wake_lock_work);
+ qdf_wake_lock_destroy(&hdd_ipa->wake_lock);
+ cancel_work_sync(&hdd_ipa->uc_rm_work.work);
+ qdf_spinlock_destroy(&hdd_ipa->rm_lock);
+
+ ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
+
+ ret = qdf_ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
+ if (ret)
+ HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
+ "RM PROD resource delete failed %d", ret);
+
+ ret = qdf_ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
+ if (ret)
+ HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
+ "RM CONS resource delete failed %d", ret);
+}
+
+static int hdd_ipa_wdi_rm_notify_completion(enum ipa_rm_event event,
+ enum ipa_rm_resource_name resource_name)
+{
+ return qdf_ipa_rm_notify_completion(event, resource_name);
+}
+#endif /* CONFIG_IPA_WDI_UNIFIED_API */
+
/**
* hdd_ipa_uc_rt_debug_host_fill - fill rt debug buffer
* @ctext: pointer to hdd context.
@@ -832,7 +1680,7 @@
qdf_mutex_release(&hdd_ipa->rt_debug_lock);
qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
- HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
+ HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
}
/**
@@ -861,14 +1709,14 @@
if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
- "IPA RT debug is not enabled");
+ "IPA RT debug is not enabled");
return;
}
HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
- "========= WLAN-IPA DEBUG BUF DUMP ==========\n");
+ "========= WLAN-IPA DEBUG BUF DUMP ==========\n");
HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
- " TM : EXEP : DROP : NETS : FWOK : TXFD : DSTR : DSCD\n");
+ " TM : EXEP : DROP : NETS : FWOK : TXFD : DSTR : DSCD\n");
qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
for (dump_count = 0;
@@ -878,16 +1726,16 @@
HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
dump_info = &hdd_ipa->rt_bug_buffer[dump_index];
HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
- "%12llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu\n",
- dump_info->time, dump_info->ipa_excep_count,
- dump_info->rx_drop_count, dump_info->net_sent_count,
- dump_info->tx_fwd_ok_count, dump_info->tx_fwd_count,
- dump_info->rx_destructor_call,
- dump_info->rx_discard_count);
+ "%12llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu\n",
+ dump_info->time, dump_info->ipa_excep_count,
+ dump_info->rx_drop_count, dump_info->net_sent_count,
+ dump_info->tx_fwd_ok_count, dump_info->tx_fwd_count,
+ dump_info->rx_destructor_call,
+ dump_info->rx_discard_count);
}
qdf_mutex_release(&hdd_ipa->rt_debug_lock);
HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
- "======= WLAN-IPA DEBUG BUF DUMP END ========\n");
+ "======= WLAN-IPA DEBUG BUF DUMP END ========\n");
}
/**
@@ -1899,7 +2747,7 @@
result = cdp_ipa_enable_pipes(soc, (struct cdp_pdev *)pdev);
if (result) {
HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
- "Enable PIPE fail, code %d", result);
+ "Enable IPA WDI PIPE failed: ret=%d", result);
goto end;
}
@@ -1945,7 +2793,7 @@
result = cdp_ipa_disable_pipes(soc, (struct cdp_pdev *)pdev);
if (result) {
HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
- "Disable WDI PIPE fail, code %d", result);
+ "Disable IPA WDI PIPE failed: ret=%d", result);
goto end;
}
@@ -1977,13 +2825,14 @@
* PROD resource may return sync or async manners
*/
if (hdd_ipa_is_rm_enabled(hdd_ctx)) {
- if (!ipa_rm_request_resource(IPA_RM_RESOURCE_WLAN_PROD)) {
+ if (!hdd_ipa_wdi_rm_request_resource(
+ hdd_ipa, IPA_RM_RESOURCE_WLAN_PROD)) {
/* RM PROD request sync return
* enable pipe immediately
*/
if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
- "IPA WDI Pipe activation failed");
+ "IPA WDI Pipe activation failed");
hdd_ipa->resource_loading = false;
return -EBUSY;
}
@@ -2036,86 +2885,6 @@
}
/**
- * hdd_ipa_uc_rm_notify_handler() - IPA uC resource notification handler
- * @context: User context registered with TL (the IPA Global context is
- * registered
- * @rxpkt: Packet containing the notification
- * @staid: ID of the station associated with the packet
- *
- * Return: None
- */
-static void
-hdd_ipa_uc_rm_notify_handler(void *context, qdf_ipa_rm_event_t event)
-{
- struct hdd_ipa_priv *hdd_ipa = context;
- QDF_STATUS status = QDF_STATUS_SUCCESS;
- struct hdd_context *hdd_ctx = hdd_ipa->hdd_ctx;
-
- /*
- * When SSR is going on or driver is unloading, just return.
- */
- status = wlan_hdd_validate_context(hdd_ctx);
- if (status)
- return;
-
- if (!hdd_ipa_is_rm_enabled(hdd_ctx))
- return;
-
- HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "event code %d",
- event);
-
- switch (event) {
- case IPA_RM_RESOURCE_GRANTED:
- /* Differed RM Granted */
- qdf_mutex_acquire(&hdd_ipa->ipa_lock);
- if ((false == hdd_ipa->resource_unloading) &&
- (!hdd_ipa->activated_fw_pipe)) {
- hdd_ipa_uc_enable_pipes(hdd_ipa);
- }
- qdf_mutex_release(&hdd_ipa->ipa_lock);
- break;
-
- case IPA_RM_RESOURCE_RELEASED:
- /* Differed RM Released */
- hdd_ipa->resource_unloading = false;
- break;
-
- default:
- HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
- "invalid event code %d", event);
- break;
- }
-}
-
-/**
- * hdd_ipa_uc_rm_notify_defer() - Defer IPA uC notification
- * @hdd_ipa: Global HDD IPA context
- * @event: IPA resource manager event to be deferred
- *
- * This function is called when a resource manager event is received
- * from firmware in interrupt context. This function will defer the
- * handling to the OL RX thread
- *
- * Return: None
- */
-static void hdd_ipa_uc_rm_notify_defer(struct work_struct *work)
-{
- qdf_ipa_rm_event_t event;
- struct uc_rm_work_struct *uc_rm_work = container_of(work,
- struct uc_rm_work_struct, work);
- struct hdd_ipa_priv *hdd_ipa = container_of(uc_rm_work,
- struct hdd_ipa_priv, uc_rm_work);
-
- cds_ssr_protect(__func__);
- event = uc_rm_work->event;
- HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
- "posted event %d", event);
-
- hdd_ipa_uc_rm_notify_handler(hdd_ipa, event);
- cds_ssr_unprotect(__func__);
-}
-
-/**
* hdd_ipa_uc_loaded_handler() - Process IPA uC loaded indication
* @hdd_ipa: hdd ipa local context
*
@@ -2139,13 +2908,7 @@
hdd_ctx = hdd_ipa->hdd_ctx;
/* Connect pipe */
- status = cdp_ipa_setup(soc, (struct cdp_pdev *)pdev,
- hdd_ipa_i2w_cb, hdd_ipa_w2i_cb,
- hdd_ipa_wdi_meter_notifier_cb,
- hdd_ctx->config->IpaDescSize,
- hdd_ipa, hdd_ipa_is_rm_enabled(hdd_ctx),
- &hdd_ipa->tx_pipe_handle,
- &hdd_ipa->rx_pipe_handle);
+ status = hdd_ipa_wdi_setup(hdd_ipa);
if (status) {
HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
"Failure to setup IPA pipes (status=%d)",
@@ -2698,7 +3461,7 @@
}
hdd_ipa_uc_proc_pending_event(hdd_ipa, true);
if (hdd_ipa->pending_cons_req)
- ipa_rm_notify_completion(
+ hdd_ipa_wdi_rm_notify_completion(
IPA_RM_RESOURCE_GRANTED,
IPA_RM_RESOURCE_WLAN_CONS);
hdd_ipa->pending_cons_req = false;
@@ -2725,8 +3488,8 @@
hdd_ipa->resource_unloading = false;
complete(&hdd_ipa->ipa_resource_comp);
if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
- ipa_rm_release_resource(
- IPA_RM_RESOURCE_WLAN_PROD);
+ hdd_ipa_wdi_rm_release_resource(
+ hdd_ipa, IPA_RM_RESOURCE_WLAN_PROD);
hdd_ipa_uc_proc_pending_event(hdd_ipa, false);
hdd_ipa->pending_cons_req = false;
}
@@ -2933,174 +3696,6 @@
INIT_WORK(work, work_handler);
}
-#ifdef FEATURE_METERING
-/**
- * __hdd_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler.
- * IPA calls to get WLAN stats or set quota limit.
- * @priv: pointer to private data registered with IPA (we register a
- *» pointer to the global IPA context)
- * @evt: the IPA event which triggered the callback
- * @data: data associated with the event
- *
- * Return: None
- */
-static void __hdd_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt,
- void *data)
-{
- struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
- struct hdd_adapter *adapter = NULL;
- qdf_ipa_get_wdi_sap_stats_t *wdi_sap_stats;
- qdf_ipa_set_wifi_quota_t *ipa_set_quota;
- int ret = 0;
-
- if (wlan_hdd_validate_context(hdd_ipa->hdd_ctx))
- return;
-
- adapter = hdd_get_adapter(hdd_ipa->hdd_ctx, QDF_STA_MODE);
-
- HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "event=%d", evt);
-
- switch (evt) {
- case IPA_GET_WDI_SAP_STATS:
- /* fill-up ipa_get_wdi_sap_stats structure after getting
- * ipa_uc_fw_stats from FW
- */
- wdi_sap_stats = data;
-
- if (!adapter) {
- HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
- "IPA uC share stats failed - no adapter");
- QDF_IPA_GET_WDI_SAP_STATS_STATS_VALID(wdi_sap_stats) =
- 0;
- return;
- }
-
- INIT_COMPLETION(hdd_ipa->ipa_uc_sharing_stats_comp);
- hdd_ipa_uc_sharing_stats_request(adapter,
- QDF_IPA_GET_WDI_SAP_STATS_RESET_STATS(wdi_sap_stats));
- ret = wait_for_completion_timeout(
- &hdd_ipa->ipa_uc_sharing_stats_comp,
- msecs_to_jiffies(IPA_UC_SHARING_STATES_WAIT_TIME));
- if (!ret) {
- HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
- "IPA uC share stats request timed out");
- QDF_IPA_GET_WDI_SAP_STATS_STATS_VALID(wdi_sap_stats)
- = 0;
- } else {
- QDF_IPA_GET_WDI_SAP_STATS_STATS_VALID(wdi_sap_stats)
- = 1;
-
- QDF_IPA_GET_WDI_SAP_STATS_IPV4_RX_PACKETS(wdi_sap_stats)
- = hdd_ipa->ipa_sharing_stats.ipv4_rx_packets;
- QDF_IPA_GET_WDI_SAP_STATS_IPV4_RX_BYTES(wdi_sap_stats)
- = hdd_ipa->ipa_sharing_stats.ipv4_rx_bytes;
- QDF_IPA_GET_WDI_SAP_STATS_IPV6_RX_PACKETS(wdi_sap_stats)
- = hdd_ipa->ipa_sharing_stats.ipv6_rx_packets;
- QDF_IPA_GET_WDI_SAP_STATS_IPV6_RX_BYTES(wdi_sap_stats)
- = hdd_ipa->ipa_sharing_stats.ipv6_rx_bytes;
- QDF_IPA_GET_WDI_SAP_STATS_IPV4_TX_PACKETS(wdi_sap_stats)
- = hdd_ipa->ipa_sharing_stats.ipv4_tx_packets;
- QDF_IPA_GET_WDI_SAP_STATS_IPV4_TX_BYTES(wdi_sap_stats)
- = hdd_ipa->ipa_sharing_stats.ipv4_tx_bytes;
- QDF_IPA_GET_WDI_SAP_STATS_IPV6_TX_PACKETS(wdi_sap_stats)
- = hdd_ipa->ipa_sharing_stats.ipv6_tx_packets;
- QDF_IPA_GET_WDI_SAP_STATS_IPV6_TX_BYTES(wdi_sap_stats)
- = hdd_ipa->ipa_sharing_stats.ipv6_tx_bytes;
- HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
- "%s:%d,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu",
- "IPA_GET_WDI_SAP_STATS",
- QDF_IPA_GET_WDI_SAP_STATS_STATS_VALID(
- wdi_sap_stats),
- QDF_IPA_GET_WDI_SAP_STATS_IPV4_RX_PACKETS(
- wdi_sap_stats),
- QDF_IPA_GET_WDI_SAP_STATS_IPV4_RX_BYTES(
- wdi_sap_stats),
- QDF_IPA_GET_WDI_SAP_STATS_IPV6_RX_PACKETS(
- wdi_sap_stats),
- QDF_IPA_GET_WDI_SAP_STATS_IPV6_RX_BYTES(
- wdi_sap_stats),
- QDF_IPA_GET_WDI_SAP_STATS_IPV4_TX_PACKETS(
- wdi_sap_stats),
- QDF_IPA_GET_WDI_SAP_STATS_IPV4_TX_BYTES(
- wdi_sap_stats),
- QDF_IPA_GET_WDI_SAP_STATS_IPV6_TX_PACKETS(
- wdi_sap_stats),
- QDF_IPA_GET_WDI_SAP_STATS_IPV6_TX_BYTES(
- wdi_sap_stats));
- }
- break;
- case IPA_SET_WIFI_QUOTA:
- /* get ipa_set_wifi_quota structure from IPA and pass to FW
- * through quota_exceeded field in ipa_uc_fw_stats
- */
- ipa_set_quota = data;
-
- if (!adapter) {
- HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
- "IPA uC set quota failed - no adapter");
- ipa_set_quota->set_valid = 0;
- return;
- }
-
- INIT_COMPLETION(hdd_ipa->ipa_uc_set_quota_comp);
- hdd_ipa_uc_set_quota(adapter, ipa_set_quota->set_quota,
- ipa_set_quota->quota_bytes);
-
- ret = wait_for_completion_timeout(
- &hdd_ipa->ipa_uc_set_quota_comp,
- msecs_to_jiffies(IPA_UC_SET_QUOTA_WAIT_TIME));
- if (!ret) {
- HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
- "IPA uC set quota request timed out");
- QDF_IPA_SET_WIFI_QUOTA_SET_VALID(ipa_set_quota) = 0;
- } else {
- QDF_IPA_SET_WIFI_QUOTA_BYTES(ipa_set_quota) =
- ((uint64_t)(hdd_ipa->ipa_quota_rsp.quota_hi)
- <<32)|hdd_ipa->ipa_quota_rsp.quota_lo;
- QDF_IPA_SET_WIFI_QUOTA_SET_VALID(ipa_set_quota) =
- hdd_ipa->ipa_quota_rsp.success;
- }
-
- HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, "SET_QUOTA: %llu, %d",
- ipa_set_quota->quota_bytes,
- ipa_set_quota->set_valid);
- break;
- }
-}
-
-/**
- * hdd_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler.
- * IPA calls to get WLAN stats or set quota limit.
- * @priv: pointer to private data registered with IPA (we register a
- * pointer to the global IPA context)
- * @evt: the IPA event which triggered the callback
- * @data: data associated with the event
- *
- * Return: None
- */
-static void hdd_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt,
- void *data)
-{
- cds_ssr_protect(__func__);
- __hdd_ipa_wdi_meter_notifier_cb(evt, data);
- cds_ssr_unprotect(__func__);
-}
-
-static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt)
-{
- init_completion(&ipa_ctxt->ipa_uc_sharing_stats_comp);
- init_completion(&ipa_ctxt->ipa_uc_set_quota_comp);
-}
-#else
-static void hdd_ipa_wdi_meter_notifier_cb(void)
-{
-}
-
-static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt)
-{
-}
-#endif
-
/**
* hdd_ipa_uc_ol_init() - Initialize IPA uC offload
* @hdd_ctx: Global HDD context
@@ -3147,13 +3742,7 @@
}
if (true == hdd_ipa->uc_loaded) {
- status = cdp_ipa_setup(soc, (struct cdp_pdev *)pdev,
- hdd_ipa_i2w_cb, hdd_ipa_w2i_cb,
- hdd_ipa_wdi_meter_notifier_cb,
- hdd_ctx->config->IpaDescSize,
- hdd_ipa, hdd_ipa_is_rm_enabled(hdd_ctx),
- &hdd_ipa->tx_pipe_handle,
- &hdd_ipa->rx_pipe_handle);
+ status = hdd_ipa_wdi_setup(hdd_ipa);
if (status) {
HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
"Failure to setup IPA pipes (status=%d)",
@@ -3606,245 +4195,6 @@
}
/**
- * hdd_ipa_wake_lock_timer_func() - Wake lock work handler
- * @work: scheduled work
- *
- * When IPA resources are released in hdd_ipa_rm_try_release() we do
- * not want to immediately release the wake lock since the system
- * would then potentially try to suspend when there is a healthy data
- * rate. Deferred work is scheduled and this function handles the
- * work. When this function is called, if the IPA resource is still
- * released then we release the wake lock.
- *
- * Return: None
- */
-static void hdd_ipa_wake_lock_timer_func(struct work_struct *work)
-{
- struct hdd_ipa_priv *hdd_ipa = container_of(to_delayed_work(work),
- struct hdd_ipa_priv,
- wake_lock_work);
-
- qdf_spin_lock_bh(&hdd_ipa->rm_lock);
-
- if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED)
- goto end;
-
- hdd_ipa->wake_lock_released = true;
- qdf_wake_lock_release(&hdd_ipa->wake_lock,
- WIFI_POWER_EVENT_WAKELOCK_IPA);
-
-end:
- qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
-}
-
-/**
- * hdd_ipa_rm_request() - Request resource from IPA
- * @hdd_ipa: Global HDD IPA context
- *
- * Return: 0 on success, negative errno on error
- */
-static int hdd_ipa_rm_request(struct hdd_ipa_priv *hdd_ipa)
-{
- int ret = 0;
-
- if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
- return 0;
-
- qdf_spin_lock_bh(&hdd_ipa->rm_lock);
-
- switch (hdd_ipa->rm_state) {
- case HDD_IPA_RM_GRANTED:
- qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
- return 0;
- case HDD_IPA_RM_GRANT_PENDING:
- qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
- return -EINPROGRESS;
- case HDD_IPA_RM_RELEASED:
- hdd_ipa->rm_state = HDD_IPA_RM_GRANT_PENDING;
- break;
- }
-
- qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
-
- ret = qdf_ipa_rm_inactivity_timer_request_resource(
- IPA_RM_RESOURCE_WLAN_PROD);
-
- qdf_spin_lock_bh(&hdd_ipa->rm_lock);
- if (ret == 0) {
- hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
- hdd_ipa->stats.num_rm_grant_imm++;
- }
-
- cancel_delayed_work(&hdd_ipa->wake_lock_work);
- if (hdd_ipa->wake_lock_released) {
- qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
- WIFI_POWER_EVENT_WAKELOCK_IPA);
- hdd_ipa->wake_lock_released = false;
- }
- qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
-
- return ret;
-}
-
-/**
- * hdd_ipa_rm_try_release() - Attempt to release IPA resource
- * @hdd_ipa: Global HDD IPA context
- *
- * Return: 0 if resources released, negative errno otherwise
- */
-static int hdd_ipa_rm_try_release(struct hdd_ipa_priv *hdd_ipa)
-{
- int ret = 0;
-
- if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
- return 0;
-
- if (atomic_read(&hdd_ipa->tx_ref_cnt))
- return -EAGAIN;
-
- qdf_spin_lock_bh(&hdd_ipa->pm_lock);
-
- if (!qdf_nbuf_is_queue_empty(&hdd_ipa->pm_queue_head)) {
- qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
- return -EAGAIN;
- }
- qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
-
- qdf_spin_lock_bh(&hdd_ipa->rm_lock);
- switch (hdd_ipa->rm_state) {
- case HDD_IPA_RM_GRANTED:
- break;
- case HDD_IPA_RM_GRANT_PENDING:
- qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
- return -EINPROGRESS;
- case HDD_IPA_RM_RELEASED:
- qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
- return 0;
- }
-
- /* IPA driver returns immediately so set the state here to avoid any
- * race condition.
- */
- hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
- hdd_ipa->stats.num_rm_release++;
- qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
-
- ret = qdf_ipa_rm_inactivity_timer_release_resource(
- IPA_RM_RESOURCE_WLAN_PROD);
-
- qdf_spin_lock_bh(&hdd_ipa->rm_lock);
- if (unlikely(ret != 0)) {
- hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
- WARN_ON(1);
- HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN,
- "ipa_rm_inactivity_timer_release_resource returnied fail");
- }
-
- /*
- * If wake_lock is released immediately, kernel would try to suspend
- * immediately as well, Just avoid ping-pong between suspend-resume
- * while there is healthy amount of data transfer going on by
- * releasing the wake_lock after some delay.
- */
- schedule_delayed_work(&hdd_ipa->wake_lock_work,
- msecs_to_jiffies
- (HDD_IPA_RX_INACTIVITY_MSEC_DELAY));
-
- qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
-
- return ret;
-}
-
-/**
- * hdd_ipa_rm_notify() - IPA resource manager notifier callback
- * @user_data: user data registered with IPA
- * @event: the IPA resource manager event that occurred
- * @data: the data associated with the event
- *
- * Return: None
- */
-static void hdd_ipa_rm_notify(void *user_data, qdf_ipa_rm_event_t event,
- unsigned long data)
-{
- struct hdd_ipa_priv *hdd_ipa = user_data;
-
- if (unlikely(!hdd_ipa))
- return;
-
- if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
- return;
-
- HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Evt: %d", event);
-
- switch (event) {
- case IPA_RM_RESOURCE_GRANTED:
- if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
- /* RM Notification comes with ISR context
- * it should be serialized into work queue to avoid
- * ISR sleep problem
- */
- hdd_ipa->uc_rm_work.event = event;
- schedule_work(&hdd_ipa->uc_rm_work.work);
- break;
- }
- qdf_spin_lock_bh(&hdd_ipa->rm_lock);
- hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
- qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
- hdd_ipa->stats.num_rm_grant++;
- break;
-
- case IPA_RM_RESOURCE_RELEASED:
- HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "RM Release");
- hdd_ipa->resource_unloading = false;
- break;
-
- default:
- HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Unknown RM Evt: %d", event);
- break;
- }
-}
-
-/**
- * hdd_ipa_rm_cons_release() - WLAN consumer resource release handler
- *
- * Callback function registered with IPA that is called when IPA wants
- * to release the WLAN consumer resource
- *
- * Return: 0 if the request is granted, negative errno otherwise
- */
-static int hdd_ipa_rm_cons_release(void)
-{
- return 0;
-}
-
-/**
- * hdd_ipa_rm_cons_request() - WLAN consumer resource request handler
- *
- * Callback function registered with IPA that is called when IPA wants
- * to access the WLAN consumer resource
- *
- * Return: 0 if the request is granted, negative errno otherwise
- */
-static int hdd_ipa_rm_cons_request(void)
-{
- int ret = 0;
-
- if (ghdd_ipa->resource_loading) {
- HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
- "IPA resource loading in progress");
- ghdd_ipa->pending_cons_req = true;
- ret = -EINPROGRESS;
- } else if (ghdd_ipa->resource_unloading) {
- HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
- "IPA resource unloading in progress");
- ghdd_ipa->pending_cons_req = true;
- ret = -EPERM;
- }
-
- return ret;
-}
-
-/**
* __hdd_ipa_set_perf_level() - Set IPA performance level
* @hdd_ctx: Global HDD context
* @tx_packets: Number of packets transmitted in the last sample period
@@ -3946,146 +4296,6 @@
return ret;
}
-/**
- * hdd_ipa_init_uc_rm_work - init ipa uc resource manager work
- * @work: struct work_struct
- * @work_handler: work_handler
- *
- * Return: none
- */
-static void hdd_ipa_init_uc_rm_work(struct work_struct *work,
- work_func_t work_handler)
-{
- INIT_WORK(work, work_handler);
-}
-
-/**
- * hdd_ipa_setup_rm() - Setup IPA resource management
- * @hdd_ipa: Global HDD IPA context
- *
- * Return: 0 on success, negative errno on error
- */
-static int hdd_ipa_setup_rm(struct hdd_ipa_priv *hdd_ipa)
-{
- qdf_ipa_rm_create_params_t create_params = { 0 };
- int ret;
-
- if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
- return 0;
-
- hdd_ipa_init_uc_rm_work(&hdd_ipa->uc_rm_work.work,
- hdd_ipa_uc_rm_notify_defer);
- memset(&create_params, 0, sizeof(create_params));
- QDF_IPA_RM_CREATE_PARAMS_NAME(&create_params) =
- IPA_RM_RESOURCE_WLAN_PROD;
- QDF_IPA_RM_CREATE_PARAMS_USER_DATA(&create_params) =
- hdd_ipa;
- QDF_IPA_RM_CREATE_PARAMS_NOTIFY_CB(&create_params) =
- hdd_ipa_rm_notify;
- QDF_IPA_RM_CREATE_PARAMS_FLOOR_VOLTAGE(&create_params) =
- IPA_VOLTAGE_SVS;
-
- ret = qdf_ipa_rm_create_resource(&create_params);
- if (ret) {
- HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
- "Create RM resource failed: %d", ret);
- goto setup_rm_fail;
- }
-
- memset(&create_params, 0, sizeof(create_params));
- QDF_IPA_RM_CREATE_PARAMS_NAME(&create_params) =
- IPA_RM_RESOURCE_WLAN_CONS;
- QDF_IPA_RM_CREATE_PARAMS_REQUEST_RESOURCE(&create_params) =
- hdd_ipa_rm_cons_request;
- QDF_IPA_RM_CREATE_PARAMS_RELEASE_RESOURCE(&create_params) =
- hdd_ipa_rm_cons_release;
- QDF_IPA_RM_CREATE_PARAMS_FLOOR_VOLTAGE(&create_params) =
- IPA_VOLTAGE_SVS;
-
- ret = qdf_ipa_rm_create_resource(&create_params);
- if (ret) {
- HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
- "Create RM CONS resource failed: %d", ret);
- goto delete_prod;
- }
-
- ipa_rm_add_dependency(IPA_RM_RESOURCE_WLAN_PROD,
- IPA_RM_RESOURCE_APPS_CONS);
-
- ret = qdf_ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_WLAN_PROD,
- HDD_IPA_RX_INACTIVITY_MSEC_DELAY);
- if (ret) {
- HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Timer init failed: %d",
- ret);
- goto timer_init_failed;
- }
-
- /* Set the lowest bandwidth to start with */
- ret = hdd_ipa_set_perf_level(hdd_ipa->hdd_ctx, 0, 0);
-
- if (ret) {
- HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
- "Set perf level failed: %d", ret);
- goto set_perf_failed;
- }
-
- qdf_wake_lock_create(&hdd_ipa->wake_lock, "wlan_ipa");
- INIT_DELAYED_WORK(&hdd_ipa->wake_lock_work,
- hdd_ipa_wake_lock_timer_func);
- qdf_spinlock_create(&hdd_ipa->rm_lock);
- hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
- hdd_ipa->wake_lock_released = true;
- atomic_set(&hdd_ipa->tx_ref_cnt, 0);
-
- return ret;
-
-set_perf_failed:
- ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
-
-timer_init_failed:
- ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
-
-delete_prod:
- ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
-
-setup_rm_fail:
- return ret;
-}
-
-/**
- * hdd_ipa_destroy_rm_resource() - Destroy IPA resources
- * @hdd_ipa: Global HDD IPA context
- *
- * Destroys all resources associated with the IPA resource manager
- *
- * Return: None
- */
-static void hdd_ipa_destroy_rm_resource(struct hdd_ipa_priv *hdd_ipa)
-{
- int ret;
-
- if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
- return;
-
- cancel_delayed_work_sync(&hdd_ipa->wake_lock_work);
- qdf_wake_lock_destroy(&hdd_ipa->wake_lock);
-
- cancel_work_sync(&hdd_ipa->uc_rm_work.work);
- qdf_spinlock_destroy(&hdd_ipa->rm_lock);
-
- ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
-
- ret = qdf_ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
- if (ret)
- HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
- "RM PROD resource delete failed %d", ret);
-
- ret = qdf_ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
- if (ret)
- HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
- "RM CONS resource delete failed %d", ret);
-}
-
#ifdef QCA_CONFIG_SMP
static int hdd_ipa_aggregated_rx_ind(qdf_nbuf_t skb)
{
@@ -4450,7 +4660,7 @@
atomic_dec(&hdd_ipa->tx_ref_cnt);
- hdd_ipa_rm_try_release(hdd_ipa);
+ hdd_ipa_wdi_rm_try_release(hdd_ipa);
}
/**
@@ -4476,7 +4686,7 @@
ipa_free_skb(ipa_tx_desc);
iface_context->stats.num_tx_drop++;
qdf_spin_unlock_bh(&iface_context->interface_lock);
- hdd_ipa_rm_try_release(hdd_ipa);
+ hdd_ipa_wdi_rm_try_release(hdd_ipa);
return;
}
@@ -4490,7 +4700,7 @@
ipa_free_skb(ipa_tx_desc);
qdf_spin_unlock_bh(&iface_context->interface_lock);
iface_context->stats.num_tx_cac_drop++;
- hdd_ipa_rm_try_release(hdd_ipa);
+ hdd_ipa_wdi_rm_try_release(hdd_ipa);
return;
}
}
@@ -4530,7 +4740,7 @@
hdd_ipa->stats.num_tx_desc_error++;
qdf_spin_unlock_bh(&hdd_ipa->q_lock);
ipa_free_skb(ipa_tx_desc);
- hdd_ipa_rm_try_release(hdd_ipa);
+ hdd_ipa_wdi_rm_try_release(hdd_ipa);
return;
}
@@ -4677,7 +4887,7 @@
* workaround to request PROD resource while data is going over CONS
* pipe to prevent the IPA hardware clockdown.
*/
- hdd_ipa_rm_request(hdd_ipa);
+ hdd_ipa_wdi_rm_request(hdd_ipa);
qdf_spin_lock_bh(&hdd_ipa->pm_lock);
/*
@@ -4913,8 +5123,9 @@
if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
ipa->keep_ipa_awake = 1;
- ret = qdf_ipa_setup_sys_pipe(ipa,
- &hdd_ipa->sys_pipe[i].conn_hdl);
+ ret = hdd_ipa_wdi_setup_sys_pipe(
+ hdd_ipa, ipa,
+ &hdd_ipa->sys_pipe[i].conn_hdl);
if (ret) {
HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
"Failed for pipe %d ret: %d", i, ret);
@@ -4978,11 +5189,11 @@
if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
ipa->keep_ipa_awake = 1;
- ret = qdf_ipa_setup_sys_pipe(ipa,
+ ret = hdd_ipa_wdi_setup_sys_pipe(hdd_ipa, ipa,
&hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].conn_hdl);
if (ret) {
HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
- "Failed for RX pipe: %d", ret);
+ "Failed for RX pipe: %d", ret);
return ret;
}
hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].conn_hdl_valid = 1;
@@ -5040,8 +5251,8 @@
for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
if (hdd_ipa->sys_pipe[i].conn_hdl_valid)
- qdf_ipa_teardown_sys_pipe(
- hdd_ipa->sys_pipe[i].conn_hdl);
+ hdd_ipa_wdi_teardown_sys_pipe(
+ hdd_ipa, hdd_ipa->sys_pipe[i].conn_hdl);
qdf_mem_zero(&hdd_ipa->sys_pipe[i],
sizeof(struct hdd_ipa_sys_pipe));
}
@@ -5064,8 +5275,8 @@
for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
if (hdd_ipa->sys_pipe[i].conn_hdl_valid) {
- ret = qdf_ipa_teardown_sys_pipe(
- hdd_ipa->sys_pipe[i].conn_hdl);
+ ret = hdd_ipa_wdi_teardown_sys_pipe(
+ hdd_ipa, hdd_ipa->sys_pipe[i].conn_hdl);
if (ret)
HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed: %d",
ret);
@@ -5148,6 +5359,7 @@
void *soc = cds_get_context(QDF_MODULE_ID_SOC);
struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
void *tl_context = NULL;
+ uint8_t iface_id;
int i, ret = 0;
HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter");
@@ -5177,6 +5389,7 @@
adapter->ipa_context = iface_context;
iface_context->adapter = adapter;
iface_context->sta_id = sta_id;
+ iface_id = iface_context->iface_id;
tl_context = (void *)cdp_peer_get_vdev_by_sta_id(
soc, (struct cdp_pdev *)pdev, sta_id);
if (tl_context == NULL) {
@@ -5194,8 +5407,11 @@
iface_context->cons_client,
adapter->session_id,
hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx));
- if (ret)
+ if (ret) {
+ HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
+ "IPA interface setup failed: ret=%d", ret);
goto end;
+ }
hdd_ipa->num_iface++;
@@ -5688,7 +5904,7 @@
memcpy(msg_ex->attribs[0].u.mac_addr, mac_addr,
IPA_MAC_ADDR_SIZE);
- ret = ipa_send_msg(&meta, msg_ex, hdd_ipa_msg_free_fn);
+ ret = qdf_ipa_send_msg(&meta, msg_ex, hdd_ipa_msg_free_fn);
if (ret) {
HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Evt: %d : %d",
@@ -5774,7 +5990,7 @@
QDF_IPA_WLAN_MSG_NAME(msg),
QDF_IPA_MSG_META_MSG_TYPE(&meta));
- ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
+ ret = qdf_ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
if (ret) {
hdd_err("%s: Evt: %d fail:%d",
@@ -5891,7 +6107,7 @@
int ret, i;
struct hdd_ipa_iface_context *iface_context = NULL;
struct ol_txrx_pdev_t *pdev = NULL;
- qdf_ipa_rm_perf_profile_t profile;
+ void *soc = cds_get_context(QDF_MODULE_ID_SOC);
if (!hdd_ipa_is_enabled(hdd_ctx))
return QDF_STATUS_SUCCESS;
@@ -5915,6 +6131,8 @@
hdd_ipa->hdd_ctx = hdd_ctx;
hdd_ipa->num_iface = 0;
+ hdd_ipa_wdi_get_wdi_version(hdd_ipa);
+
/* Create the interface context */
for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
iface_context = &hdd_ipa->iface_context[i];
@@ -5936,7 +6154,7 @@
qdf_mutex_create(&hdd_ipa->event_lock);
qdf_mutex_create(&hdd_ipa->ipa_lock);
- ret = hdd_ipa_setup_rm(hdd_ipa);
+ ret = hdd_ipa_wdi_setup_rm(hdd_ipa);
if (ret)
goto fail_setup_rm;
@@ -5963,8 +6181,15 @@
if (ret)
goto fail_create_sys_pipe;
}
- if (hdd_ipa_uc_register_uc_ready(hdd_ipa))
+
+ ret = hdd_ipa_wdi_init(hdd_ipa);
+ if (ret) {
+ HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
+ "IPA WDI init failed: ret=%d", ret);
+ if (ret == -EACCES)
+ ret = hdd_ipa_uc_send_wdi_control_msg(false);
goto fail_create_sys_pipe;
+ }
} else {
ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
if (ret)
@@ -5973,19 +6198,18 @@
/* When IPA clock scaling is disabled, initialze maximum clock */
if (!hdd_ipa_is_clk_scaling_enabled(hdd_ctx)) {
- profile.max_supported_bandwidth_mbps = 800;
hdd_debug("IPA clock scaling is disabled.");
hdd_debug("Set initial CONS/PROD perf: %d",
- profile.max_supported_bandwidth_mbps);
- ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_CONS,
- &profile);
+ HDD_IPA_MAX_BANDWIDTH);
+ ret = cdp_ipa_set_perf_level(soc, IPA_RM_RESOURCE_WLAN_CONS,
+ HDD_IPA_MAX_BANDWIDTH);
if (ret) {
hdd_err("RM CONS set perf profile failed: %d", ret);
goto fail_create_sys_pipe;
}
- ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_PROD,
- &profile);
+ ret = cdp_ipa_set_perf_level(soc, IPA_RM_RESOURCE_WLAN_PROD,
+ HDD_IPA_MAX_BANDWIDTH);
if (ret) {
hdd_err("RM PROD set perf profile failed: %d", ret);
goto fail_create_sys_pipe;
@@ -5998,7 +6222,7 @@
return QDF_STATUS_SUCCESS;
fail_create_sys_pipe:
- hdd_ipa_destroy_rm_resource(hdd_ipa);
+ hdd_ipa_wdi_destroy_rm(hdd_ipa);
fail_setup_rm:
qdf_spinlock_destroy(&hdd_ipa->pm_lock);
qdf_mem_free(hdd_ipa);
@@ -6086,7 +6310,7 @@
if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
hdd_ipa_teardown_sys_pipe(hdd_ipa);
- hdd_ipa_destroy_rm_resource(hdd_ipa);
+ hdd_ipa_wdi_destroy_rm(hdd_ipa);
__hdd_ipa_flush(hdd_ctx);
@@ -6100,9 +6324,7 @@
}
if (hdd_ipa_uc_is_enabled(hdd_ctx)) {
- if (ipa_uc_dereg_rdyCB())
- HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
- "UC Ready CB deregister fail");
+ hdd_ipa_wdi_cleanup();
hdd_ipa_uc_rt_debug_deinit(hdd_ctx);
qdf_mutex_destroy(&hdd_ipa->event_lock);
qdf_mutex_destroy(&hdd_ipa->ipa_lock);