qcacld-3.0: Add interface to WDI-stats and quota limit

Add structure changes for querying WDI-stats, register the callback
functions for IPA to query WDI stats and sets the quota limit

Change-Id: I05d9d50fad735fa0a57c4de23c81461f6e12b648
CRs-Fixed: 1095710
This commit is contained in:
Yun Park 2016-10-05 10:51:33 -07:00 • committed by Sandeep Puligilla
commit 637d6486f2
8 changed files with 641 additions and 35 deletions

6
Kbuild
View file

@ -119,6 +119,7 @@ ifeq ($(KERNEL_BUILD), 0)
endif
ifeq ($(CONFIG_ARCH_MSM8998), y)
CONFIG_QCACLD_FEATURE_GREEN_AP := y
CONFIG_QCACLD_FEATURE_METERING := y
endif
ifeq ($(CONFIG_ARCH_SDM660), y)
@ -1903,6 +1904,11 @@ ifeq ($(CONFIG_QCACLD_FEATURE_GREEN_AP),y)
CDEFINES += -DFEATURE_GREEN_AP
endif
#Stats & Quota Metering feature
ifeq ($(CONFIG_QCACLD_FEATURE_METERING),y)
CDEFINES += -DFEATURE_METERING
endif
#Enable RX Full re-order OL feature only "LL and NON-MDM9630 platform"
ifneq ($(CONFIG_ARCH_MDM9630), y)
ifeq ($(CONFIG_HIF_PCI), 1)

View file

@ -1330,4 +1330,143 @@ int htt_h2t_ipa_uc_get_stats(struct htt_pdev_t *pdev)
HTT_SEND_HTC_PKT(pdev, pkt);
return A_OK;
}
/**
* htt_h2t_ipa_uc_get_share_stats() - WDI UC wifi sharing state request to FW
* @pdev: handle to the HTT instance
*
* Return: A_OK success
* A_NO_MEMORY No memory fail
*/
int htt_h2t_ipa_uc_get_share_stats(struct htt_pdev_t *pdev, uint8_t reset_stats)
{
struct htt_htc_pkt *pkt;
qdf_nbuf_t msg;
uint32_t *msg_word;
pkt = htt_htc_pkt_alloc(pdev);
if (!pkt)
return -A_NO_MEMORY;
/* show that this is not a tx frame download
* (not required, but helpful)
*/
pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID;
pkt->pdev_ctxt = NULL; /* not used during send-done callback */
/* reserve room for HTC header */
msg = qdf_nbuf_alloc(pdev->osdev,
HTT_MSG_BUF_SIZE(HTT_WDI_IPA_OP_REQUEST_SZ)+
HTT_MSG_BUF_SIZE(HTT_WDI_IPA_OP_REQ_GET_SHARING_STATS_SZ),
HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, false);
if (!msg) {
htt_htc_pkt_free(pdev, pkt);
return -A_NO_MEMORY;
}
/* set the length of the message */
qdf_nbuf_put_tail(msg, HTT_WDI_IPA_OP_REQUEST_SZ+
HTT_WDI_IPA_OP_REQ_GET_SHARING_STATS_SZ);
/* fill in the message contents */
msg_word = (uint32_t *) qdf_nbuf_data(msg);
/* rewind beyond alignment pad to get to the HTC header reserved area */
qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING);
*msg_word = 0;
HTT_WDI_IPA_OP_REQUEST_OP_CODE_SET(*msg_word,
HTT_WDI_IPA_OPCODE_GET_SHARING_STATS);
HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_WDI_IPA_OP_REQ);
msg_word++;
*msg_word = 0;
HTT_WDI_IPA_OP_REQ_GET_SHARING_STATS_RESET_STATS_SET(*msg_word,
reset_stats);
SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt,
htt_h2t_send_complete_free_netbuf,
qdf_nbuf_data(msg),
qdf_nbuf_len(msg),
pdev->htc_tx_endpoint,
1); /* tag - not relevant here */
SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg);
HTT_SEND_HTC_PKT(pdev, pkt);
return A_OK;
}
/**
* htt_h2t_ipa_uc_set_quota() - WDI UC state query request to firmware
* @pdev: handle to the HTT instance
*
* Return: A_OK success
* A_NO_MEMORY No memory fail
*/
int htt_h2t_ipa_uc_set_quota(struct htt_pdev_t *pdev, uint64_t quota_bytes)
{
struct htt_htc_pkt *pkt;
qdf_nbuf_t msg;
uint32_t *msg_word;
pkt = htt_htc_pkt_alloc(pdev);
if (!pkt)
return -A_NO_MEMORY;
/* show that this is not a tx frame download
* (not required, but helpful)
*/
pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID;
pkt->pdev_ctxt = NULL; /* not used during send-done callback */
/* reserve room for HTC header */
msg = qdf_nbuf_alloc(pdev->osdev,
HTT_MSG_BUF_SIZE(HTT_WDI_IPA_OP_REQUEST_SZ)+
HTT_MSG_BUF_SIZE(HTT_WDI_IPA_OP_REQ_SET_QUOTA_SZ),
HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, false);
if (!msg) {
htt_htc_pkt_free(pdev, pkt);
return -A_NO_MEMORY;
}
/* set the length of the message */
qdf_nbuf_put_tail(msg, HTT_WDI_IPA_OP_REQUEST_SZ+
HTT_WDI_IPA_OP_REQ_SET_QUOTA_SZ);
/* fill in the message contents */
msg_word = (uint32_t *) qdf_nbuf_data(msg);
/* rewind beyond alignment pad to get to the HTC header reserved area */
qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING);
*msg_word = 0;
HTT_WDI_IPA_OP_REQUEST_OP_CODE_SET(*msg_word,
HTT_WDI_IPA_OPCODE_SET_QUOTA);
HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_WDI_IPA_OP_REQ);
msg_word++;
*msg_word = 0;
HTT_WDI_IPA_OP_REQ_SET_QUOTA_SET_QUOTA_SET(*msg_word, quota_bytes > 0);
msg_word++;
*msg_word = 0;
HTT_WDI_IPA_OP_REQ_SET_QUOTA_QUOTA_LO_SET(*msg_word,
(uint32_t)(quota_bytes &
HTT_WDI_IPA_OP_REQ_SET_QUOTA_QUOTA_LO_M));
msg_word++;
*msg_word = 0;
HTT_WDI_IPA_OP_REQ_SET_QUOTA_QUOTA_HI_SET(*msg_word,
(uint32_t)(quota_bytes>>32 &
HTT_WDI_IPA_OP_REQ_SET_QUOTA_QUOTA_HI_M));
SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt,
htt_h2t_send_complete_free_netbuf,
qdf_nbuf_data(msg),
qdf_nbuf_len(msg),
pdev->htc_tx_endpoint,
1); /* tag - not relevant here */
SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg);
HTT_SEND_HTC_PKT(pdev, pkt);
return A_OK;
}
#endif /* IPA_OFFLOAD */

View file

@ -243,6 +243,11 @@ htt_h2t_ipa_uc_set_active(struct htt_pdev_t *pdev, bool uc_active, bool is_tx);
int htt_h2t_ipa_uc_get_stats(struct htt_pdev_t *pdev);
int htt_h2t_ipa_uc_get_share_stats(struct htt_pdev_t *pdev,
uint8_t reset_stats);
int htt_h2t_ipa_uc_set_quota(struct htt_pdev_t *pdev, uint64_t quota_bytes);
int htt_ipa_uc_attach(struct htt_pdev_t *pdev);
void htt_ipa_uc_detach(struct htt_pdev_t *pdev);
@ -340,6 +345,30 @@ static inline int htt_h2t_ipa_uc_get_stats(struct htt_pdev_t *pdev)
return 0;
}
/**
* htt_h2t_ipa_uc_get_share_stats() - WDI UC wifi sharing state request to FW
* @pdev: handle to the HTT instance
*
* Return: 0 success
*/
static inline int htt_h2t_ipa_uc_get_share_stats(struct htt_pdev_t *pdev,
uint8_t reset_stats)
{
return 0;
}
/**
* htt_h2t_ipa_uc_set_quota() - WDI UC set quota request to firmware
* @pdev: handle to the HTT instance
*
* Return: 0 success
*/
static inline int htt_h2t_ipa_uc_set_quota(struct htt_pdev_t *pdev,
uint64_t quota_bytes)
{
return 0;
}
/**
* htt_ipa_uc_attach() - Allocate UC data path resources
* @pdev: handle to the HTT instance

View file

@ -4368,6 +4368,20 @@ static void ol_txrx_ipa_uc_get_stat(struct cdp_pdev *ppdev)
struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev;
htt_h2t_ipa_uc_get_stats(pdev->htt_pdev);
}
static void ol_txrx_ipa_uc_get_share_stats(struct cdp_pdev *ppdev,
uint8_t reset_stats)
{
struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev;
htt_h2t_ipa_uc_get_share_stats(pdev->htt_pdev, reset_stats);
}
static void ol_txrx_ipa_uc_set_quota(struct cdp_pdev *ppdev,
uint64_t quota_bytes)
{
struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev;
htt_h2t_ipa_uc_set_quota(pdev->htt_pdev, quota_bytes);
}
#endif /* IPA_UC_OFFLOAD */
/*
@ -5357,7 +5371,9 @@ static struct cdp_ipa_ops ol_ops_ipa = {
.ipa_register_op_cb = ol_txrx_ipa_uc_register_op_cb,
.ipa_get_stat = ol_txrx_ipa_uc_get_stat,
.ipa_tx_data_frame = ol_tx_send_ipa_data_frame,
.ipa_set_uc_tx_partition_base = ol_cfg_set_ipa_uc_tx_partition_base
.ipa_set_uc_tx_partition_base = ol_cfg_set_ipa_uc_tx_partition_base,
.ipa_uc_get_share_stats = ol_txrx_ipa_uc_get_share_stats,
.ipa_uc_set_quota = ol_txrx_ipa_uc_set_quota
#endif /* IPA_OFFLOAD */
};

View file

@ -98,6 +98,10 @@ void hdd_ipa_uc_stat_query(hdd_context_t *hdd_ctx, uint32_t *ipa_tx_diff,
uint32_t *ipa_rx_diff);
void hdd_ipa_uc_rt_debug_host_dump(hdd_context_t *hdd_ctx);
void hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason);
void hdd_ipa_uc_sharing_stats_request(hdd_adapter_t *adapter,
uint8_t reset_stats);
void hdd_ipa_uc_set_quota(hdd_adapter_t *adapter, uint8_t set_quota,
uint64_t quota_bytes);
bool hdd_ipa_is_enabled(hdd_context_t *pHddCtx);
bool hdd_ipa_uc_is_enabled(hdd_context_t *pHddCtx);
#ifndef QCA_LL_TX_FLOW_CONTROL_V2

View file

@ -97,6 +97,11 @@ enum hdd_ipa_uc_op_code {
HDD_IPA_UC_OPCODE_RX_SUSPEND = 2,
HDD_IPA_UC_OPCODE_RX_RESUME = 3,
HDD_IPA_UC_OPCODE_STATS = 4,
#ifdef FEATURE_METERING
HDD_IPA_UC_OPCODE_SHARING_STATS = 5,
HDD_IPA_UC_OPCODE_QUOTA_RSP = 6,
HDD_IPA_UC_OPCODE_QUOTA_IND = 7,
#endif
HDD_IPA_UC_OPCODE_UC_READY = 8,
/* keep this last */
HDD_IPA_UC_OPCODE_MAX
@ -375,6 +380,30 @@ struct uc_rt_debug_info {
uint64_t rx_destructor_call;
};
#ifdef FEATURE_METERING
struct ipa_uc_sharing_stats {
uint64_t ipv4_rx_packets;
uint64_t ipv4_rx_bytes;
uint64_t ipv6_rx_packets;
uint64_t ipv6_rx_bytes;
uint64_t ipv4_tx_packets;
uint64_t ipv4_tx_bytes;
uint64_t ipv6_tx_packets;
uint64_t ipv6_tx_bytes;
};
struct ipa_uc_quota_rsp {
uint8_t success;
uint8_t reserved[3];
uint32_t quota_lo; /* quota limit low bytes */
uint32_t quota_hi; /* quota limit high bytes */
};
struct ipa_uc_quota_ind {
uint64_t quota_bytes; /* quota limit in bytes */
};
#endif
struct hdd_ipa_priv {
struct hdd_ipa_sys_pipe sys_pipe[HDD_IPA_MAX_SYSBAM_PIPE];
struct hdd_ipa_iface_context iface_context[HDD_IPA_MAX_IFACE];
@ -454,9 +483,15 @@ struct hdd_ipa_priv {
/* IPA UC doorbell registers paddr */
qdf_dma_addr_t tx_comp_doorbell_paddr;
qdf_dma_addr_t rx_ready_doorbell_paddr;
uint8_t vdev_to_iface[CSR_ROAM_SESSION_MAX];
bool vdev_offload_enabled[CSR_ROAM_SESSION_MAX];
#ifdef FEATURE_METERING
struct ipa_uc_sharing_stats ipa_sharing_stats;
struct ipa_uc_quota_rsp ipa_quota_rsp;
struct ipa_uc_quota_ind ipa_quota_ind;
struct completion ipa_uc_sharing_stats_comp;
struct completion ipa_uc_set_quota_comp;
#endif
};
/**
@ -596,6 +631,11 @@ static struct hdd_ipa_tx_hdr ipa_tx_hdr = {
}
};
#ifdef FEATURE_METERING
#define IPA_UC_SHARING_STATES_WAIT_TIME 500
#define IPA_UC_SET_QUOTA_WAIT_TIME 500
#endif
static struct hdd_ipa_priv *ghdd_ipa;
/* Local Function Prototypes */
@ -802,20 +842,13 @@ static inline bool hdd_ipa_uc_sta_is_enabled(hdd_context_t *hdd_ctx)
*
* Return: None
*/
#ifdef IPA_UC_STA_OFFLOAD
static inline void hdd_ipa_uc_sta_reset_sta_connected(
struct hdd_ipa_priv *hdd_ipa)
{
vos_lock_acquire(&hdd_ipa->event_lock);
qdf_mutex_acquire(&hdd_ipa->ipa_lock);
hdd_ipa->sta_connected = 0;
vos_lock_release(&hdd_ipa->event_lock);
qdf_mutex_release(&hdd_ipa->ipa_lock);
}
#else
static inline void hdd_ipa_uc_sta_reset_sta_connected(
struct hdd_ipa_priv *hdd_ipa)
{
}
#endif
/**
* hdd_ipa_is_pre_filter_enabled() - Is IPA pre-filter enabled?
@ -1019,7 +1052,8 @@ static void hdd_ipa_uc_rt_debug_handler(void *ctext)
if (!dummy_ptr) {
hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
hdd_ipa_uc_stat_request(
hdd_get_adapter(hdd_ctx, QDF_SAP_MODE), 1);
hdd_get_adapter(hdd_ctx, QDF_SAP_MODE),
HDD_IPA_UC_STAT_REASON_DEBUG);
} else {
kfree(dummy_ptr);
}
@ -1735,9 +1769,8 @@ static void __hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason)
hdd_context_t *hdd_ctx;
struct hdd_ipa_priv *hdd_ipa;
if (!adapter) {
if (!adapter)
return;
}
hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
@ -1755,12 +1788,14 @@ static void __hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason)
if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
(false == hdd_ipa->resource_loading)) {
hdd_ipa->stat_req_reason = reason;
qdf_mutex_release(&hdd_ipa->ipa_lock);
wma_cli_set_command(
(int)adapter->sessionId,
(int)WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID,
0, VDEV_CMD);
} else {
qdf_mutex_release(&hdd_ipa->ipa_lock);
}
qdf_mutex_release(&hdd_ipa->ipa_lock);
}
/**
@ -1777,6 +1812,85 @@ void hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason)
cds_ssr_unprotect(__func__);
}
#ifdef FEATURE_METERING
/**
* hdd_ipa_uc_sharing_stats_request() - Get IPA stats from IPA.
* @adapter: network adapter
* @reset_stats: reset stat countis after response
*
* Return: None
*/
void hdd_ipa_uc_sharing_stats_request(hdd_adapter_t *adapter,
uint8_t reset_stats)
{
hdd_context_t *pHddCtx;
struct hdd_ipa_priv *hdd_ipa;
if (!adapter)
return;
pHddCtx = adapter->pHddCtx;
hdd_ipa = pHddCtx->hdd_ipa;
if (!hdd_ipa_is_enabled(pHddCtx) ||
!(hdd_ipa_uc_is_enabled(pHddCtx))) {
return;
}
HDD_IPA_LOG(LOG1, "SHARING_STATS: reset_stats=%d", reset_stats);
qdf_mutex_acquire(&hdd_ipa->ipa_lock);
if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
(false == hdd_ipa->resource_loading)) {
qdf_mutex_release(&hdd_ipa->ipa_lock);
wma_cli_set_command(
(int)adapter->sessionId,
(int)WMA_VDEV_TXRX_GET_IPA_UC_SHARING_STATS_CMDID,
reset_stats, VDEV_CMD);
} else {
qdf_mutex_release(&hdd_ipa->ipa_lock);
}
}
/**
* hdd_ipa_uc_set_quota() - Set quota limit bytes from IPA.
* @adapter: network adapter
* @set_quota: when 1, FW starts quota monitoring
* @quota_bytes: quota limit in bytes
*
* Return: None
*/
void hdd_ipa_uc_set_quota(hdd_adapter_t *adapter, uint8_t set_quota,
uint64_t quota_bytes)
{
hdd_context_t *pHddCtx;
struct hdd_ipa_priv *hdd_ipa;
if (!adapter)
return;
pHddCtx = adapter->pHddCtx;
hdd_ipa = pHddCtx->hdd_ipa;
if (!hdd_ipa_is_enabled(pHddCtx) ||
!(hdd_ipa_uc_is_enabled(pHddCtx))) {
return;
}
HDD_IPA_LOG(LOG1, "SET_QUOTA: set_quota=%d, quota_bytes=%llu",
set_quota, quota_bytes);
qdf_mutex_acquire(&hdd_ipa->ipa_lock);
if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
(false == hdd_ipa->resource_loading)) {
qdf_mutex_release(&hdd_ipa->ipa_lock);
wma_cli_set_command(
(int)adapter->sessionId,
(int)WMA_VDEV_TXRX_SET_IPA_UC_QUOTA_CMDID,
(set_quota ? quota_bytes : 0), VDEV_CMD);
} else {
qdf_mutex_release(&hdd_ipa->ipa_lock);
}
}
#endif
/**
* hdd_ipa_uc_find_add_assoc_sta() - Find associated station
* @hdd_ipa: Global HDD IPA context
@ -2139,6 +2253,97 @@ static void hdd_ipa_uc_loaded_handler(struct hdd_ipa_priv *ipa_ctxt)
}
}
/**
* hdd_ipa_uc_op_metering() - IPA uC operation for stats and quota limit
* @hdd_ctx: Global HDD context
* @op_msg: operation message received from firmware
*
* Return: QDF_STATUS enumeration
*/
#ifdef FEATURE_METERING
static QDF_STATUS hdd_ipa_uc_op_metering(hdd_context_t *hdd_ctx,
struct op_msg_type *op_msg)
{
struct op_msg_type *msg = op_msg;
struct ipa_uc_sharing_stats *uc_sharing_stats;
struct ipa_uc_quota_rsp *uc_quota_rsp;
struct ipa_uc_quota_ind *uc_quota_ind;
struct hdd_ipa_priv *hdd_ipa;
hdd_adapter_t *adapter;
hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
if (HDD_IPA_UC_OPCODE_SHARING_STATS == msg->op_code) {
/* fill-up ipa_uc_sharing_stats structure from FW */
uc_sharing_stats = (struct ipa_uc_sharing_stats *)
((uint8_t *)op_msg + sizeof(struct op_msg_type));
memcpy(&(hdd_ipa->ipa_sharing_stats), uc_sharing_stats,
sizeof(struct ipa_uc_sharing_stats));
complete(&hdd_ipa->ipa_uc_sharing_stats_comp);
HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
"%s: %llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu",
"HDD_IPA_UC_OPCODE_SHARING_STATS",
hdd_ipa->ipa_sharing_stats.ipv4_rx_packets,
hdd_ipa->ipa_sharing_stats.ipv4_rx_bytes,
hdd_ipa->ipa_sharing_stats.ipv6_rx_packets,
hdd_ipa->ipa_sharing_stats.ipv6_rx_bytes,
hdd_ipa->ipa_sharing_stats.ipv4_tx_packets,
hdd_ipa->ipa_sharing_stats.ipv4_tx_bytes,
hdd_ipa->ipa_sharing_stats.ipv6_tx_packets,
hdd_ipa->ipa_sharing_stats.ipv6_tx_bytes);
} else if (HDD_IPA_UC_OPCODE_QUOTA_RSP == msg->op_code) {
/* received set quota response */
uc_quota_rsp = (struct ipa_uc_quota_rsp *)
((uint8_t *)op_msg + sizeof(struct op_msg_type));
memcpy(&(hdd_ipa->ipa_quota_rsp), uc_quota_rsp,
sizeof(struct ipa_uc_quota_rsp));
complete(&hdd_ipa->ipa_uc_set_quota_comp);
HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
"%s: success=%d, quota_bytes=%llu",
"HDD_IPA_UC_OPCODE_QUOTA_RSP",
hdd_ipa->ipa_quota_rsp.success,
((uint64_t)(hdd_ipa->ipa_quota_rsp.quota_hi)<<32)|
hdd_ipa->ipa_quota_rsp.quota_lo);
} else if (HDD_IPA_UC_OPCODE_QUOTA_IND == msg->op_code) {
/* hit quota limit */
uc_quota_ind = (struct ipa_uc_quota_ind *)
((uint8_t *)op_msg + sizeof(struct op_msg_type));
hdd_ipa->ipa_quota_ind.quota_bytes =
uc_quota_ind->quota_bytes;
/* send quota exceeded indication to IPA */
HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
"OPCODE_QUOTA_IND: quota exceed! (quota_bytes=%llu)",
hdd_ipa->ipa_quota_ind.quota_bytes);
adapter = hdd_get_adapter(hdd_ipa->hdd_ctx, QDF_STA_MODE);
if (adapter)
ipa_broadcast_wdi_quota_reach_ind(
adapter->dev->ifindex,
uc_quota_ind->quota_bytes);
else
HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
"Failed quota_reach_ind: NULL adapter");
} else {
return QDF_STATUS_E_INVAL;
}
return QDF_STATUS_SUCCESS;
}
#else
static QDF_STATUS hdd_ipa_uc_op_metering(hdd_context_t *hdd_ctx,
struct op_msg_type *op_msg)
{
return QDF_STATUS_E_INVAL;
}
#endif
/**
* hdd_ipa_uc_op_cb() - IPA uC operation callback
* @op_msg: operation message received from firmware
@ -2426,9 +2631,9 @@ static void hdd_ipa_uc_op_cb(struct op_msg_type *op_msg, void *usr_ctxt)
qdf_mutex_acquire(&hdd_ipa->ipa_lock);
hdd_ipa_uc_loaded_handler(hdd_ipa);
qdf_mutex_release(&hdd_ipa->ipa_lock);
} else {
HDD_IPA_LOG(LOGE, "INVALID REASON %d",
hdd_ipa->stat_req_reason);
} else if (hdd_ipa_uc_op_metering(hdd_ctx, op_msg)) {
HDD_IPA_LOG(LOGE, "Invalid message: op_code=%d, reason=%d",
msg->op_code, hdd_ipa->stat_req_reason);
}
qdf_mem_free(op_msg);
}
@ -2583,11 +2788,165 @@ end:
* Return: none
*/
static void hdd_ipa_init_uc_op_work(struct work_struct *work,
work_func_t work_handler)
work_func_t work_handler)
{
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(enum ipa_wdi_meter_evt_type evt,
void *data)
{
struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
hdd_adapter_t *adapter = NULL;
struct ipa_get_wdi_sap_stats *wdi_sap_stats;
struct ipa_set_wifi_quota *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");
wdi_sap_stats->stats_valid = 0;
return;
}
INIT_COMPLETION(hdd_ipa->ipa_uc_sharing_stats_comp);
INIT_COMPLETION(hdd_ipa->ipa_uc_set_quota_comp);
hdd_ipa_uc_sharing_stats_request(adapter,
wdi_sap_stats->reset_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");
wdi_sap_stats->stats_valid = 0;
} else {
wdi_sap_stats->stats_valid = 1;
wdi_sap_stats->ipv4_rx_packets =
hdd_ipa->ipa_sharing_stats.ipv4_rx_packets;
wdi_sap_stats->ipv4_rx_bytes =
hdd_ipa->ipa_sharing_stats.ipv4_rx_bytes;
wdi_sap_stats->ipv6_rx_packets =
hdd_ipa->ipa_sharing_stats.ipv6_rx_packets;
wdi_sap_stats->ipv6_rx_bytes =
hdd_ipa->ipa_sharing_stats.ipv6_rx_bytes;
wdi_sap_stats->ipv4_tx_packets =
hdd_ipa->ipa_sharing_stats.ipv4_tx_packets;
wdi_sap_stats->ipv4_tx_bytes =
hdd_ipa->ipa_sharing_stats.ipv4_tx_bytes;
wdi_sap_stats->ipv6_tx_packets =
hdd_ipa->ipa_sharing_stats.ipv6_tx_packets;
wdi_sap_stats->ipv6_tx_bytes =
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",
wdi_sap_stats->stats_valid,
wdi_sap_stats->ipv4_rx_packets,
wdi_sap_stats->ipv4_rx_bytes,
wdi_sap_stats->ipv6_rx_packets,
wdi_sap_stats->ipv6_rx_bytes,
wdi_sap_stats->ipv4_tx_packets,
wdi_sap_stats->ipv4_tx_bytes,
wdi_sap_stats->ipv6_tx_packets,
wdi_sap_stats->ipv6_tx_bytes);
}
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;
}
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");
ipa_set_quota->set_valid = 0;
} else {
ipa_set_quota->quota_bytes =
((uint64_t)(hdd_ipa->ipa_quota_rsp.quota_hi)
<<32)|hdd_ipa->ipa_quota_rsp.quota_lo;
ipa_set_quota->set_valid =
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(enum ipa_wdi_meter_evt_type 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,
struct ipa_wdi_in_params *pipe_in)
{
pipe_in->wdi_notify = hdd_ipa_wdi_meter_notifier_cb;
init_completion(&ipa_ctxt->ipa_uc_sharing_stats_comp);
init_completion(&ipa_ctxt->ipa_uc_set_quota_comp);
}
#else
static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt,
struct ipa_wdi_in_params *pipe_in)
{
}
#endif
/**
* hdd_ipa_uc_ol_init() - Initialize IPA uC offload
* @hdd_ctx: Global HDD context
@ -2682,25 +3041,32 @@ QDF_STATUS hdd_ipa_uc_ol_init(hdd_context_t *hdd_ctx)
stat = QDF_STATUS_E_FAILURE;
goto fail_return;
}
/* Micro Controller Doorbell register */
HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
"CONS DB pipe out 0x%x TX PIPE Handle 0x%x",
(unsigned int)pipe_out.uc_door_bell_pa,
ipa_ctxt->tx_pipe_handle);
"CONS DB pipe out 0x%x TX PIPE Handle 0x%x",
(unsigned int)pipe_out.uc_door_bell_pa,
ipa_ctxt->tx_pipe_handle);
ipa_ctxt->tx_comp_doorbell_paddr = pipe_out.uc_door_bell_pa;
/* WLAN TX PIPE Handle */
ipa_ctxt->tx_pipe_handle = pipe_out.clnt_hdl;
HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
"TX : 0x%x, %d, 0x%x, 0x%x, %d, %d, 0x%x",
(unsigned int)pipe_in.u.dl.comp_ring_base_pa,
pipe_in.u.dl.comp_ring_size,
(unsigned int)pipe_in.u.dl.ce_ring_base_pa,
(unsigned int)pipe_in.u.dl.ce_door_bell_pa,
pipe_in.u.dl.ce_ring_size,
pipe_in.u.dl.num_tx_buffers,
(unsigned int)ipa_ctxt->tx_comp_doorbell_paddr);
"TX: %s 0x%x, %s %d, %s 0x%x, %s 0x%x, %s %d, %s %d, %s 0x%x",
"comp_ring_base_pa",
(unsigned int)pipe_in.u.dl.comp_ring_base_pa,
"comp_ring_size",
pipe_in.u.dl.comp_ring_size,
"ce_ring_base_pa",
(unsigned int)pipe_in.u.dl.ce_ring_base_pa,
"ce_door_bell_pa",
(unsigned int)pipe_in.u.dl.ce_door_bell_pa,
"ce_ring_size",
pipe_in.u.dl.ce_ring_size,
"num_tx_buffers",
pipe_in.u.dl.num_tx_buffers,
"tx_comp_doorbell_paddr",
(unsigned int)ipa_ctxt->tx_comp_doorbell_paddr);
}
/* RX PIPE */
@ -2727,6 +3093,8 @@ QDF_STATUS hdd_ipa_uc_ol_init(hdd_context_t *hdd_ctx)
ipa_ctxt->ipa_resource.rx_proc_done_idx_paddr;
HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt);
hdd_ipa_init_metering(ipa_ctxt, &pipe_in);
qdf_mem_copy(&ipa_ctxt->prod_pipe_in, &pipe_in,
sizeof(struct ipa_wdi_in_params));
hdd_ipa_uc_get_db_paddr(&ipa_ctxt->rx_ready_doorbell_paddr,
@ -2749,10 +3117,14 @@ QDF_STATUS hdd_ipa_uc_ol_init(hdd_context_t *hdd_ctx)
(unsigned int)pipe_out.uc_door_bell_pa,
ipa_ctxt->tx_pipe_handle);
HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
"RX : RRBPA 0x%x, RRS %d, PDIPA 0x%x, RDY_DB_PAD 0x%x",
"RX: %s 0x%x, %s %d, %s 0x%x, %s 0x%x",
"rdy_ring_base_pa",
(unsigned int)pipe_in.u.ul.rdy_ring_base_pa,
"rdy_ring_size",
pipe_in.u.ul.rdy_ring_size,
"rdy_ring_rp_pa",
(unsigned int)pipe_in.u.ul.rdy_ring_rp_pa,
"rx_ready_doorbell_paddr",
(unsigned int)ipa_ctxt->rx_ready_doorbell_paddr);
}
@ -3865,7 +4237,7 @@ static enum hdd_ipa_forward_type hdd_ipa_intrabss_forward(
}
/**
* hdd_ipa_w2i_cb() - WLAN to IPA callback handler
* __hdd_ipa_w2i_cb() - WLAN to IPA callback handler
* @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

View file

@ -1750,6 +1750,8 @@ typedef struct {
* @WMA_VDEV_IBSS_PS_SET_1RX_CHAIN_IN_ATIM_WINDOW: set IBSS power save ATIM
* @WMA_VDEV_DFS_CONTROL_CMDID: DFS control command
* @WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID: get IPA microcontroller fw stats
* @WMA_VDEV_TXRX_GET_IPA_UC_SHARING_STATS_CMDID: get IPA uC wifi-sharing stats
* @WMA_VDEV_TXRX_SET_IPA_UC_QUOTA_CMDID: set IPA uC quota limit
*
* wma command ids for configuration request which
* does not involve sending a wmi command.
@ -1769,6 +1771,8 @@ enum wma_cfg_cmd_id {
WMA_VDEV_IBSS_PS_SET_1RX_CHAIN_IN_ATIM_WINDOW,
WMA_VDEV_DFS_CONTROL_CMDID,
WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID,
WMA_VDEV_TXRX_GET_IPA_UC_SHARING_STATS_CMDID,
WMA_VDEV_TXRX_SET_IPA_UC_QUOTA_CMDID,
WMA_CMD_ID_MAX
};

View file

@ -786,6 +786,7 @@ static int32_t wma_set_priv_cfg(tp_wma_handle wma_handle,
case WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID:
{
void *soc = cds_get_context(QDF_MODULE_ID_SOC);
struct cdp_pdev *pdev;
pdev = cds_get_context(QDF_MODULE_ID_TXRX);
@ -793,8 +794,43 @@ static int32_t wma_set_priv_cfg(tp_wma_handle wma_handle,
WMA_LOGE("pdev NULL for uc stat");
return -EINVAL;
}
cdp_ipa_get_stat(cds_get_context(QDF_MODULE_ID_SOC),
pdev);
cdp_ipa_get_stat(soc, pdev);
}
break;
case WMA_VDEV_TXRX_GET_IPA_UC_SHARING_STATS_CMDID:
{
void *soc = cds_get_context(QDF_MODULE_ID_SOC);
struct cdp_pdev *pdev;
uint8_t reset_stats = privcmd->param_value;
WMA_LOGE("%s: reset_stats=%d",
"WMA_VDEV_TXRX_GET_IPA_UC_SHARING_STATS_CMDID",
reset_stats);
pdev = cds_get_context(QDF_MODULE_ID_TXRX);
if (!pdev) {
WMA_LOGE("pdev NULL for uc stat");
return -EINVAL;
}
cdp_ipa_uc_get_share_stats(soc, pdev, reset_stats);
}
break;
case WMA_VDEV_TXRX_SET_IPA_UC_QUOTA_CMDID:
{
void *soc = cds_get_context(QDF_MODULE_ID_SOC);
struct cdp_pdev *pdev;
uint64_t quota_bytes = privcmd->param_value;
WMA_LOGE("%s: quota_bytes=%llu",
"WMA_VDEV_TXRX_SET_IPA_UC_QUOTA_CMDID",
quota_bytes);
pdev = cds_get_context(QDF_MODULE_ID_TXRX);
if (!pdev) {
WMA_LOGE("pdev NULL for uc stat");
return -EINVAL;
}
cdp_ipa_uc_set_quota(soc, pdev, quota_bytes);
}
break;