162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 262306a36Sopenharmony_ci/* Copyright (c) 2021, Microsoft Corporation. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <net/mana/gdma.h> 562306a36Sopenharmony_ci#include <net/mana/hw_channel.h> 662306a36Sopenharmony_ci 762306a36Sopenharmony_cistatic int mana_hwc_get_msg_index(struct hw_channel_context *hwc, u16 *msg_id) 862306a36Sopenharmony_ci{ 962306a36Sopenharmony_ci struct gdma_resource *r = &hwc->inflight_msg_res; 1062306a36Sopenharmony_ci unsigned long flags; 1162306a36Sopenharmony_ci u32 index; 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci down(&hwc->sema); 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci spin_lock_irqsave(&r->lock, flags); 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci index = find_first_zero_bit(hwc->inflight_msg_res.map, 1862306a36Sopenharmony_ci hwc->inflight_msg_res.size); 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci bitmap_set(hwc->inflight_msg_res.map, index, 1); 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci spin_unlock_irqrestore(&r->lock, flags); 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci *msg_id = index; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci return 0; 2762306a36Sopenharmony_ci} 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic void mana_hwc_put_msg_index(struct hw_channel_context *hwc, u16 msg_id) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci struct gdma_resource *r = &hwc->inflight_msg_res; 3262306a36Sopenharmony_ci unsigned long flags; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci spin_lock_irqsave(&r->lock, flags); 3562306a36Sopenharmony_ci bitmap_clear(hwc->inflight_msg_res.map, msg_id, 1); 3662306a36Sopenharmony_ci spin_unlock_irqrestore(&r->lock, flags); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci up(&hwc->sema); 3962306a36Sopenharmony_ci} 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic int mana_hwc_verify_resp_msg(const struct hwc_caller_ctx *caller_ctx, 4262306a36Sopenharmony_ci const struct gdma_resp_hdr *resp_msg, 4362306a36Sopenharmony_ci u32 resp_len) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci if (resp_len < sizeof(*resp_msg)) 4662306a36Sopenharmony_ci return -EPROTO; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci if (resp_len > caller_ctx->output_buflen) 4962306a36Sopenharmony_ci return -EPROTO; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci return 0; 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic void mana_hwc_handle_resp(struct hw_channel_context *hwc, u32 resp_len, 5562306a36Sopenharmony_ci const struct gdma_resp_hdr *resp_msg) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci struct hwc_caller_ctx *ctx; 5862306a36Sopenharmony_ci int err; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci if (!test_bit(resp_msg->response.hwc_msg_id, 6162306a36Sopenharmony_ci hwc->inflight_msg_res.map)) { 6262306a36Sopenharmony_ci dev_err(hwc->dev, "hwc_rx: invalid msg_id = %u\n", 6362306a36Sopenharmony_ci resp_msg->response.hwc_msg_id); 6462306a36Sopenharmony_ci return; 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci ctx = hwc->caller_ctx + resp_msg->response.hwc_msg_id; 6862306a36Sopenharmony_ci err = mana_hwc_verify_resp_msg(ctx, resp_msg, resp_len); 6962306a36Sopenharmony_ci if (err) 7062306a36Sopenharmony_ci goto out; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci ctx->status_code = resp_msg->status; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci memcpy(ctx->output_buf, resp_msg, resp_len); 7562306a36Sopenharmony_ciout: 7662306a36Sopenharmony_ci ctx->error = err; 7762306a36Sopenharmony_ci complete(&ctx->comp_event); 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic int mana_hwc_post_rx_wqe(const struct hwc_wq *hwc_rxq, 8162306a36Sopenharmony_ci struct hwc_work_request *req) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci struct device *dev = hwc_rxq->hwc->dev; 8462306a36Sopenharmony_ci struct gdma_sge *sge; 8562306a36Sopenharmony_ci int err; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci sge = &req->sge; 8862306a36Sopenharmony_ci sge->address = (u64)req->buf_sge_addr; 8962306a36Sopenharmony_ci sge->mem_key = hwc_rxq->msg_buf->gpa_mkey; 9062306a36Sopenharmony_ci sge->size = req->buf_len; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci memset(&req->wqe_req, 0, sizeof(struct gdma_wqe_request)); 9362306a36Sopenharmony_ci req->wqe_req.sgl = sge; 9462306a36Sopenharmony_ci req->wqe_req.num_sge = 1; 9562306a36Sopenharmony_ci req->wqe_req.client_data_unit = 0; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci err = mana_gd_post_and_ring(hwc_rxq->gdma_wq, &req->wqe_req, NULL); 9862306a36Sopenharmony_ci if (err) 9962306a36Sopenharmony_ci dev_err(dev, "Failed to post WQE on HWC RQ: %d\n", err); 10062306a36Sopenharmony_ci return err; 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic void mana_hwc_init_event_handler(void *ctx, struct gdma_queue *q_self, 10462306a36Sopenharmony_ci struct gdma_event *event) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci struct hw_channel_context *hwc = ctx; 10762306a36Sopenharmony_ci struct gdma_dev *gd = hwc->gdma_dev; 10862306a36Sopenharmony_ci union hwc_init_type_data type_data; 10962306a36Sopenharmony_ci union hwc_init_eq_id_db eq_db; 11062306a36Sopenharmony_ci u32 type, val; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci switch (event->type) { 11362306a36Sopenharmony_ci case GDMA_EQE_HWC_INIT_EQ_ID_DB: 11462306a36Sopenharmony_ci eq_db.as_uint32 = event->details[0]; 11562306a36Sopenharmony_ci hwc->cq->gdma_eq->id = eq_db.eq_id; 11662306a36Sopenharmony_ci gd->doorbell = eq_db.doorbell; 11762306a36Sopenharmony_ci break; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci case GDMA_EQE_HWC_INIT_DATA: 12062306a36Sopenharmony_ci type_data.as_uint32 = event->details[0]; 12162306a36Sopenharmony_ci type = type_data.type; 12262306a36Sopenharmony_ci val = type_data.value; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci switch (type) { 12562306a36Sopenharmony_ci case HWC_INIT_DATA_CQID: 12662306a36Sopenharmony_ci hwc->cq->gdma_cq->id = val; 12762306a36Sopenharmony_ci break; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci case HWC_INIT_DATA_RQID: 13062306a36Sopenharmony_ci hwc->rxq->gdma_wq->id = val; 13162306a36Sopenharmony_ci break; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci case HWC_INIT_DATA_SQID: 13462306a36Sopenharmony_ci hwc->txq->gdma_wq->id = val; 13562306a36Sopenharmony_ci break; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci case HWC_INIT_DATA_QUEUE_DEPTH: 13862306a36Sopenharmony_ci hwc->hwc_init_q_depth_max = (u16)val; 13962306a36Sopenharmony_ci break; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci case HWC_INIT_DATA_MAX_REQUEST: 14262306a36Sopenharmony_ci hwc->hwc_init_max_req_msg_size = val; 14362306a36Sopenharmony_ci break; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci case HWC_INIT_DATA_MAX_RESPONSE: 14662306a36Sopenharmony_ci hwc->hwc_init_max_resp_msg_size = val; 14762306a36Sopenharmony_ci break; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci case HWC_INIT_DATA_MAX_NUM_CQS: 15062306a36Sopenharmony_ci gd->gdma_context->max_num_cqs = val; 15162306a36Sopenharmony_ci break; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci case HWC_INIT_DATA_PDID: 15462306a36Sopenharmony_ci hwc->gdma_dev->pdid = val; 15562306a36Sopenharmony_ci break; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci case HWC_INIT_DATA_GPA_MKEY: 15862306a36Sopenharmony_ci hwc->rxq->msg_buf->gpa_mkey = val; 15962306a36Sopenharmony_ci hwc->txq->msg_buf->gpa_mkey = val; 16062306a36Sopenharmony_ci break; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci case HWC_INIT_DATA_PF_DEST_RQ_ID: 16362306a36Sopenharmony_ci hwc->pf_dest_vrq_id = val; 16462306a36Sopenharmony_ci break; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci case HWC_INIT_DATA_PF_DEST_CQ_ID: 16762306a36Sopenharmony_ci hwc->pf_dest_vrcq_id = val; 16862306a36Sopenharmony_ci break; 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci break; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci case GDMA_EQE_HWC_INIT_DONE: 17462306a36Sopenharmony_ci complete(&hwc->hwc_init_eqe_comp); 17562306a36Sopenharmony_ci break; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci case GDMA_EQE_HWC_SOC_RECONFIG_DATA: 17862306a36Sopenharmony_ci type_data.as_uint32 = event->details[0]; 17962306a36Sopenharmony_ci type = type_data.type; 18062306a36Sopenharmony_ci val = type_data.value; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci switch (type) { 18362306a36Sopenharmony_ci case HWC_DATA_CFG_HWC_TIMEOUT: 18462306a36Sopenharmony_ci hwc->hwc_timeout = val; 18562306a36Sopenharmony_ci break; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci default: 18862306a36Sopenharmony_ci dev_warn(hwc->dev, "Received unknown reconfig type %u\n", type); 18962306a36Sopenharmony_ci break; 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci break; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci default: 19562306a36Sopenharmony_ci dev_warn(hwc->dev, "Received unknown gdma event %u\n", event->type); 19662306a36Sopenharmony_ci /* Ignore unknown events, which should never happen. */ 19762306a36Sopenharmony_ci break; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cistatic void mana_hwc_rx_event_handler(void *ctx, u32 gdma_rxq_id, 20262306a36Sopenharmony_ci const struct hwc_rx_oob *rx_oob) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci struct hw_channel_context *hwc = ctx; 20562306a36Sopenharmony_ci struct hwc_wq *hwc_rxq = hwc->rxq; 20662306a36Sopenharmony_ci struct hwc_work_request *rx_req; 20762306a36Sopenharmony_ci struct gdma_resp_hdr *resp; 20862306a36Sopenharmony_ci struct gdma_wqe *dma_oob; 20962306a36Sopenharmony_ci struct gdma_queue *rq; 21062306a36Sopenharmony_ci struct gdma_sge *sge; 21162306a36Sopenharmony_ci u64 rq_base_addr; 21262306a36Sopenharmony_ci u64 rx_req_idx; 21362306a36Sopenharmony_ci u8 *wqe; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (WARN_ON_ONCE(hwc_rxq->gdma_wq->id != gdma_rxq_id)) 21662306a36Sopenharmony_ci return; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci rq = hwc_rxq->gdma_wq; 21962306a36Sopenharmony_ci wqe = mana_gd_get_wqe_ptr(rq, rx_oob->wqe_offset / GDMA_WQE_BU_SIZE); 22062306a36Sopenharmony_ci dma_oob = (struct gdma_wqe *)wqe; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci sge = (struct gdma_sge *)(wqe + 8 + dma_oob->inline_oob_size_div4 * 4); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci /* Select the RX work request for virtual address and for reposting. */ 22562306a36Sopenharmony_ci rq_base_addr = hwc_rxq->msg_buf->mem_info.dma_handle; 22662306a36Sopenharmony_ci rx_req_idx = (sge->address - rq_base_addr) / hwc->max_req_msg_size; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci rx_req = &hwc_rxq->msg_buf->reqs[rx_req_idx]; 22962306a36Sopenharmony_ci resp = (struct gdma_resp_hdr *)rx_req->buf_va; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci if (resp->response.hwc_msg_id >= hwc->num_inflight_msg) { 23262306a36Sopenharmony_ci dev_err(hwc->dev, "HWC RX: wrong msg_id=%u\n", 23362306a36Sopenharmony_ci resp->response.hwc_msg_id); 23462306a36Sopenharmony_ci return; 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci mana_hwc_handle_resp(hwc, rx_oob->tx_oob_data_size, resp); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci /* Do no longer use 'resp', because the buffer is posted to the HW 24062306a36Sopenharmony_ci * in the below mana_hwc_post_rx_wqe(). 24162306a36Sopenharmony_ci */ 24262306a36Sopenharmony_ci resp = NULL; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci mana_hwc_post_rx_wqe(hwc_rxq, rx_req); 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic void mana_hwc_tx_event_handler(void *ctx, u32 gdma_txq_id, 24862306a36Sopenharmony_ci const struct hwc_rx_oob *rx_oob) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci struct hw_channel_context *hwc = ctx; 25162306a36Sopenharmony_ci struct hwc_wq *hwc_txq = hwc->txq; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci WARN_ON_ONCE(!hwc_txq || hwc_txq->gdma_wq->id != gdma_txq_id); 25462306a36Sopenharmony_ci} 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_cistatic int mana_hwc_create_gdma_wq(struct hw_channel_context *hwc, 25762306a36Sopenharmony_ci enum gdma_queue_type type, u64 queue_size, 25862306a36Sopenharmony_ci struct gdma_queue **queue) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci struct gdma_queue_spec spec = {}; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci if (type != GDMA_SQ && type != GDMA_RQ) 26362306a36Sopenharmony_ci return -EINVAL; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci spec.type = type; 26662306a36Sopenharmony_ci spec.monitor_avl_buf = false; 26762306a36Sopenharmony_ci spec.queue_size = queue_size; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci return mana_gd_create_hwc_queue(hwc->gdma_dev, &spec, queue); 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic int mana_hwc_create_gdma_cq(struct hw_channel_context *hwc, 27362306a36Sopenharmony_ci u64 queue_size, 27462306a36Sopenharmony_ci void *ctx, gdma_cq_callback *cb, 27562306a36Sopenharmony_ci struct gdma_queue *parent_eq, 27662306a36Sopenharmony_ci struct gdma_queue **queue) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci struct gdma_queue_spec spec = {}; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci spec.type = GDMA_CQ; 28162306a36Sopenharmony_ci spec.monitor_avl_buf = false; 28262306a36Sopenharmony_ci spec.queue_size = queue_size; 28362306a36Sopenharmony_ci spec.cq.context = ctx; 28462306a36Sopenharmony_ci spec.cq.callback = cb; 28562306a36Sopenharmony_ci spec.cq.parent_eq = parent_eq; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci return mana_gd_create_hwc_queue(hwc->gdma_dev, &spec, queue); 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistatic int mana_hwc_create_gdma_eq(struct hw_channel_context *hwc, 29162306a36Sopenharmony_ci u64 queue_size, 29262306a36Sopenharmony_ci void *ctx, gdma_eq_callback *cb, 29362306a36Sopenharmony_ci struct gdma_queue **queue) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci struct gdma_queue_spec spec = {}; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci spec.type = GDMA_EQ; 29862306a36Sopenharmony_ci spec.monitor_avl_buf = false; 29962306a36Sopenharmony_ci spec.queue_size = queue_size; 30062306a36Sopenharmony_ci spec.eq.context = ctx; 30162306a36Sopenharmony_ci spec.eq.callback = cb; 30262306a36Sopenharmony_ci spec.eq.log2_throttle_limit = DEFAULT_LOG2_THROTTLING_FOR_ERROR_EQ; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci return mana_gd_create_hwc_queue(hwc->gdma_dev, &spec, queue); 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic void mana_hwc_comp_event(void *ctx, struct gdma_queue *q_self) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci struct hwc_rx_oob comp_data = {}; 31062306a36Sopenharmony_ci struct gdma_comp *completions; 31162306a36Sopenharmony_ci struct hwc_cq *hwc_cq = ctx; 31262306a36Sopenharmony_ci int comp_read, i; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci WARN_ON_ONCE(hwc_cq->gdma_cq != q_self); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci completions = hwc_cq->comp_buf; 31762306a36Sopenharmony_ci comp_read = mana_gd_poll_cq(q_self, completions, hwc_cq->queue_depth); 31862306a36Sopenharmony_ci WARN_ON_ONCE(comp_read <= 0 || comp_read > hwc_cq->queue_depth); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci for (i = 0; i < comp_read; ++i) { 32162306a36Sopenharmony_ci comp_data = *(struct hwc_rx_oob *)completions[i].cqe_data; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci if (completions[i].is_sq) 32462306a36Sopenharmony_ci hwc_cq->tx_event_handler(hwc_cq->tx_event_ctx, 32562306a36Sopenharmony_ci completions[i].wq_num, 32662306a36Sopenharmony_ci &comp_data); 32762306a36Sopenharmony_ci else 32862306a36Sopenharmony_ci hwc_cq->rx_event_handler(hwc_cq->rx_event_ctx, 32962306a36Sopenharmony_ci completions[i].wq_num, 33062306a36Sopenharmony_ci &comp_data); 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci mana_gd_ring_cq(q_self, SET_ARM_BIT); 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistatic void mana_hwc_destroy_cq(struct gdma_context *gc, struct hwc_cq *hwc_cq) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci kfree(hwc_cq->comp_buf); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci if (hwc_cq->gdma_cq) 34162306a36Sopenharmony_ci mana_gd_destroy_queue(gc, hwc_cq->gdma_cq); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if (hwc_cq->gdma_eq) 34462306a36Sopenharmony_ci mana_gd_destroy_queue(gc, hwc_cq->gdma_eq); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci kfree(hwc_cq); 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cistatic int mana_hwc_create_cq(struct hw_channel_context *hwc, u16 q_depth, 35062306a36Sopenharmony_ci gdma_eq_callback *callback, void *ctx, 35162306a36Sopenharmony_ci hwc_rx_event_handler_t *rx_ev_hdlr, 35262306a36Sopenharmony_ci void *rx_ev_ctx, 35362306a36Sopenharmony_ci hwc_tx_event_handler_t *tx_ev_hdlr, 35462306a36Sopenharmony_ci void *tx_ev_ctx, struct hwc_cq **hwc_cq_ptr) 35562306a36Sopenharmony_ci{ 35662306a36Sopenharmony_ci struct gdma_queue *eq, *cq; 35762306a36Sopenharmony_ci struct gdma_comp *comp_buf; 35862306a36Sopenharmony_ci struct hwc_cq *hwc_cq; 35962306a36Sopenharmony_ci u32 eq_size, cq_size; 36062306a36Sopenharmony_ci int err; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci eq_size = roundup_pow_of_two(GDMA_EQE_SIZE * q_depth); 36362306a36Sopenharmony_ci if (eq_size < MINIMUM_SUPPORTED_PAGE_SIZE) 36462306a36Sopenharmony_ci eq_size = MINIMUM_SUPPORTED_PAGE_SIZE; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci cq_size = roundup_pow_of_two(GDMA_CQE_SIZE * q_depth); 36762306a36Sopenharmony_ci if (cq_size < MINIMUM_SUPPORTED_PAGE_SIZE) 36862306a36Sopenharmony_ci cq_size = MINIMUM_SUPPORTED_PAGE_SIZE; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci hwc_cq = kzalloc(sizeof(*hwc_cq), GFP_KERNEL); 37162306a36Sopenharmony_ci if (!hwc_cq) 37262306a36Sopenharmony_ci return -ENOMEM; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci err = mana_hwc_create_gdma_eq(hwc, eq_size, ctx, callback, &eq); 37562306a36Sopenharmony_ci if (err) { 37662306a36Sopenharmony_ci dev_err(hwc->dev, "Failed to create HWC EQ for RQ: %d\n", err); 37762306a36Sopenharmony_ci goto out; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci hwc_cq->gdma_eq = eq; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci err = mana_hwc_create_gdma_cq(hwc, cq_size, hwc_cq, mana_hwc_comp_event, 38262306a36Sopenharmony_ci eq, &cq); 38362306a36Sopenharmony_ci if (err) { 38462306a36Sopenharmony_ci dev_err(hwc->dev, "Failed to create HWC CQ for RQ: %d\n", err); 38562306a36Sopenharmony_ci goto out; 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci hwc_cq->gdma_cq = cq; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci comp_buf = kcalloc(q_depth, sizeof(*comp_buf), GFP_KERNEL); 39062306a36Sopenharmony_ci if (!comp_buf) { 39162306a36Sopenharmony_ci err = -ENOMEM; 39262306a36Sopenharmony_ci goto out; 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci hwc_cq->hwc = hwc; 39662306a36Sopenharmony_ci hwc_cq->comp_buf = comp_buf; 39762306a36Sopenharmony_ci hwc_cq->queue_depth = q_depth; 39862306a36Sopenharmony_ci hwc_cq->rx_event_handler = rx_ev_hdlr; 39962306a36Sopenharmony_ci hwc_cq->rx_event_ctx = rx_ev_ctx; 40062306a36Sopenharmony_ci hwc_cq->tx_event_handler = tx_ev_hdlr; 40162306a36Sopenharmony_ci hwc_cq->tx_event_ctx = tx_ev_ctx; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci *hwc_cq_ptr = hwc_cq; 40462306a36Sopenharmony_ci return 0; 40562306a36Sopenharmony_ciout: 40662306a36Sopenharmony_ci mana_hwc_destroy_cq(hwc->gdma_dev->gdma_context, hwc_cq); 40762306a36Sopenharmony_ci return err; 40862306a36Sopenharmony_ci} 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_cistatic int mana_hwc_alloc_dma_buf(struct hw_channel_context *hwc, u16 q_depth, 41162306a36Sopenharmony_ci u32 max_msg_size, 41262306a36Sopenharmony_ci struct hwc_dma_buf **dma_buf_ptr) 41362306a36Sopenharmony_ci{ 41462306a36Sopenharmony_ci struct gdma_context *gc = hwc->gdma_dev->gdma_context; 41562306a36Sopenharmony_ci struct hwc_work_request *hwc_wr; 41662306a36Sopenharmony_ci struct hwc_dma_buf *dma_buf; 41762306a36Sopenharmony_ci struct gdma_mem_info *gmi; 41862306a36Sopenharmony_ci void *virt_addr; 41962306a36Sopenharmony_ci u32 buf_size; 42062306a36Sopenharmony_ci u8 *base_pa; 42162306a36Sopenharmony_ci int err; 42262306a36Sopenharmony_ci u16 i; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci dma_buf = kzalloc(struct_size(dma_buf, reqs, q_depth), GFP_KERNEL); 42562306a36Sopenharmony_ci if (!dma_buf) 42662306a36Sopenharmony_ci return -ENOMEM; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci dma_buf->num_reqs = q_depth; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci buf_size = PAGE_ALIGN(q_depth * max_msg_size); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci gmi = &dma_buf->mem_info; 43362306a36Sopenharmony_ci err = mana_gd_alloc_memory(gc, buf_size, gmi); 43462306a36Sopenharmony_ci if (err) { 43562306a36Sopenharmony_ci dev_err(hwc->dev, "Failed to allocate DMA buffer: %d\n", err); 43662306a36Sopenharmony_ci goto out; 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci virt_addr = dma_buf->mem_info.virt_addr; 44062306a36Sopenharmony_ci base_pa = (u8 *)dma_buf->mem_info.dma_handle; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci for (i = 0; i < q_depth; i++) { 44362306a36Sopenharmony_ci hwc_wr = &dma_buf->reqs[i]; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci hwc_wr->buf_va = virt_addr + i * max_msg_size; 44662306a36Sopenharmony_ci hwc_wr->buf_sge_addr = base_pa + i * max_msg_size; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci hwc_wr->buf_len = max_msg_size; 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci *dma_buf_ptr = dma_buf; 45262306a36Sopenharmony_ci return 0; 45362306a36Sopenharmony_ciout: 45462306a36Sopenharmony_ci kfree(dma_buf); 45562306a36Sopenharmony_ci return err; 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_cistatic void mana_hwc_dealloc_dma_buf(struct hw_channel_context *hwc, 45962306a36Sopenharmony_ci struct hwc_dma_buf *dma_buf) 46062306a36Sopenharmony_ci{ 46162306a36Sopenharmony_ci if (!dma_buf) 46262306a36Sopenharmony_ci return; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci mana_gd_free_memory(&dma_buf->mem_info); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci kfree(dma_buf); 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cistatic void mana_hwc_destroy_wq(struct hw_channel_context *hwc, 47062306a36Sopenharmony_ci struct hwc_wq *hwc_wq) 47162306a36Sopenharmony_ci{ 47262306a36Sopenharmony_ci mana_hwc_dealloc_dma_buf(hwc, hwc_wq->msg_buf); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci if (hwc_wq->gdma_wq) 47562306a36Sopenharmony_ci mana_gd_destroy_queue(hwc->gdma_dev->gdma_context, 47662306a36Sopenharmony_ci hwc_wq->gdma_wq); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci kfree(hwc_wq); 47962306a36Sopenharmony_ci} 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_cistatic int mana_hwc_create_wq(struct hw_channel_context *hwc, 48262306a36Sopenharmony_ci enum gdma_queue_type q_type, u16 q_depth, 48362306a36Sopenharmony_ci u32 max_msg_size, struct hwc_cq *hwc_cq, 48462306a36Sopenharmony_ci struct hwc_wq **hwc_wq_ptr) 48562306a36Sopenharmony_ci{ 48662306a36Sopenharmony_ci struct gdma_queue *queue; 48762306a36Sopenharmony_ci struct hwc_wq *hwc_wq; 48862306a36Sopenharmony_ci u32 queue_size; 48962306a36Sopenharmony_ci int err; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci WARN_ON(q_type != GDMA_SQ && q_type != GDMA_RQ); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci if (q_type == GDMA_RQ) 49462306a36Sopenharmony_ci queue_size = roundup_pow_of_two(GDMA_MAX_RQE_SIZE * q_depth); 49562306a36Sopenharmony_ci else 49662306a36Sopenharmony_ci queue_size = roundup_pow_of_two(GDMA_MAX_SQE_SIZE * q_depth); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci if (queue_size < MINIMUM_SUPPORTED_PAGE_SIZE) 49962306a36Sopenharmony_ci queue_size = MINIMUM_SUPPORTED_PAGE_SIZE; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci hwc_wq = kzalloc(sizeof(*hwc_wq), GFP_KERNEL); 50262306a36Sopenharmony_ci if (!hwc_wq) 50362306a36Sopenharmony_ci return -ENOMEM; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci err = mana_hwc_create_gdma_wq(hwc, q_type, queue_size, &queue); 50662306a36Sopenharmony_ci if (err) 50762306a36Sopenharmony_ci goto out; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci hwc_wq->hwc = hwc; 51062306a36Sopenharmony_ci hwc_wq->gdma_wq = queue; 51162306a36Sopenharmony_ci hwc_wq->queue_depth = q_depth; 51262306a36Sopenharmony_ci hwc_wq->hwc_cq = hwc_cq; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci err = mana_hwc_alloc_dma_buf(hwc, q_depth, max_msg_size, 51562306a36Sopenharmony_ci &hwc_wq->msg_buf); 51662306a36Sopenharmony_ci if (err) 51762306a36Sopenharmony_ci goto out; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci *hwc_wq_ptr = hwc_wq; 52062306a36Sopenharmony_ci return 0; 52162306a36Sopenharmony_ciout: 52262306a36Sopenharmony_ci if (err) 52362306a36Sopenharmony_ci mana_hwc_destroy_wq(hwc, hwc_wq); 52462306a36Sopenharmony_ci return err; 52562306a36Sopenharmony_ci} 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_cistatic int mana_hwc_post_tx_wqe(const struct hwc_wq *hwc_txq, 52862306a36Sopenharmony_ci struct hwc_work_request *req, 52962306a36Sopenharmony_ci u32 dest_virt_rq_id, u32 dest_virt_rcq_id, 53062306a36Sopenharmony_ci bool dest_pf) 53162306a36Sopenharmony_ci{ 53262306a36Sopenharmony_ci struct device *dev = hwc_txq->hwc->dev; 53362306a36Sopenharmony_ci struct hwc_tx_oob *tx_oob; 53462306a36Sopenharmony_ci struct gdma_sge *sge; 53562306a36Sopenharmony_ci int err; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci if (req->msg_size == 0 || req->msg_size > req->buf_len) { 53862306a36Sopenharmony_ci dev_err(dev, "wrong msg_size: %u, buf_len: %u\n", 53962306a36Sopenharmony_ci req->msg_size, req->buf_len); 54062306a36Sopenharmony_ci return -EINVAL; 54162306a36Sopenharmony_ci } 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci tx_oob = &req->tx_oob; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci tx_oob->vrq_id = dest_virt_rq_id; 54662306a36Sopenharmony_ci tx_oob->dest_vfid = 0; 54762306a36Sopenharmony_ci tx_oob->vrcq_id = dest_virt_rcq_id; 54862306a36Sopenharmony_ci tx_oob->vscq_id = hwc_txq->hwc_cq->gdma_cq->id; 54962306a36Sopenharmony_ci tx_oob->loopback = false; 55062306a36Sopenharmony_ci tx_oob->lso_override = false; 55162306a36Sopenharmony_ci tx_oob->dest_pf = dest_pf; 55262306a36Sopenharmony_ci tx_oob->vsq_id = hwc_txq->gdma_wq->id; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci sge = &req->sge; 55562306a36Sopenharmony_ci sge->address = (u64)req->buf_sge_addr; 55662306a36Sopenharmony_ci sge->mem_key = hwc_txq->msg_buf->gpa_mkey; 55762306a36Sopenharmony_ci sge->size = req->msg_size; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci memset(&req->wqe_req, 0, sizeof(struct gdma_wqe_request)); 56062306a36Sopenharmony_ci req->wqe_req.sgl = sge; 56162306a36Sopenharmony_ci req->wqe_req.num_sge = 1; 56262306a36Sopenharmony_ci req->wqe_req.inline_oob_size = sizeof(struct hwc_tx_oob); 56362306a36Sopenharmony_ci req->wqe_req.inline_oob_data = tx_oob; 56462306a36Sopenharmony_ci req->wqe_req.client_data_unit = 0; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci err = mana_gd_post_and_ring(hwc_txq->gdma_wq, &req->wqe_req, NULL); 56762306a36Sopenharmony_ci if (err) 56862306a36Sopenharmony_ci dev_err(dev, "Failed to post WQE on HWC SQ: %d\n", err); 56962306a36Sopenharmony_ci return err; 57062306a36Sopenharmony_ci} 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_cistatic int mana_hwc_init_inflight_msg(struct hw_channel_context *hwc, 57362306a36Sopenharmony_ci u16 num_msg) 57462306a36Sopenharmony_ci{ 57562306a36Sopenharmony_ci int err; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci sema_init(&hwc->sema, num_msg); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci err = mana_gd_alloc_res_map(num_msg, &hwc->inflight_msg_res); 58062306a36Sopenharmony_ci if (err) 58162306a36Sopenharmony_ci dev_err(hwc->dev, "Failed to init inflight_msg_res: %d\n", err); 58262306a36Sopenharmony_ci return err; 58362306a36Sopenharmony_ci} 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_cistatic int mana_hwc_test_channel(struct hw_channel_context *hwc, u16 q_depth, 58662306a36Sopenharmony_ci u32 max_req_msg_size, u32 max_resp_msg_size) 58762306a36Sopenharmony_ci{ 58862306a36Sopenharmony_ci struct gdma_context *gc = hwc->gdma_dev->gdma_context; 58962306a36Sopenharmony_ci struct hwc_wq *hwc_rxq = hwc->rxq; 59062306a36Sopenharmony_ci struct hwc_work_request *req; 59162306a36Sopenharmony_ci struct hwc_caller_ctx *ctx; 59262306a36Sopenharmony_ci int err; 59362306a36Sopenharmony_ci int i; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci /* Post all WQEs on the RQ */ 59662306a36Sopenharmony_ci for (i = 0; i < q_depth; i++) { 59762306a36Sopenharmony_ci req = &hwc_rxq->msg_buf->reqs[i]; 59862306a36Sopenharmony_ci err = mana_hwc_post_rx_wqe(hwc_rxq, req); 59962306a36Sopenharmony_ci if (err) 60062306a36Sopenharmony_ci return err; 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci ctx = kcalloc(q_depth, sizeof(*ctx), GFP_KERNEL); 60462306a36Sopenharmony_ci if (!ctx) 60562306a36Sopenharmony_ci return -ENOMEM; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci for (i = 0; i < q_depth; ++i) 60862306a36Sopenharmony_ci init_completion(&ctx[i].comp_event); 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci hwc->caller_ctx = ctx; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci return mana_gd_test_eq(gc, hwc->cq->gdma_eq); 61362306a36Sopenharmony_ci} 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_cistatic int mana_hwc_establish_channel(struct gdma_context *gc, u16 *q_depth, 61662306a36Sopenharmony_ci u32 *max_req_msg_size, 61762306a36Sopenharmony_ci u32 *max_resp_msg_size) 61862306a36Sopenharmony_ci{ 61962306a36Sopenharmony_ci struct hw_channel_context *hwc = gc->hwc.driver_data; 62062306a36Sopenharmony_ci struct gdma_queue *rq = hwc->rxq->gdma_wq; 62162306a36Sopenharmony_ci struct gdma_queue *sq = hwc->txq->gdma_wq; 62262306a36Sopenharmony_ci struct gdma_queue *eq = hwc->cq->gdma_eq; 62362306a36Sopenharmony_ci struct gdma_queue *cq = hwc->cq->gdma_cq; 62462306a36Sopenharmony_ci int err; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci init_completion(&hwc->hwc_init_eqe_comp); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci err = mana_smc_setup_hwc(&gc->shm_channel, false, 62962306a36Sopenharmony_ci eq->mem_info.dma_handle, 63062306a36Sopenharmony_ci cq->mem_info.dma_handle, 63162306a36Sopenharmony_ci rq->mem_info.dma_handle, 63262306a36Sopenharmony_ci sq->mem_info.dma_handle, 63362306a36Sopenharmony_ci eq->eq.msix_index); 63462306a36Sopenharmony_ci if (err) 63562306a36Sopenharmony_ci return err; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci if (!wait_for_completion_timeout(&hwc->hwc_init_eqe_comp, 60 * HZ)) 63862306a36Sopenharmony_ci return -ETIMEDOUT; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci *q_depth = hwc->hwc_init_q_depth_max; 64162306a36Sopenharmony_ci *max_req_msg_size = hwc->hwc_init_max_req_msg_size; 64262306a36Sopenharmony_ci *max_resp_msg_size = hwc->hwc_init_max_resp_msg_size; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci /* Both were set in mana_hwc_init_event_handler(). */ 64562306a36Sopenharmony_ci if (WARN_ON(cq->id >= gc->max_num_cqs)) 64662306a36Sopenharmony_ci return -EPROTO; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci gc->cq_table = vcalloc(gc->max_num_cqs, sizeof(struct gdma_queue *)); 64962306a36Sopenharmony_ci if (!gc->cq_table) 65062306a36Sopenharmony_ci return -ENOMEM; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci gc->cq_table[cq->id] = cq; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci return 0; 65562306a36Sopenharmony_ci} 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_cistatic int mana_hwc_init_queues(struct hw_channel_context *hwc, u16 q_depth, 65862306a36Sopenharmony_ci u32 max_req_msg_size, u32 max_resp_msg_size) 65962306a36Sopenharmony_ci{ 66062306a36Sopenharmony_ci int err; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci err = mana_hwc_init_inflight_msg(hwc, q_depth); 66362306a36Sopenharmony_ci if (err) 66462306a36Sopenharmony_ci return err; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci /* CQ is shared by SQ and RQ, so CQ's queue depth is the sum of SQ 66762306a36Sopenharmony_ci * queue depth and RQ queue depth. 66862306a36Sopenharmony_ci */ 66962306a36Sopenharmony_ci err = mana_hwc_create_cq(hwc, q_depth * 2, 67062306a36Sopenharmony_ci mana_hwc_init_event_handler, hwc, 67162306a36Sopenharmony_ci mana_hwc_rx_event_handler, hwc, 67262306a36Sopenharmony_ci mana_hwc_tx_event_handler, hwc, &hwc->cq); 67362306a36Sopenharmony_ci if (err) { 67462306a36Sopenharmony_ci dev_err(hwc->dev, "Failed to create HWC CQ: %d\n", err); 67562306a36Sopenharmony_ci goto out; 67662306a36Sopenharmony_ci } 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci err = mana_hwc_create_wq(hwc, GDMA_RQ, q_depth, max_req_msg_size, 67962306a36Sopenharmony_ci hwc->cq, &hwc->rxq); 68062306a36Sopenharmony_ci if (err) { 68162306a36Sopenharmony_ci dev_err(hwc->dev, "Failed to create HWC RQ: %d\n", err); 68262306a36Sopenharmony_ci goto out; 68362306a36Sopenharmony_ci } 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci err = mana_hwc_create_wq(hwc, GDMA_SQ, q_depth, max_resp_msg_size, 68662306a36Sopenharmony_ci hwc->cq, &hwc->txq); 68762306a36Sopenharmony_ci if (err) { 68862306a36Sopenharmony_ci dev_err(hwc->dev, "Failed to create HWC SQ: %d\n", err); 68962306a36Sopenharmony_ci goto out; 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci hwc->num_inflight_msg = q_depth; 69362306a36Sopenharmony_ci hwc->max_req_msg_size = max_req_msg_size; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci return 0; 69662306a36Sopenharmony_ciout: 69762306a36Sopenharmony_ci /* mana_hwc_create_channel() will do the cleanup.*/ 69862306a36Sopenharmony_ci return err; 69962306a36Sopenharmony_ci} 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ciint mana_hwc_create_channel(struct gdma_context *gc) 70262306a36Sopenharmony_ci{ 70362306a36Sopenharmony_ci u32 max_req_msg_size, max_resp_msg_size; 70462306a36Sopenharmony_ci struct gdma_dev *gd = &gc->hwc; 70562306a36Sopenharmony_ci struct hw_channel_context *hwc; 70662306a36Sopenharmony_ci u16 q_depth_max; 70762306a36Sopenharmony_ci int err; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci hwc = kzalloc(sizeof(*hwc), GFP_KERNEL); 71062306a36Sopenharmony_ci if (!hwc) 71162306a36Sopenharmony_ci return -ENOMEM; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci gd->gdma_context = gc; 71462306a36Sopenharmony_ci gd->driver_data = hwc; 71562306a36Sopenharmony_ci hwc->gdma_dev = gd; 71662306a36Sopenharmony_ci hwc->dev = gc->dev; 71762306a36Sopenharmony_ci hwc->hwc_timeout = HW_CHANNEL_WAIT_RESOURCE_TIMEOUT_MS; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci /* HWC's instance number is always 0. */ 72062306a36Sopenharmony_ci gd->dev_id.as_uint32 = 0; 72162306a36Sopenharmony_ci gd->dev_id.type = GDMA_DEVICE_HWC; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci gd->pdid = INVALID_PDID; 72462306a36Sopenharmony_ci gd->doorbell = INVALID_DOORBELL; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci /* mana_hwc_init_queues() only creates the required data structures, 72762306a36Sopenharmony_ci * and doesn't touch the HWC device. 72862306a36Sopenharmony_ci */ 72962306a36Sopenharmony_ci err = mana_hwc_init_queues(hwc, HW_CHANNEL_VF_BOOTSTRAP_QUEUE_DEPTH, 73062306a36Sopenharmony_ci HW_CHANNEL_MAX_REQUEST_SIZE, 73162306a36Sopenharmony_ci HW_CHANNEL_MAX_RESPONSE_SIZE); 73262306a36Sopenharmony_ci if (err) { 73362306a36Sopenharmony_ci dev_err(hwc->dev, "Failed to initialize HWC: %d\n", err); 73462306a36Sopenharmony_ci goto out; 73562306a36Sopenharmony_ci } 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci err = mana_hwc_establish_channel(gc, &q_depth_max, &max_req_msg_size, 73862306a36Sopenharmony_ci &max_resp_msg_size); 73962306a36Sopenharmony_ci if (err) { 74062306a36Sopenharmony_ci dev_err(hwc->dev, "Failed to establish HWC: %d\n", err); 74162306a36Sopenharmony_ci goto out; 74262306a36Sopenharmony_ci } 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci err = mana_hwc_test_channel(gc->hwc.driver_data, 74562306a36Sopenharmony_ci HW_CHANNEL_VF_BOOTSTRAP_QUEUE_DEPTH, 74662306a36Sopenharmony_ci max_req_msg_size, max_resp_msg_size); 74762306a36Sopenharmony_ci if (err) { 74862306a36Sopenharmony_ci dev_err(hwc->dev, "Failed to test HWC: %d\n", err); 74962306a36Sopenharmony_ci goto out; 75062306a36Sopenharmony_ci } 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci return 0; 75362306a36Sopenharmony_ciout: 75462306a36Sopenharmony_ci mana_hwc_destroy_channel(gc); 75562306a36Sopenharmony_ci return err; 75662306a36Sopenharmony_ci} 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_civoid mana_hwc_destroy_channel(struct gdma_context *gc) 75962306a36Sopenharmony_ci{ 76062306a36Sopenharmony_ci struct hw_channel_context *hwc = gc->hwc.driver_data; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci if (!hwc) 76362306a36Sopenharmony_ci return; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci /* gc->max_num_cqs is set in mana_hwc_init_event_handler(). If it's 76662306a36Sopenharmony_ci * non-zero, the HWC worked and we should tear down the HWC here. 76762306a36Sopenharmony_ci */ 76862306a36Sopenharmony_ci if (gc->max_num_cqs > 0) { 76962306a36Sopenharmony_ci mana_smc_teardown_hwc(&gc->shm_channel, false); 77062306a36Sopenharmony_ci gc->max_num_cqs = 0; 77162306a36Sopenharmony_ci } 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci kfree(hwc->caller_ctx); 77462306a36Sopenharmony_ci hwc->caller_ctx = NULL; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci if (hwc->txq) 77762306a36Sopenharmony_ci mana_hwc_destroy_wq(hwc, hwc->txq); 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci if (hwc->rxq) 78062306a36Sopenharmony_ci mana_hwc_destroy_wq(hwc, hwc->rxq); 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci if (hwc->cq) 78362306a36Sopenharmony_ci mana_hwc_destroy_cq(hwc->gdma_dev->gdma_context, hwc->cq); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci mana_gd_free_res_map(&hwc->inflight_msg_res); 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci hwc->num_inflight_msg = 0; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci hwc->gdma_dev->doorbell = INVALID_DOORBELL; 79062306a36Sopenharmony_ci hwc->gdma_dev->pdid = INVALID_PDID; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci hwc->hwc_timeout = 0; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci kfree(hwc); 79562306a36Sopenharmony_ci gc->hwc.driver_data = NULL; 79662306a36Sopenharmony_ci gc->hwc.gdma_context = NULL; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci vfree(gc->cq_table); 79962306a36Sopenharmony_ci gc->cq_table = NULL; 80062306a36Sopenharmony_ci} 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ciint mana_hwc_send_request(struct hw_channel_context *hwc, u32 req_len, 80362306a36Sopenharmony_ci const void *req, u32 resp_len, void *resp) 80462306a36Sopenharmony_ci{ 80562306a36Sopenharmony_ci struct gdma_context *gc = hwc->gdma_dev->gdma_context; 80662306a36Sopenharmony_ci struct hwc_work_request *tx_wr; 80762306a36Sopenharmony_ci struct hwc_wq *txq = hwc->txq; 80862306a36Sopenharmony_ci struct gdma_req_hdr *req_msg; 80962306a36Sopenharmony_ci struct hwc_caller_ctx *ctx; 81062306a36Sopenharmony_ci u32 dest_vrcq = 0; 81162306a36Sopenharmony_ci u32 dest_vrq = 0; 81262306a36Sopenharmony_ci u16 msg_id; 81362306a36Sopenharmony_ci int err; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci mana_hwc_get_msg_index(hwc, &msg_id); 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci tx_wr = &txq->msg_buf->reqs[msg_id]; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci if (req_len > tx_wr->buf_len) { 82062306a36Sopenharmony_ci dev_err(hwc->dev, "HWC: req msg size: %d > %d\n", req_len, 82162306a36Sopenharmony_ci tx_wr->buf_len); 82262306a36Sopenharmony_ci err = -EINVAL; 82362306a36Sopenharmony_ci goto out; 82462306a36Sopenharmony_ci } 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci ctx = hwc->caller_ctx + msg_id; 82762306a36Sopenharmony_ci ctx->output_buf = resp; 82862306a36Sopenharmony_ci ctx->output_buflen = resp_len; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci req_msg = (struct gdma_req_hdr *)tx_wr->buf_va; 83162306a36Sopenharmony_ci if (req) 83262306a36Sopenharmony_ci memcpy(req_msg, req, req_len); 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci req_msg->req.hwc_msg_id = msg_id; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci tx_wr->msg_size = req_len; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci if (gc->is_pf) { 83962306a36Sopenharmony_ci dest_vrq = hwc->pf_dest_vrq_id; 84062306a36Sopenharmony_ci dest_vrcq = hwc->pf_dest_vrcq_id; 84162306a36Sopenharmony_ci } 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci err = mana_hwc_post_tx_wqe(txq, tx_wr, dest_vrq, dest_vrcq, false); 84462306a36Sopenharmony_ci if (err) { 84562306a36Sopenharmony_ci dev_err(hwc->dev, "HWC: Failed to post send WQE: %d\n", err); 84662306a36Sopenharmony_ci goto out; 84762306a36Sopenharmony_ci } 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci if (!wait_for_completion_timeout(&ctx->comp_event, 85062306a36Sopenharmony_ci (msecs_to_jiffies(hwc->hwc_timeout) * HZ))) { 85162306a36Sopenharmony_ci dev_err(hwc->dev, "HWC: Request timed out!\n"); 85262306a36Sopenharmony_ci err = -ETIMEDOUT; 85362306a36Sopenharmony_ci goto out; 85462306a36Sopenharmony_ci } 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci if (ctx->error) { 85762306a36Sopenharmony_ci err = ctx->error; 85862306a36Sopenharmony_ci goto out; 85962306a36Sopenharmony_ci } 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci if (ctx->status_code && ctx->status_code != GDMA_STATUS_MORE_ENTRIES) { 86262306a36Sopenharmony_ci dev_err(hwc->dev, "HWC: Failed hw_channel req: 0x%x\n", 86362306a36Sopenharmony_ci ctx->status_code); 86462306a36Sopenharmony_ci err = -EPROTO; 86562306a36Sopenharmony_ci goto out; 86662306a36Sopenharmony_ci } 86762306a36Sopenharmony_ciout: 86862306a36Sopenharmony_ci mana_hwc_put_msg_index(hwc, msg_id); 86962306a36Sopenharmony_ci return err; 87062306a36Sopenharmony_ci} 871