|
@@ -963,23 +963,27 @@ static void wma_data_tx_ack_work_handler(void *ack_work)
|
|
|
wma_handle = work->wma_handle;
|
|
|
if (!wma_handle || cds_is_load_or_unload_in_progress()) {
|
|
|
wma_err("Driver load/unload in progress");
|
|
|
- goto end;
|
|
|
+ goto free_frame;
|
|
|
}
|
|
|
+
|
|
|
+ wma_debug("Data Tx Ack Cb Status %d", work->status);
|
|
|
ack_cb = wma_handle->umac_data_ota_ack_cb;
|
|
|
+ if (!ack_cb) {
|
|
|
+ wma_err("Data Tx Ack Cb is NULL");
|
|
|
+ goto free_frame;
|
|
|
+ }
|
|
|
|
|
|
- if (work->status)
|
|
|
- wma_debug("Data Tx Ack Cb Status %d", work->status);
|
|
|
- else
|
|
|
- wma_debug("Data Tx Ack Cb Status %d", work->status);
|
|
|
+ ack_cb(wma_handle->mac_context, work->frame, work->status,
|
|
|
+ NULL);
|
|
|
+ goto end;
|
|
|
|
|
|
- /* Call the Ack Cb registered by UMAC */
|
|
|
- if (ack_cb)
|
|
|
- ack_cb(wma_handle->mac_context, NULL, work->status, NULL);
|
|
|
- else
|
|
|
- wma_err("Data Tx Ack Cb is NULL");
|
|
|
+free_frame:
|
|
|
+ if (work->frame)
|
|
|
+ qdf_nbuf_free(work->frame);
|
|
|
|
|
|
end:
|
|
|
qdf_mem_free(work);
|
|
|
+
|
|
|
if (wma_handle) {
|
|
|
wma_handle->umac_data_ota_ack_cb = NULL;
|
|
|
wma_handle->last_umac_data_nbuf = NULL;
|
|
@@ -1002,38 +1006,59 @@ void
|
|
|
wma_data_tx_ack_comp_hdlr(void *wma_context, qdf_nbuf_t netbuf, int32_t status)
|
|
|
{
|
|
|
tp_wma_handle wma_handle = (tp_wma_handle) wma_context;
|
|
|
+ struct wma_tx_ack_work_ctx *ack_work;
|
|
|
+ QDF_STATUS qdf_status;
|
|
|
|
|
|
if (wma_validate_handle(wma_handle))
|
|
|
return;
|
|
|
|
|
|
+ if (!netbuf) {
|
|
|
+ wma_debug("netbuf is NULL");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
/*
|
|
|
* if netBuf does not match with pending nbuf then just free the
|
|
|
* netbuf and do not call ack cb
|
|
|
*/
|
|
|
if (wma_handle->last_umac_data_nbuf != netbuf) {
|
|
|
- if (wma_handle->umac_data_ota_ack_cb) {
|
|
|
- wma_err("nbuf does not match but umac_data_ota_ack_cb is not null");
|
|
|
- } else {
|
|
|
- wma_err("nbuf does not match and umac_data_ota_ack_cb is also null");
|
|
|
- }
|
|
|
+ wma_err("nbuf does not match but umac_data_ota_ack_cb is %s null",
|
|
|
+ wma_handle->umac_data_ota_ack_cb ? "not" : "");
|
|
|
goto free_nbuf;
|
|
|
}
|
|
|
|
|
|
- if (wma_handle->umac_data_ota_ack_cb) {
|
|
|
- struct wma_tx_ack_work_ctx *ack_work;
|
|
|
+ if (!wma_handle->umac_data_ota_ack_cb) {
|
|
|
+ wma_err_rl("ota_ack cb not registered");
|
|
|
+ goto free_nbuf;
|
|
|
+ }
|
|
|
|
|
|
- ack_work = qdf_mem_malloc(sizeof(struct wma_tx_ack_work_ctx));
|
|
|
+ ack_work = qdf_mem_malloc(sizeof(struct wma_tx_ack_work_ctx));
|
|
|
+ if (ack_work) {
|
|
|
wma_handle->ack_work_ctx = ack_work;
|
|
|
- if (ack_work) {
|
|
|
- ack_work->wma_handle = wma_handle;
|
|
|
- ack_work->sub_type = 0;
|
|
|
- ack_work->status = status;
|
|
|
-
|
|
|
- qdf_create_work(0, &ack_work->ack_cmp_work,
|
|
|
- wma_data_tx_ack_work_handler,
|
|
|
- ack_work);
|
|
|
- qdf_sched_work(0, &ack_work->ack_cmp_work);
|
|
|
+
|
|
|
+ ack_work->wma_handle = wma_handle;
|
|
|
+ ack_work->sub_type = 0;
|
|
|
+ ack_work->status = status;
|
|
|
+ ack_work->frame = netbuf;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * free of the netbuf will be done by the scheduled work so
|
|
|
+ * just do unmap here
|
|
|
+ */
|
|
|
+ qdf_nbuf_unmap_single(wma_handle->qdf_dev, netbuf,
|
|
|
+ QDF_DMA_TO_DEVICE);
|
|
|
+
|
|
|
+ qdf_status = qdf_create_work(0, &ack_work->ack_cmp_work,
|
|
|
+ wma_data_tx_ack_work_handler,
|
|
|
+ ack_work);
|
|
|
+ if (QDF_IS_STATUS_ERROR(qdf_status)) {
|
|
|
+ qdf_nbuf_free(netbuf);
|
|
|
+ wma_err("Failed to create TX ack work");
|
|
|
+ return;
|
|
|
}
|
|
|
+
|
|
|
+ qdf_sched_work(0, &ack_work->ack_cmp_work);
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
free_nbuf:
|