12246cbc2SShay Agroskin // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
21738cd3eSNetanel Belgazal /*
32246cbc2SShay Agroskin * Copyright 2015-2020 Amazon.com, Inc. or its affiliates. All rights reserved.
41738cd3eSNetanel Belgazal */
51738cd3eSNetanel Belgazal
61738cd3eSNetanel Belgazal #include "ena_com.h"
71738cd3eSNetanel Belgazal
81738cd3eSNetanel Belgazal /*****************************************************************************/
91738cd3eSNetanel Belgazal /*****************************************************************************/
101738cd3eSNetanel Belgazal
111738cd3eSNetanel Belgazal /* Timeout in micro-sec */
127102a18aSNetanel Belgazal #define ADMIN_CMD_TIMEOUT_US (3000000)
131738cd3eSNetanel Belgazal
147102a18aSNetanel Belgazal #define ENA_ASYNC_QUEUE_DEPTH 16
151738cd3eSNetanel Belgazal #define ENA_ADMIN_QUEUE_DEPTH 32
161738cd3eSNetanel Belgazal
171738cd3eSNetanel Belgazal
181738cd3eSNetanel Belgazal #define ENA_CTRL_MAJOR 0
191738cd3eSNetanel Belgazal #define ENA_CTRL_MINOR 0
201738cd3eSNetanel Belgazal #define ENA_CTRL_SUB_MINOR 1
211738cd3eSNetanel Belgazal
221738cd3eSNetanel Belgazal #define MIN_ENA_CTRL_VER \
231738cd3eSNetanel Belgazal (((ENA_CTRL_MAJOR) << \
241738cd3eSNetanel Belgazal (ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_SHIFT)) | \
251738cd3eSNetanel Belgazal ((ENA_CTRL_MINOR) << \
261738cd3eSNetanel Belgazal (ENA_REGS_CONTROLLER_VERSION_MINOR_VERSION_SHIFT)) | \
271738cd3eSNetanel Belgazal (ENA_CTRL_SUB_MINOR))
281738cd3eSNetanel Belgazal
291738cd3eSNetanel Belgazal #define ENA_DMA_ADDR_TO_UINT32_LOW(x) ((u32)((u64)(x)))
301738cd3eSNetanel Belgazal #define ENA_DMA_ADDR_TO_UINT32_HIGH(x) ((u32)(((u64)(x)) >> 32))
311738cd3eSNetanel Belgazal
321738cd3eSNetanel Belgazal #define ENA_MMIO_READ_TIMEOUT 0xFFFFFFFF
331738cd3eSNetanel Belgazal
34689b2bdaSArthur Kiyanovski #define ENA_COM_BOUNCE_BUFFER_CNTRL_CNT 4
35689b2bdaSArthur Kiyanovski
36a2cc5198SNetanel Belgazal #define ENA_REGS_ADMIN_INTR_MASK 1
37a2cc5198SNetanel Belgazal
381e9cb763SKrister Johansen #define ENA_MAX_BACKOFF_DELAY_EXP 16U
391e9cb763SKrister Johansen
404bb7f4cfSArthur Kiyanovski #define ENA_MIN_ADMIN_POLL_US 100
414bb7f4cfSArthur Kiyanovski
424bb7f4cfSArthur Kiyanovski #define ENA_MAX_ADMIN_POLL_US 5000
4388aef2f5SNetanel Belgazal
441738cd3eSNetanel Belgazal /*****************************************************************************/
451738cd3eSNetanel Belgazal /*****************************************************************************/
461738cd3eSNetanel Belgazal /*****************************************************************************/
471738cd3eSNetanel Belgazal
481738cd3eSNetanel Belgazal enum ena_cmd_status {
491738cd3eSNetanel Belgazal ENA_CMD_SUBMITTED,
501738cd3eSNetanel Belgazal ENA_CMD_COMPLETED,
511738cd3eSNetanel Belgazal /* Abort - canceled by the driver */
521738cd3eSNetanel Belgazal ENA_CMD_ABORTED,
531738cd3eSNetanel Belgazal };
541738cd3eSNetanel Belgazal
551738cd3eSNetanel Belgazal struct ena_comp_ctx {
561738cd3eSNetanel Belgazal struct completion wait_event;
571738cd3eSNetanel Belgazal struct ena_admin_acq_entry *user_cqe;
581738cd3eSNetanel Belgazal u32 comp_size;
591738cd3eSNetanel Belgazal enum ena_cmd_status status;
601738cd3eSNetanel Belgazal /* status from the device */
611738cd3eSNetanel Belgazal u8 comp_status;
621738cd3eSNetanel Belgazal u8 cmd_opcode;
631738cd3eSNetanel Belgazal bool occupied;
641738cd3eSNetanel Belgazal };
651738cd3eSNetanel Belgazal
661738cd3eSNetanel Belgazal struct ena_com_stats_ctx {
671738cd3eSNetanel Belgazal struct ena_admin_aq_get_stats_cmd get_cmd;
681738cd3eSNetanel Belgazal struct ena_admin_acq_get_stats_resp get_resp;
691738cd3eSNetanel Belgazal };
701738cd3eSNetanel Belgazal
ena_com_mem_addr_set(struct ena_com_dev * ena_dev,struct ena_common_mem_addr * ena_addr,dma_addr_t addr)71c2b54204SSameeh Jubran static int ena_com_mem_addr_set(struct ena_com_dev *ena_dev,
721738cd3eSNetanel Belgazal struct ena_common_mem_addr *ena_addr,
731738cd3eSNetanel Belgazal dma_addr_t addr)
741738cd3eSNetanel Belgazal {
751738cd3eSNetanel Belgazal if ((addr & GENMASK_ULL(ena_dev->dma_addr_bits - 1, 0)) != addr) {
76da580ca8SShay Agroskin netdev_err(ena_dev->net_device,
77da580ca8SShay Agroskin "DMA address has more bits that the device supports\n");
781738cd3eSNetanel Belgazal return -EINVAL;
791738cd3eSNetanel Belgazal }
801738cd3eSNetanel Belgazal
813ae5907cSNetanel Belgazal ena_addr->mem_addr_low = lower_32_bits(addr);
823ae5907cSNetanel Belgazal ena_addr->mem_addr_high = (u16)upper_32_bits(addr);
831738cd3eSNetanel Belgazal
841738cd3eSNetanel Belgazal return 0;
851738cd3eSNetanel Belgazal }
861738cd3eSNetanel Belgazal
ena_com_admin_init_sq(struct ena_com_admin_queue * admin_queue)87bf2746e8SShay Agroskin static int ena_com_admin_init_sq(struct ena_com_admin_queue *admin_queue)
881738cd3eSNetanel Belgazal {
89da580ca8SShay Agroskin struct ena_com_dev *ena_dev = admin_queue->ena_dev;
90bf2746e8SShay Agroskin struct ena_com_admin_sq *sq = &admin_queue->sq;
91bf2746e8SShay Agroskin u16 size = ADMIN_SQ_SIZE(admin_queue->q_depth);
921738cd3eSNetanel Belgazal
93*26668c2dSDavid Arinzon sq->entries = dma_alloc_coherent(admin_queue->q_dmadev, size, &sq->dma_addr, GFP_KERNEL);
941738cd3eSNetanel Belgazal
951738cd3eSNetanel Belgazal if (!sq->entries) {
96da580ca8SShay Agroskin netdev_err(ena_dev->net_device, "Memory allocation failed\n");
971738cd3eSNetanel Belgazal return -ENOMEM;
981738cd3eSNetanel Belgazal }
991738cd3eSNetanel Belgazal
1001738cd3eSNetanel Belgazal sq->head = 0;
1011738cd3eSNetanel Belgazal sq->tail = 0;
1021738cd3eSNetanel Belgazal sq->phase = 1;
1031738cd3eSNetanel Belgazal
1041738cd3eSNetanel Belgazal sq->db_addr = NULL;
1051738cd3eSNetanel Belgazal
1061738cd3eSNetanel Belgazal return 0;
1071738cd3eSNetanel Belgazal }
1081738cd3eSNetanel Belgazal
ena_com_admin_init_cq(struct ena_com_admin_queue * admin_queue)109bf2746e8SShay Agroskin static int ena_com_admin_init_cq(struct ena_com_admin_queue *admin_queue)
1101738cd3eSNetanel Belgazal {
111da580ca8SShay Agroskin struct ena_com_dev *ena_dev = admin_queue->ena_dev;
112bf2746e8SShay Agroskin struct ena_com_admin_cq *cq = &admin_queue->cq;
113bf2746e8SShay Agroskin u16 size = ADMIN_CQ_SIZE(admin_queue->q_depth);
1141738cd3eSNetanel Belgazal
115*26668c2dSDavid Arinzon cq->entries = dma_alloc_coherent(admin_queue->q_dmadev, size, &cq->dma_addr, GFP_KERNEL);
1161738cd3eSNetanel Belgazal
1171738cd3eSNetanel Belgazal if (!cq->entries) {
118da580ca8SShay Agroskin netdev_err(ena_dev->net_device, "Memory allocation failed\n");
1191738cd3eSNetanel Belgazal return -ENOMEM;
1201738cd3eSNetanel Belgazal }
1211738cd3eSNetanel Belgazal
1221738cd3eSNetanel Belgazal cq->head = 0;
1231738cd3eSNetanel Belgazal cq->phase = 1;
1241738cd3eSNetanel Belgazal
1251738cd3eSNetanel Belgazal return 0;
1261738cd3eSNetanel Belgazal }
1271738cd3eSNetanel Belgazal
ena_com_admin_init_aenq(struct ena_com_dev * ena_dev,struct ena_aenq_handlers * aenq_handlers)128bf2746e8SShay Agroskin static int ena_com_admin_init_aenq(struct ena_com_dev *ena_dev,
1291738cd3eSNetanel Belgazal struct ena_aenq_handlers *aenq_handlers)
1301738cd3eSNetanel Belgazal {
131bf2746e8SShay Agroskin struct ena_com_aenq *aenq = &ena_dev->aenq;
1321738cd3eSNetanel Belgazal u32 addr_low, addr_high, aenq_caps;
1331738cd3eSNetanel Belgazal u16 size;
1341738cd3eSNetanel Belgazal
135bf2746e8SShay Agroskin ena_dev->aenq.q_depth = ENA_ASYNC_QUEUE_DEPTH;
1361738cd3eSNetanel Belgazal size = ADMIN_AENQ_SIZE(ENA_ASYNC_QUEUE_DEPTH);
137*26668c2dSDavid Arinzon aenq->entries = dma_alloc_coherent(ena_dev->dmadev, size, &aenq->dma_addr, GFP_KERNEL);
1381738cd3eSNetanel Belgazal
1391738cd3eSNetanel Belgazal if (!aenq->entries) {
140da580ca8SShay Agroskin netdev_err(ena_dev->net_device, "Memory allocation failed\n");
1411738cd3eSNetanel Belgazal return -ENOMEM;
1421738cd3eSNetanel Belgazal }
1431738cd3eSNetanel Belgazal
1441738cd3eSNetanel Belgazal aenq->head = aenq->q_depth;
1451738cd3eSNetanel Belgazal aenq->phase = 1;
1461738cd3eSNetanel Belgazal
1471738cd3eSNetanel Belgazal addr_low = ENA_DMA_ADDR_TO_UINT32_LOW(aenq->dma_addr);
1481738cd3eSNetanel Belgazal addr_high = ENA_DMA_ADDR_TO_UINT32_HIGH(aenq->dma_addr);
1491738cd3eSNetanel Belgazal
150bf2746e8SShay Agroskin writel(addr_low, ena_dev->reg_bar + ENA_REGS_AENQ_BASE_LO_OFF);
151bf2746e8SShay Agroskin writel(addr_high, ena_dev->reg_bar + ENA_REGS_AENQ_BASE_HI_OFF);
1521738cd3eSNetanel Belgazal
1531738cd3eSNetanel Belgazal aenq_caps = 0;
154bf2746e8SShay Agroskin aenq_caps |= ena_dev->aenq.q_depth & ENA_REGS_AENQ_CAPS_AENQ_DEPTH_MASK;
155*26668c2dSDavid Arinzon aenq_caps |=
156*26668c2dSDavid Arinzon (sizeof(struct ena_admin_aenq_entry) << ENA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE_SHIFT) &
1571738cd3eSNetanel Belgazal ENA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE_MASK;
158bf2746e8SShay Agroskin writel(aenq_caps, ena_dev->reg_bar + ENA_REGS_AENQ_CAPS_OFF);
1591738cd3eSNetanel Belgazal
1601738cd3eSNetanel Belgazal if (unlikely(!aenq_handlers)) {
161*26668c2dSDavid Arinzon netdev_err(ena_dev->net_device, "AENQ handlers pointer is NULL\n");
1621738cd3eSNetanel Belgazal return -EINVAL;
1631738cd3eSNetanel Belgazal }
1641738cd3eSNetanel Belgazal
1651738cd3eSNetanel Belgazal aenq->aenq_handlers = aenq_handlers;
1661738cd3eSNetanel Belgazal
1671738cd3eSNetanel Belgazal return 0;
1681738cd3eSNetanel Belgazal }
1691738cd3eSNetanel Belgazal
comp_ctxt_release(struct ena_com_admin_queue * queue,struct ena_comp_ctx * comp_ctx)170c2b54204SSameeh Jubran static void comp_ctxt_release(struct ena_com_admin_queue *queue,
1711738cd3eSNetanel Belgazal struct ena_comp_ctx *comp_ctx)
1721738cd3eSNetanel Belgazal {
1731738cd3eSNetanel Belgazal comp_ctx->occupied = false;
1741738cd3eSNetanel Belgazal atomic_dec(&queue->outstanding_cmds);
1751738cd3eSNetanel Belgazal }
1761738cd3eSNetanel Belgazal
get_comp_ctxt(struct ena_com_admin_queue * admin_queue,u16 command_id,bool capture)177bf2746e8SShay Agroskin static struct ena_comp_ctx *get_comp_ctxt(struct ena_com_admin_queue *admin_queue,
1781738cd3eSNetanel Belgazal u16 command_id, bool capture)
1791738cd3eSNetanel Belgazal {
180bf2746e8SShay Agroskin if (unlikely(command_id >= admin_queue->q_depth)) {
181da580ca8SShay Agroskin netdev_err(admin_queue->ena_dev->net_device,
182da580ca8SShay Agroskin "Command id is larger than the queue size. cmd_id: %u queue size %d\n",
183bf2746e8SShay Agroskin command_id, admin_queue->q_depth);
1841738cd3eSNetanel Belgazal return NULL;
1851738cd3eSNetanel Belgazal }
1861738cd3eSNetanel Belgazal
187bf2746e8SShay Agroskin if (unlikely(!admin_queue->comp_ctx)) {
188*26668c2dSDavid Arinzon netdev_err(admin_queue->ena_dev->net_device, "Completion context is NULL\n");
1890a39a35fSArthur Kiyanovski return NULL;
1900a39a35fSArthur Kiyanovski }
1910a39a35fSArthur Kiyanovski
192bf2746e8SShay Agroskin if (unlikely(admin_queue->comp_ctx[command_id].occupied && capture)) {
193*26668c2dSDavid Arinzon netdev_err(admin_queue->ena_dev->net_device, "Completion context is occupied\n");
1941738cd3eSNetanel Belgazal return NULL;
1951738cd3eSNetanel Belgazal }
1961738cd3eSNetanel Belgazal
1971738cd3eSNetanel Belgazal if (capture) {
198bf2746e8SShay Agroskin atomic_inc(&admin_queue->outstanding_cmds);
199bf2746e8SShay Agroskin admin_queue->comp_ctx[command_id].occupied = true;
2001738cd3eSNetanel Belgazal }
2011738cd3eSNetanel Belgazal
202bf2746e8SShay Agroskin return &admin_queue->comp_ctx[command_id];
2031738cd3eSNetanel Belgazal }
2041738cd3eSNetanel Belgazal
__ena_com_submit_admin_cmd(struct ena_com_admin_queue * admin_queue,struct ena_admin_aq_entry * cmd,size_t cmd_size_in_bytes,struct ena_admin_acq_entry * comp,size_t comp_size_in_bytes)2051738cd3eSNetanel Belgazal static struct ena_comp_ctx *__ena_com_submit_admin_cmd(struct ena_com_admin_queue *admin_queue,
2061738cd3eSNetanel Belgazal struct ena_admin_aq_entry *cmd,
2071738cd3eSNetanel Belgazal size_t cmd_size_in_bytes,
2081738cd3eSNetanel Belgazal struct ena_admin_acq_entry *comp,
2091738cd3eSNetanel Belgazal size_t comp_size_in_bytes)
2101738cd3eSNetanel Belgazal {
2111738cd3eSNetanel Belgazal struct ena_comp_ctx *comp_ctx;
2121738cd3eSNetanel Belgazal u16 tail_masked, cmd_id;
2131738cd3eSNetanel Belgazal u16 queue_size_mask;
2141738cd3eSNetanel Belgazal u16 cnt;
2151738cd3eSNetanel Belgazal
2161738cd3eSNetanel Belgazal queue_size_mask = admin_queue->q_depth - 1;
2171738cd3eSNetanel Belgazal
2181738cd3eSNetanel Belgazal tail_masked = admin_queue->sq.tail & queue_size_mask;
2191738cd3eSNetanel Belgazal
2201738cd3eSNetanel Belgazal /* In case of queue FULL */
221bd791175SArthur Kiyanovski cnt = (u16)atomic_read(&admin_queue->outstanding_cmds);
2221738cd3eSNetanel Belgazal if (cnt >= admin_queue->q_depth) {
223*26668c2dSDavid Arinzon netdev_dbg(admin_queue->ena_dev->net_device, "Admin queue is full.\n");
2241738cd3eSNetanel Belgazal admin_queue->stats.out_of_space++;
2251738cd3eSNetanel Belgazal return ERR_PTR(-ENOSPC);
2261738cd3eSNetanel Belgazal }
2271738cd3eSNetanel Belgazal
2281738cd3eSNetanel Belgazal cmd_id = admin_queue->curr_cmd_id;
2291738cd3eSNetanel Belgazal
2301738cd3eSNetanel Belgazal cmd->aq_common_descriptor.flags |= admin_queue->sq.phase &
2311738cd3eSNetanel Belgazal ENA_ADMIN_AQ_COMMON_DESC_PHASE_MASK;
2321738cd3eSNetanel Belgazal
2331738cd3eSNetanel Belgazal cmd->aq_common_descriptor.command_id |= cmd_id &
2341738cd3eSNetanel Belgazal ENA_ADMIN_AQ_COMMON_DESC_COMMAND_ID_MASK;
2351738cd3eSNetanel Belgazal
2361738cd3eSNetanel Belgazal comp_ctx = get_comp_ctxt(admin_queue, cmd_id, true);
2371738cd3eSNetanel Belgazal if (unlikely(!comp_ctx))
2381738cd3eSNetanel Belgazal return ERR_PTR(-EINVAL);
2391738cd3eSNetanel Belgazal
2401738cd3eSNetanel Belgazal comp_ctx->status = ENA_CMD_SUBMITTED;
2411738cd3eSNetanel Belgazal comp_ctx->comp_size = (u32)comp_size_in_bytes;
2421738cd3eSNetanel Belgazal comp_ctx->user_cqe = comp;
2431738cd3eSNetanel Belgazal comp_ctx->cmd_opcode = cmd->aq_common_descriptor.opcode;
2441738cd3eSNetanel Belgazal
2451738cd3eSNetanel Belgazal reinit_completion(&comp_ctx->wait_event);
2461738cd3eSNetanel Belgazal
2471738cd3eSNetanel Belgazal memcpy(&admin_queue->sq.entries[tail_masked], cmd, cmd_size_in_bytes);
2481738cd3eSNetanel Belgazal
2491738cd3eSNetanel Belgazal admin_queue->curr_cmd_id = (admin_queue->curr_cmd_id + 1) &
2501738cd3eSNetanel Belgazal queue_size_mask;
2511738cd3eSNetanel Belgazal
2521738cd3eSNetanel Belgazal admin_queue->sq.tail++;
2531738cd3eSNetanel Belgazal admin_queue->stats.submitted_cmd++;
2541738cd3eSNetanel Belgazal
2551738cd3eSNetanel Belgazal if (unlikely((admin_queue->sq.tail & queue_size_mask) == 0))
2561738cd3eSNetanel Belgazal admin_queue->sq.phase = !admin_queue->sq.phase;
2571738cd3eSNetanel Belgazal
2581738cd3eSNetanel Belgazal writel(admin_queue->sq.tail, admin_queue->sq.db_addr);
2591738cd3eSNetanel Belgazal
2601738cd3eSNetanel Belgazal return comp_ctx;
2611738cd3eSNetanel Belgazal }
2621738cd3eSNetanel Belgazal
ena_com_init_comp_ctxt(struct ena_com_admin_queue * admin_queue)263bf2746e8SShay Agroskin static int ena_com_init_comp_ctxt(struct ena_com_admin_queue *admin_queue)
2641738cd3eSNetanel Belgazal {
265da580ca8SShay Agroskin struct ena_com_dev *ena_dev = admin_queue->ena_dev;
266bf2746e8SShay Agroskin size_t size = admin_queue->q_depth * sizeof(struct ena_comp_ctx);
2671738cd3eSNetanel Belgazal struct ena_comp_ctx *comp_ctx;
2681738cd3eSNetanel Belgazal u16 i;
2691738cd3eSNetanel Belgazal
270*26668c2dSDavid Arinzon admin_queue->comp_ctx = devm_kzalloc(admin_queue->q_dmadev, size, GFP_KERNEL);
271bf2746e8SShay Agroskin if (unlikely(!admin_queue->comp_ctx)) {
272da580ca8SShay Agroskin netdev_err(ena_dev->net_device, "Memory allocation failed\n");
2731738cd3eSNetanel Belgazal return -ENOMEM;
2741738cd3eSNetanel Belgazal }
2751738cd3eSNetanel Belgazal
276bf2746e8SShay Agroskin for (i = 0; i < admin_queue->q_depth; i++) {
277bf2746e8SShay Agroskin comp_ctx = get_comp_ctxt(admin_queue, i, false);
2781738cd3eSNetanel Belgazal if (comp_ctx)
2791738cd3eSNetanel Belgazal init_completion(&comp_ctx->wait_event);
2801738cd3eSNetanel Belgazal }
2811738cd3eSNetanel Belgazal
2821738cd3eSNetanel Belgazal return 0;
2831738cd3eSNetanel Belgazal }
2841738cd3eSNetanel Belgazal
ena_com_submit_admin_cmd(struct ena_com_admin_queue * admin_queue,struct ena_admin_aq_entry * cmd,size_t cmd_size_in_bytes,struct ena_admin_acq_entry * comp,size_t comp_size_in_bytes)2851738cd3eSNetanel Belgazal static struct ena_comp_ctx *ena_com_submit_admin_cmd(struct ena_com_admin_queue *admin_queue,
2861738cd3eSNetanel Belgazal struct ena_admin_aq_entry *cmd,
2871738cd3eSNetanel Belgazal size_t cmd_size_in_bytes,
2881738cd3eSNetanel Belgazal struct ena_admin_acq_entry *comp,
2891738cd3eSNetanel Belgazal size_t comp_size_in_bytes)
2901738cd3eSNetanel Belgazal {
291bd791175SArthur Kiyanovski unsigned long flags = 0;
2921738cd3eSNetanel Belgazal struct ena_comp_ctx *comp_ctx;
2931738cd3eSNetanel Belgazal
2941738cd3eSNetanel Belgazal spin_lock_irqsave(&admin_queue->q_lock, flags);
2951738cd3eSNetanel Belgazal if (unlikely(!admin_queue->running_state)) {
2961738cd3eSNetanel Belgazal spin_unlock_irqrestore(&admin_queue->q_lock, flags);
2971738cd3eSNetanel Belgazal return ERR_PTR(-ENODEV);
2981738cd3eSNetanel Belgazal }
2991738cd3eSNetanel Belgazal comp_ctx = __ena_com_submit_admin_cmd(admin_queue, cmd,
3001738cd3eSNetanel Belgazal cmd_size_in_bytes,
3011738cd3eSNetanel Belgazal comp,
3021738cd3eSNetanel Belgazal comp_size_in_bytes);
3031f4cf93bSTobias Klauser if (IS_ERR(comp_ctx))
3041738cd3eSNetanel Belgazal admin_queue->running_state = false;
3051738cd3eSNetanel Belgazal spin_unlock_irqrestore(&admin_queue->q_lock, flags);
3061738cd3eSNetanel Belgazal
3071738cd3eSNetanel Belgazal return comp_ctx;
3081738cd3eSNetanel Belgazal }
3091738cd3eSNetanel Belgazal
ena_com_init_io_sq(struct ena_com_dev * ena_dev,struct ena_com_create_io_ctx * ctx,struct ena_com_io_sq * io_sq)3101738cd3eSNetanel Belgazal static int ena_com_init_io_sq(struct ena_com_dev *ena_dev,
3111738cd3eSNetanel Belgazal struct ena_com_create_io_ctx *ctx,
3121738cd3eSNetanel Belgazal struct ena_com_io_sq *io_sq)
3131738cd3eSNetanel Belgazal {
3141738cd3eSNetanel Belgazal size_t size;
3151738cd3eSNetanel Belgazal
31691750110SNetanel Belgazal memset(&io_sq->desc_addr, 0x0, sizeof(io_sq->desc_addr));
3171738cd3eSNetanel Belgazal
318bd791175SArthur Kiyanovski io_sq->dma_addr_bits = (u8)ena_dev->dma_addr_bits;
3191738cd3eSNetanel Belgazal io_sq->desc_entry_size =
3201738cd3eSNetanel Belgazal (io_sq->direction == ENA_COM_IO_QUEUE_DIRECTION_TX) ?
3211738cd3eSNetanel Belgazal sizeof(struct ena_eth_io_tx_desc) :
3221738cd3eSNetanel Belgazal sizeof(struct ena_eth_io_rx_desc);
3231738cd3eSNetanel Belgazal
3241738cd3eSNetanel Belgazal size = io_sq->desc_entry_size * io_sq->q_depth;
3251738cd3eSNetanel Belgazal
3261738cd3eSNetanel Belgazal if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST) {
3271738cd3eSNetanel Belgazal io_sq->desc_addr.virt_addr =
328*26668c2dSDavid Arinzon dma_alloc_coherent(ena_dev->dmadev, size, &io_sq->desc_addr.phys_addr,
3291738cd3eSNetanel Belgazal GFP_KERNEL);
3301738cd3eSNetanel Belgazal if (!io_sq->desc_addr.virt_addr) {
3311738cd3eSNetanel Belgazal io_sq->desc_addr.virt_addr =
332750afb08SLuis Chamberlain dma_alloc_coherent(ena_dev->dmadev, size,
333*26668c2dSDavid Arinzon &io_sq->desc_addr.phys_addr, GFP_KERNEL);
3341738cd3eSNetanel Belgazal }
3351738cd3eSNetanel Belgazal
3361738cd3eSNetanel Belgazal if (!io_sq->desc_addr.virt_addr) {
337*26668c2dSDavid Arinzon netdev_err(ena_dev->net_device, "Memory allocation failed\n");
3381738cd3eSNetanel Belgazal return -ENOMEM;
3391738cd3eSNetanel Belgazal }
340689b2bdaSArthur Kiyanovski }
341689b2bdaSArthur Kiyanovski
342689b2bdaSArthur Kiyanovski if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) {
343689b2bdaSArthur Kiyanovski /* Allocate bounce buffers */
344689b2bdaSArthur Kiyanovski io_sq->bounce_buf_ctrl.buffer_size =
345689b2bdaSArthur Kiyanovski ena_dev->llq_info.desc_list_entry_size;
346689b2bdaSArthur Kiyanovski io_sq->bounce_buf_ctrl.buffers_num =
347689b2bdaSArthur Kiyanovski ENA_COM_BOUNCE_BUFFER_CNTRL_CNT;
348689b2bdaSArthur Kiyanovski io_sq->bounce_buf_ctrl.next_to_use = 0;
349689b2bdaSArthur Kiyanovski
3504d142ddaSDavid Arinzon size = (size_t)io_sq->bounce_buf_ctrl.buffer_size *
351689b2bdaSArthur Kiyanovski io_sq->bounce_buf_ctrl.buffers_num;
352689b2bdaSArthur Kiyanovski
353*26668c2dSDavid Arinzon io_sq->bounce_buf_ctrl.base_buffer = devm_kzalloc(ena_dev->dmadev, size, GFP_KERNEL);
354689b2bdaSArthur Kiyanovski if (!io_sq->bounce_buf_ctrl.base_buffer)
355689b2bdaSArthur Kiyanovski io_sq->bounce_buf_ctrl.base_buffer =
356689b2bdaSArthur Kiyanovski devm_kzalloc(ena_dev->dmadev, size, GFP_KERNEL);
357689b2bdaSArthur Kiyanovski
358689b2bdaSArthur Kiyanovski if (!io_sq->bounce_buf_ctrl.base_buffer) {
359*26668c2dSDavid Arinzon netdev_err(ena_dev->net_device, "Bounce buffer memory allocation failed\n");
360689b2bdaSArthur Kiyanovski return -ENOMEM;
361689b2bdaSArthur Kiyanovski }
362689b2bdaSArthur Kiyanovski
363689b2bdaSArthur Kiyanovski memcpy(&io_sq->llq_info, &ena_dev->llq_info,
364689b2bdaSArthur Kiyanovski sizeof(io_sq->llq_info));
365689b2bdaSArthur Kiyanovski
366689b2bdaSArthur Kiyanovski /* Initiate the first bounce buffer */
367689b2bdaSArthur Kiyanovski io_sq->llq_buf_ctrl.curr_bounce_buf =
368689b2bdaSArthur Kiyanovski ena_com_get_next_bounce_buffer(&io_sq->bounce_buf_ctrl);
369689b2bdaSArthur Kiyanovski memset(io_sq->llq_buf_ctrl.curr_bounce_buf,
370689b2bdaSArthur Kiyanovski 0x0, io_sq->llq_info.desc_list_entry_size);
371689b2bdaSArthur Kiyanovski io_sq->llq_buf_ctrl.descs_left_in_line =
372689b2bdaSArthur Kiyanovski io_sq->llq_info.descs_num_before_header;
3730e3a3f6dSArthur Kiyanovski io_sq->disable_meta_caching =
3740e3a3f6dSArthur Kiyanovski io_sq->llq_info.disable_meta_caching;
37505d62ca2SSameeh Jubran
37605d62ca2SSameeh Jubran if (io_sq->llq_info.max_entries_in_tx_burst > 0)
37705d62ca2SSameeh Jubran io_sq->entries_in_tx_burst_left =
37805d62ca2SSameeh Jubran io_sq->llq_info.max_entries_in_tx_burst;
379689b2bdaSArthur Kiyanovski }
3801738cd3eSNetanel Belgazal
3811738cd3eSNetanel Belgazal io_sq->tail = 0;
3821738cd3eSNetanel Belgazal io_sq->next_to_comp = 0;
3831738cd3eSNetanel Belgazal io_sq->phase = 1;
3841738cd3eSNetanel Belgazal
3851738cd3eSNetanel Belgazal return 0;
3861738cd3eSNetanel Belgazal }
3871738cd3eSNetanel Belgazal
ena_com_init_io_cq(struct ena_com_dev * ena_dev,struct ena_com_create_io_ctx * ctx,struct ena_com_io_cq * io_cq)3881738cd3eSNetanel Belgazal static int ena_com_init_io_cq(struct ena_com_dev *ena_dev,
3891738cd3eSNetanel Belgazal struct ena_com_create_io_ctx *ctx,
3901738cd3eSNetanel Belgazal struct ena_com_io_cq *io_cq)
3911738cd3eSNetanel Belgazal {
3921738cd3eSNetanel Belgazal size_t size;
3931738cd3eSNetanel Belgazal
39491750110SNetanel Belgazal memset(&io_cq->cdesc_addr, 0x0, sizeof(io_cq->cdesc_addr));
3951738cd3eSNetanel Belgazal
3961738cd3eSNetanel Belgazal /* Use the basic completion descriptor for Rx */
3971738cd3eSNetanel Belgazal io_cq->cdesc_entry_size_in_bytes =
3981738cd3eSNetanel Belgazal (io_cq->direction == ENA_COM_IO_QUEUE_DIRECTION_TX) ?
3991738cd3eSNetanel Belgazal sizeof(struct ena_eth_io_tx_cdesc) :
4001738cd3eSNetanel Belgazal sizeof(struct ena_eth_io_rx_cdesc_base);
4011738cd3eSNetanel Belgazal
4021738cd3eSNetanel Belgazal size = io_cq->cdesc_entry_size_in_bytes * io_cq->q_depth;
4031738cd3eSNetanel Belgazal
4041738cd3eSNetanel Belgazal io_cq->cdesc_addr.virt_addr =
405*26668c2dSDavid Arinzon dma_alloc_coherent(ena_dev->dmadev, size, &io_cq->cdesc_addr.phys_addr, GFP_KERNEL);
4061738cd3eSNetanel Belgazal if (!io_cq->cdesc_addr.virt_addr) {
4071738cd3eSNetanel Belgazal io_cq->cdesc_addr.virt_addr =
408*26668c2dSDavid Arinzon dma_alloc_coherent(ena_dev->dmadev, size, &io_cq->cdesc_addr.phys_addr,
4091738cd3eSNetanel Belgazal GFP_KERNEL);
4101738cd3eSNetanel Belgazal }
4111738cd3eSNetanel Belgazal
4121738cd3eSNetanel Belgazal if (!io_cq->cdesc_addr.virt_addr) {
413da580ca8SShay Agroskin netdev_err(ena_dev->net_device, "Memory allocation failed\n");
4141738cd3eSNetanel Belgazal return -ENOMEM;
4151738cd3eSNetanel Belgazal }
4161738cd3eSNetanel Belgazal
4171738cd3eSNetanel Belgazal io_cq->phase = 1;
4181738cd3eSNetanel Belgazal io_cq->head = 0;
4191738cd3eSNetanel Belgazal
4201738cd3eSNetanel Belgazal return 0;
4211738cd3eSNetanel Belgazal }
4221738cd3eSNetanel Belgazal
ena_com_handle_single_admin_completion(struct ena_com_admin_queue * admin_queue,struct ena_admin_acq_entry * cqe)4231738cd3eSNetanel Belgazal static void ena_com_handle_single_admin_completion(struct ena_com_admin_queue *admin_queue,
4241738cd3eSNetanel Belgazal struct ena_admin_acq_entry *cqe)
4251738cd3eSNetanel Belgazal {
4261738cd3eSNetanel Belgazal struct ena_comp_ctx *comp_ctx;
4271738cd3eSNetanel Belgazal u16 cmd_id;
4281738cd3eSNetanel Belgazal
4291738cd3eSNetanel Belgazal cmd_id = cqe->acq_common_descriptor.command &
4301738cd3eSNetanel Belgazal ENA_ADMIN_ACQ_COMMON_DESC_COMMAND_ID_MASK;
4311738cd3eSNetanel Belgazal
4321738cd3eSNetanel Belgazal comp_ctx = get_comp_ctxt(admin_queue, cmd_id, false);
4331738cd3eSNetanel Belgazal if (unlikely(!comp_ctx)) {
434da580ca8SShay Agroskin netdev_err(admin_queue->ena_dev->net_device,
435da580ca8SShay Agroskin "comp_ctx is NULL. Changing the admin queue running state\n");
4361738cd3eSNetanel Belgazal admin_queue->running_state = false;
4371738cd3eSNetanel Belgazal return;
4381738cd3eSNetanel Belgazal }
4391738cd3eSNetanel Belgazal
4401738cd3eSNetanel Belgazal comp_ctx->status = ENA_CMD_COMPLETED;
4411738cd3eSNetanel Belgazal comp_ctx->comp_status = cqe->acq_common_descriptor.status;
4421738cd3eSNetanel Belgazal
4431738cd3eSNetanel Belgazal if (comp_ctx->user_cqe)
4441738cd3eSNetanel Belgazal memcpy(comp_ctx->user_cqe, (void *)cqe, comp_ctx->comp_size);
4451738cd3eSNetanel Belgazal
4461738cd3eSNetanel Belgazal if (!admin_queue->polling)
4471738cd3eSNetanel Belgazal complete(&comp_ctx->wait_event);
4481738cd3eSNetanel Belgazal }
4491738cd3eSNetanel Belgazal
ena_com_handle_admin_completion(struct ena_com_admin_queue * admin_queue)4501738cd3eSNetanel Belgazal static void ena_com_handle_admin_completion(struct ena_com_admin_queue *admin_queue)
4511738cd3eSNetanel Belgazal {
4521738cd3eSNetanel Belgazal struct ena_admin_acq_entry *cqe = NULL;
4531738cd3eSNetanel Belgazal u16 comp_num = 0;
4541738cd3eSNetanel Belgazal u16 head_masked;
4551738cd3eSNetanel Belgazal u8 phase;
4561738cd3eSNetanel Belgazal
4571738cd3eSNetanel Belgazal head_masked = admin_queue->cq.head & (admin_queue->q_depth - 1);
4581738cd3eSNetanel Belgazal phase = admin_queue->cq.phase;
4591738cd3eSNetanel Belgazal
4601738cd3eSNetanel Belgazal cqe = &admin_queue->cq.entries[head_masked];
4611738cd3eSNetanel Belgazal
4621738cd3eSNetanel Belgazal /* Go over all the completions */
46328abf4e9SNetanel Belgazal while ((READ_ONCE(cqe->acq_common_descriptor.flags) &
4641738cd3eSNetanel Belgazal ENA_ADMIN_ACQ_COMMON_DESC_PHASE_MASK) == phase) {
4651738cd3eSNetanel Belgazal /* Do not read the rest of the completion entry before the
4661738cd3eSNetanel Belgazal * phase bit was validated
4671738cd3eSNetanel Belgazal */
46837dff155SNetanel Belgazal dma_rmb();
4691738cd3eSNetanel Belgazal ena_com_handle_single_admin_completion(admin_queue, cqe);
4701738cd3eSNetanel Belgazal
4711738cd3eSNetanel Belgazal head_masked++;
4721738cd3eSNetanel Belgazal comp_num++;
4731738cd3eSNetanel Belgazal if (unlikely(head_masked == admin_queue->q_depth)) {
4741738cd3eSNetanel Belgazal head_masked = 0;
4751738cd3eSNetanel Belgazal phase = !phase;
4761738cd3eSNetanel Belgazal }
4771738cd3eSNetanel Belgazal
4781738cd3eSNetanel Belgazal cqe = &admin_queue->cq.entries[head_masked];
4791738cd3eSNetanel Belgazal }
4801738cd3eSNetanel Belgazal
4811738cd3eSNetanel Belgazal admin_queue->cq.head += comp_num;
4821738cd3eSNetanel Belgazal admin_queue->cq.phase = phase;
4831738cd3eSNetanel Belgazal admin_queue->sq.head += comp_num;
4841738cd3eSNetanel Belgazal admin_queue->stats.completed_cmd += comp_num;
4851738cd3eSNetanel Belgazal }
4861738cd3eSNetanel Belgazal
ena_com_comp_status_to_errno(struct ena_com_admin_queue * admin_queue,u8 comp_status)487da580ca8SShay Agroskin static int ena_com_comp_status_to_errno(struct ena_com_admin_queue *admin_queue,
488da580ca8SShay Agroskin u8 comp_status)
4891738cd3eSNetanel Belgazal {
4901738cd3eSNetanel Belgazal if (unlikely(comp_status != 0))
491*26668c2dSDavid Arinzon netdev_err(admin_queue->ena_dev->net_device, "Admin command failed[%u]\n",
492*26668c2dSDavid Arinzon comp_status);
4931738cd3eSNetanel Belgazal
4941738cd3eSNetanel Belgazal switch (comp_status) {
4951738cd3eSNetanel Belgazal case ENA_ADMIN_SUCCESS:
4961738cd3eSNetanel Belgazal return 0;
4971738cd3eSNetanel Belgazal case ENA_ADMIN_RESOURCE_ALLOCATION_FAILURE:
4981738cd3eSNetanel Belgazal return -ENOMEM;
4991738cd3eSNetanel Belgazal case ENA_ADMIN_UNSUPPORTED_OPCODE:
500d1497638SNetanel Belgazal return -EOPNOTSUPP;
5011738cd3eSNetanel Belgazal case ENA_ADMIN_BAD_OPCODE:
5021738cd3eSNetanel Belgazal case ENA_ADMIN_MALFORMED_REQUEST:
5031738cd3eSNetanel Belgazal case ENA_ADMIN_ILLEGAL_PARAMETER:
5041738cd3eSNetanel Belgazal case ENA_ADMIN_UNKNOWN_ERROR:
5051738cd3eSNetanel Belgazal return -EINVAL;
506f49ed500SShay Agroskin case ENA_ADMIN_RESOURCE_BUSY:
507f49ed500SShay Agroskin return -EAGAIN;
5081738cd3eSNetanel Belgazal }
5091738cd3eSNetanel Belgazal
510adb3fb38SArthur Kiyanovski return -EINVAL;
5111738cd3eSNetanel Belgazal }
5121738cd3eSNetanel Belgazal
ena_delay_exponential_backoff_us(u32 exp,u32 delay_us)5134bb7f4cfSArthur Kiyanovski static void ena_delay_exponential_backoff_us(u32 exp, u32 delay_us)
5144bb7f4cfSArthur Kiyanovski {
5151e9cb763SKrister Johansen exp = min_t(u32, exp, ENA_MAX_BACKOFF_DELAY_EXP);
5164bb7f4cfSArthur Kiyanovski delay_us = max_t(u32, ENA_MIN_ADMIN_POLL_US, delay_us);
5174bb7f4cfSArthur Kiyanovski delay_us = min_t(u32, delay_us * (1U << exp), ENA_MAX_ADMIN_POLL_US);
5184bb7f4cfSArthur Kiyanovski usleep_range(delay_us, 2 * delay_us);
5194bb7f4cfSArthur Kiyanovski }
5204bb7f4cfSArthur Kiyanovski
ena_com_wait_and_process_admin_cq_polling(struct ena_comp_ctx * comp_ctx,struct ena_com_admin_queue * admin_queue)5211738cd3eSNetanel Belgazal static int ena_com_wait_and_process_admin_cq_polling(struct ena_comp_ctx *comp_ctx,
5221738cd3eSNetanel Belgazal struct ena_com_admin_queue *admin_queue)
5231738cd3eSNetanel Belgazal {
524bd791175SArthur Kiyanovski unsigned long flags = 0;
525bd791175SArthur Kiyanovski unsigned long timeout;
5261738cd3eSNetanel Belgazal int ret;
5274bb7f4cfSArthur Kiyanovski u32 exp = 0;
5281738cd3eSNetanel Belgazal
52982ef30f1SNetanel Belgazal timeout = jiffies + usecs_to_jiffies(admin_queue->completion_timeout);
5301738cd3eSNetanel Belgazal
531a77c1aafSNetanel Belgazal while (1) {
532a77c1aafSNetanel Belgazal spin_lock_irqsave(&admin_queue->q_lock, flags);
533a77c1aafSNetanel Belgazal ena_com_handle_admin_completion(admin_queue);
534a77c1aafSNetanel Belgazal spin_unlock_irqrestore(&admin_queue->q_lock, flags);
535a77c1aafSNetanel Belgazal
536a77c1aafSNetanel Belgazal if (comp_ctx->status != ENA_CMD_SUBMITTED)
537a77c1aafSNetanel Belgazal break;
538a77c1aafSNetanel Belgazal
539a77c1aafSNetanel Belgazal if (time_is_before_jiffies(timeout)) {
540da580ca8SShay Agroskin netdev_err(admin_queue->ena_dev->net_device,
541da580ca8SShay Agroskin "Wait for completion (polling) timeout\n");
5421738cd3eSNetanel Belgazal /* ENA didn't have any completion */
5431738cd3eSNetanel Belgazal spin_lock_irqsave(&admin_queue->q_lock, flags);
5441738cd3eSNetanel Belgazal admin_queue->stats.no_completion++;
5451738cd3eSNetanel Belgazal admin_queue->running_state = false;
5461738cd3eSNetanel Belgazal spin_unlock_irqrestore(&admin_queue->q_lock, flags);
5471738cd3eSNetanel Belgazal
5481738cd3eSNetanel Belgazal ret = -ETIME;
5491738cd3eSNetanel Belgazal goto err;
5501738cd3eSNetanel Belgazal }
5511738cd3eSNetanel Belgazal
5524bb7f4cfSArthur Kiyanovski ena_delay_exponential_backoff_us(exp++,
5534bb7f4cfSArthur Kiyanovski admin_queue->ena_dev->ena_min_poll_delay_us);
5541738cd3eSNetanel Belgazal }
5551738cd3eSNetanel Belgazal
5561738cd3eSNetanel Belgazal if (unlikely(comp_ctx->status == ENA_CMD_ABORTED)) {
557*26668c2dSDavid Arinzon netdev_err(admin_queue->ena_dev->net_device, "Command was aborted\n");
5581738cd3eSNetanel Belgazal spin_lock_irqsave(&admin_queue->q_lock, flags);
5591738cd3eSNetanel Belgazal admin_queue->stats.aborted_cmd++;
5601738cd3eSNetanel Belgazal spin_unlock_irqrestore(&admin_queue->q_lock, flags);
5611738cd3eSNetanel Belgazal ret = -ENODEV;
5621738cd3eSNetanel Belgazal goto err;
5631738cd3eSNetanel Belgazal }
5641738cd3eSNetanel Belgazal
565*26668c2dSDavid Arinzon WARN(comp_ctx->status != ENA_CMD_COMPLETED, "Invalid comp status %d\n", comp_ctx->status);
5661738cd3eSNetanel Belgazal
567da580ca8SShay Agroskin ret = ena_com_comp_status_to_errno(admin_queue, comp_ctx->comp_status);
5681738cd3eSNetanel Belgazal err:
5691738cd3eSNetanel Belgazal comp_ctxt_release(admin_queue, comp_ctx);
5701738cd3eSNetanel Belgazal return ret;
5711738cd3eSNetanel Belgazal }
5721738cd3eSNetanel Belgazal
57381929a4aSJesse Brandeburg /*
574689b2bdaSArthur Kiyanovski * Set the LLQ configurations of the firmware
575689b2bdaSArthur Kiyanovski *
576689b2bdaSArthur Kiyanovski * The driver provides only the enabled feature values to the device,
577689b2bdaSArthur Kiyanovski * which in turn, checks if they are supported.
578689b2bdaSArthur Kiyanovski */
ena_com_set_llq(struct ena_com_dev * ena_dev)579689b2bdaSArthur Kiyanovski static int ena_com_set_llq(struct ena_com_dev *ena_dev)
580689b2bdaSArthur Kiyanovski {
581689b2bdaSArthur Kiyanovski struct ena_com_admin_queue *admin_queue;
582689b2bdaSArthur Kiyanovski struct ena_admin_set_feat_cmd cmd;
583689b2bdaSArthur Kiyanovski struct ena_admin_set_feat_resp resp;
584689b2bdaSArthur Kiyanovski struct ena_com_llq_info *llq_info = &ena_dev->llq_info;
585689b2bdaSArthur Kiyanovski int ret;
586689b2bdaSArthur Kiyanovski
587689b2bdaSArthur Kiyanovski memset(&cmd, 0x0, sizeof(cmd));
588689b2bdaSArthur Kiyanovski admin_queue = &ena_dev->admin_queue;
589689b2bdaSArthur Kiyanovski
590689b2bdaSArthur Kiyanovski cmd.aq_common_descriptor.opcode = ENA_ADMIN_SET_FEATURE;
591689b2bdaSArthur Kiyanovski cmd.feat_common.feature_id = ENA_ADMIN_LLQ;
592689b2bdaSArthur Kiyanovski
593689b2bdaSArthur Kiyanovski cmd.u.llq.header_location_ctrl_enabled = llq_info->header_location_ctrl;
594689b2bdaSArthur Kiyanovski cmd.u.llq.entry_size_ctrl_enabled = llq_info->desc_list_entry_size_ctrl;
595689b2bdaSArthur Kiyanovski cmd.u.llq.desc_num_before_header_enabled = llq_info->descs_num_before_header;
596689b2bdaSArthur Kiyanovski cmd.u.llq.descriptors_stride_ctrl_enabled = llq_info->desc_stride_ctrl;
597689b2bdaSArthur Kiyanovski
5980e3a3f6dSArthur Kiyanovski cmd.u.llq.accel_mode.u.set.enabled_flags =
5990e3a3f6dSArthur Kiyanovski BIT(ENA_ADMIN_DISABLE_META_CACHING) |
6000e3a3f6dSArthur Kiyanovski BIT(ENA_ADMIN_LIMIT_TX_BURST);
6010e3a3f6dSArthur Kiyanovski
602689b2bdaSArthur Kiyanovski ret = ena_com_execute_admin_command(admin_queue,
603689b2bdaSArthur Kiyanovski (struct ena_admin_aq_entry *)&cmd,
604689b2bdaSArthur Kiyanovski sizeof(cmd),
605689b2bdaSArthur Kiyanovski (struct ena_admin_acq_entry *)&resp,
606689b2bdaSArthur Kiyanovski sizeof(resp));
607689b2bdaSArthur Kiyanovski
608689b2bdaSArthur Kiyanovski if (unlikely(ret))
609*26668c2dSDavid Arinzon netdev_err(ena_dev->net_device, "Failed to set LLQ configurations: %d\n", ret);
610689b2bdaSArthur Kiyanovski
611689b2bdaSArthur Kiyanovski return ret;
612689b2bdaSArthur Kiyanovski }
613689b2bdaSArthur Kiyanovski
ena_com_config_llq_info(struct ena_com_dev * ena_dev,struct ena_admin_feature_llq_desc * llq_features,struct ena_llq_configurations * llq_default_cfg)614689b2bdaSArthur Kiyanovski static int ena_com_config_llq_info(struct ena_com_dev *ena_dev,
615689b2bdaSArthur Kiyanovski struct ena_admin_feature_llq_desc *llq_features,
616689b2bdaSArthur Kiyanovski struct ena_llq_configurations *llq_default_cfg)
617689b2bdaSArthur Kiyanovski {
618689b2bdaSArthur Kiyanovski struct ena_com_llq_info *llq_info = &ena_dev->llq_info;
6190e3a3f6dSArthur Kiyanovski struct ena_admin_accel_mode_get llq_accel_mode_get;
620689b2bdaSArthur Kiyanovski u16 supported_feat;
621689b2bdaSArthur Kiyanovski int rc;
622689b2bdaSArthur Kiyanovski
623689b2bdaSArthur Kiyanovski memset(llq_info, 0, sizeof(*llq_info));
624689b2bdaSArthur Kiyanovski
625689b2bdaSArthur Kiyanovski supported_feat = llq_features->header_location_ctrl_supported;
626689b2bdaSArthur Kiyanovski
627689b2bdaSArthur Kiyanovski if (likely(supported_feat & llq_default_cfg->llq_header_location)) {
628689b2bdaSArthur Kiyanovski llq_info->header_location_ctrl =
629689b2bdaSArthur Kiyanovski llq_default_cfg->llq_header_location;
630689b2bdaSArthur Kiyanovski } else {
631da580ca8SShay Agroskin netdev_err(ena_dev->net_device,
632*26668c2dSDavid Arinzon "Invalid header location control, supported: 0x%x\n", supported_feat);
633689b2bdaSArthur Kiyanovski return -EINVAL;
634689b2bdaSArthur Kiyanovski }
635689b2bdaSArthur Kiyanovski
636689b2bdaSArthur Kiyanovski if (likely(llq_info->header_location_ctrl == ENA_ADMIN_INLINE_HEADER)) {
637689b2bdaSArthur Kiyanovski supported_feat = llq_features->descriptors_stride_ctrl_supported;
638689b2bdaSArthur Kiyanovski if (likely(supported_feat & llq_default_cfg->llq_stride_ctrl)) {
639689b2bdaSArthur Kiyanovski llq_info->desc_stride_ctrl = llq_default_cfg->llq_stride_ctrl;
640689b2bdaSArthur Kiyanovski } else {
641689b2bdaSArthur Kiyanovski if (supported_feat & ENA_ADMIN_MULTIPLE_DESCS_PER_ENTRY) {
642689b2bdaSArthur Kiyanovski llq_info->desc_stride_ctrl = ENA_ADMIN_MULTIPLE_DESCS_PER_ENTRY;
643689b2bdaSArthur Kiyanovski } else if (supported_feat & ENA_ADMIN_SINGLE_DESC_PER_ENTRY) {
644689b2bdaSArthur Kiyanovski llq_info->desc_stride_ctrl = ENA_ADMIN_SINGLE_DESC_PER_ENTRY;
645689b2bdaSArthur Kiyanovski } else {
646da580ca8SShay Agroskin netdev_err(ena_dev->net_device,
647da580ca8SShay Agroskin "Invalid desc_stride_ctrl, supported: 0x%x\n",
648689b2bdaSArthur Kiyanovski supported_feat);
649689b2bdaSArthur Kiyanovski return -EINVAL;
650689b2bdaSArthur Kiyanovski }
651689b2bdaSArthur Kiyanovski
652da580ca8SShay Agroskin netdev_err(ena_dev->net_device,
653da580ca8SShay Agroskin "Default llq stride ctrl is not supported, performing fallback, default: 0x%x, supported: 0x%x, used: 0x%x\n",
654*26668c2dSDavid Arinzon llq_default_cfg->llq_stride_ctrl, supported_feat,
655*26668c2dSDavid Arinzon llq_info->desc_stride_ctrl);
656689b2bdaSArthur Kiyanovski }
657689b2bdaSArthur Kiyanovski } else {
658689b2bdaSArthur Kiyanovski llq_info->desc_stride_ctrl = 0;
659689b2bdaSArthur Kiyanovski }
660689b2bdaSArthur Kiyanovski
661689b2bdaSArthur Kiyanovski supported_feat = llq_features->entry_size_ctrl_supported;
662689b2bdaSArthur Kiyanovski if (likely(supported_feat & llq_default_cfg->llq_ring_entry_size)) {
663689b2bdaSArthur Kiyanovski llq_info->desc_list_entry_size_ctrl = llq_default_cfg->llq_ring_entry_size;
664689b2bdaSArthur Kiyanovski llq_info->desc_list_entry_size = llq_default_cfg->llq_ring_entry_size_value;
665689b2bdaSArthur Kiyanovski } else {
666689b2bdaSArthur Kiyanovski if (supported_feat & ENA_ADMIN_LIST_ENTRY_SIZE_128B) {
667689b2bdaSArthur Kiyanovski llq_info->desc_list_entry_size_ctrl = ENA_ADMIN_LIST_ENTRY_SIZE_128B;
668689b2bdaSArthur Kiyanovski llq_info->desc_list_entry_size = 128;
669689b2bdaSArthur Kiyanovski } else if (supported_feat & ENA_ADMIN_LIST_ENTRY_SIZE_192B) {
670689b2bdaSArthur Kiyanovski llq_info->desc_list_entry_size_ctrl = ENA_ADMIN_LIST_ENTRY_SIZE_192B;
671689b2bdaSArthur Kiyanovski llq_info->desc_list_entry_size = 192;
672689b2bdaSArthur Kiyanovski } else if (supported_feat & ENA_ADMIN_LIST_ENTRY_SIZE_256B) {
673689b2bdaSArthur Kiyanovski llq_info->desc_list_entry_size_ctrl = ENA_ADMIN_LIST_ENTRY_SIZE_256B;
674689b2bdaSArthur Kiyanovski llq_info->desc_list_entry_size = 256;
675689b2bdaSArthur Kiyanovski } else {
676da580ca8SShay Agroskin netdev_err(ena_dev->net_device,
677*26668c2dSDavid Arinzon "Invalid entry_size_ctrl, supported: 0x%x\n", supported_feat);
678689b2bdaSArthur Kiyanovski return -EINVAL;
679689b2bdaSArthur Kiyanovski }
680689b2bdaSArthur Kiyanovski
681da580ca8SShay Agroskin netdev_err(ena_dev->net_device,
682da580ca8SShay Agroskin "Default llq ring entry size is not supported, performing fallback, default: 0x%x, supported: 0x%x, used: 0x%x\n",
683689b2bdaSArthur Kiyanovski llq_default_cfg->llq_ring_entry_size, supported_feat,
684689b2bdaSArthur Kiyanovski llq_info->desc_list_entry_size);
685689b2bdaSArthur Kiyanovski }
686689b2bdaSArthur Kiyanovski if (unlikely(llq_info->desc_list_entry_size & 0x7)) {
687689b2bdaSArthur Kiyanovski /* The desc list entry size should be whole multiply of 8
688689b2bdaSArthur Kiyanovski * This requirement comes from __iowrite64_copy()
689689b2bdaSArthur Kiyanovski */
690da580ca8SShay Agroskin netdev_err(ena_dev->net_device, "Illegal entry size %d\n",
691da580ca8SShay Agroskin llq_info->desc_list_entry_size);
692689b2bdaSArthur Kiyanovski return -EINVAL;
693689b2bdaSArthur Kiyanovski }
694689b2bdaSArthur Kiyanovski
695689b2bdaSArthur Kiyanovski if (llq_info->desc_stride_ctrl == ENA_ADMIN_MULTIPLE_DESCS_PER_ENTRY)
696689b2bdaSArthur Kiyanovski llq_info->descs_per_entry = llq_info->desc_list_entry_size /
697689b2bdaSArthur Kiyanovski sizeof(struct ena_eth_io_tx_desc);
698689b2bdaSArthur Kiyanovski else
699689b2bdaSArthur Kiyanovski llq_info->descs_per_entry = 1;
700689b2bdaSArthur Kiyanovski
701689b2bdaSArthur Kiyanovski supported_feat = llq_features->desc_num_before_header_supported;
702689b2bdaSArthur Kiyanovski if (likely(supported_feat & llq_default_cfg->llq_num_decs_before_header)) {
703689b2bdaSArthur Kiyanovski llq_info->descs_num_before_header = llq_default_cfg->llq_num_decs_before_header;
704689b2bdaSArthur Kiyanovski } else {
705689b2bdaSArthur Kiyanovski if (supported_feat & ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_2) {
706689b2bdaSArthur Kiyanovski llq_info->descs_num_before_header = ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_2;
707689b2bdaSArthur Kiyanovski } else if (supported_feat & ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_1) {
708689b2bdaSArthur Kiyanovski llq_info->descs_num_before_header = ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_1;
709689b2bdaSArthur Kiyanovski } else if (supported_feat & ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_4) {
710689b2bdaSArthur Kiyanovski llq_info->descs_num_before_header = ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_4;
711689b2bdaSArthur Kiyanovski } else if (supported_feat & ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_8) {
712689b2bdaSArthur Kiyanovski llq_info->descs_num_before_header = ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_8;
713689b2bdaSArthur Kiyanovski } else {
714da580ca8SShay Agroskin netdev_err(ena_dev->net_device,
715da580ca8SShay Agroskin "Invalid descs_num_before_header, supported: 0x%x\n",
716689b2bdaSArthur Kiyanovski supported_feat);
717689b2bdaSArthur Kiyanovski return -EINVAL;
718689b2bdaSArthur Kiyanovski }
719689b2bdaSArthur Kiyanovski
720da580ca8SShay Agroskin netdev_err(ena_dev->net_device,
721da580ca8SShay Agroskin "Default llq num descs before header is not supported, performing fallback, default: 0x%x, supported: 0x%x, used: 0x%x\n",
722*26668c2dSDavid Arinzon llq_default_cfg->llq_num_decs_before_header, supported_feat,
723*26668c2dSDavid Arinzon llq_info->descs_num_before_header);
724689b2bdaSArthur Kiyanovski }
7250e3a3f6dSArthur Kiyanovski /* Check for accelerated queue supported */
7260e3a3f6dSArthur Kiyanovski llq_accel_mode_get = llq_features->accel_mode.u.get;
727689b2bdaSArthur Kiyanovski
7280e3a3f6dSArthur Kiyanovski llq_info->disable_meta_caching =
7290e3a3f6dSArthur Kiyanovski !!(llq_accel_mode_get.supported_flags &
7300e3a3f6dSArthur Kiyanovski BIT(ENA_ADMIN_DISABLE_META_CACHING));
7310e3a3f6dSArthur Kiyanovski
7320e3a3f6dSArthur Kiyanovski if (llq_accel_mode_get.supported_flags & BIT(ENA_ADMIN_LIMIT_TX_BURST))
73305d62ca2SSameeh Jubran llq_info->max_entries_in_tx_burst =
7340e3a3f6dSArthur Kiyanovski llq_accel_mode_get.max_tx_burst_size /
7350e3a3f6dSArthur Kiyanovski llq_default_cfg->llq_ring_entry_size_value;
73605d62ca2SSameeh Jubran
737689b2bdaSArthur Kiyanovski rc = ena_com_set_llq(ena_dev);
738689b2bdaSArthur Kiyanovski if (rc)
739*26668c2dSDavid Arinzon netdev_err(ena_dev->net_device, "Cannot set LLQ configuration: %d\n", rc);
740689b2bdaSArthur Kiyanovski
7419a27de0cSSameeh Jubran return rc;
742689b2bdaSArthur Kiyanovski }
743689b2bdaSArthur Kiyanovski
ena_com_wait_and_process_admin_cq_interrupts(struct ena_comp_ctx * comp_ctx,struct ena_com_admin_queue * admin_queue)7441738cd3eSNetanel Belgazal static int ena_com_wait_and_process_admin_cq_interrupts(struct ena_comp_ctx *comp_ctx,
7451738cd3eSNetanel Belgazal struct ena_com_admin_queue *admin_queue)
7461738cd3eSNetanel Belgazal {
747bd791175SArthur Kiyanovski unsigned long flags = 0;
7481738cd3eSNetanel Belgazal int ret;
7491738cd3eSNetanel Belgazal
7501738cd3eSNetanel Belgazal wait_for_completion_timeout(&comp_ctx->wait_event,
751*26668c2dSDavid Arinzon usecs_to_jiffies(admin_queue->completion_timeout));
7521738cd3eSNetanel Belgazal
7531738cd3eSNetanel Belgazal /* In case the command wasn't completed find out the root cause.
7541738cd3eSNetanel Belgazal * There might be 2 kinds of errors
7551738cd3eSNetanel Belgazal * 1) No completion (timeout reached)
7561738cd3eSNetanel Belgazal * 2) There is completion but the device didn't get any msi-x interrupt.
7571738cd3eSNetanel Belgazal */
7581738cd3eSNetanel Belgazal if (unlikely(comp_ctx->status == ENA_CMD_SUBMITTED)) {
7591738cd3eSNetanel Belgazal spin_lock_irqsave(&admin_queue->q_lock, flags);
7601738cd3eSNetanel Belgazal ena_com_handle_admin_completion(admin_queue);
7611738cd3eSNetanel Belgazal admin_queue->stats.no_completion++;
7621738cd3eSNetanel Belgazal spin_unlock_irqrestore(&admin_queue->q_lock, flags);
7631738cd3eSNetanel Belgazal
764a4e262cdSSameeh Jubran if (comp_ctx->status == ENA_CMD_COMPLETED) {
765da580ca8SShay Agroskin netdev_err(admin_queue->ena_dev->net_device,
766da580ca8SShay Agroskin "The ena device sent a completion but the driver didn't receive a MSI-X interrupt (cmd %d), autopolling mode is %s\n",
767*26668c2dSDavid Arinzon comp_ctx->cmd_opcode, admin_queue->auto_polling ? "ON" : "OFF");
768a4e262cdSSameeh Jubran /* Check if fallback to polling is enabled */
769a4e262cdSSameeh Jubran if (admin_queue->auto_polling)
770a4e262cdSSameeh Jubran admin_queue->polling = true;
771a4e262cdSSameeh Jubran } else {
772da580ca8SShay Agroskin netdev_err(admin_queue->ena_dev->net_device,
773da580ca8SShay Agroskin "The ena device didn't send a completion for the admin cmd %d status %d\n",
7741738cd3eSNetanel Belgazal comp_ctx->cmd_opcode, comp_ctx->status);
775a4e262cdSSameeh Jubran }
776a4e262cdSSameeh Jubran /* Check if shifted to polling mode.
777a4e262cdSSameeh Jubran * This will happen if there is a completion without an interrupt
778a4e262cdSSameeh Jubran * and autopolling mode is enabled. Continuing normal execution in such case
779a4e262cdSSameeh Jubran */
780a4e262cdSSameeh Jubran if (!admin_queue->polling) {
7811738cd3eSNetanel Belgazal admin_queue->running_state = false;
7821738cd3eSNetanel Belgazal ret = -ETIME;
7831738cd3eSNetanel Belgazal goto err;
7841738cd3eSNetanel Belgazal }
785a4e262cdSSameeh Jubran }
7861738cd3eSNetanel Belgazal
787da580ca8SShay Agroskin ret = ena_com_comp_status_to_errno(admin_queue, comp_ctx->comp_status);
7881738cd3eSNetanel Belgazal err:
7891738cd3eSNetanel Belgazal comp_ctxt_release(admin_queue, comp_ctx);
7901738cd3eSNetanel Belgazal return ret;
7911738cd3eSNetanel Belgazal }
7921738cd3eSNetanel Belgazal
7931738cd3eSNetanel Belgazal /* This method read the hardware device register through posting writes
7941738cd3eSNetanel Belgazal * and waiting for response
7951738cd3eSNetanel Belgazal * On timeout the function will return ENA_MMIO_READ_TIMEOUT
7961738cd3eSNetanel Belgazal */
ena_com_reg_bar_read32(struct ena_com_dev * ena_dev,u16 offset)7971738cd3eSNetanel Belgazal static u32 ena_com_reg_bar_read32(struct ena_com_dev *ena_dev, u16 offset)
7981738cd3eSNetanel Belgazal {
7991738cd3eSNetanel Belgazal struct ena_com_mmio_read *mmio_read = &ena_dev->mmio_read;
8001738cd3eSNetanel Belgazal volatile struct ena_admin_ena_mmio_req_read_less_resp *read_resp =
8011738cd3eSNetanel Belgazal mmio_read->read_resp;
80282ef30f1SNetanel Belgazal u32 mmio_read_reg, ret, i;
803bd791175SArthur Kiyanovski unsigned long flags = 0;
80482ef30f1SNetanel Belgazal u32 timeout = mmio_read->reg_read_to;
8051738cd3eSNetanel Belgazal
8061738cd3eSNetanel Belgazal might_sleep();
8071738cd3eSNetanel Belgazal
80882ef30f1SNetanel Belgazal if (timeout == 0)
80982ef30f1SNetanel Belgazal timeout = ENA_REG_READ_TIMEOUT;
81082ef30f1SNetanel Belgazal
8111738cd3eSNetanel Belgazal /* If readless is disabled, perform regular read */
8121738cd3eSNetanel Belgazal if (!mmio_read->readless_supported)
8131738cd3eSNetanel Belgazal return readl(ena_dev->reg_bar + offset);
8141738cd3eSNetanel Belgazal
8151738cd3eSNetanel Belgazal spin_lock_irqsave(&mmio_read->lock, flags);
8161738cd3eSNetanel Belgazal mmio_read->seq_num++;
8171738cd3eSNetanel Belgazal
8181738cd3eSNetanel Belgazal read_resp->req_id = mmio_read->seq_num + 0xDEAD;
8191738cd3eSNetanel Belgazal mmio_read_reg = (offset << ENA_REGS_MMIO_REG_READ_REG_OFF_SHIFT) &
8201738cd3eSNetanel Belgazal ENA_REGS_MMIO_REG_READ_REG_OFF_MASK;
8211738cd3eSNetanel Belgazal mmio_read_reg |= mmio_read->seq_num &
8221738cd3eSNetanel Belgazal ENA_REGS_MMIO_REG_READ_REQ_ID_MASK;
8231738cd3eSNetanel Belgazal
82437dff155SNetanel Belgazal writel(mmio_read_reg, ena_dev->reg_bar + ENA_REGS_MMIO_REG_READ_OFF);
8251738cd3eSNetanel Belgazal
82682ef30f1SNetanel Belgazal for (i = 0; i < timeout; i++) {
82728abf4e9SNetanel Belgazal if (READ_ONCE(read_resp->req_id) == mmio_read->seq_num)
8281738cd3eSNetanel Belgazal break;
8291738cd3eSNetanel Belgazal
8301738cd3eSNetanel Belgazal udelay(1);
8311738cd3eSNetanel Belgazal }
8321738cd3eSNetanel Belgazal
83382ef30f1SNetanel Belgazal if (unlikely(i == timeout)) {
834da580ca8SShay Agroskin netdev_err(ena_dev->net_device,
835b788ff0aSYixing Liu "Reading reg failed for timeout. expected: req id[%u] offset[%u] actual: req id[%u] offset[%u]\n",
836*26668c2dSDavid Arinzon mmio_read->seq_num, offset, read_resp->req_id, read_resp->reg_off);
8371738cd3eSNetanel Belgazal ret = ENA_MMIO_READ_TIMEOUT;
8381738cd3eSNetanel Belgazal goto err;
8391738cd3eSNetanel Belgazal }
8401738cd3eSNetanel Belgazal
8411738cd3eSNetanel Belgazal if (read_resp->reg_off != offset) {
842*26668c2dSDavid Arinzon netdev_err(ena_dev->net_device, "Read failure: wrong offset provided\n");
8431738cd3eSNetanel Belgazal ret = ENA_MMIO_READ_TIMEOUT;
8441738cd3eSNetanel Belgazal } else {
8451738cd3eSNetanel Belgazal ret = read_resp->reg_val;
8461738cd3eSNetanel Belgazal }
8471738cd3eSNetanel Belgazal err:
8481738cd3eSNetanel Belgazal spin_unlock_irqrestore(&mmio_read->lock, flags);
8491738cd3eSNetanel Belgazal
8501738cd3eSNetanel Belgazal return ret;
8511738cd3eSNetanel Belgazal }
8521738cd3eSNetanel Belgazal
8531738cd3eSNetanel Belgazal /* There are two types to wait for completion.
8541738cd3eSNetanel Belgazal * Polling mode - wait until the completion is available.
8551738cd3eSNetanel Belgazal * Async mode - wait on wait queue until the completion is ready
8561738cd3eSNetanel Belgazal * (or the timeout expired).
8571738cd3eSNetanel Belgazal * It is expected that the IRQ called ena_com_handle_admin_completion
8581738cd3eSNetanel Belgazal * to mark the completions.
8591738cd3eSNetanel Belgazal */
ena_com_wait_and_process_admin_cq(struct ena_comp_ctx * comp_ctx,struct ena_com_admin_queue * admin_queue)8601738cd3eSNetanel Belgazal static int ena_com_wait_and_process_admin_cq(struct ena_comp_ctx *comp_ctx,
8611738cd3eSNetanel Belgazal struct ena_com_admin_queue *admin_queue)
8621738cd3eSNetanel Belgazal {
8631738cd3eSNetanel Belgazal if (admin_queue->polling)
8641738cd3eSNetanel Belgazal return ena_com_wait_and_process_admin_cq_polling(comp_ctx,
8651738cd3eSNetanel Belgazal admin_queue);
8661738cd3eSNetanel Belgazal
8671738cd3eSNetanel Belgazal return ena_com_wait_and_process_admin_cq_interrupts(comp_ctx,
8681738cd3eSNetanel Belgazal admin_queue);
8691738cd3eSNetanel Belgazal }
8701738cd3eSNetanel Belgazal
ena_com_destroy_io_sq(struct ena_com_dev * ena_dev,struct ena_com_io_sq * io_sq)8711738cd3eSNetanel Belgazal static int ena_com_destroy_io_sq(struct ena_com_dev *ena_dev,
8721738cd3eSNetanel Belgazal struct ena_com_io_sq *io_sq)
8731738cd3eSNetanel Belgazal {
8741738cd3eSNetanel Belgazal struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
8751738cd3eSNetanel Belgazal struct ena_admin_aq_destroy_sq_cmd destroy_cmd;
8761738cd3eSNetanel Belgazal struct ena_admin_acq_destroy_sq_resp_desc destroy_resp;
8771738cd3eSNetanel Belgazal u8 direction;
8781738cd3eSNetanel Belgazal int ret;
8791738cd3eSNetanel Belgazal
88091750110SNetanel Belgazal memset(&destroy_cmd, 0x0, sizeof(destroy_cmd));
8811738cd3eSNetanel Belgazal
8821738cd3eSNetanel Belgazal if (io_sq->direction == ENA_COM_IO_QUEUE_DIRECTION_TX)
8831738cd3eSNetanel Belgazal direction = ENA_ADMIN_SQ_DIRECTION_TX;
8841738cd3eSNetanel Belgazal else
8851738cd3eSNetanel Belgazal direction = ENA_ADMIN_SQ_DIRECTION_RX;
8861738cd3eSNetanel Belgazal
8871738cd3eSNetanel Belgazal destroy_cmd.sq.sq_identity |= (direction <<
8881738cd3eSNetanel Belgazal ENA_ADMIN_SQ_SQ_DIRECTION_SHIFT) &
8891738cd3eSNetanel Belgazal ENA_ADMIN_SQ_SQ_DIRECTION_MASK;
8901738cd3eSNetanel Belgazal
8911738cd3eSNetanel Belgazal destroy_cmd.sq.sq_idx = io_sq->idx;
8921738cd3eSNetanel Belgazal destroy_cmd.aq_common_descriptor.opcode = ENA_ADMIN_DESTROY_SQ;
8931738cd3eSNetanel Belgazal
8941738cd3eSNetanel Belgazal ret = ena_com_execute_admin_command(admin_queue,
8951738cd3eSNetanel Belgazal (struct ena_admin_aq_entry *)&destroy_cmd,
8961738cd3eSNetanel Belgazal sizeof(destroy_cmd),
8971738cd3eSNetanel Belgazal (struct ena_admin_acq_entry *)&destroy_resp,
8981738cd3eSNetanel Belgazal sizeof(destroy_resp));
8991738cd3eSNetanel Belgazal
9001738cd3eSNetanel Belgazal if (unlikely(ret && (ret != -ENODEV)))
901*26668c2dSDavid Arinzon netdev_err(ena_dev->net_device, "Failed to destroy io sq error: %d\n", ret);
9021738cd3eSNetanel Belgazal
9031738cd3eSNetanel Belgazal return ret;
9041738cd3eSNetanel Belgazal }
9051738cd3eSNetanel Belgazal
ena_com_io_queue_free(struct ena_com_dev * ena_dev,struct ena_com_io_sq * io_sq,struct ena_com_io_cq * io_cq)9061738cd3eSNetanel Belgazal static void ena_com_io_queue_free(struct ena_com_dev *ena_dev,
9071738cd3eSNetanel Belgazal struct ena_com_io_sq *io_sq,
9081738cd3eSNetanel Belgazal struct ena_com_io_cq *io_cq)
9091738cd3eSNetanel Belgazal {
9101738cd3eSNetanel Belgazal size_t size;
9111738cd3eSNetanel Belgazal
9121738cd3eSNetanel Belgazal if (io_cq->cdesc_addr.virt_addr) {
9131738cd3eSNetanel Belgazal size = io_cq->cdesc_entry_size_in_bytes * io_cq->q_depth;
9141738cd3eSNetanel Belgazal
915*26668c2dSDavid Arinzon dma_free_coherent(ena_dev->dmadev, size, io_cq->cdesc_addr.virt_addr,
9161738cd3eSNetanel Belgazal io_cq->cdesc_addr.phys_addr);
9171738cd3eSNetanel Belgazal
9181738cd3eSNetanel Belgazal io_cq->cdesc_addr.virt_addr = NULL;
9191738cd3eSNetanel Belgazal }
9201738cd3eSNetanel Belgazal
9211738cd3eSNetanel Belgazal if (io_sq->desc_addr.virt_addr) {
9221738cd3eSNetanel Belgazal size = io_sq->desc_entry_size * io_sq->q_depth;
9231738cd3eSNetanel Belgazal
924*26668c2dSDavid Arinzon dma_free_coherent(ena_dev->dmadev, size, io_sq->desc_addr.virt_addr,
9251738cd3eSNetanel Belgazal io_sq->desc_addr.phys_addr);
9261738cd3eSNetanel Belgazal
9271738cd3eSNetanel Belgazal io_sq->desc_addr.virt_addr = NULL;
9281738cd3eSNetanel Belgazal }
929689b2bdaSArthur Kiyanovski
930689b2bdaSArthur Kiyanovski if (io_sq->bounce_buf_ctrl.base_buffer) {
931689b2bdaSArthur Kiyanovski devm_kfree(ena_dev->dmadev, io_sq->bounce_buf_ctrl.base_buffer);
932689b2bdaSArthur Kiyanovski io_sq->bounce_buf_ctrl.base_buffer = NULL;
933689b2bdaSArthur Kiyanovski }
9341738cd3eSNetanel Belgazal }
9351738cd3eSNetanel Belgazal
wait_for_reset_state(struct ena_com_dev * ena_dev,u32 timeout,u16 exp_state)9361738cd3eSNetanel Belgazal static int wait_for_reset_state(struct ena_com_dev *ena_dev, u32 timeout,
9371738cd3eSNetanel Belgazal u16 exp_state)
9381738cd3eSNetanel Belgazal {
9394bb7f4cfSArthur Kiyanovski u32 val, exp = 0;
9404bb7f4cfSArthur Kiyanovski unsigned long timeout_stamp;
9411738cd3eSNetanel Belgazal
9424bb7f4cfSArthur Kiyanovski /* Convert timeout from resolution of 100ms to us resolution. */
9434bb7f4cfSArthur Kiyanovski timeout_stamp = jiffies + usecs_to_jiffies(100 * 1000 * timeout);
94488aef2f5SNetanel Belgazal
9454bb7f4cfSArthur Kiyanovski while (1) {
9461738cd3eSNetanel Belgazal val = ena_com_reg_bar_read32(ena_dev, ENA_REGS_DEV_STS_OFF);
9471738cd3eSNetanel Belgazal
9481738cd3eSNetanel Belgazal if (unlikely(val == ENA_MMIO_READ_TIMEOUT)) {
949*26668c2dSDavid Arinzon netdev_err(ena_dev->net_device, "Reg read timeout occurred\n");
9501738cd3eSNetanel Belgazal return -ETIME;
9511738cd3eSNetanel Belgazal }
9521738cd3eSNetanel Belgazal
9531738cd3eSNetanel Belgazal if ((val & ENA_REGS_DEV_STS_RESET_IN_PROGRESS_MASK) ==
9541738cd3eSNetanel Belgazal exp_state)
9551738cd3eSNetanel Belgazal return 0;
9561738cd3eSNetanel Belgazal
9574bb7f4cfSArthur Kiyanovski if (time_is_before_jiffies(timeout_stamp))
9581738cd3eSNetanel Belgazal return -ETIME;
9594bb7f4cfSArthur Kiyanovski
9604bb7f4cfSArthur Kiyanovski ena_delay_exponential_backoff_us(exp++, ena_dev->ena_min_poll_delay_us);
9614bb7f4cfSArthur Kiyanovski }
9621738cd3eSNetanel Belgazal }
9631738cd3eSNetanel Belgazal
ena_com_check_supported_feature_id(struct ena_com_dev * ena_dev,enum ena_admin_aq_feature_id feature_id)9641738cd3eSNetanel Belgazal static bool ena_com_check_supported_feature_id(struct ena_com_dev *ena_dev,
9651738cd3eSNetanel Belgazal enum ena_admin_aq_feature_id feature_id)
9661738cd3eSNetanel Belgazal {
9671738cd3eSNetanel Belgazal u32 feature_mask = 1 << feature_id;
9681738cd3eSNetanel Belgazal
9691738cd3eSNetanel Belgazal /* Device attributes is always supported */
9701738cd3eSNetanel Belgazal if ((feature_id != ENA_ADMIN_DEVICE_ATTRIBUTES) &&
9711738cd3eSNetanel Belgazal !(ena_dev->supported_features & feature_mask))
9721738cd3eSNetanel Belgazal return false;
9731738cd3eSNetanel Belgazal
9741738cd3eSNetanel Belgazal return true;
9751738cd3eSNetanel Belgazal }
9761738cd3eSNetanel Belgazal
ena_com_get_feature_ex(struct ena_com_dev * ena_dev,struct ena_admin_get_feat_resp * get_resp,enum ena_admin_aq_feature_id feature_id,dma_addr_t control_buf_dma_addr,u32 control_buff_size,u8 feature_ver)9771738cd3eSNetanel Belgazal static int ena_com_get_feature_ex(struct ena_com_dev *ena_dev,
9781738cd3eSNetanel Belgazal struct ena_admin_get_feat_resp *get_resp,
9791738cd3eSNetanel Belgazal enum ena_admin_aq_feature_id feature_id,
9801738cd3eSNetanel Belgazal dma_addr_t control_buf_dma_addr,
981ba8ef506SArthur Kiyanovski u32 control_buff_size,
982ba8ef506SArthur Kiyanovski u8 feature_ver)
9831738cd3eSNetanel Belgazal {
9841738cd3eSNetanel Belgazal struct ena_com_admin_queue *admin_queue;
9851738cd3eSNetanel Belgazal struct ena_admin_get_feat_cmd get_cmd;
9861738cd3eSNetanel Belgazal int ret;
9871738cd3eSNetanel Belgazal
9881738cd3eSNetanel Belgazal if (!ena_com_check_supported_feature_id(ena_dev, feature_id)) {
989*26668c2dSDavid Arinzon netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n", feature_id);
990d1497638SNetanel Belgazal return -EOPNOTSUPP;
9911738cd3eSNetanel Belgazal }
9921738cd3eSNetanel Belgazal
9931738cd3eSNetanel Belgazal memset(&get_cmd, 0x0, sizeof(get_cmd));
9941738cd3eSNetanel Belgazal admin_queue = &ena_dev->admin_queue;
9951738cd3eSNetanel Belgazal
9961738cd3eSNetanel Belgazal get_cmd.aq_common_descriptor.opcode = ENA_ADMIN_GET_FEATURE;
9971738cd3eSNetanel Belgazal
9981738cd3eSNetanel Belgazal if (control_buff_size)
9991738cd3eSNetanel Belgazal get_cmd.aq_common_descriptor.flags =
10001738cd3eSNetanel Belgazal ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_INDIRECT_MASK;
10011738cd3eSNetanel Belgazal else
10021738cd3eSNetanel Belgazal get_cmd.aq_common_descriptor.flags = 0;
10031738cd3eSNetanel Belgazal
10041738cd3eSNetanel Belgazal ret = ena_com_mem_addr_set(ena_dev,
10051738cd3eSNetanel Belgazal &get_cmd.control_buffer.address,
10061738cd3eSNetanel Belgazal control_buf_dma_addr);
10071738cd3eSNetanel Belgazal if (unlikely(ret)) {
1008da580ca8SShay Agroskin netdev_err(ena_dev->net_device, "Memory address set failed\n");
10091738cd3eSNetanel Belgazal return ret;
10101738cd3eSNetanel Belgazal }
10111738cd3eSNetanel Belgazal
10121738cd3eSNetanel Belgazal get_cmd.control_buffer.length = control_buff_size;
1013ba8ef506SArthur Kiyanovski get_cmd.feat_common.feature_version = feature_ver;
10141738cd3eSNetanel Belgazal get_cmd.feat_common.feature_id = feature_id;
10151738cd3eSNetanel Belgazal
10161738cd3eSNetanel Belgazal ret = ena_com_execute_admin_command(admin_queue,
10171738cd3eSNetanel Belgazal (struct ena_admin_aq_entry *)
10181738cd3eSNetanel Belgazal &get_cmd,
10191738cd3eSNetanel Belgazal sizeof(get_cmd),
10201738cd3eSNetanel Belgazal (struct ena_admin_acq_entry *)
10211738cd3eSNetanel Belgazal get_resp,
10221738cd3eSNetanel Belgazal sizeof(*get_resp));
10231738cd3eSNetanel Belgazal
10241738cd3eSNetanel Belgazal if (unlikely(ret))
1025da580ca8SShay Agroskin netdev_err(ena_dev->net_device,
1026*26668c2dSDavid Arinzon "Failed to submit get_feature command %d error: %d\n", feature_id, ret);
10271738cd3eSNetanel Belgazal
10281738cd3eSNetanel Belgazal return ret;
10291738cd3eSNetanel Belgazal }
10301738cd3eSNetanel Belgazal
ena_com_get_feature(struct ena_com_dev * ena_dev,struct ena_admin_get_feat_resp * get_resp,enum ena_admin_aq_feature_id feature_id,u8 feature_ver)10311738cd3eSNetanel Belgazal static int ena_com_get_feature(struct ena_com_dev *ena_dev,
10321738cd3eSNetanel Belgazal struct ena_admin_get_feat_resp *get_resp,
1033ba8ef506SArthur Kiyanovski enum ena_admin_aq_feature_id feature_id,
1034ba8ef506SArthur Kiyanovski u8 feature_ver)
10351738cd3eSNetanel Belgazal {
10361738cd3eSNetanel Belgazal return ena_com_get_feature_ex(ena_dev,
10371738cd3eSNetanel Belgazal get_resp,
10381738cd3eSNetanel Belgazal feature_id,
10391738cd3eSNetanel Belgazal 0,
1040ba8ef506SArthur Kiyanovski 0,
1041ba8ef506SArthur Kiyanovski feature_ver);
10421738cd3eSNetanel Belgazal }
10431738cd3eSNetanel Belgazal
ena_com_get_current_hash_function(struct ena_com_dev * ena_dev)1044470793a7SArthur Kiyanovski int ena_com_get_current_hash_function(struct ena_com_dev *ena_dev)
1045470793a7SArthur Kiyanovski {
1046470793a7SArthur Kiyanovski return ena_dev->rss.hash_func;
1047470793a7SArthur Kiyanovski }
1048470793a7SArthur Kiyanovski
ena_com_hash_key_fill_default_key(struct ena_com_dev * ena_dev)10490d1c3de7SArthur Kiyanovski static void ena_com_hash_key_fill_default_key(struct ena_com_dev *ena_dev)
10500d1c3de7SArthur Kiyanovski {
10510d1c3de7SArthur Kiyanovski struct ena_admin_feature_rss_flow_hash_control *hash_key =
10520d1c3de7SArthur Kiyanovski (ena_dev->rss).hash_key;
10530d1c3de7SArthur Kiyanovski
10540d1c3de7SArthur Kiyanovski netdev_rss_key_fill(&hash_key->key, sizeof(hash_key->key));
10550deca83fSShay Agroskin /* The key buffer is stored in the device in an array of
10560deca83fSShay Agroskin * uint32 elements.
10570d1c3de7SArthur Kiyanovski */
10580deca83fSShay Agroskin hash_key->key_parts = ENA_ADMIN_RSS_KEY_PARTS;
10590d1c3de7SArthur Kiyanovski }
10600d1c3de7SArthur Kiyanovski
ena_com_hash_key_allocate(struct ena_com_dev * ena_dev)10611738cd3eSNetanel Belgazal static int ena_com_hash_key_allocate(struct ena_com_dev *ena_dev)
10621738cd3eSNetanel Belgazal {
10631738cd3eSNetanel Belgazal struct ena_rss *rss = &ena_dev->rss;
10646a4f7dc8SSameeh Jubran
1065*26668c2dSDavid Arinzon if (!ena_com_check_supported_feature_id(ena_dev, ENA_ADMIN_RSS_HASH_FUNCTION))
10666a4f7dc8SSameeh Jubran return -EOPNOTSUPP;
10671738cd3eSNetanel Belgazal
1068*26668c2dSDavid Arinzon rss->hash_key = dma_alloc_coherent(ena_dev->dmadev, sizeof(*rss->hash_key),
10691738cd3eSNetanel Belgazal &rss->hash_key_dma_addr, GFP_KERNEL);
10701738cd3eSNetanel Belgazal
10711738cd3eSNetanel Belgazal if (unlikely(!rss->hash_key))
10721738cd3eSNetanel Belgazal return -ENOMEM;
10731738cd3eSNetanel Belgazal
10741738cd3eSNetanel Belgazal return 0;
10751738cd3eSNetanel Belgazal }
10761738cd3eSNetanel Belgazal
ena_com_hash_key_destroy(struct ena_com_dev * ena_dev)10771738cd3eSNetanel Belgazal static void ena_com_hash_key_destroy(struct ena_com_dev *ena_dev)
10781738cd3eSNetanel Belgazal {
10791738cd3eSNetanel Belgazal struct ena_rss *rss = &ena_dev->rss;
10801738cd3eSNetanel Belgazal
10811738cd3eSNetanel Belgazal if (rss->hash_key)
1082*26668c2dSDavid Arinzon dma_free_coherent(ena_dev->dmadev, sizeof(*rss->hash_key), rss->hash_key,
1083*26668c2dSDavid Arinzon rss->hash_key_dma_addr);
10841738cd3eSNetanel Belgazal rss->hash_key = NULL;
10851738cd3eSNetanel Belgazal }
10861738cd3eSNetanel Belgazal
ena_com_hash_ctrl_init(struct ena_com_dev * ena_dev)10871738cd3eSNetanel Belgazal static int ena_com_hash_ctrl_init(struct ena_com_dev *ena_dev)
10881738cd3eSNetanel Belgazal {
10891738cd3eSNetanel Belgazal struct ena_rss *rss = &ena_dev->rss;
10901738cd3eSNetanel Belgazal
1091*26668c2dSDavid Arinzon rss->hash_ctrl = dma_alloc_coherent(ena_dev->dmadev, sizeof(*rss->hash_ctrl),
10921738cd3eSNetanel Belgazal &rss->hash_ctrl_dma_addr, GFP_KERNEL);
10931738cd3eSNetanel Belgazal
10941738cd3eSNetanel Belgazal if (unlikely(!rss->hash_ctrl))
10951738cd3eSNetanel Belgazal return -ENOMEM;
10961738cd3eSNetanel Belgazal
10971738cd3eSNetanel Belgazal return 0;
10981738cd3eSNetanel Belgazal }
10991738cd3eSNetanel Belgazal
ena_com_hash_ctrl_destroy(struct ena_com_dev * ena_dev)11001738cd3eSNetanel Belgazal static void ena_com_hash_ctrl_destroy(struct ena_com_dev *ena_dev)
11011738cd3eSNetanel Belgazal {
11021738cd3eSNetanel Belgazal struct ena_rss *rss = &ena_dev->rss;
11031738cd3eSNetanel Belgazal
11041738cd3eSNetanel Belgazal if (rss->hash_ctrl)
1105*26668c2dSDavid Arinzon dma_free_coherent(ena_dev->dmadev, sizeof(*rss->hash_ctrl), rss->hash_ctrl,
1106*26668c2dSDavid Arinzon rss->hash_ctrl_dma_addr);
11071738cd3eSNetanel Belgazal rss->hash_ctrl = NULL;
11081738cd3eSNetanel Belgazal }
11091738cd3eSNetanel Belgazal
ena_com_indirect_table_allocate(struct ena_com_dev * ena_dev,u16 log_size)11101738cd3eSNetanel Belgazal static int ena_com_indirect_table_allocate(struct ena_com_dev *ena_dev,
11111738cd3eSNetanel Belgazal u16 log_size)
11121738cd3eSNetanel Belgazal {
11131738cd3eSNetanel Belgazal struct ena_rss *rss = &ena_dev->rss;
11141738cd3eSNetanel Belgazal struct ena_admin_get_feat_resp get_resp;
11151738cd3eSNetanel Belgazal size_t tbl_size;
11161738cd3eSNetanel Belgazal int ret;
11171738cd3eSNetanel Belgazal
11181738cd3eSNetanel Belgazal ret = ena_com_get_feature(ena_dev, &get_resp,
11190deca83fSShay Agroskin ENA_ADMIN_RSS_INDIRECTION_TABLE_CONFIG, 0);
11201738cd3eSNetanel Belgazal if (unlikely(ret))
11211738cd3eSNetanel Belgazal return ret;
11221738cd3eSNetanel Belgazal
11231738cd3eSNetanel Belgazal if ((get_resp.u.ind_table.min_size > log_size) ||
11241738cd3eSNetanel Belgazal (get_resp.u.ind_table.max_size < log_size)) {
1125da580ca8SShay Agroskin netdev_err(ena_dev->net_device,
1126da580ca8SShay Agroskin "Indirect table size doesn't fit. requested size: %d while min is:%d and max %d\n",
11271738cd3eSNetanel Belgazal 1 << log_size, 1 << get_resp.u.ind_table.min_size,
11281738cd3eSNetanel Belgazal 1 << get_resp.u.ind_table.max_size);
11291738cd3eSNetanel Belgazal return -EINVAL;
11301738cd3eSNetanel Belgazal }
11311738cd3eSNetanel Belgazal
11321738cd3eSNetanel Belgazal tbl_size = (1ULL << log_size) *
11331738cd3eSNetanel Belgazal sizeof(struct ena_admin_rss_ind_table_entry);
11341738cd3eSNetanel Belgazal
1135*26668c2dSDavid Arinzon rss->rss_ind_tbl = dma_alloc_coherent(ena_dev->dmadev, tbl_size, &rss->rss_ind_tbl_dma_addr,
1136*26668c2dSDavid Arinzon GFP_KERNEL);
11371738cd3eSNetanel Belgazal if (unlikely(!rss->rss_ind_tbl))
11381738cd3eSNetanel Belgazal goto mem_err1;
11391738cd3eSNetanel Belgazal
11401738cd3eSNetanel Belgazal tbl_size = (1ULL << log_size) * sizeof(u16);
1141*26668c2dSDavid Arinzon rss->host_rss_ind_tbl = devm_kzalloc(ena_dev->dmadev, tbl_size, GFP_KERNEL);
11421738cd3eSNetanel Belgazal if (unlikely(!rss->host_rss_ind_tbl))
11431738cd3eSNetanel Belgazal goto mem_err2;
11441738cd3eSNetanel Belgazal
11451738cd3eSNetanel Belgazal rss->tbl_log_size = log_size;
11461738cd3eSNetanel Belgazal
11471738cd3eSNetanel Belgazal return 0;
11481738cd3eSNetanel Belgazal
11491738cd3eSNetanel Belgazal mem_err2:
11501738cd3eSNetanel Belgazal tbl_size = (1ULL << log_size) *
11511738cd3eSNetanel Belgazal sizeof(struct ena_admin_rss_ind_table_entry);
11521738cd3eSNetanel Belgazal
1153*26668c2dSDavid Arinzon dma_free_coherent(ena_dev->dmadev, tbl_size, rss->rss_ind_tbl, rss->rss_ind_tbl_dma_addr);
11541738cd3eSNetanel Belgazal rss->rss_ind_tbl = NULL;
11551738cd3eSNetanel Belgazal mem_err1:
11561738cd3eSNetanel Belgazal rss->tbl_log_size = 0;
11571738cd3eSNetanel Belgazal return -ENOMEM;
11581738cd3eSNetanel Belgazal }
11591738cd3eSNetanel Belgazal
ena_com_indirect_table_destroy(struct ena_com_dev * ena_dev)11601738cd3eSNetanel Belgazal static void ena_com_indirect_table_destroy(struct ena_com_dev *ena_dev)
11611738cd3eSNetanel Belgazal {
11621738cd3eSNetanel Belgazal struct ena_rss *rss = &ena_dev->rss;
11631738cd3eSNetanel Belgazal size_t tbl_size = (1ULL << rss->tbl_log_size) *
11641738cd3eSNetanel Belgazal sizeof(struct ena_admin_rss_ind_table_entry);
11651738cd3eSNetanel Belgazal
11661738cd3eSNetanel Belgazal if (rss->rss_ind_tbl)
11671738cd3eSNetanel Belgazal dma_free_coherent(ena_dev->dmadev, tbl_size, rss->rss_ind_tbl,
11681738cd3eSNetanel Belgazal rss->rss_ind_tbl_dma_addr);
11691738cd3eSNetanel Belgazal rss->rss_ind_tbl = NULL;
11701738cd3eSNetanel Belgazal
11711738cd3eSNetanel Belgazal if (rss->host_rss_ind_tbl)
11721738cd3eSNetanel Belgazal devm_kfree(ena_dev->dmadev, rss->host_rss_ind_tbl);
11731738cd3eSNetanel Belgazal rss->host_rss_ind_tbl = NULL;
11741738cd3eSNetanel Belgazal }
11751738cd3eSNetanel Belgazal
ena_com_create_io_sq(struct ena_com_dev * ena_dev,struct ena_com_io_sq * io_sq,u16 cq_idx)11761738cd3eSNetanel Belgazal static int ena_com_create_io_sq(struct ena_com_dev *ena_dev,
11771738cd3eSNetanel Belgazal struct ena_com_io_sq *io_sq, u16 cq_idx)
11781738cd3eSNetanel Belgazal {
11791738cd3eSNetanel Belgazal struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
11801738cd3eSNetanel Belgazal struct ena_admin_aq_create_sq_cmd create_cmd;
11811738cd3eSNetanel Belgazal struct ena_admin_acq_create_sq_resp_desc cmd_completion;
11821738cd3eSNetanel Belgazal u8 direction;
11831738cd3eSNetanel Belgazal int ret;
11841738cd3eSNetanel Belgazal
118591750110SNetanel Belgazal memset(&create_cmd, 0x0, sizeof(create_cmd));
11861738cd3eSNetanel Belgazal
11871738cd3eSNetanel Belgazal create_cmd.aq_common_descriptor.opcode = ENA_ADMIN_CREATE_SQ;
11881738cd3eSNetanel Belgazal
11891738cd3eSNetanel Belgazal if (io_sq->direction == ENA_COM_IO_QUEUE_DIRECTION_TX)
11901738cd3eSNetanel Belgazal direction = ENA_ADMIN_SQ_DIRECTION_TX;
11911738cd3eSNetanel Belgazal else
11921738cd3eSNetanel Belgazal direction = ENA_ADMIN_SQ_DIRECTION_RX;
11931738cd3eSNetanel Belgazal
11941738cd3eSNetanel Belgazal create_cmd.sq_identity |= (direction <<
11951738cd3eSNetanel Belgazal ENA_ADMIN_AQ_CREATE_SQ_CMD_SQ_DIRECTION_SHIFT) &
11961738cd3eSNetanel Belgazal ENA_ADMIN_AQ_CREATE_SQ_CMD_SQ_DIRECTION_MASK;
11971738cd3eSNetanel Belgazal
11981738cd3eSNetanel Belgazal create_cmd.sq_caps_2 |= io_sq->mem_queue_type &
11991738cd3eSNetanel Belgazal ENA_ADMIN_AQ_CREATE_SQ_CMD_PLACEMENT_POLICY_MASK;
12001738cd3eSNetanel Belgazal
12011738cd3eSNetanel Belgazal create_cmd.sq_caps_2 |= (ENA_ADMIN_COMPLETION_POLICY_DESC <<
12021738cd3eSNetanel Belgazal ENA_ADMIN_AQ_CREATE_SQ_CMD_COMPLETION_POLICY_SHIFT) &
12031738cd3eSNetanel Belgazal ENA_ADMIN_AQ_CREATE_SQ_CMD_COMPLETION_POLICY_MASK;
12041738cd3eSNetanel Belgazal
12051738cd3eSNetanel Belgazal create_cmd.sq_caps_3 |=
12061738cd3eSNetanel Belgazal ENA_ADMIN_AQ_CREATE_SQ_CMD_IS_PHYSICALLY_CONTIGUOUS_MASK;
12071738cd3eSNetanel Belgazal
12081738cd3eSNetanel Belgazal create_cmd.cq_idx = cq_idx;
12091738cd3eSNetanel Belgazal create_cmd.sq_depth = io_sq->q_depth;
12101738cd3eSNetanel Belgazal
12111738cd3eSNetanel Belgazal if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST) {
12121738cd3eSNetanel Belgazal ret = ena_com_mem_addr_set(ena_dev,
12131738cd3eSNetanel Belgazal &create_cmd.sq_ba,
12141738cd3eSNetanel Belgazal io_sq->desc_addr.phys_addr);
12151738cd3eSNetanel Belgazal if (unlikely(ret)) {
1216*26668c2dSDavid Arinzon netdev_err(ena_dev->net_device, "Memory address set failed\n");
12171738cd3eSNetanel Belgazal return ret;
12181738cd3eSNetanel Belgazal }
12191738cd3eSNetanel Belgazal }
12201738cd3eSNetanel Belgazal
12211738cd3eSNetanel Belgazal ret = ena_com_execute_admin_command(admin_queue,
12221738cd3eSNetanel Belgazal (struct ena_admin_aq_entry *)&create_cmd,
12231738cd3eSNetanel Belgazal sizeof(create_cmd),
12241738cd3eSNetanel Belgazal (struct ena_admin_acq_entry *)&cmd_completion,
12251738cd3eSNetanel Belgazal sizeof(cmd_completion));
12261738cd3eSNetanel Belgazal if (unlikely(ret)) {
1227*26668c2dSDavid Arinzon netdev_err(ena_dev->net_device, "Failed to create IO SQ. error: %d\n", ret);
12281738cd3eSNetanel Belgazal return ret;
12291738cd3eSNetanel Belgazal }
12301738cd3eSNetanel Belgazal
12311738cd3eSNetanel Belgazal io_sq->idx = cmd_completion.sq_idx;
12321738cd3eSNetanel Belgazal
12331738cd3eSNetanel Belgazal io_sq->db_addr = (u32 __iomem *)((uintptr_t)ena_dev->reg_bar +
12341738cd3eSNetanel Belgazal (uintptr_t)cmd_completion.sq_doorbell_offset);
12351738cd3eSNetanel Belgazal
12361738cd3eSNetanel Belgazal if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) {
12371738cd3eSNetanel Belgazal io_sq->header_addr = (u8 __iomem *)((uintptr_t)ena_dev->mem_bar
12381738cd3eSNetanel Belgazal + cmd_completion.llq_headers_offset);
12391738cd3eSNetanel Belgazal
12401738cd3eSNetanel Belgazal io_sq->desc_addr.pbuf_dev_addr =
12411738cd3eSNetanel Belgazal (u8 __iomem *)((uintptr_t)ena_dev->mem_bar +
12421738cd3eSNetanel Belgazal cmd_completion.llq_descriptors_offset);
12431738cd3eSNetanel Belgazal }
12441738cd3eSNetanel Belgazal
1245*26668c2dSDavid Arinzon netdev_dbg(ena_dev->net_device, "Created sq[%u], depth[%u]\n", io_sq->idx, io_sq->q_depth);
12461738cd3eSNetanel Belgazal
12471738cd3eSNetanel Belgazal return ret;
12481738cd3eSNetanel Belgazal }
12491738cd3eSNetanel Belgazal
ena_com_ind_tbl_convert_to_device(struct ena_com_dev * ena_dev)12501738cd3eSNetanel Belgazal static int ena_com_ind_tbl_convert_to_device(struct ena_com_dev *ena_dev)
12511738cd3eSNetanel Belgazal {
12521738cd3eSNetanel Belgazal struct ena_rss *rss = &ena_dev->rss;
12531738cd3eSNetanel Belgazal struct ena_com_io_sq *io_sq;
12541738cd3eSNetanel Belgazal u16 qid;
12551738cd3eSNetanel Belgazal int i;
12561738cd3eSNetanel Belgazal
12571738cd3eSNetanel Belgazal for (i = 0; i < 1 << rss->tbl_log_size; i++) {
12581738cd3eSNetanel Belgazal qid = rss->host_rss_ind_tbl[i];
12591738cd3eSNetanel Belgazal if (qid >= ENA_TOTAL_NUM_QUEUES)
12601738cd3eSNetanel Belgazal return -EINVAL;
12611738cd3eSNetanel Belgazal
12621738cd3eSNetanel Belgazal io_sq = &ena_dev->io_sq_queues[qid];
12631738cd3eSNetanel Belgazal
12641738cd3eSNetanel Belgazal if (io_sq->direction != ENA_COM_IO_QUEUE_DIRECTION_RX)
12651738cd3eSNetanel Belgazal return -EINVAL;
12661738cd3eSNetanel Belgazal
12671738cd3eSNetanel Belgazal rss->rss_ind_tbl[i].cq_idx = io_sq->idx;
12681738cd3eSNetanel Belgazal }
12691738cd3eSNetanel Belgazal
12701738cd3eSNetanel Belgazal return 0;
12711738cd3eSNetanel Belgazal }
12721738cd3eSNetanel Belgazal
ena_com_update_intr_delay_resolution(struct ena_com_dev * ena_dev,u16 intr_delay_resolution)12731738cd3eSNetanel Belgazal static void ena_com_update_intr_delay_resolution(struct ena_com_dev *ena_dev,
12741738cd3eSNetanel Belgazal u16 intr_delay_resolution)
12751738cd3eSNetanel Belgazal {
1276da447b3bSArthur Kiyanovski u16 prev_intr_delay_resolution = ena_dev->intr_delay_resolution;
127779226ceaSArthur Kiyanovski
1278da447b3bSArthur Kiyanovski if (unlikely(!intr_delay_resolution)) {
1279da580ca8SShay Agroskin netdev_err(ena_dev->net_device,
1280da580ca8SShay Agroskin "Illegal intr_delay_resolution provided. Going to use default 1 usec resolution\n");
128179226ceaSArthur Kiyanovski intr_delay_resolution = ENA_DEFAULT_INTR_DELAY_RESOLUTION;
12821738cd3eSNetanel Belgazal }
12831738cd3eSNetanel Belgazal
12841738cd3eSNetanel Belgazal /* update Rx */
128579226ceaSArthur Kiyanovski ena_dev->intr_moder_rx_interval =
128679226ceaSArthur Kiyanovski ena_dev->intr_moder_rx_interval *
128779226ceaSArthur Kiyanovski prev_intr_delay_resolution /
128879226ceaSArthur Kiyanovski intr_delay_resolution;
12891738cd3eSNetanel Belgazal
12901738cd3eSNetanel Belgazal /* update Tx */
129179226ceaSArthur Kiyanovski ena_dev->intr_moder_tx_interval =
129279226ceaSArthur Kiyanovski ena_dev->intr_moder_tx_interval *
129379226ceaSArthur Kiyanovski prev_intr_delay_resolution /
129479226ceaSArthur Kiyanovski intr_delay_resolution;
129579226ceaSArthur Kiyanovski
129679226ceaSArthur Kiyanovski ena_dev->intr_delay_resolution = intr_delay_resolution;
12971738cd3eSNetanel Belgazal }
12981738cd3eSNetanel Belgazal
12991738cd3eSNetanel Belgazal /*****************************************************************************/
13001738cd3eSNetanel Belgazal /******************************* API ******************************/
13011738cd3eSNetanel Belgazal /*****************************************************************************/
13021738cd3eSNetanel Belgazal
ena_com_execute_admin_command(struct ena_com_admin_queue * admin_queue,struct ena_admin_aq_entry * cmd,size_t cmd_size,struct ena_admin_acq_entry * comp,size_t comp_size)13031738cd3eSNetanel Belgazal int ena_com_execute_admin_command(struct ena_com_admin_queue *admin_queue,
13041738cd3eSNetanel Belgazal struct ena_admin_aq_entry *cmd,
13051738cd3eSNetanel Belgazal size_t cmd_size,
13061738cd3eSNetanel Belgazal struct ena_admin_acq_entry *comp,
13071738cd3eSNetanel Belgazal size_t comp_size)
13081738cd3eSNetanel Belgazal {
13091738cd3eSNetanel Belgazal struct ena_comp_ctx *comp_ctx;
13101738cd3eSNetanel Belgazal int ret;
13111738cd3eSNetanel Belgazal
13121738cd3eSNetanel Belgazal comp_ctx = ena_com_submit_admin_cmd(admin_queue, cmd, cmd_size,
13131738cd3eSNetanel Belgazal comp, comp_size);
13141f4cf93bSTobias Klauser if (IS_ERR(comp_ctx)) {
1315e9548fdfSShay Agroskin ret = PTR_ERR(comp_ctx);
1316e9548fdfSShay Agroskin if (ret == -ENODEV)
1317da580ca8SShay Agroskin netdev_dbg(admin_queue->ena_dev->net_device,
1318e9548fdfSShay Agroskin "Failed to submit command [%d]\n", ret);
13195add6e4aSNetanel Belgazal else
1320da580ca8SShay Agroskin netdev_err(admin_queue->ena_dev->net_device,
1321e9548fdfSShay Agroskin "Failed to submit command [%d]\n", ret);
13225add6e4aSNetanel Belgazal
1323e9548fdfSShay Agroskin return ret;
13241738cd3eSNetanel Belgazal }
13251738cd3eSNetanel Belgazal
13261738cd3eSNetanel Belgazal ret = ena_com_wait_and_process_admin_cq(comp_ctx, admin_queue);
13271738cd3eSNetanel Belgazal if (unlikely(ret)) {
13281738cd3eSNetanel Belgazal if (admin_queue->running_state)
1329da580ca8SShay Agroskin netdev_err(admin_queue->ena_dev->net_device,
1330da580ca8SShay Agroskin "Failed to process command. ret = %d\n", ret);
13311738cd3eSNetanel Belgazal else
1332da580ca8SShay Agroskin netdev_dbg(admin_queue->ena_dev->net_device,
1333da580ca8SShay Agroskin "Failed to process command. ret = %d\n", ret);
13341738cd3eSNetanel Belgazal }
13351738cd3eSNetanel Belgazal return ret;
13361738cd3eSNetanel Belgazal }
13371738cd3eSNetanel Belgazal
ena_com_create_io_cq(struct ena_com_dev * ena_dev,struct ena_com_io_cq * io_cq)13381738cd3eSNetanel Belgazal int ena_com_create_io_cq(struct ena_com_dev *ena_dev,
13391738cd3eSNetanel Belgazal struct ena_com_io_cq *io_cq)
13401738cd3eSNetanel Belgazal {
13411738cd3eSNetanel Belgazal struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
13421738cd3eSNetanel Belgazal struct ena_admin_aq_create_cq_cmd create_cmd;
13431738cd3eSNetanel Belgazal struct ena_admin_acq_create_cq_resp_desc cmd_completion;
13441738cd3eSNetanel Belgazal int ret;
13451738cd3eSNetanel Belgazal
134691750110SNetanel Belgazal memset(&create_cmd, 0x0, sizeof(create_cmd));
13471738cd3eSNetanel Belgazal
13481738cd3eSNetanel Belgazal create_cmd.aq_common_descriptor.opcode = ENA_ADMIN_CREATE_CQ;
13491738cd3eSNetanel Belgazal
13501738cd3eSNetanel Belgazal create_cmd.cq_caps_2 |= (io_cq->cdesc_entry_size_in_bytes / 4) &
13511738cd3eSNetanel Belgazal ENA_ADMIN_AQ_CREATE_CQ_CMD_CQ_ENTRY_SIZE_WORDS_MASK;
13521738cd3eSNetanel Belgazal create_cmd.cq_caps_1 |=
13531738cd3eSNetanel Belgazal ENA_ADMIN_AQ_CREATE_CQ_CMD_INTERRUPT_MODE_ENABLED_MASK;
13541738cd3eSNetanel Belgazal
13551738cd3eSNetanel Belgazal create_cmd.msix_vector = io_cq->msix_vector;
13561738cd3eSNetanel Belgazal create_cmd.cq_depth = io_cq->q_depth;
13571738cd3eSNetanel Belgazal
13581738cd3eSNetanel Belgazal ret = ena_com_mem_addr_set(ena_dev,
13591738cd3eSNetanel Belgazal &create_cmd.cq_ba,
13601738cd3eSNetanel Belgazal io_cq->cdesc_addr.phys_addr);
13611738cd3eSNetanel Belgazal if (unlikely(ret)) {
1362da580ca8SShay Agroskin netdev_err(ena_dev->net_device, "Memory address set failed\n");
13631738cd3eSNetanel Belgazal return ret;
13641738cd3eSNetanel Belgazal }
13651738cd3eSNetanel Belgazal
13661738cd3eSNetanel Belgazal ret = ena_com_execute_admin_command(admin_queue,
13671738cd3eSNetanel Belgazal (struct ena_admin_aq_entry *)&create_cmd,
13681738cd3eSNetanel Belgazal sizeof(create_cmd),
13691738cd3eSNetanel Belgazal (struct ena_admin_acq_entry *)&cmd_completion,
13701738cd3eSNetanel Belgazal sizeof(cmd_completion));
13711738cd3eSNetanel Belgazal if (unlikely(ret)) {
1372*26668c2dSDavid Arinzon netdev_err(ena_dev->net_device, "Failed to create IO CQ. error: %d\n", ret);
13731738cd3eSNetanel Belgazal return ret;
13741738cd3eSNetanel Belgazal }
13751738cd3eSNetanel Belgazal
13761738cd3eSNetanel Belgazal io_cq->idx = cmd_completion.cq_idx;
13771738cd3eSNetanel Belgazal
13781738cd3eSNetanel Belgazal io_cq->unmask_reg = (u32 __iomem *)((uintptr_t)ena_dev->reg_bar +
13791738cd3eSNetanel Belgazal cmd_completion.cq_interrupt_unmask_register_offset);
13801738cd3eSNetanel Belgazal
13811738cd3eSNetanel Belgazal if (cmd_completion.cq_head_db_register_offset)
13821738cd3eSNetanel Belgazal io_cq->cq_head_db_reg =
13831738cd3eSNetanel Belgazal (u32 __iomem *)((uintptr_t)ena_dev->reg_bar +
13841738cd3eSNetanel Belgazal cmd_completion.cq_head_db_register_offset);
13851738cd3eSNetanel Belgazal
13861738cd3eSNetanel Belgazal if (cmd_completion.numa_node_register_offset)
13871738cd3eSNetanel Belgazal io_cq->numa_node_cfg_reg =
13881738cd3eSNetanel Belgazal (u32 __iomem *)((uintptr_t)ena_dev->reg_bar +
13891738cd3eSNetanel Belgazal cmd_completion.numa_node_register_offset);
13901738cd3eSNetanel Belgazal
1391*26668c2dSDavid Arinzon netdev_dbg(ena_dev->net_device, "Created cq[%u], depth[%u]\n", io_cq->idx, io_cq->q_depth);
13921738cd3eSNetanel Belgazal
13931738cd3eSNetanel Belgazal return ret;
13941738cd3eSNetanel Belgazal }
13951738cd3eSNetanel Belgazal
ena_com_get_io_handlers(struct ena_com_dev * ena_dev,u16 qid,struct ena_com_io_sq ** io_sq,struct ena_com_io_cq ** io_cq)13961738cd3eSNetanel Belgazal int ena_com_get_io_handlers(struct ena_com_dev *ena_dev, u16 qid,
13971738cd3eSNetanel Belgazal struct ena_com_io_sq **io_sq,
13981738cd3eSNetanel Belgazal struct ena_com_io_cq **io_cq)
13991738cd3eSNetanel Belgazal {
14001738cd3eSNetanel Belgazal if (qid >= ENA_TOTAL_NUM_QUEUES) {
1401*26668c2dSDavid Arinzon netdev_err(ena_dev->net_device, "Invalid queue number %d but the max is %d\n", qid,
14021738cd3eSNetanel Belgazal ENA_TOTAL_NUM_QUEUES);
14031738cd3eSNetanel Belgazal return -EINVAL;
14041738cd3eSNetanel Belgazal }
14051738cd3eSNetanel Belgazal
14061738cd3eSNetanel Belgazal *io_sq = &ena_dev->io_sq_queues[qid];
14071738cd3eSNetanel Belgazal *io_cq = &ena_dev->io_cq_queues[qid];
14081738cd3eSNetanel Belgazal
14091738cd3eSNetanel Belgazal return 0;
14101738cd3eSNetanel Belgazal }
14111738cd3eSNetanel Belgazal
ena_com_abort_admin_commands(struct ena_com_dev * ena_dev)14121738cd3eSNetanel Belgazal void ena_com_abort_admin_commands(struct ena_com_dev *ena_dev)
14131738cd3eSNetanel Belgazal {
14141738cd3eSNetanel Belgazal struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
14151738cd3eSNetanel Belgazal struct ena_comp_ctx *comp_ctx;
14161738cd3eSNetanel Belgazal u16 i;
14171738cd3eSNetanel Belgazal
14181738cd3eSNetanel Belgazal if (!admin_queue->comp_ctx)
14191738cd3eSNetanel Belgazal return;
14201738cd3eSNetanel Belgazal
14211738cd3eSNetanel Belgazal for (i = 0; i < admin_queue->q_depth; i++) {
14221738cd3eSNetanel Belgazal comp_ctx = get_comp_ctxt(admin_queue, i, false);
14231738cd3eSNetanel Belgazal if (unlikely(!comp_ctx))
14241738cd3eSNetanel Belgazal break;
14251738cd3eSNetanel Belgazal
14261738cd3eSNetanel Belgazal comp_ctx->status = ENA_CMD_ABORTED;
14271738cd3eSNetanel Belgazal
14281738cd3eSNetanel Belgazal complete(&comp_ctx->wait_event);
14291738cd3eSNetanel Belgazal }
14301738cd3eSNetanel Belgazal }
14311738cd3eSNetanel Belgazal
ena_com_wait_for_abort_completion(struct ena_com_dev * ena_dev)14321738cd3eSNetanel Belgazal void ena_com_wait_for_abort_completion(struct ena_com_dev *ena_dev)
14331738cd3eSNetanel Belgazal {
14341738cd3eSNetanel Belgazal struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
1435bd791175SArthur Kiyanovski unsigned long flags = 0;
14364bb7f4cfSArthur Kiyanovski u32 exp = 0;
14371738cd3eSNetanel Belgazal
14381738cd3eSNetanel Belgazal spin_lock_irqsave(&admin_queue->q_lock, flags);
14391738cd3eSNetanel Belgazal while (atomic_read(&admin_queue->outstanding_cmds) != 0) {
14401738cd3eSNetanel Belgazal spin_unlock_irqrestore(&admin_queue->q_lock, flags);
1441*26668c2dSDavid Arinzon ena_delay_exponential_backoff_us(exp++, ena_dev->ena_min_poll_delay_us);
14421738cd3eSNetanel Belgazal spin_lock_irqsave(&admin_queue->q_lock, flags);
14431738cd3eSNetanel Belgazal }
14441738cd3eSNetanel Belgazal spin_unlock_irqrestore(&admin_queue->q_lock, flags);
14451738cd3eSNetanel Belgazal }
14461738cd3eSNetanel Belgazal
ena_com_destroy_io_cq(struct ena_com_dev * ena_dev,struct ena_com_io_cq * io_cq)14471738cd3eSNetanel Belgazal int ena_com_destroy_io_cq(struct ena_com_dev *ena_dev,
14481738cd3eSNetanel Belgazal struct ena_com_io_cq *io_cq)
14491738cd3eSNetanel Belgazal {
14501738cd3eSNetanel Belgazal struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
14511738cd3eSNetanel Belgazal struct ena_admin_aq_destroy_cq_cmd destroy_cmd;
14521738cd3eSNetanel Belgazal struct ena_admin_acq_destroy_cq_resp_desc destroy_resp;
14531738cd3eSNetanel Belgazal int ret;
14541738cd3eSNetanel Belgazal
145591750110SNetanel Belgazal memset(&destroy_cmd, 0x0, sizeof(destroy_cmd));
14561738cd3eSNetanel Belgazal
14571738cd3eSNetanel Belgazal destroy_cmd.cq_idx = io_cq->idx;
14581738cd3eSNetanel Belgazal destroy_cmd.aq_common_descriptor.opcode = ENA_ADMIN_DESTROY_CQ;
14591738cd3eSNetanel Belgazal
14601738cd3eSNetanel Belgazal ret = ena_com_execute_admin_command(admin_queue,
14611738cd3eSNetanel Belgazal (struct ena_admin_aq_entry *)&destroy_cmd,
14621738cd3eSNetanel Belgazal sizeof(destroy_cmd),
14631738cd3eSNetanel Belgazal (struct ena_admin_acq_entry *)&destroy_resp,
14641738cd3eSNetanel Belgazal sizeof(destroy_resp));
14651738cd3eSNetanel Belgazal
14661738cd3eSNetanel Belgazal if (unlikely(ret && (ret != -ENODEV)))
1467*26668c2dSDavid Arinzon netdev_err(ena_dev->net_device, "Failed to destroy IO CQ. error: %d\n", ret);
14681738cd3eSNetanel Belgazal
14691738cd3eSNetanel Belgazal return ret;
14701738cd3eSNetanel Belgazal }
14711738cd3eSNetanel Belgazal
ena_com_get_admin_running_state(struct ena_com_dev * ena_dev)14721738cd3eSNetanel Belgazal bool ena_com_get_admin_running_state(struct ena_com_dev *ena_dev)
14731738cd3eSNetanel Belgazal {
14741738cd3eSNetanel Belgazal return ena_dev->admin_queue.running_state;
14751738cd3eSNetanel Belgazal }
14761738cd3eSNetanel Belgazal
ena_com_set_admin_running_state(struct ena_com_dev * ena_dev,bool state)14771738cd3eSNetanel Belgazal void ena_com_set_admin_running_state(struct ena_com_dev *ena_dev, bool state)
14781738cd3eSNetanel Belgazal {
14791738cd3eSNetanel Belgazal struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
1480bd791175SArthur Kiyanovski unsigned long flags = 0;
14811738cd3eSNetanel Belgazal
14821738cd3eSNetanel Belgazal spin_lock_irqsave(&admin_queue->q_lock, flags);
14831738cd3eSNetanel Belgazal ena_dev->admin_queue.running_state = state;
14841738cd3eSNetanel Belgazal spin_unlock_irqrestore(&admin_queue->q_lock, flags);
14851738cd3eSNetanel Belgazal }
14861738cd3eSNetanel Belgazal
ena_com_admin_aenq_enable(struct ena_com_dev * ena_dev)14871738cd3eSNetanel Belgazal void ena_com_admin_aenq_enable(struct ena_com_dev *ena_dev)
14881738cd3eSNetanel Belgazal {
14891738cd3eSNetanel Belgazal u16 depth = ena_dev->aenq.q_depth;
14901738cd3eSNetanel Belgazal
14911738cd3eSNetanel Belgazal WARN(ena_dev->aenq.head != depth, "Invalid AENQ state\n");
14921738cd3eSNetanel Belgazal
14931738cd3eSNetanel Belgazal /* Init head_db to mark that all entries in the queue
14941738cd3eSNetanel Belgazal * are initially available
14951738cd3eSNetanel Belgazal */
14961738cd3eSNetanel Belgazal writel(depth, ena_dev->reg_bar + ENA_REGS_AENQ_HEAD_DB_OFF);
14971738cd3eSNetanel Belgazal }
14981738cd3eSNetanel Belgazal
ena_com_set_aenq_config(struct ena_com_dev * ena_dev,u32 groups_flag)14991738cd3eSNetanel Belgazal int ena_com_set_aenq_config(struct ena_com_dev *ena_dev, u32 groups_flag)
15001738cd3eSNetanel Belgazal {
15011738cd3eSNetanel Belgazal struct ena_com_admin_queue *admin_queue;
15021738cd3eSNetanel Belgazal struct ena_admin_set_feat_cmd cmd;
15031738cd3eSNetanel Belgazal struct ena_admin_set_feat_resp resp;
15041738cd3eSNetanel Belgazal struct ena_admin_get_feat_resp get_resp;
15051738cd3eSNetanel Belgazal int ret;
15061738cd3eSNetanel Belgazal
1507ba8ef506SArthur Kiyanovski ret = ena_com_get_feature(ena_dev, &get_resp, ENA_ADMIN_AENQ_CONFIG, 0);
15081738cd3eSNetanel Belgazal if (ret) {
1509da580ca8SShay Agroskin dev_info(ena_dev->dmadev, "Can't get aenq configuration\n");
15101738cd3eSNetanel Belgazal return ret;
15111738cd3eSNetanel Belgazal }
15121738cd3eSNetanel Belgazal
15131738cd3eSNetanel Belgazal if ((get_resp.u.aenq.supported_groups & groups_flag) != groups_flag) {
1514da580ca8SShay Agroskin netdev_warn(ena_dev->net_device,
1515da580ca8SShay Agroskin "Trying to set unsupported aenq events. supported flag: 0x%x asked flag: 0x%x\n",
15161738cd3eSNetanel Belgazal get_resp.u.aenq.supported_groups, groups_flag);
1517d1497638SNetanel Belgazal return -EOPNOTSUPP;
15181738cd3eSNetanel Belgazal }
15191738cd3eSNetanel Belgazal
15201738cd3eSNetanel Belgazal memset(&cmd, 0x0, sizeof(cmd));
15211738cd3eSNetanel Belgazal admin_queue = &ena_dev->admin_queue;
15221738cd3eSNetanel Belgazal
15231738cd3eSNetanel Belgazal cmd.aq_common_descriptor.opcode = ENA_ADMIN_SET_FEATURE;
15241738cd3eSNetanel Belgazal cmd.aq_common_descriptor.flags = 0;
15251738cd3eSNetanel Belgazal cmd.feat_common.feature_id = ENA_ADMIN_AENQ_CONFIG;
15261738cd3eSNetanel Belgazal cmd.u.aenq.enabled_groups = groups_flag;
15271738cd3eSNetanel Belgazal
15281738cd3eSNetanel Belgazal ret = ena_com_execute_admin_command(admin_queue,
15291738cd3eSNetanel Belgazal (struct ena_admin_aq_entry *)&cmd,
15301738cd3eSNetanel Belgazal sizeof(cmd),
15311738cd3eSNetanel Belgazal (struct ena_admin_acq_entry *)&resp,
15321738cd3eSNetanel Belgazal sizeof(resp));
15331738cd3eSNetanel Belgazal
15341738cd3eSNetanel Belgazal if (unlikely(ret))
1535*26668c2dSDavid Arinzon netdev_err(ena_dev->net_device, "Failed to config AENQ ret: %d\n", ret);
15361738cd3eSNetanel Belgazal
15371738cd3eSNetanel Belgazal return ret;
15381738cd3eSNetanel Belgazal }
15391738cd3eSNetanel Belgazal
ena_com_get_dma_width(struct ena_com_dev * ena_dev)15401738cd3eSNetanel Belgazal int ena_com_get_dma_width(struct ena_com_dev *ena_dev)
15411738cd3eSNetanel Belgazal {
15421738cd3eSNetanel Belgazal u32 caps = ena_com_reg_bar_read32(ena_dev, ENA_REGS_CAPS_OFF);
1543e9548fdfSShay Agroskin u32 width;
15441738cd3eSNetanel Belgazal
15451738cd3eSNetanel Belgazal if (unlikely(caps == ENA_MMIO_READ_TIMEOUT)) {
1546da580ca8SShay Agroskin netdev_err(ena_dev->net_device, "Reg read timeout occurred\n");
15471738cd3eSNetanel Belgazal return -ETIME;
15481738cd3eSNetanel Belgazal }
15491738cd3eSNetanel Belgazal
15501738cd3eSNetanel Belgazal width = (caps & ENA_REGS_CAPS_DMA_ADDR_WIDTH_MASK) >>
15511738cd3eSNetanel Belgazal ENA_REGS_CAPS_DMA_ADDR_WIDTH_SHIFT;
15521738cd3eSNetanel Belgazal
1553da580ca8SShay Agroskin netdev_dbg(ena_dev->net_device, "ENA dma width: %d\n", width);
15541738cd3eSNetanel Belgazal
15551738cd3eSNetanel Belgazal if ((width < 32) || width > ENA_MAX_PHYS_ADDR_SIZE_BITS) {
1556*26668c2dSDavid Arinzon netdev_err(ena_dev->net_device, "DMA width illegal value: %d\n", width);
15571738cd3eSNetanel Belgazal return -EINVAL;
15581738cd3eSNetanel Belgazal }
15591738cd3eSNetanel Belgazal
15601738cd3eSNetanel Belgazal ena_dev->dma_addr_bits = width;
15611738cd3eSNetanel Belgazal
15621738cd3eSNetanel Belgazal return width;
15631738cd3eSNetanel Belgazal }
15641738cd3eSNetanel Belgazal
ena_com_validate_version(struct ena_com_dev * ena_dev)15651738cd3eSNetanel Belgazal int ena_com_validate_version(struct ena_com_dev *ena_dev)
15661738cd3eSNetanel Belgazal {
15671738cd3eSNetanel Belgazal u32 ver;
15681738cd3eSNetanel Belgazal u32 ctrl_ver;
15691738cd3eSNetanel Belgazal u32 ctrl_ver_masked;
15701738cd3eSNetanel Belgazal
15711738cd3eSNetanel Belgazal /* Make sure the ENA version and the controller version are at least
15721738cd3eSNetanel Belgazal * as the driver expects
15731738cd3eSNetanel Belgazal */
15741738cd3eSNetanel Belgazal ver = ena_com_reg_bar_read32(ena_dev, ENA_REGS_VERSION_OFF);
15751738cd3eSNetanel Belgazal ctrl_ver = ena_com_reg_bar_read32(ena_dev,
15761738cd3eSNetanel Belgazal ENA_REGS_CONTROLLER_VERSION_OFF);
15771738cd3eSNetanel Belgazal
1578*26668c2dSDavid Arinzon if (unlikely((ver == ENA_MMIO_READ_TIMEOUT) || (ctrl_ver == ENA_MMIO_READ_TIMEOUT))) {
1579da580ca8SShay Agroskin netdev_err(ena_dev->net_device, "Reg read timeout occurred\n");
15801738cd3eSNetanel Belgazal return -ETIME;
15811738cd3eSNetanel Belgazal }
15821738cd3eSNetanel Belgazal
1583da580ca8SShay Agroskin dev_info(ena_dev->dmadev, "ENA device version: %d.%d\n",
1584*26668c2dSDavid Arinzon (ver & ENA_REGS_VERSION_MAJOR_VERSION_MASK) >> ENA_REGS_VERSION_MAJOR_VERSION_SHIFT,
15851738cd3eSNetanel Belgazal ver & ENA_REGS_VERSION_MINOR_VERSION_MASK);
15861738cd3eSNetanel Belgazal
1587*26668c2dSDavid Arinzon dev_info(ena_dev->dmadev, "ENA controller version: %d.%d.%d implementation version %d\n",
15881738cd3eSNetanel Belgazal (ctrl_ver & ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_MASK) >>
15891738cd3eSNetanel Belgazal ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_SHIFT,
15901738cd3eSNetanel Belgazal (ctrl_ver & ENA_REGS_CONTROLLER_VERSION_MINOR_VERSION_MASK) >>
15911738cd3eSNetanel Belgazal ENA_REGS_CONTROLLER_VERSION_MINOR_VERSION_SHIFT,
15921738cd3eSNetanel Belgazal (ctrl_ver & ENA_REGS_CONTROLLER_VERSION_SUBMINOR_VERSION_MASK),
15931738cd3eSNetanel Belgazal (ctrl_ver & ENA_REGS_CONTROLLER_VERSION_IMPL_ID_MASK) >>
15941738cd3eSNetanel Belgazal ENA_REGS_CONTROLLER_VERSION_IMPL_ID_SHIFT);
15951738cd3eSNetanel Belgazal
15961738cd3eSNetanel Belgazal ctrl_ver_masked =
15971738cd3eSNetanel Belgazal (ctrl_ver & ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_MASK) |
15981738cd3eSNetanel Belgazal (ctrl_ver & ENA_REGS_CONTROLLER_VERSION_MINOR_VERSION_MASK) |
15991738cd3eSNetanel Belgazal (ctrl_ver & ENA_REGS_CONTROLLER_VERSION_SUBMINOR_VERSION_MASK);
16001738cd3eSNetanel Belgazal
16011738cd3eSNetanel Belgazal /* Validate the ctrl version without the implementation ID */
16021738cd3eSNetanel Belgazal if (ctrl_ver_masked < MIN_ENA_CTRL_VER) {
1603da580ca8SShay Agroskin netdev_err(ena_dev->net_device,
1604da580ca8SShay Agroskin "ENA ctrl version is lower than the minimal ctrl version the driver supports\n");
16051738cd3eSNetanel Belgazal return -1;
16061738cd3eSNetanel Belgazal }
16071738cd3eSNetanel Belgazal
16081738cd3eSNetanel Belgazal return 0;
16091738cd3eSNetanel Belgazal }
16101738cd3eSNetanel Belgazal
1611bf2746e8SShay Agroskin static void
ena_com_free_ena_admin_queue_comp_ctx(struct ena_com_dev * ena_dev,struct ena_com_admin_queue * admin_queue)1612bf2746e8SShay Agroskin ena_com_free_ena_admin_queue_comp_ctx(struct ena_com_dev *ena_dev,
1613bf2746e8SShay Agroskin struct ena_com_admin_queue *admin_queue)
1614bf2746e8SShay Agroskin
1615bf2746e8SShay Agroskin {
1616bf2746e8SShay Agroskin if (!admin_queue->comp_ctx)
1617bf2746e8SShay Agroskin return;
1618bf2746e8SShay Agroskin
1619bf2746e8SShay Agroskin devm_kfree(ena_dev->dmadev, admin_queue->comp_ctx);
1620bf2746e8SShay Agroskin
1621bf2746e8SShay Agroskin admin_queue->comp_ctx = NULL;
1622bf2746e8SShay Agroskin }
1623bf2746e8SShay Agroskin
ena_com_admin_destroy(struct ena_com_dev * ena_dev)16241738cd3eSNetanel Belgazal void ena_com_admin_destroy(struct ena_com_dev *ena_dev)
16251738cd3eSNetanel Belgazal {
16261738cd3eSNetanel Belgazal struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
16271738cd3eSNetanel Belgazal struct ena_com_admin_cq *cq = &admin_queue->cq;
16281738cd3eSNetanel Belgazal struct ena_com_admin_sq *sq = &admin_queue->sq;
16291738cd3eSNetanel Belgazal struct ena_com_aenq *aenq = &ena_dev->aenq;
16301738cd3eSNetanel Belgazal u16 size;
16311738cd3eSNetanel Belgazal
1632bf2746e8SShay Agroskin ena_com_free_ena_admin_queue_comp_ctx(ena_dev, admin_queue);
1633bf2746e8SShay Agroskin
16341738cd3eSNetanel Belgazal size = ADMIN_SQ_SIZE(admin_queue->q_depth);
16351738cd3eSNetanel Belgazal if (sq->entries)
1636*26668c2dSDavid Arinzon dma_free_coherent(ena_dev->dmadev, size, sq->entries, sq->dma_addr);
16371738cd3eSNetanel Belgazal sq->entries = NULL;
16381738cd3eSNetanel Belgazal
16391738cd3eSNetanel Belgazal size = ADMIN_CQ_SIZE(admin_queue->q_depth);
16401738cd3eSNetanel Belgazal if (cq->entries)
1641*26668c2dSDavid Arinzon dma_free_coherent(ena_dev->dmadev, size, cq->entries, cq->dma_addr);
16421738cd3eSNetanel Belgazal cq->entries = NULL;
16431738cd3eSNetanel Belgazal
16441738cd3eSNetanel Belgazal size = ADMIN_AENQ_SIZE(aenq->q_depth);
16451738cd3eSNetanel Belgazal if (ena_dev->aenq.entries)
1646*26668c2dSDavid Arinzon dma_free_coherent(ena_dev->dmadev, size, aenq->entries, aenq->dma_addr);
16471738cd3eSNetanel Belgazal aenq->entries = NULL;
16481738cd3eSNetanel Belgazal }
16491738cd3eSNetanel Belgazal
ena_com_set_admin_polling_mode(struct ena_com_dev * ena_dev,bool polling)16501738cd3eSNetanel Belgazal void ena_com_set_admin_polling_mode(struct ena_com_dev *ena_dev, bool polling)
16511738cd3eSNetanel Belgazal {
1652a2cc5198SNetanel Belgazal u32 mask_value = 0;
1653a2cc5198SNetanel Belgazal
1654a2cc5198SNetanel Belgazal if (polling)
1655a2cc5198SNetanel Belgazal mask_value = ENA_REGS_ADMIN_INTR_MASK;
1656a2cc5198SNetanel Belgazal
1657a2cc5198SNetanel Belgazal writel(mask_value, ena_dev->reg_bar + ENA_REGS_INTR_MASK_OFF);
16581738cd3eSNetanel Belgazal ena_dev->admin_queue.polling = polling;
16591738cd3eSNetanel Belgazal }
16601738cd3eSNetanel Belgazal
ena_com_set_admin_auto_polling_mode(struct ena_com_dev * ena_dev,bool polling)1661a4e262cdSSameeh Jubran void ena_com_set_admin_auto_polling_mode(struct ena_com_dev *ena_dev,
1662a4e262cdSSameeh Jubran bool polling)
1663a4e262cdSSameeh Jubran {
1664a4e262cdSSameeh Jubran ena_dev->admin_queue.auto_polling = polling;
1665a4e262cdSSameeh Jubran }
1666a4e262cdSSameeh Jubran
ena_com_mmio_reg_read_request_init(struct ena_com_dev * ena_dev)16671738cd3eSNetanel Belgazal int ena_com_mmio_reg_read_request_init(struct ena_com_dev *ena_dev)
16681738cd3eSNetanel Belgazal {
16691738cd3eSNetanel Belgazal struct ena_com_mmio_read *mmio_read = &ena_dev->mmio_read;
16701738cd3eSNetanel Belgazal
16711738cd3eSNetanel Belgazal spin_lock_init(&mmio_read->lock);
1672*26668c2dSDavid Arinzon mmio_read->read_resp = dma_alloc_coherent(ena_dev->dmadev, sizeof(*mmio_read->read_resp),
16731738cd3eSNetanel Belgazal &mmio_read->read_resp_dma_addr, GFP_KERNEL);
16741738cd3eSNetanel Belgazal if (unlikely(!mmio_read->read_resp))
1675bd791175SArthur Kiyanovski goto err;
16761738cd3eSNetanel Belgazal
16771738cd3eSNetanel Belgazal ena_com_mmio_reg_read_request_write_dev_addr(ena_dev);
16781738cd3eSNetanel Belgazal
16791738cd3eSNetanel Belgazal mmio_read->read_resp->req_id = 0x0;
16801738cd3eSNetanel Belgazal mmio_read->seq_num = 0x0;
16811738cd3eSNetanel Belgazal mmio_read->readless_supported = true;
16821738cd3eSNetanel Belgazal
16831738cd3eSNetanel Belgazal return 0;
1684bd791175SArthur Kiyanovski
1685bd791175SArthur Kiyanovski err:
1686bd791175SArthur Kiyanovski
1687bd791175SArthur Kiyanovski return -ENOMEM;
16881738cd3eSNetanel Belgazal }
16891738cd3eSNetanel Belgazal
ena_com_set_mmio_read_mode(struct ena_com_dev * ena_dev,bool readless_supported)16901738cd3eSNetanel Belgazal void ena_com_set_mmio_read_mode(struct ena_com_dev *ena_dev, bool readless_supported)
16911738cd3eSNetanel Belgazal {
16921738cd3eSNetanel Belgazal struct ena_com_mmio_read *mmio_read = &ena_dev->mmio_read;
16931738cd3eSNetanel Belgazal
16941738cd3eSNetanel Belgazal mmio_read->readless_supported = readless_supported;
16951738cd3eSNetanel Belgazal }
16961738cd3eSNetanel Belgazal
ena_com_mmio_reg_read_request_destroy(struct ena_com_dev * ena_dev)16971738cd3eSNetanel Belgazal void ena_com_mmio_reg_read_request_destroy(struct ena_com_dev *ena_dev)
16981738cd3eSNetanel Belgazal {
16991738cd3eSNetanel Belgazal struct ena_com_mmio_read *mmio_read = &ena_dev->mmio_read;
17001738cd3eSNetanel Belgazal
17011738cd3eSNetanel Belgazal writel(0x0, ena_dev->reg_bar + ENA_REGS_MMIO_RESP_LO_OFF);
17021738cd3eSNetanel Belgazal writel(0x0, ena_dev->reg_bar + ENA_REGS_MMIO_RESP_HI_OFF);
17031738cd3eSNetanel Belgazal
1704*26668c2dSDavid Arinzon dma_free_coherent(ena_dev->dmadev, sizeof(*mmio_read->read_resp), mmio_read->read_resp,
1705*26668c2dSDavid Arinzon mmio_read->read_resp_dma_addr);
17061738cd3eSNetanel Belgazal
17071738cd3eSNetanel Belgazal mmio_read->read_resp = NULL;
17081738cd3eSNetanel Belgazal }
17091738cd3eSNetanel Belgazal
ena_com_mmio_reg_read_request_write_dev_addr(struct ena_com_dev * ena_dev)17101738cd3eSNetanel Belgazal void ena_com_mmio_reg_read_request_write_dev_addr(struct ena_com_dev *ena_dev)
17111738cd3eSNetanel Belgazal {
17121738cd3eSNetanel Belgazal struct ena_com_mmio_read *mmio_read = &ena_dev->mmio_read;
17131738cd3eSNetanel Belgazal u32 addr_low, addr_high;
17141738cd3eSNetanel Belgazal
17151738cd3eSNetanel Belgazal addr_low = ENA_DMA_ADDR_TO_UINT32_LOW(mmio_read->read_resp_dma_addr);
17161738cd3eSNetanel Belgazal addr_high = ENA_DMA_ADDR_TO_UINT32_HIGH(mmio_read->read_resp_dma_addr);
17171738cd3eSNetanel Belgazal
17181738cd3eSNetanel Belgazal writel(addr_low, ena_dev->reg_bar + ENA_REGS_MMIO_RESP_LO_OFF);
17191738cd3eSNetanel Belgazal writel(addr_high, ena_dev->reg_bar + ENA_REGS_MMIO_RESP_HI_OFF);
17201738cd3eSNetanel Belgazal }
17211738cd3eSNetanel Belgazal
ena_com_admin_init(struct ena_com_dev * ena_dev,struct ena_aenq_handlers * aenq_handlers)17221738cd3eSNetanel Belgazal int ena_com_admin_init(struct ena_com_dev *ena_dev,
1723f1e90f6eSArthur Kiyanovski struct ena_aenq_handlers *aenq_handlers)
17241738cd3eSNetanel Belgazal {
17251738cd3eSNetanel Belgazal struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
17261738cd3eSNetanel Belgazal u32 aq_caps, acq_caps, dev_sts, addr_low, addr_high;
17271738cd3eSNetanel Belgazal int ret;
17281738cd3eSNetanel Belgazal
17291738cd3eSNetanel Belgazal dev_sts = ena_com_reg_bar_read32(ena_dev, ENA_REGS_DEV_STS_OFF);
17301738cd3eSNetanel Belgazal
17311738cd3eSNetanel Belgazal if (unlikely(dev_sts == ENA_MMIO_READ_TIMEOUT)) {
1732da580ca8SShay Agroskin netdev_err(ena_dev->net_device, "Reg read timeout occurred\n");
17331738cd3eSNetanel Belgazal return -ETIME;
17341738cd3eSNetanel Belgazal }
17351738cd3eSNetanel Belgazal
17361738cd3eSNetanel Belgazal if (!(dev_sts & ENA_REGS_DEV_STS_READY_MASK)) {
1737*26668c2dSDavid Arinzon netdev_err(ena_dev->net_device, "Device isn't ready, abort com init\n");
17381738cd3eSNetanel Belgazal return -ENODEV;
17391738cd3eSNetanel Belgazal }
17401738cd3eSNetanel Belgazal
17411738cd3eSNetanel Belgazal admin_queue->q_depth = ENA_ADMIN_QUEUE_DEPTH;
17421738cd3eSNetanel Belgazal
17431738cd3eSNetanel Belgazal admin_queue->q_dmadev = ena_dev->dmadev;
17441738cd3eSNetanel Belgazal admin_queue->polling = false;
17451738cd3eSNetanel Belgazal admin_queue->curr_cmd_id = 0;
17461738cd3eSNetanel Belgazal
17471738cd3eSNetanel Belgazal atomic_set(&admin_queue->outstanding_cmds, 0);
17481738cd3eSNetanel Belgazal
17491738cd3eSNetanel Belgazal spin_lock_init(&admin_queue->q_lock);
17501738cd3eSNetanel Belgazal
17511738cd3eSNetanel Belgazal ret = ena_com_init_comp_ctxt(admin_queue);
17521738cd3eSNetanel Belgazal if (ret)
17531738cd3eSNetanel Belgazal goto error;
17541738cd3eSNetanel Belgazal
17551738cd3eSNetanel Belgazal ret = ena_com_admin_init_sq(admin_queue);
17561738cd3eSNetanel Belgazal if (ret)
17571738cd3eSNetanel Belgazal goto error;
17581738cd3eSNetanel Belgazal
17591738cd3eSNetanel Belgazal ret = ena_com_admin_init_cq(admin_queue);
17601738cd3eSNetanel Belgazal if (ret)
17611738cd3eSNetanel Belgazal goto error;
17621738cd3eSNetanel Belgazal
17631738cd3eSNetanel Belgazal admin_queue->sq.db_addr = (u32 __iomem *)((uintptr_t)ena_dev->reg_bar +
17641738cd3eSNetanel Belgazal ENA_REGS_AQ_DB_OFF);
17651738cd3eSNetanel Belgazal
17661738cd3eSNetanel Belgazal addr_low = ENA_DMA_ADDR_TO_UINT32_LOW(admin_queue->sq.dma_addr);
17671738cd3eSNetanel Belgazal addr_high = ENA_DMA_ADDR_TO_UINT32_HIGH(admin_queue->sq.dma_addr);
17681738cd3eSNetanel Belgazal
17691738cd3eSNetanel Belgazal writel(addr_low, ena_dev->reg_bar + ENA_REGS_AQ_BASE_LO_OFF);
17701738cd3eSNetanel Belgazal writel(addr_high, ena_dev->reg_bar + ENA_REGS_AQ_BASE_HI_OFF);
17711738cd3eSNetanel Belgazal
17721738cd3eSNetanel Belgazal addr_low = ENA_DMA_ADDR_TO_UINT32_LOW(admin_queue->cq.dma_addr);
17731738cd3eSNetanel Belgazal addr_high = ENA_DMA_ADDR_TO_UINT32_HIGH(admin_queue->cq.dma_addr);
17741738cd3eSNetanel Belgazal
17751738cd3eSNetanel Belgazal writel(addr_low, ena_dev->reg_bar + ENA_REGS_ACQ_BASE_LO_OFF);
17761738cd3eSNetanel Belgazal writel(addr_high, ena_dev->reg_bar + ENA_REGS_ACQ_BASE_HI_OFF);
17771738cd3eSNetanel Belgazal
17781738cd3eSNetanel Belgazal aq_caps = 0;
17791738cd3eSNetanel Belgazal aq_caps |= admin_queue->q_depth & ENA_REGS_AQ_CAPS_AQ_DEPTH_MASK;
17801738cd3eSNetanel Belgazal aq_caps |= (sizeof(struct ena_admin_aq_entry) <<
17811738cd3eSNetanel Belgazal ENA_REGS_AQ_CAPS_AQ_ENTRY_SIZE_SHIFT) &
17821738cd3eSNetanel Belgazal ENA_REGS_AQ_CAPS_AQ_ENTRY_SIZE_MASK;
17831738cd3eSNetanel Belgazal
17841738cd3eSNetanel Belgazal acq_caps = 0;
17851738cd3eSNetanel Belgazal acq_caps |= admin_queue->q_depth & ENA_REGS_ACQ_CAPS_ACQ_DEPTH_MASK;
17861738cd3eSNetanel Belgazal acq_caps |= (sizeof(struct ena_admin_acq_entry) <<
17871738cd3eSNetanel Belgazal ENA_REGS_ACQ_CAPS_ACQ_ENTRY_SIZE_SHIFT) &
17881738cd3eSNetanel Belgazal ENA_REGS_ACQ_CAPS_ACQ_ENTRY_SIZE_MASK;
17891738cd3eSNetanel Belgazal
17901738cd3eSNetanel Belgazal writel(aq_caps, ena_dev->reg_bar + ENA_REGS_AQ_CAPS_OFF);
17911738cd3eSNetanel Belgazal writel(acq_caps, ena_dev->reg_bar + ENA_REGS_ACQ_CAPS_OFF);
17921738cd3eSNetanel Belgazal ret = ena_com_admin_init_aenq(ena_dev, aenq_handlers);
17931738cd3eSNetanel Belgazal if (ret)
17941738cd3eSNetanel Belgazal goto error;
17951738cd3eSNetanel Belgazal
17964bb7f4cfSArthur Kiyanovski admin_queue->ena_dev = ena_dev;
17971738cd3eSNetanel Belgazal admin_queue->running_state = true;
17981738cd3eSNetanel Belgazal
17991738cd3eSNetanel Belgazal return 0;
18001738cd3eSNetanel Belgazal error:
18011738cd3eSNetanel Belgazal ena_com_admin_destroy(ena_dev);
18021738cd3eSNetanel Belgazal
18031738cd3eSNetanel Belgazal return ret;
18041738cd3eSNetanel Belgazal }
18051738cd3eSNetanel Belgazal
ena_com_create_io_queue(struct ena_com_dev * ena_dev,struct ena_com_create_io_ctx * ctx)18061738cd3eSNetanel Belgazal int ena_com_create_io_queue(struct ena_com_dev *ena_dev,
18071738cd3eSNetanel Belgazal struct ena_com_create_io_ctx *ctx)
18081738cd3eSNetanel Belgazal {
18091738cd3eSNetanel Belgazal struct ena_com_io_sq *io_sq;
18101738cd3eSNetanel Belgazal struct ena_com_io_cq *io_cq;
18111738cd3eSNetanel Belgazal int ret;
18121738cd3eSNetanel Belgazal
18131738cd3eSNetanel Belgazal if (ctx->qid >= ENA_TOTAL_NUM_QUEUES) {
1814*26668c2dSDavid Arinzon netdev_err(ena_dev->net_device, "Qid (%d) is bigger than max num of queues (%d)\n",
18151738cd3eSNetanel Belgazal ctx->qid, ENA_TOTAL_NUM_QUEUES);
18161738cd3eSNetanel Belgazal return -EINVAL;
18171738cd3eSNetanel Belgazal }
18181738cd3eSNetanel Belgazal
18191738cd3eSNetanel Belgazal io_sq = &ena_dev->io_sq_queues[ctx->qid];
18201738cd3eSNetanel Belgazal io_cq = &ena_dev->io_cq_queues[ctx->qid];
18211738cd3eSNetanel Belgazal
182291750110SNetanel Belgazal memset(io_sq, 0x0, sizeof(*io_sq));
182391750110SNetanel Belgazal memset(io_cq, 0x0, sizeof(*io_cq));
18241738cd3eSNetanel Belgazal
18251738cd3eSNetanel Belgazal /* Init CQ */
18261738cd3eSNetanel Belgazal io_cq->q_depth = ctx->queue_size;
18271738cd3eSNetanel Belgazal io_cq->direction = ctx->direction;
18281738cd3eSNetanel Belgazal io_cq->qid = ctx->qid;
18291738cd3eSNetanel Belgazal
18301738cd3eSNetanel Belgazal io_cq->msix_vector = ctx->msix_vector;
18311738cd3eSNetanel Belgazal
18321738cd3eSNetanel Belgazal io_sq->q_depth = ctx->queue_size;
18331738cd3eSNetanel Belgazal io_sq->direction = ctx->direction;
18341738cd3eSNetanel Belgazal io_sq->qid = ctx->qid;
18351738cd3eSNetanel Belgazal
18361738cd3eSNetanel Belgazal io_sq->mem_queue_type = ctx->mem_queue_type;
18371738cd3eSNetanel Belgazal
18381738cd3eSNetanel Belgazal if (ctx->direction == ENA_COM_IO_QUEUE_DIRECTION_TX)
18391738cd3eSNetanel Belgazal /* header length is limited to 8 bits */
1840*26668c2dSDavid Arinzon io_sq->tx_max_header_size = min_t(u32, ena_dev->tx_max_header_size, SZ_256);
18411738cd3eSNetanel Belgazal
18421738cd3eSNetanel Belgazal ret = ena_com_init_io_sq(ena_dev, ctx, io_sq);
18431738cd3eSNetanel Belgazal if (ret)
18441738cd3eSNetanel Belgazal goto error;
18451738cd3eSNetanel Belgazal ret = ena_com_init_io_cq(ena_dev, ctx, io_cq);
18461738cd3eSNetanel Belgazal if (ret)
18471738cd3eSNetanel Belgazal goto error;
18481738cd3eSNetanel Belgazal
18491738cd3eSNetanel Belgazal ret = ena_com_create_io_cq(ena_dev, io_cq);
18501738cd3eSNetanel Belgazal if (ret)
18511738cd3eSNetanel Belgazal goto error;
18521738cd3eSNetanel Belgazal
18531738cd3eSNetanel Belgazal ret = ena_com_create_io_sq(ena_dev, io_sq, io_cq->idx);
18541738cd3eSNetanel Belgazal if (ret)
18551738cd3eSNetanel Belgazal goto destroy_io_cq;
18561738cd3eSNetanel Belgazal
18571738cd3eSNetanel Belgazal return 0;
18581738cd3eSNetanel Belgazal
18591738cd3eSNetanel Belgazal destroy_io_cq:
18601738cd3eSNetanel Belgazal ena_com_destroy_io_cq(ena_dev, io_cq);
18611738cd3eSNetanel Belgazal error:
18621738cd3eSNetanel Belgazal ena_com_io_queue_free(ena_dev, io_sq, io_cq);
18631738cd3eSNetanel Belgazal return ret;
18641738cd3eSNetanel Belgazal }
18651738cd3eSNetanel Belgazal
ena_com_destroy_io_queue(struct ena_com_dev * ena_dev,u16 qid)18661738cd3eSNetanel Belgazal void ena_com_destroy_io_queue(struct ena_com_dev *ena_dev, u16 qid)
18671738cd3eSNetanel Belgazal {
18681738cd3eSNetanel Belgazal struct ena_com_io_sq *io_sq;
18691738cd3eSNetanel Belgazal struct ena_com_io_cq *io_cq;
18701738cd3eSNetanel Belgazal
18711738cd3eSNetanel Belgazal if (qid >= ENA_TOTAL_NUM_QUEUES) {
1872*26668c2dSDavid Arinzon netdev_err(ena_dev->net_device, "Qid (%d) is bigger than max num of queues (%d)\n",
1873da580ca8SShay Agroskin qid, ENA_TOTAL_NUM_QUEUES);
18741738cd3eSNetanel Belgazal return;
18751738cd3eSNetanel Belgazal }
18761738cd3eSNetanel Belgazal
18771738cd3eSNetanel Belgazal io_sq = &ena_dev->io_sq_queues[qid];
18781738cd3eSNetanel Belgazal io_cq = &ena_dev->io_cq_queues[qid];
18791738cd3eSNetanel Belgazal
18801738cd3eSNetanel Belgazal ena_com_destroy_io_sq(ena_dev, io_sq);
18811738cd3eSNetanel Belgazal ena_com_destroy_io_cq(ena_dev, io_cq);
18821738cd3eSNetanel Belgazal
18831738cd3eSNetanel Belgazal ena_com_io_queue_free(ena_dev, io_sq, io_cq);
18841738cd3eSNetanel Belgazal }
18851738cd3eSNetanel Belgazal
ena_com_get_link_params(struct ena_com_dev * ena_dev,struct ena_admin_get_feat_resp * resp)18861738cd3eSNetanel Belgazal int ena_com_get_link_params(struct ena_com_dev *ena_dev,
18871738cd3eSNetanel Belgazal struct ena_admin_get_feat_resp *resp)
18881738cd3eSNetanel Belgazal {
1889ba8ef506SArthur Kiyanovski return ena_com_get_feature(ena_dev, resp, ENA_ADMIN_LINK_CONFIG, 0);
18901738cd3eSNetanel Belgazal }
18911738cd3eSNetanel Belgazal
ena_com_get_dev_attr_feat(struct ena_com_dev * ena_dev,struct ena_com_dev_get_features_ctx * get_feat_ctx)18921738cd3eSNetanel Belgazal int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev,
18931738cd3eSNetanel Belgazal struct ena_com_dev_get_features_ctx *get_feat_ctx)
18941738cd3eSNetanel Belgazal {
18951738cd3eSNetanel Belgazal struct ena_admin_get_feat_resp get_resp;
18961738cd3eSNetanel Belgazal int rc;
18971738cd3eSNetanel Belgazal
18981738cd3eSNetanel Belgazal rc = ena_com_get_feature(ena_dev, &get_resp,
1899ba8ef506SArthur Kiyanovski ENA_ADMIN_DEVICE_ATTRIBUTES, 0);
19001738cd3eSNetanel Belgazal if (rc)
19011738cd3eSNetanel Belgazal return rc;
19021738cd3eSNetanel Belgazal
19031738cd3eSNetanel Belgazal memcpy(&get_feat_ctx->dev_attr, &get_resp.u.dev_attr,
19041738cd3eSNetanel Belgazal sizeof(get_resp.u.dev_attr));
1905bf2746e8SShay Agroskin
19061738cd3eSNetanel Belgazal ena_dev->supported_features = get_resp.u.dev_attr.supported_features;
1907a2d5d6a7SArthur Kiyanovski ena_dev->capabilities = get_resp.u.dev_attr.capabilities;
19081738cd3eSNetanel Belgazal
1909ba8ef506SArthur Kiyanovski if (ena_dev->supported_features & BIT(ENA_ADMIN_MAX_QUEUES_EXT)) {
19101738cd3eSNetanel Belgazal rc = ena_com_get_feature(ena_dev, &get_resp,
1911ba8ef506SArthur Kiyanovski ENA_ADMIN_MAX_QUEUES_EXT,
1912ba8ef506SArthur Kiyanovski ENA_FEATURE_MAX_QUEUE_EXT_VER);
19131738cd3eSNetanel Belgazal if (rc)
19141738cd3eSNetanel Belgazal return rc;
19151738cd3eSNetanel Belgazal
1916*26668c2dSDavid Arinzon if (get_resp.u.max_queue_ext.version != ENA_FEATURE_MAX_QUEUE_EXT_VER)
1917ba8ef506SArthur Kiyanovski return -EINVAL;
1918ba8ef506SArthur Kiyanovski
1919ba8ef506SArthur Kiyanovski memcpy(&get_feat_ctx->max_queue_ext, &get_resp.u.max_queue_ext,
1920ba8ef506SArthur Kiyanovski sizeof(get_resp.u.max_queue_ext));
1921ba8ef506SArthur Kiyanovski ena_dev->tx_max_header_size =
1922ba8ef506SArthur Kiyanovski get_resp.u.max_queue_ext.max_queue_ext.max_tx_header_size;
1923ba8ef506SArthur Kiyanovski } else {
1924ba8ef506SArthur Kiyanovski rc = ena_com_get_feature(ena_dev, &get_resp,
1925ba8ef506SArthur Kiyanovski ENA_ADMIN_MAX_QUEUES_NUM, 0);
19261738cd3eSNetanel Belgazal memcpy(&get_feat_ctx->max_queues, &get_resp.u.max_queue,
19271738cd3eSNetanel Belgazal sizeof(get_resp.u.max_queue));
1928ba8ef506SArthur Kiyanovski ena_dev->tx_max_header_size =
1929ba8ef506SArthur Kiyanovski get_resp.u.max_queue.max_header_size;
1930ba8ef506SArthur Kiyanovski
1931ba8ef506SArthur Kiyanovski if (rc)
1932ba8ef506SArthur Kiyanovski return rc;
1933ba8ef506SArthur Kiyanovski }
19341738cd3eSNetanel Belgazal
19351738cd3eSNetanel Belgazal rc = ena_com_get_feature(ena_dev, &get_resp,
1936ba8ef506SArthur Kiyanovski ENA_ADMIN_AENQ_CONFIG, 0);
19371738cd3eSNetanel Belgazal if (rc)
19381738cd3eSNetanel Belgazal return rc;
19391738cd3eSNetanel Belgazal
19401738cd3eSNetanel Belgazal memcpy(&get_feat_ctx->aenq, &get_resp.u.aenq,
19411738cd3eSNetanel Belgazal sizeof(get_resp.u.aenq));
19421738cd3eSNetanel Belgazal
19431738cd3eSNetanel Belgazal rc = ena_com_get_feature(ena_dev, &get_resp,
1944ba8ef506SArthur Kiyanovski ENA_ADMIN_STATELESS_OFFLOAD_CONFIG, 0);
19451738cd3eSNetanel Belgazal if (rc)
19461738cd3eSNetanel Belgazal return rc;
19471738cd3eSNetanel Belgazal
19481738cd3eSNetanel Belgazal memcpy(&get_feat_ctx->offload, &get_resp.u.offload,
19491738cd3eSNetanel Belgazal sizeof(get_resp.u.offload));
19501738cd3eSNetanel Belgazal
195182ef30f1SNetanel Belgazal /* Driver hints isn't mandatory admin command. So in case the
195282ef30f1SNetanel Belgazal * command isn't supported set driver hints to 0
195382ef30f1SNetanel Belgazal */
1954ba8ef506SArthur Kiyanovski rc = ena_com_get_feature(ena_dev, &get_resp, ENA_ADMIN_HW_HINTS, 0);
195582ef30f1SNetanel Belgazal
195682ef30f1SNetanel Belgazal if (!rc)
1957*26668c2dSDavid Arinzon memcpy(&get_feat_ctx->hw_hints, &get_resp.u.hw_hints, sizeof(get_resp.u.hw_hints));
195882ef30f1SNetanel Belgazal else if (rc == -EOPNOTSUPP)
1959*26668c2dSDavid Arinzon memset(&get_feat_ctx->hw_hints, 0x0, sizeof(get_feat_ctx->hw_hints));
196082ef30f1SNetanel Belgazal else
196182ef30f1SNetanel Belgazal return rc;
196282ef30f1SNetanel Belgazal
1963ba8ef506SArthur Kiyanovski rc = ena_com_get_feature(ena_dev, &get_resp, ENA_ADMIN_LLQ, 0);
1964689b2bdaSArthur Kiyanovski if (!rc)
1965*26668c2dSDavid Arinzon memcpy(&get_feat_ctx->llq, &get_resp.u.llq, sizeof(get_resp.u.llq));
1966689b2bdaSArthur Kiyanovski else if (rc == -EOPNOTSUPP)
1967689b2bdaSArthur Kiyanovski memset(&get_feat_ctx->llq, 0x0, sizeof(get_feat_ctx->llq));
1968689b2bdaSArthur Kiyanovski else
1969689b2bdaSArthur Kiyanovski return rc;
1970689b2bdaSArthur Kiyanovski
19711738cd3eSNetanel Belgazal return 0;
19721738cd3eSNetanel Belgazal }
19731738cd3eSNetanel Belgazal
ena_com_admin_q_comp_intr_handler(struct ena_com_dev * ena_dev)19741738cd3eSNetanel Belgazal void ena_com_admin_q_comp_intr_handler(struct ena_com_dev *ena_dev)
19751738cd3eSNetanel Belgazal {
19761738cd3eSNetanel Belgazal ena_com_handle_admin_completion(&ena_dev->admin_queue);
19771738cd3eSNetanel Belgazal }
19781738cd3eSNetanel Belgazal
19791738cd3eSNetanel Belgazal /* ena_handle_specific_aenq_event:
19801738cd3eSNetanel Belgazal * return the handler that is relevant to the specific event group
19811738cd3eSNetanel Belgazal */
ena_com_get_specific_aenq_cb(struct ena_com_dev * ena_dev,u16 group)1982bf2746e8SShay Agroskin static ena_aenq_handler ena_com_get_specific_aenq_cb(struct ena_com_dev *ena_dev,
19831738cd3eSNetanel Belgazal u16 group)
19841738cd3eSNetanel Belgazal {
1985bf2746e8SShay Agroskin struct ena_aenq_handlers *aenq_handlers = ena_dev->aenq.aenq_handlers;
19861738cd3eSNetanel Belgazal
19871738cd3eSNetanel Belgazal if ((group < ENA_MAX_HANDLERS) && aenq_handlers->handlers[group])
19881738cd3eSNetanel Belgazal return aenq_handlers->handlers[group];
19891738cd3eSNetanel Belgazal
19901738cd3eSNetanel Belgazal return aenq_handlers->unimplemented_handler;
19911738cd3eSNetanel Belgazal }
19921738cd3eSNetanel Belgazal
19931738cd3eSNetanel Belgazal /* ena_aenq_intr_handler:
19941738cd3eSNetanel Belgazal * handles the aenq incoming events.
19951738cd3eSNetanel Belgazal * pop events from the queue and apply the specific handler
19961738cd3eSNetanel Belgazal */
ena_com_aenq_intr_handler(struct ena_com_dev * ena_dev,void * data)1997bf2746e8SShay Agroskin void ena_com_aenq_intr_handler(struct ena_com_dev *ena_dev, void *data)
19981738cd3eSNetanel Belgazal {
19991738cd3eSNetanel Belgazal struct ena_admin_aenq_entry *aenq_e;
20001738cd3eSNetanel Belgazal struct ena_admin_aenq_common_desc *aenq_common;
2001bf2746e8SShay Agroskin struct ena_com_aenq *aenq = &ena_dev->aenq;
2002f391503bSArthur Kiyanovski u64 timestamp;
20031738cd3eSNetanel Belgazal ena_aenq_handler handler_cb;
20041738cd3eSNetanel Belgazal u16 masked_head, processed = 0;
20051738cd3eSNetanel Belgazal u8 phase;
20061738cd3eSNetanel Belgazal
20071738cd3eSNetanel Belgazal masked_head = aenq->head & (aenq->q_depth - 1);
20081738cd3eSNetanel Belgazal phase = aenq->phase;
20091738cd3eSNetanel Belgazal aenq_e = &aenq->entries[masked_head]; /* Get first entry */
20101738cd3eSNetanel Belgazal aenq_common = &aenq_e->aenq_common_desc;
20111738cd3eSNetanel Belgazal
20121738cd3eSNetanel Belgazal /* Go over all the events */
2013*26668c2dSDavid Arinzon while ((READ_ONCE(aenq_common->flags) & ENA_ADMIN_AENQ_COMMON_DESC_PHASE_MASK) == phase) {
201437dff155SNetanel Belgazal /* Make sure the phase bit (ownership) is as expected before
201537dff155SNetanel Belgazal * reading the rest of the descriptor.
201637dff155SNetanel Belgazal */
201737dff155SNetanel Belgazal dma_rmb();
201837dff155SNetanel Belgazal
2019f391503bSArthur Kiyanovski timestamp = (u64)aenq_common->timestamp_low |
2020f391503bSArthur Kiyanovski ((u64)aenq_common->timestamp_high << 32);
2021bf2746e8SShay Agroskin
2022*26668c2dSDavid Arinzon netdev_dbg(ena_dev->net_device, "AENQ! Group[%x] Syndrome[%x] timestamp: [%llus]\n",
2023bf2746e8SShay Agroskin aenq_common->group, aenq_common->syndrome, timestamp);
20241738cd3eSNetanel Belgazal
20251738cd3eSNetanel Belgazal /* Handle specific event*/
2026bf2746e8SShay Agroskin handler_cb = ena_com_get_specific_aenq_cb(ena_dev,
20271738cd3eSNetanel Belgazal aenq_common->group);
20281738cd3eSNetanel Belgazal handler_cb(data, aenq_e); /* call the actual event handler*/
20291738cd3eSNetanel Belgazal
20301738cd3eSNetanel Belgazal /* Get next event entry */
20311738cd3eSNetanel Belgazal masked_head++;
20321738cd3eSNetanel Belgazal processed++;
20331738cd3eSNetanel Belgazal
20341738cd3eSNetanel Belgazal if (unlikely(masked_head == aenq->q_depth)) {
20351738cd3eSNetanel Belgazal masked_head = 0;
20361738cd3eSNetanel Belgazal phase = !phase;
20371738cd3eSNetanel Belgazal }
20381738cd3eSNetanel Belgazal aenq_e = &aenq->entries[masked_head];
20391738cd3eSNetanel Belgazal aenq_common = &aenq_e->aenq_common_desc;
20401738cd3eSNetanel Belgazal }
20411738cd3eSNetanel Belgazal
20421738cd3eSNetanel Belgazal aenq->head += processed;
20431738cd3eSNetanel Belgazal aenq->phase = phase;
20441738cd3eSNetanel Belgazal
20451738cd3eSNetanel Belgazal /* Don't update aenq doorbell if there weren't any processed events */
20461738cd3eSNetanel Belgazal if (!processed)
20471738cd3eSNetanel Belgazal return;
20481738cd3eSNetanel Belgazal
20491738cd3eSNetanel Belgazal /* write the aenq doorbell after all AENQ descriptors were read */
20501738cd3eSNetanel Belgazal mb();
2051*26668c2dSDavid Arinzon writel_relaxed((u32)aenq->head, ena_dev->reg_bar + ENA_REGS_AENQ_HEAD_DB_OFF);
20521738cd3eSNetanel Belgazal }
20531738cd3eSNetanel Belgazal
ena_com_dev_reset(struct ena_com_dev * ena_dev,enum ena_regs_reset_reason_types reset_reason)2054e2eed0e3SNetanel Belgazal int ena_com_dev_reset(struct ena_com_dev *ena_dev,
2055e2eed0e3SNetanel Belgazal enum ena_regs_reset_reason_types reset_reason)
20561738cd3eSNetanel Belgazal {
20571738cd3eSNetanel Belgazal u32 stat, timeout, cap, reset_val;
20581738cd3eSNetanel Belgazal int rc;
20591738cd3eSNetanel Belgazal
20601738cd3eSNetanel Belgazal stat = ena_com_reg_bar_read32(ena_dev, ENA_REGS_DEV_STS_OFF);
20611738cd3eSNetanel Belgazal cap = ena_com_reg_bar_read32(ena_dev, ENA_REGS_CAPS_OFF);
20621738cd3eSNetanel Belgazal
2063*26668c2dSDavid Arinzon if (unlikely((stat == ENA_MMIO_READ_TIMEOUT) || (cap == ENA_MMIO_READ_TIMEOUT))) {
2064da580ca8SShay Agroskin netdev_err(ena_dev->net_device, "Reg read32 timeout occurred\n");
20651738cd3eSNetanel Belgazal return -ETIME;
20661738cd3eSNetanel Belgazal }
20671738cd3eSNetanel Belgazal
20681738cd3eSNetanel Belgazal if ((stat & ENA_REGS_DEV_STS_READY_MASK) == 0) {
2069*26668c2dSDavid Arinzon netdev_err(ena_dev->net_device, "Device isn't ready, can't reset device\n");
20701738cd3eSNetanel Belgazal return -EINVAL;
20711738cd3eSNetanel Belgazal }
20721738cd3eSNetanel Belgazal
20731738cd3eSNetanel Belgazal timeout = (cap & ENA_REGS_CAPS_RESET_TIMEOUT_MASK) >>
20741738cd3eSNetanel Belgazal ENA_REGS_CAPS_RESET_TIMEOUT_SHIFT;
20751738cd3eSNetanel Belgazal if (timeout == 0) {
2076da580ca8SShay Agroskin netdev_err(ena_dev->net_device, "Invalid timeout value\n");
20771738cd3eSNetanel Belgazal return -EINVAL;
20781738cd3eSNetanel Belgazal }
20791738cd3eSNetanel Belgazal
20801738cd3eSNetanel Belgazal /* start reset */
20811738cd3eSNetanel Belgazal reset_val = ENA_REGS_DEV_CTL_DEV_RESET_MASK;
2082e2eed0e3SNetanel Belgazal reset_val |= (reset_reason << ENA_REGS_DEV_CTL_RESET_REASON_SHIFT) &
2083e2eed0e3SNetanel Belgazal ENA_REGS_DEV_CTL_RESET_REASON_MASK;
20841738cd3eSNetanel Belgazal writel(reset_val, ena_dev->reg_bar + ENA_REGS_DEV_CTL_OFF);
20851738cd3eSNetanel Belgazal
20861738cd3eSNetanel Belgazal /* Write again the MMIO read request address */
20871738cd3eSNetanel Belgazal ena_com_mmio_reg_read_request_write_dev_addr(ena_dev);
20881738cd3eSNetanel Belgazal
20891738cd3eSNetanel Belgazal rc = wait_for_reset_state(ena_dev, timeout,
20901738cd3eSNetanel Belgazal ENA_REGS_DEV_STS_RESET_IN_PROGRESS_MASK);
20911738cd3eSNetanel Belgazal if (rc != 0) {
2092*26668c2dSDavid Arinzon netdev_err(ena_dev->net_device, "Reset indication didn't turn on\n");
20931738cd3eSNetanel Belgazal return rc;
20941738cd3eSNetanel Belgazal }
20951738cd3eSNetanel Belgazal
20961738cd3eSNetanel Belgazal /* reset done */
20971738cd3eSNetanel Belgazal writel(0, ena_dev->reg_bar + ENA_REGS_DEV_CTL_OFF);
20981738cd3eSNetanel Belgazal rc = wait_for_reset_state(ena_dev, timeout, 0);
20991738cd3eSNetanel Belgazal if (rc != 0) {
2100*26668c2dSDavid Arinzon netdev_err(ena_dev->net_device, "Reset indication didn't turn off\n");
21011738cd3eSNetanel Belgazal return rc;
21021738cd3eSNetanel Belgazal }
21031738cd3eSNetanel Belgazal
210482ef30f1SNetanel Belgazal timeout = (cap & ENA_REGS_CAPS_ADMIN_CMD_TO_MASK) >>
210582ef30f1SNetanel Belgazal ENA_REGS_CAPS_ADMIN_CMD_TO_SHIFT;
210682ef30f1SNetanel Belgazal if (timeout)
210782ef30f1SNetanel Belgazal /* the resolution of timeout reg is 100ms */
210882ef30f1SNetanel Belgazal ena_dev->admin_queue.completion_timeout = timeout * 100000;
210982ef30f1SNetanel Belgazal else
211082ef30f1SNetanel Belgazal ena_dev->admin_queue.completion_timeout = ADMIN_CMD_TIMEOUT_US;
211182ef30f1SNetanel Belgazal
21121738cd3eSNetanel Belgazal return 0;
21131738cd3eSNetanel Belgazal }
21141738cd3eSNetanel Belgazal
ena_get_dev_stats(struct ena_com_dev * ena_dev,struct ena_com_stats_ctx * ctx,enum ena_admin_get_stats_type type)21151738cd3eSNetanel Belgazal static int ena_get_dev_stats(struct ena_com_dev *ena_dev,
21161738cd3eSNetanel Belgazal struct ena_com_stats_ctx *ctx,
21171738cd3eSNetanel Belgazal enum ena_admin_get_stats_type type)
21181738cd3eSNetanel Belgazal {
21191738cd3eSNetanel Belgazal struct ena_admin_aq_get_stats_cmd *get_cmd = &ctx->get_cmd;
21201738cd3eSNetanel Belgazal struct ena_admin_acq_get_stats_resp *get_resp = &ctx->get_resp;
21211738cd3eSNetanel Belgazal struct ena_com_admin_queue *admin_queue;
21221738cd3eSNetanel Belgazal int ret;
21231738cd3eSNetanel Belgazal
21241738cd3eSNetanel Belgazal admin_queue = &ena_dev->admin_queue;
21251738cd3eSNetanel Belgazal
21261738cd3eSNetanel Belgazal get_cmd->aq_common_descriptor.opcode = ENA_ADMIN_GET_STATS;
21271738cd3eSNetanel Belgazal get_cmd->aq_common_descriptor.flags = 0;
21281738cd3eSNetanel Belgazal get_cmd->type = type;
21291738cd3eSNetanel Belgazal
21301738cd3eSNetanel Belgazal ret = ena_com_execute_admin_command(admin_queue,
21311738cd3eSNetanel Belgazal (struct ena_admin_aq_entry *)get_cmd,
21321738cd3eSNetanel Belgazal sizeof(*get_cmd),
21331738cd3eSNetanel Belgazal (struct ena_admin_acq_entry *)get_resp,
21341738cd3eSNetanel Belgazal sizeof(*get_resp));
21351738cd3eSNetanel Belgazal
21361738cd3eSNetanel Belgazal if (unlikely(ret))
2137*26668c2dSDavid Arinzon netdev_err(ena_dev->net_device, "Failed to get stats. error: %d\n", ret);
21381738cd3eSNetanel Belgazal
21391738cd3eSNetanel Belgazal return ret;
21401738cd3eSNetanel Belgazal }
21411738cd3eSNetanel Belgazal
ena_com_get_eni_stats(struct ena_com_dev * ena_dev,struct ena_admin_eni_stats * stats)2142713865daSSameeh Jubran int ena_com_get_eni_stats(struct ena_com_dev *ena_dev,
2143713865daSSameeh Jubran struct ena_admin_eni_stats *stats)
2144713865daSSameeh Jubran {
2145713865daSSameeh Jubran struct ena_com_stats_ctx ctx;
2146713865daSSameeh Jubran int ret;
2147713865daSSameeh Jubran
2148a2d5d6a7SArthur Kiyanovski if (!ena_com_get_cap(ena_dev, ENA_ADMIN_ENI_STATS)) {
2149*26668c2dSDavid Arinzon netdev_err(ena_dev->net_device, "Capability %d isn't supported\n",
2150a2d5d6a7SArthur Kiyanovski ENA_ADMIN_ENI_STATS);
2151a2d5d6a7SArthur Kiyanovski return -EOPNOTSUPP;
2152a2d5d6a7SArthur Kiyanovski }
2153a2d5d6a7SArthur Kiyanovski
2154713865daSSameeh Jubran memset(&ctx, 0x0, sizeof(ctx));
2155713865daSSameeh Jubran ret = ena_get_dev_stats(ena_dev, &ctx, ENA_ADMIN_GET_STATS_TYPE_ENI);
2156713865daSSameeh Jubran if (likely(ret == 0))
2157713865daSSameeh Jubran memcpy(stats, &ctx.get_resp.u.eni_stats,
2158713865daSSameeh Jubran sizeof(ctx.get_resp.u.eni_stats));
2159713865daSSameeh Jubran
2160713865daSSameeh Jubran return ret;
2161713865daSSameeh Jubran }
2162713865daSSameeh Jubran
ena_com_get_dev_basic_stats(struct ena_com_dev * ena_dev,struct ena_admin_basic_stats * stats)21631738cd3eSNetanel Belgazal int ena_com_get_dev_basic_stats(struct ena_com_dev *ena_dev,
21641738cd3eSNetanel Belgazal struct ena_admin_basic_stats *stats)
21651738cd3eSNetanel Belgazal {
21661738cd3eSNetanel Belgazal struct ena_com_stats_ctx ctx;
21671738cd3eSNetanel Belgazal int ret;
21681738cd3eSNetanel Belgazal
21691738cd3eSNetanel Belgazal memset(&ctx, 0x0, sizeof(ctx));
21701738cd3eSNetanel Belgazal ret = ena_get_dev_stats(ena_dev, &ctx, ENA_ADMIN_GET_STATS_TYPE_BASIC);
21711738cd3eSNetanel Belgazal if (likely(ret == 0))
2172713865daSSameeh Jubran memcpy(stats, &ctx.get_resp.u.basic_stats,
2173713865daSSameeh Jubran sizeof(ctx.get_resp.u.basic_stats));
21741738cd3eSNetanel Belgazal
21751738cd3eSNetanel Belgazal return ret;
21761738cd3eSNetanel Belgazal }
21771738cd3eSNetanel Belgazal
ena_com_set_dev_mtu(struct ena_com_dev * ena_dev,u32 mtu)2178e9548fdfSShay Agroskin int ena_com_set_dev_mtu(struct ena_com_dev *ena_dev, u32 mtu)
21791738cd3eSNetanel Belgazal {
21801738cd3eSNetanel Belgazal struct ena_com_admin_queue *admin_queue;
21811738cd3eSNetanel Belgazal struct ena_admin_set_feat_cmd cmd;
21821738cd3eSNetanel Belgazal struct ena_admin_set_feat_resp resp;
21831738cd3eSNetanel Belgazal int ret;
21841738cd3eSNetanel Belgazal
21851738cd3eSNetanel Belgazal if (!ena_com_check_supported_feature_id(ena_dev, ENA_ADMIN_MTU)) {
2186*26668c2dSDavid Arinzon netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n", ENA_ADMIN_MTU);
2187d1497638SNetanel Belgazal return -EOPNOTSUPP;
21881738cd3eSNetanel Belgazal }
21891738cd3eSNetanel Belgazal
21901738cd3eSNetanel Belgazal memset(&cmd, 0x0, sizeof(cmd));
21911738cd3eSNetanel Belgazal admin_queue = &ena_dev->admin_queue;
21921738cd3eSNetanel Belgazal
21931738cd3eSNetanel Belgazal cmd.aq_common_descriptor.opcode = ENA_ADMIN_SET_FEATURE;
21941738cd3eSNetanel Belgazal cmd.aq_common_descriptor.flags = 0;
21951738cd3eSNetanel Belgazal cmd.feat_common.feature_id = ENA_ADMIN_MTU;
21961738cd3eSNetanel Belgazal cmd.u.mtu.mtu = mtu;
21971738cd3eSNetanel Belgazal
21981738cd3eSNetanel Belgazal ret = ena_com_execute_admin_command(admin_queue,
21991738cd3eSNetanel Belgazal (struct ena_admin_aq_entry *)&cmd,
22001738cd3eSNetanel Belgazal sizeof(cmd),
22011738cd3eSNetanel Belgazal (struct ena_admin_acq_entry *)&resp,
22021738cd3eSNetanel Belgazal sizeof(resp));
22031738cd3eSNetanel Belgazal
22041738cd3eSNetanel Belgazal if (unlikely(ret))
2205*26668c2dSDavid Arinzon netdev_err(ena_dev->net_device, "Failed to set mtu %d. error: %d\n", mtu, ret);
22061738cd3eSNetanel Belgazal
22071738cd3eSNetanel Belgazal return ret;
22081738cd3eSNetanel Belgazal }
22091738cd3eSNetanel Belgazal
ena_com_get_offload_settings(struct ena_com_dev * ena_dev,struct ena_admin_feature_offload_desc * offload)22101738cd3eSNetanel Belgazal int ena_com_get_offload_settings(struct ena_com_dev *ena_dev,
22111738cd3eSNetanel Belgazal struct ena_admin_feature_offload_desc *offload)
22121738cd3eSNetanel Belgazal {
22131738cd3eSNetanel Belgazal int ret;
22141738cd3eSNetanel Belgazal struct ena_admin_get_feat_resp resp;
22151738cd3eSNetanel Belgazal
22161738cd3eSNetanel Belgazal ret = ena_com_get_feature(ena_dev, &resp,
2217ba8ef506SArthur Kiyanovski ENA_ADMIN_STATELESS_OFFLOAD_CONFIG, 0);
22181738cd3eSNetanel Belgazal if (unlikely(ret)) {
2219*26668c2dSDavid Arinzon netdev_err(ena_dev->net_device, "Failed to get offload capabilities %d\n", ret);
22201738cd3eSNetanel Belgazal return ret;
22211738cd3eSNetanel Belgazal }
22221738cd3eSNetanel Belgazal
22231738cd3eSNetanel Belgazal memcpy(offload, &resp.u.offload, sizeof(resp.u.offload));
22241738cd3eSNetanel Belgazal
22251738cd3eSNetanel Belgazal return 0;
22261738cd3eSNetanel Belgazal }
22271738cd3eSNetanel Belgazal
ena_com_set_hash_function(struct ena_com_dev * ena_dev)22281738cd3eSNetanel Belgazal int ena_com_set_hash_function(struct ena_com_dev *ena_dev)
22291738cd3eSNetanel Belgazal {
22301738cd3eSNetanel Belgazal struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
22311738cd3eSNetanel Belgazal struct ena_rss *rss = &ena_dev->rss;
22321738cd3eSNetanel Belgazal struct ena_admin_set_feat_cmd cmd;
22331738cd3eSNetanel Belgazal struct ena_admin_set_feat_resp resp;
22341738cd3eSNetanel Belgazal struct ena_admin_get_feat_resp get_resp;
22351738cd3eSNetanel Belgazal int ret;
22361738cd3eSNetanel Belgazal
2237*26668c2dSDavid Arinzon if (!ena_com_check_supported_feature_id(ena_dev, ENA_ADMIN_RSS_HASH_FUNCTION)) {
2238da580ca8SShay Agroskin netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n",
22391738cd3eSNetanel Belgazal ENA_ADMIN_RSS_HASH_FUNCTION);
2240d1497638SNetanel Belgazal return -EOPNOTSUPP;
22411738cd3eSNetanel Belgazal }
22421738cd3eSNetanel Belgazal
22431738cd3eSNetanel Belgazal /* Validate hash function is supported */
22441738cd3eSNetanel Belgazal ret = ena_com_get_feature(ena_dev, &get_resp,
2245ba8ef506SArthur Kiyanovski ENA_ADMIN_RSS_HASH_FUNCTION, 0);
22461738cd3eSNetanel Belgazal if (unlikely(ret))
22471738cd3eSNetanel Belgazal return ret;
22481738cd3eSNetanel Belgazal
2249d3cfe7ddSSameeh Jubran if (!(get_resp.u.flow_hash_func.supported_func & BIT(rss->hash_func))) {
2250*26668c2dSDavid Arinzon netdev_err(ena_dev->net_device, "Func hash %d isn't supported by device, abort\n",
22511738cd3eSNetanel Belgazal rss->hash_func);
2252d1497638SNetanel Belgazal return -EOPNOTSUPP;
22531738cd3eSNetanel Belgazal }
22541738cd3eSNetanel Belgazal
22551738cd3eSNetanel Belgazal memset(&cmd, 0x0, sizeof(cmd));
22561738cd3eSNetanel Belgazal
22571738cd3eSNetanel Belgazal cmd.aq_common_descriptor.opcode = ENA_ADMIN_SET_FEATURE;
22581738cd3eSNetanel Belgazal cmd.aq_common_descriptor.flags =
22591738cd3eSNetanel Belgazal ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_INDIRECT_MASK;
22601738cd3eSNetanel Belgazal cmd.feat_common.feature_id = ENA_ADMIN_RSS_HASH_FUNCTION;
22611738cd3eSNetanel Belgazal cmd.u.flow_hash_func.init_val = rss->hash_init_val;
22621738cd3eSNetanel Belgazal cmd.u.flow_hash_func.selected_func = 1 << rss->hash_func;
22631738cd3eSNetanel Belgazal
22641738cd3eSNetanel Belgazal ret = ena_com_mem_addr_set(ena_dev,
22651738cd3eSNetanel Belgazal &cmd.control_buffer.address,
22661738cd3eSNetanel Belgazal rss->hash_key_dma_addr);
22671738cd3eSNetanel Belgazal if (unlikely(ret)) {
2268da580ca8SShay Agroskin netdev_err(ena_dev->net_device, "Memory address set failed\n");
22691738cd3eSNetanel Belgazal return ret;
22701738cd3eSNetanel Belgazal }
22711738cd3eSNetanel Belgazal
22721738cd3eSNetanel Belgazal cmd.control_buffer.length = sizeof(*rss->hash_key);
22731738cd3eSNetanel Belgazal
22741738cd3eSNetanel Belgazal ret = ena_com_execute_admin_command(admin_queue,
22751738cd3eSNetanel Belgazal (struct ena_admin_aq_entry *)&cmd,
22761738cd3eSNetanel Belgazal sizeof(cmd),
22771738cd3eSNetanel Belgazal (struct ena_admin_acq_entry *)&resp,
22781738cd3eSNetanel Belgazal sizeof(resp));
22791738cd3eSNetanel Belgazal if (unlikely(ret)) {
2280*26668c2dSDavid Arinzon netdev_err(ena_dev->net_device, "Failed to set hash function %d. error: %d\n",
22811738cd3eSNetanel Belgazal rss->hash_func, ret);
22821738cd3eSNetanel Belgazal return -EINVAL;
22831738cd3eSNetanel Belgazal }
22841738cd3eSNetanel Belgazal
22851738cd3eSNetanel Belgazal return 0;
22861738cd3eSNetanel Belgazal }
22871738cd3eSNetanel Belgazal
ena_com_fill_hash_function(struct ena_com_dev * ena_dev,enum ena_admin_hash_functions func,const u8 * key,u16 key_len,u32 init_val)22881738cd3eSNetanel Belgazal int ena_com_fill_hash_function(struct ena_com_dev *ena_dev,
22891738cd3eSNetanel Belgazal enum ena_admin_hash_functions func,
22901738cd3eSNetanel Belgazal const u8 *key, u16 key_len, u32 init_val)
22911738cd3eSNetanel Belgazal {
22920a39a35fSArthur Kiyanovski struct ena_admin_feature_rss_flow_hash_control *hash_key;
22931738cd3eSNetanel Belgazal struct ena_admin_get_feat_resp get_resp;
229480f8443fSArthur Kiyanovski enum ena_admin_hash_functions old_func;
22950a39a35fSArthur Kiyanovski struct ena_rss *rss = &ena_dev->rss;
22961738cd3eSNetanel Belgazal int rc;
22971738cd3eSNetanel Belgazal
22980a39a35fSArthur Kiyanovski hash_key = rss->hash_key;
22990a39a35fSArthur Kiyanovski
23001738cd3eSNetanel Belgazal /* Make sure size is a mult of DWs */
23011738cd3eSNetanel Belgazal if (unlikely(key_len & 0x3))
23021738cd3eSNetanel Belgazal return -EINVAL;
23031738cd3eSNetanel Belgazal
23041738cd3eSNetanel Belgazal rc = ena_com_get_feature_ex(ena_dev, &get_resp,
23051738cd3eSNetanel Belgazal ENA_ADMIN_RSS_HASH_FUNCTION,
23061738cd3eSNetanel Belgazal rss->hash_key_dma_addr,
2307ba8ef506SArthur Kiyanovski sizeof(*rss->hash_key), 0);
23081738cd3eSNetanel Belgazal if (unlikely(rc))
23091738cd3eSNetanel Belgazal return rc;
23101738cd3eSNetanel Belgazal
2311b0ae3ac4SArthur Kiyanovski if (!(BIT(func) & get_resp.u.flow_hash_func.supported_func)) {
2312*26668c2dSDavid Arinzon netdev_err(ena_dev->net_device, "Flow hash function %d isn't supported\n", func);
2313d1497638SNetanel Belgazal return -EOPNOTSUPP;
23141738cd3eSNetanel Belgazal }
23151738cd3eSNetanel Belgazal
2316332b49ffSDavid Arinzon if ((func == ENA_ADMIN_TOEPLITZ) && key) {
231791a65b7dSArthur Kiyanovski if (key_len != sizeof(hash_key->key)) {
2318da580ca8SShay Agroskin netdev_err(ena_dev->net_device,
2319*26668c2dSDavid Arinzon "key len (%u) doesn't equal the supported size (%zu)\n", key_len,
2320*26668c2dSDavid Arinzon sizeof(hash_key->key));
23211738cd3eSNetanel Belgazal return -EINVAL;
23221738cd3eSNetanel Belgazal }
23231738cd3eSNetanel Belgazal memcpy(hash_key->key, key, key_len);
23240deca83fSShay Agroskin hash_key->key_parts = key_len / sizeof(hash_key->key[0]);
232591a65b7dSArthur Kiyanovski }
23261738cd3eSNetanel Belgazal
2327332b49ffSDavid Arinzon rss->hash_init_val = init_val;
232880f8443fSArthur Kiyanovski old_func = rss->hash_func;
232911bd7a00SSameeh Jubran rss->hash_func = func;
23301738cd3eSNetanel Belgazal rc = ena_com_set_hash_function(ena_dev);
23311738cd3eSNetanel Belgazal
23321738cd3eSNetanel Belgazal /* Restore the old function */
23331738cd3eSNetanel Belgazal if (unlikely(rc))
233480f8443fSArthur Kiyanovski rss->hash_func = old_func;
23351738cd3eSNetanel Belgazal
23361738cd3eSNetanel Belgazal return rc;
23371738cd3eSNetanel Belgazal }
23381738cd3eSNetanel Belgazal
ena_com_get_hash_function(struct ena_com_dev * ena_dev,enum ena_admin_hash_functions * func)23391738cd3eSNetanel Belgazal int ena_com_get_hash_function(struct ena_com_dev *ena_dev,
2340f66c2ea3SSameeh Jubran enum ena_admin_hash_functions *func)
23411738cd3eSNetanel Belgazal {
23421738cd3eSNetanel Belgazal struct ena_rss *rss = &ena_dev->rss;
23431738cd3eSNetanel Belgazal struct ena_admin_get_feat_resp get_resp;
23441738cd3eSNetanel Belgazal int rc;
23451738cd3eSNetanel Belgazal
2346e9a1de37SArthur Kiyanovski if (unlikely(!func))
2347e9a1de37SArthur Kiyanovski return -EINVAL;
2348e9a1de37SArthur Kiyanovski
23491738cd3eSNetanel Belgazal rc = ena_com_get_feature_ex(ena_dev, &get_resp,
23501738cd3eSNetanel Belgazal ENA_ADMIN_RSS_HASH_FUNCTION,
23511738cd3eSNetanel Belgazal rss->hash_key_dma_addr,
2352ba8ef506SArthur Kiyanovski sizeof(*rss->hash_key), 0);
23531738cd3eSNetanel Belgazal if (unlikely(rc))
23541738cd3eSNetanel Belgazal return rc;
23551738cd3eSNetanel Belgazal
23564844470dSArthur Kiyanovski /* ffs() returns 1 in case the lsb is set */
23574844470dSArthur Kiyanovski rss->hash_func = ffs(get_resp.u.flow_hash_func.selected_func);
23584844470dSArthur Kiyanovski if (rss->hash_func)
23594844470dSArthur Kiyanovski rss->hash_func--;
23604844470dSArthur Kiyanovski
23611738cd3eSNetanel Belgazal *func = rss->hash_func;
23621738cd3eSNetanel Belgazal
2363f66c2ea3SSameeh Jubran return 0;
2364f66c2ea3SSameeh Jubran }
2365f66c2ea3SSameeh Jubran
ena_com_get_hash_key(struct ena_com_dev * ena_dev,u8 * key)2366f66c2ea3SSameeh Jubran int ena_com_get_hash_key(struct ena_com_dev *ena_dev, u8 *key)
2367f66c2ea3SSameeh Jubran {
2368f66c2ea3SSameeh Jubran struct ena_admin_feature_rss_flow_hash_control *hash_key =
2369f66c2ea3SSameeh Jubran ena_dev->rss.hash_key;
2370f66c2ea3SSameeh Jubran
23711738cd3eSNetanel Belgazal if (key)
23720deca83fSShay Agroskin memcpy(key, hash_key->key,
23730deca83fSShay Agroskin (size_t)(hash_key->key_parts) * sizeof(hash_key->key[0]));
23741738cd3eSNetanel Belgazal
23751738cd3eSNetanel Belgazal return 0;
23761738cd3eSNetanel Belgazal }
23771738cd3eSNetanel Belgazal
ena_com_get_hash_ctrl(struct ena_com_dev * ena_dev,enum ena_admin_flow_hash_proto proto,u16 * fields)23781738cd3eSNetanel Belgazal int ena_com_get_hash_ctrl(struct ena_com_dev *ena_dev,
23791738cd3eSNetanel Belgazal enum ena_admin_flow_hash_proto proto,
23801738cd3eSNetanel Belgazal u16 *fields)
23811738cd3eSNetanel Belgazal {
23821738cd3eSNetanel Belgazal struct ena_rss *rss = &ena_dev->rss;
23831738cd3eSNetanel Belgazal struct ena_admin_get_feat_resp get_resp;
23841738cd3eSNetanel Belgazal int rc;
23851738cd3eSNetanel Belgazal
23861738cd3eSNetanel Belgazal rc = ena_com_get_feature_ex(ena_dev, &get_resp,
23871738cd3eSNetanel Belgazal ENA_ADMIN_RSS_HASH_INPUT,
23881738cd3eSNetanel Belgazal rss->hash_ctrl_dma_addr,
2389ba8ef506SArthur Kiyanovski sizeof(*rss->hash_ctrl), 0);
23901738cd3eSNetanel Belgazal if (unlikely(rc))
23911738cd3eSNetanel Belgazal return rc;
23921738cd3eSNetanel Belgazal
23931738cd3eSNetanel Belgazal if (fields)
23941738cd3eSNetanel Belgazal *fields = rss->hash_ctrl->selected_fields[proto].fields;
23951738cd3eSNetanel Belgazal
23961738cd3eSNetanel Belgazal return 0;
23971738cd3eSNetanel Belgazal }
23981738cd3eSNetanel Belgazal
ena_com_set_hash_ctrl(struct ena_com_dev * ena_dev)23991738cd3eSNetanel Belgazal int ena_com_set_hash_ctrl(struct ena_com_dev *ena_dev)
24001738cd3eSNetanel Belgazal {
24011738cd3eSNetanel Belgazal struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
24021738cd3eSNetanel Belgazal struct ena_rss *rss = &ena_dev->rss;
24031738cd3eSNetanel Belgazal struct ena_admin_feature_rss_hash_control *hash_ctrl = rss->hash_ctrl;
24041738cd3eSNetanel Belgazal struct ena_admin_set_feat_cmd cmd;
24051738cd3eSNetanel Belgazal struct ena_admin_set_feat_resp resp;
24061738cd3eSNetanel Belgazal int ret;
24071738cd3eSNetanel Belgazal
2408*26668c2dSDavid Arinzon if (!ena_com_check_supported_feature_id(ena_dev, ENA_ADMIN_RSS_HASH_INPUT)) {
2409da580ca8SShay Agroskin netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n",
24105add6e4aSNetanel Belgazal ENA_ADMIN_RSS_HASH_INPUT);
2411d1497638SNetanel Belgazal return -EOPNOTSUPP;
24121738cd3eSNetanel Belgazal }
24131738cd3eSNetanel Belgazal
24141738cd3eSNetanel Belgazal memset(&cmd, 0x0, sizeof(cmd));
24151738cd3eSNetanel Belgazal
24161738cd3eSNetanel Belgazal cmd.aq_common_descriptor.opcode = ENA_ADMIN_SET_FEATURE;
24171738cd3eSNetanel Belgazal cmd.aq_common_descriptor.flags =
24181738cd3eSNetanel Belgazal ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_INDIRECT_MASK;
24191738cd3eSNetanel Belgazal cmd.feat_common.feature_id = ENA_ADMIN_RSS_HASH_INPUT;
24201738cd3eSNetanel Belgazal cmd.u.flow_hash_input.enabled_input_sort =
24211738cd3eSNetanel Belgazal ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L3_SORT_MASK |
24221738cd3eSNetanel Belgazal ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L4_SORT_MASK;
24231738cd3eSNetanel Belgazal
24241738cd3eSNetanel Belgazal ret = ena_com_mem_addr_set(ena_dev,
24251738cd3eSNetanel Belgazal &cmd.control_buffer.address,
24261738cd3eSNetanel Belgazal rss->hash_ctrl_dma_addr);
24271738cd3eSNetanel Belgazal if (unlikely(ret)) {
2428da580ca8SShay Agroskin netdev_err(ena_dev->net_device, "Memory address set failed\n");
24291738cd3eSNetanel Belgazal return ret;
24301738cd3eSNetanel Belgazal }
24311738cd3eSNetanel Belgazal cmd.control_buffer.length = sizeof(*hash_ctrl);
24321738cd3eSNetanel Belgazal
24331738cd3eSNetanel Belgazal ret = ena_com_execute_admin_command(admin_queue,
24341738cd3eSNetanel Belgazal (struct ena_admin_aq_entry *)&cmd,
24351738cd3eSNetanel Belgazal sizeof(cmd),
24361738cd3eSNetanel Belgazal (struct ena_admin_acq_entry *)&resp,
24371738cd3eSNetanel Belgazal sizeof(resp));
24381738cd3eSNetanel Belgazal if (unlikely(ret))
2439*26668c2dSDavid Arinzon netdev_err(ena_dev->net_device, "Failed to set hash input. error: %d\n", ret);
24401738cd3eSNetanel Belgazal
24411738cd3eSNetanel Belgazal return ret;
24421738cd3eSNetanel Belgazal }
24431738cd3eSNetanel Belgazal
ena_com_set_default_hash_ctrl(struct ena_com_dev * ena_dev)24441738cd3eSNetanel Belgazal int ena_com_set_default_hash_ctrl(struct ena_com_dev *ena_dev)
24451738cd3eSNetanel Belgazal {
24461738cd3eSNetanel Belgazal struct ena_rss *rss = &ena_dev->rss;
24471738cd3eSNetanel Belgazal struct ena_admin_feature_rss_hash_control *hash_ctrl =
24481738cd3eSNetanel Belgazal rss->hash_ctrl;
24491738cd3eSNetanel Belgazal u16 available_fields = 0;
24501738cd3eSNetanel Belgazal int rc, i;
24511738cd3eSNetanel Belgazal
24521738cd3eSNetanel Belgazal /* Get the supported hash input */
24531738cd3eSNetanel Belgazal rc = ena_com_get_hash_ctrl(ena_dev, 0, NULL);
24541738cd3eSNetanel Belgazal if (unlikely(rc))
24551738cd3eSNetanel Belgazal return rc;
24561738cd3eSNetanel Belgazal
24571738cd3eSNetanel Belgazal hash_ctrl->selected_fields[ENA_ADMIN_RSS_TCP4].fields =
24581738cd3eSNetanel Belgazal ENA_ADMIN_RSS_L3_SA | ENA_ADMIN_RSS_L3_DA |
24591738cd3eSNetanel Belgazal ENA_ADMIN_RSS_L4_DP | ENA_ADMIN_RSS_L4_SP;
24601738cd3eSNetanel Belgazal
24611738cd3eSNetanel Belgazal hash_ctrl->selected_fields[ENA_ADMIN_RSS_UDP4].fields =
24621738cd3eSNetanel Belgazal ENA_ADMIN_RSS_L3_SA | ENA_ADMIN_RSS_L3_DA |
24631738cd3eSNetanel Belgazal ENA_ADMIN_RSS_L4_DP | ENA_ADMIN_RSS_L4_SP;
24641738cd3eSNetanel Belgazal
24651738cd3eSNetanel Belgazal hash_ctrl->selected_fields[ENA_ADMIN_RSS_TCP6].fields =
24661738cd3eSNetanel Belgazal ENA_ADMIN_RSS_L3_SA | ENA_ADMIN_RSS_L3_DA |
24671738cd3eSNetanel Belgazal ENA_ADMIN_RSS_L4_DP | ENA_ADMIN_RSS_L4_SP;
24681738cd3eSNetanel Belgazal
24691738cd3eSNetanel Belgazal hash_ctrl->selected_fields[ENA_ADMIN_RSS_UDP6].fields =
24701738cd3eSNetanel Belgazal ENA_ADMIN_RSS_L3_SA | ENA_ADMIN_RSS_L3_DA |
24711738cd3eSNetanel Belgazal ENA_ADMIN_RSS_L4_DP | ENA_ADMIN_RSS_L4_SP;
24721738cd3eSNetanel Belgazal
24731738cd3eSNetanel Belgazal hash_ctrl->selected_fields[ENA_ADMIN_RSS_IP4].fields =
24741738cd3eSNetanel Belgazal ENA_ADMIN_RSS_L3_SA | ENA_ADMIN_RSS_L3_DA;
24751738cd3eSNetanel Belgazal
24761738cd3eSNetanel Belgazal hash_ctrl->selected_fields[ENA_ADMIN_RSS_IP6].fields =
24771738cd3eSNetanel Belgazal ENA_ADMIN_RSS_L3_SA | ENA_ADMIN_RSS_L3_DA;
24781738cd3eSNetanel Belgazal
24791738cd3eSNetanel Belgazal hash_ctrl->selected_fields[ENA_ADMIN_RSS_IP4_FRAG].fields =
24801738cd3eSNetanel Belgazal ENA_ADMIN_RSS_L3_SA | ENA_ADMIN_RSS_L3_DA;
24811738cd3eSNetanel Belgazal
2482422e21e7SNetanel Belgazal hash_ctrl->selected_fields[ENA_ADMIN_RSS_NOT_IP].fields =
24831738cd3eSNetanel Belgazal ENA_ADMIN_RSS_L2_DA | ENA_ADMIN_RSS_L2_SA;
24841738cd3eSNetanel Belgazal
24851738cd3eSNetanel Belgazal for (i = 0; i < ENA_ADMIN_RSS_PROTO_NUM; i++) {
24861738cd3eSNetanel Belgazal available_fields = hash_ctrl->selected_fields[i].fields &
24871738cd3eSNetanel Belgazal hash_ctrl->supported_fields[i].fields;
24881738cd3eSNetanel Belgazal if (available_fields != hash_ctrl->selected_fields[i].fields) {
2489da580ca8SShay Agroskin netdev_err(ena_dev->net_device,
2490da580ca8SShay Agroskin "Hash control doesn't support all the desire configuration. proto %x supported %x selected %x\n",
24911738cd3eSNetanel Belgazal i, hash_ctrl->supported_fields[i].fields,
24921738cd3eSNetanel Belgazal hash_ctrl->selected_fields[i].fields);
2493d1497638SNetanel Belgazal return -EOPNOTSUPP;
24941738cd3eSNetanel Belgazal }
24951738cd3eSNetanel Belgazal }
24961738cd3eSNetanel Belgazal
24971738cd3eSNetanel Belgazal rc = ena_com_set_hash_ctrl(ena_dev);
24981738cd3eSNetanel Belgazal
24991738cd3eSNetanel Belgazal /* In case of failure, restore the old hash ctrl */
25001738cd3eSNetanel Belgazal if (unlikely(rc))
25011738cd3eSNetanel Belgazal ena_com_get_hash_ctrl(ena_dev, 0, NULL);
25021738cd3eSNetanel Belgazal
25031738cd3eSNetanel Belgazal return rc;
25041738cd3eSNetanel Belgazal }
25051738cd3eSNetanel Belgazal
ena_com_fill_hash_ctrl(struct ena_com_dev * ena_dev,enum ena_admin_flow_hash_proto proto,u16 hash_fields)25061738cd3eSNetanel Belgazal int ena_com_fill_hash_ctrl(struct ena_com_dev *ena_dev,
25071738cd3eSNetanel Belgazal enum ena_admin_flow_hash_proto proto,
25081738cd3eSNetanel Belgazal u16 hash_fields)
25091738cd3eSNetanel Belgazal {
25101738cd3eSNetanel Belgazal struct ena_rss *rss = &ena_dev->rss;
25111738cd3eSNetanel Belgazal struct ena_admin_feature_rss_hash_control *hash_ctrl = rss->hash_ctrl;
25121738cd3eSNetanel Belgazal u16 supported_fields;
25131738cd3eSNetanel Belgazal int rc;
25141738cd3eSNetanel Belgazal
25151738cd3eSNetanel Belgazal if (proto >= ENA_ADMIN_RSS_PROTO_NUM) {
2516*26668c2dSDavid Arinzon netdev_err(ena_dev->net_device, "Invalid proto num (%u)\n", proto);
25171738cd3eSNetanel Belgazal return -EINVAL;
25181738cd3eSNetanel Belgazal }
25191738cd3eSNetanel Belgazal
25201738cd3eSNetanel Belgazal /* Get the ctrl table */
25211738cd3eSNetanel Belgazal rc = ena_com_get_hash_ctrl(ena_dev, proto, NULL);
25221738cd3eSNetanel Belgazal if (unlikely(rc))
25231738cd3eSNetanel Belgazal return rc;
25241738cd3eSNetanel Belgazal
25251738cd3eSNetanel Belgazal /* Make sure all the fields are supported */
25261738cd3eSNetanel Belgazal supported_fields = hash_ctrl->supported_fields[proto].fields;
25271738cd3eSNetanel Belgazal if ((hash_fields & supported_fields) != hash_fields) {
2528da580ca8SShay Agroskin netdev_err(ena_dev->net_device,
2529da580ca8SShay Agroskin "Proto %d doesn't support the required fields %x. supports only: %x\n",
25301738cd3eSNetanel Belgazal proto, hash_fields, supported_fields);
25311738cd3eSNetanel Belgazal }
25321738cd3eSNetanel Belgazal
25331738cd3eSNetanel Belgazal hash_ctrl->selected_fields[proto].fields = hash_fields;
25341738cd3eSNetanel Belgazal
25351738cd3eSNetanel Belgazal rc = ena_com_set_hash_ctrl(ena_dev);
25361738cd3eSNetanel Belgazal
25371738cd3eSNetanel Belgazal /* In case of failure, restore the old hash ctrl */
25381738cd3eSNetanel Belgazal if (unlikely(rc))
25391738cd3eSNetanel Belgazal ena_com_get_hash_ctrl(ena_dev, 0, NULL);
25401738cd3eSNetanel Belgazal
25411738cd3eSNetanel Belgazal return 0;
25421738cd3eSNetanel Belgazal }
25431738cd3eSNetanel Belgazal
ena_com_indirect_table_fill_entry(struct ena_com_dev * ena_dev,u16 entry_idx,u16 entry_value)25441738cd3eSNetanel Belgazal int ena_com_indirect_table_fill_entry(struct ena_com_dev *ena_dev,
25451738cd3eSNetanel Belgazal u16 entry_idx, u16 entry_value)
25461738cd3eSNetanel Belgazal {
25471738cd3eSNetanel Belgazal struct ena_rss *rss = &ena_dev->rss;
25481738cd3eSNetanel Belgazal
25491738cd3eSNetanel Belgazal if (unlikely(entry_idx >= (1 << rss->tbl_log_size)))
25501738cd3eSNetanel Belgazal return -EINVAL;
25511738cd3eSNetanel Belgazal
25521738cd3eSNetanel Belgazal if (unlikely((entry_value > ENA_TOTAL_NUM_QUEUES)))
25531738cd3eSNetanel Belgazal return -EINVAL;
25541738cd3eSNetanel Belgazal
25551738cd3eSNetanel Belgazal rss->host_rss_ind_tbl[entry_idx] = entry_value;
25561738cd3eSNetanel Belgazal
25571738cd3eSNetanel Belgazal return 0;
25581738cd3eSNetanel Belgazal }
25591738cd3eSNetanel Belgazal
ena_com_indirect_table_set(struct ena_com_dev * ena_dev)25601738cd3eSNetanel Belgazal int ena_com_indirect_table_set(struct ena_com_dev *ena_dev)
25611738cd3eSNetanel Belgazal {
25621738cd3eSNetanel Belgazal struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
25631738cd3eSNetanel Belgazal struct ena_rss *rss = &ena_dev->rss;
25641738cd3eSNetanel Belgazal struct ena_admin_set_feat_cmd cmd;
25651738cd3eSNetanel Belgazal struct ena_admin_set_feat_resp resp;
25661738cd3eSNetanel Belgazal int ret;
25671738cd3eSNetanel Belgazal
2568*26668c2dSDavid Arinzon if (!ena_com_check_supported_feature_id(ena_dev, ENA_ADMIN_RSS_INDIRECTION_TABLE_CONFIG)) {
2569da580ca8SShay Agroskin netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n",
25700deca83fSShay Agroskin ENA_ADMIN_RSS_INDIRECTION_TABLE_CONFIG);
2571d1497638SNetanel Belgazal return -EOPNOTSUPP;
25721738cd3eSNetanel Belgazal }
25731738cd3eSNetanel Belgazal
25741738cd3eSNetanel Belgazal ret = ena_com_ind_tbl_convert_to_device(ena_dev);
25751738cd3eSNetanel Belgazal if (ret) {
2576da580ca8SShay Agroskin netdev_err(ena_dev->net_device,
2577da580ca8SShay Agroskin "Failed to convert host indirection table to device table\n");
25781738cd3eSNetanel Belgazal return ret;
25791738cd3eSNetanel Belgazal }
25801738cd3eSNetanel Belgazal
25811738cd3eSNetanel Belgazal memset(&cmd, 0x0, sizeof(cmd));
25821738cd3eSNetanel Belgazal
25831738cd3eSNetanel Belgazal cmd.aq_common_descriptor.opcode = ENA_ADMIN_SET_FEATURE;
25841738cd3eSNetanel Belgazal cmd.aq_common_descriptor.flags =
25851738cd3eSNetanel Belgazal ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_INDIRECT_MASK;
25860deca83fSShay Agroskin cmd.feat_common.feature_id = ENA_ADMIN_RSS_INDIRECTION_TABLE_CONFIG;
25871738cd3eSNetanel Belgazal cmd.u.ind_table.size = rss->tbl_log_size;
25881738cd3eSNetanel Belgazal cmd.u.ind_table.inline_index = 0xFFFFFFFF;
25891738cd3eSNetanel Belgazal
25901738cd3eSNetanel Belgazal ret = ena_com_mem_addr_set(ena_dev,
25911738cd3eSNetanel Belgazal &cmd.control_buffer.address,
25921738cd3eSNetanel Belgazal rss->rss_ind_tbl_dma_addr);
25931738cd3eSNetanel Belgazal if (unlikely(ret)) {
2594da580ca8SShay Agroskin netdev_err(ena_dev->net_device, "Memory address set failed\n");
25951738cd3eSNetanel Belgazal return ret;
25961738cd3eSNetanel Belgazal }
25971738cd3eSNetanel Belgazal
25981738cd3eSNetanel Belgazal cmd.control_buffer.length = (1ULL << rss->tbl_log_size) *
25991738cd3eSNetanel Belgazal sizeof(struct ena_admin_rss_ind_table_entry);
26001738cd3eSNetanel Belgazal
26011738cd3eSNetanel Belgazal ret = ena_com_execute_admin_command(admin_queue,
26021738cd3eSNetanel Belgazal (struct ena_admin_aq_entry *)&cmd,
26031738cd3eSNetanel Belgazal sizeof(cmd),
26041738cd3eSNetanel Belgazal (struct ena_admin_acq_entry *)&resp,
26051738cd3eSNetanel Belgazal sizeof(resp));
26061738cd3eSNetanel Belgazal
26071738cd3eSNetanel Belgazal if (unlikely(ret))
2608*26668c2dSDavid Arinzon netdev_err(ena_dev->net_device, "Failed to set indirect table. error: %d\n", ret);
26091738cd3eSNetanel Belgazal
26101738cd3eSNetanel Belgazal return ret;
26111738cd3eSNetanel Belgazal }
26121738cd3eSNetanel Belgazal
ena_com_indirect_table_get(struct ena_com_dev * ena_dev,u32 * ind_tbl)26131738cd3eSNetanel Belgazal int ena_com_indirect_table_get(struct ena_com_dev *ena_dev, u32 *ind_tbl)
26141738cd3eSNetanel Belgazal {
26151738cd3eSNetanel Belgazal struct ena_rss *rss = &ena_dev->rss;
26161738cd3eSNetanel Belgazal struct ena_admin_get_feat_resp get_resp;
26171738cd3eSNetanel Belgazal u32 tbl_size;
26181738cd3eSNetanel Belgazal int i, rc;
26191738cd3eSNetanel Belgazal
26201738cd3eSNetanel Belgazal tbl_size = (1ULL << rss->tbl_log_size) *
26211738cd3eSNetanel Belgazal sizeof(struct ena_admin_rss_ind_table_entry);
26221738cd3eSNetanel Belgazal
26231738cd3eSNetanel Belgazal rc = ena_com_get_feature_ex(ena_dev, &get_resp,
26240deca83fSShay Agroskin ENA_ADMIN_RSS_INDIRECTION_TABLE_CONFIG,
26251738cd3eSNetanel Belgazal rss->rss_ind_tbl_dma_addr,
2626ba8ef506SArthur Kiyanovski tbl_size, 0);
26271738cd3eSNetanel Belgazal if (unlikely(rc))
26281738cd3eSNetanel Belgazal return rc;
26291738cd3eSNetanel Belgazal
26301738cd3eSNetanel Belgazal if (!ind_tbl)
26311738cd3eSNetanel Belgazal return 0;
26321738cd3eSNetanel Belgazal
26331738cd3eSNetanel Belgazal for (i = 0; i < (1 << rss->tbl_log_size); i++)
26341738cd3eSNetanel Belgazal ind_tbl[i] = rss->host_rss_ind_tbl[i];
26351738cd3eSNetanel Belgazal
26361738cd3eSNetanel Belgazal return 0;
26371738cd3eSNetanel Belgazal }
26381738cd3eSNetanel Belgazal
ena_com_rss_init(struct ena_com_dev * ena_dev,u16 indr_tbl_log_size)26391738cd3eSNetanel Belgazal int ena_com_rss_init(struct ena_com_dev *ena_dev, u16 indr_tbl_log_size)
26401738cd3eSNetanel Belgazal {
26411738cd3eSNetanel Belgazal int rc;
26421738cd3eSNetanel Belgazal
26431738cd3eSNetanel Belgazal memset(&ena_dev->rss, 0x0, sizeof(ena_dev->rss));
26441738cd3eSNetanel Belgazal
26451738cd3eSNetanel Belgazal rc = ena_com_indirect_table_allocate(ena_dev, indr_tbl_log_size);
26461738cd3eSNetanel Belgazal if (unlikely(rc))
26471738cd3eSNetanel Belgazal goto err_indr_tbl;
26481738cd3eSNetanel Belgazal
26496a4f7dc8SSameeh Jubran /* The following function might return unsupported in case the
26506a4f7dc8SSameeh Jubran * device doesn't support setting the key / hash function. We can safely
26516a4f7dc8SSameeh Jubran * ignore this error and have indirection table support only.
26526a4f7dc8SSameeh Jubran */
26531738cd3eSNetanel Belgazal rc = ena_com_hash_key_allocate(ena_dev);
26540af3c4e2SSameeh Jubran if (likely(!rc))
26550d1c3de7SArthur Kiyanovski ena_com_hash_key_fill_default_key(ena_dev);
26560af3c4e2SSameeh Jubran else if (rc != -EOPNOTSUPP)
26570af3c4e2SSameeh Jubran goto err_hash_key;
26580d1c3de7SArthur Kiyanovski
26591738cd3eSNetanel Belgazal rc = ena_com_hash_ctrl_init(ena_dev);
26601738cd3eSNetanel Belgazal if (unlikely(rc))
26611738cd3eSNetanel Belgazal goto err_hash_ctrl;
26621738cd3eSNetanel Belgazal
26631738cd3eSNetanel Belgazal return 0;
26641738cd3eSNetanel Belgazal
26651738cd3eSNetanel Belgazal err_hash_ctrl:
26661738cd3eSNetanel Belgazal ena_com_hash_key_destroy(ena_dev);
26671738cd3eSNetanel Belgazal err_hash_key:
26681738cd3eSNetanel Belgazal ena_com_indirect_table_destroy(ena_dev);
26691738cd3eSNetanel Belgazal err_indr_tbl:
26701738cd3eSNetanel Belgazal
26711738cd3eSNetanel Belgazal return rc;
26721738cd3eSNetanel Belgazal }
26731738cd3eSNetanel Belgazal
ena_com_rss_destroy(struct ena_com_dev * ena_dev)26741738cd3eSNetanel Belgazal void ena_com_rss_destroy(struct ena_com_dev *ena_dev)
26751738cd3eSNetanel Belgazal {
26761738cd3eSNetanel Belgazal ena_com_indirect_table_destroy(ena_dev);
26771738cd3eSNetanel Belgazal ena_com_hash_key_destroy(ena_dev);
26781738cd3eSNetanel Belgazal ena_com_hash_ctrl_destroy(ena_dev);
26791738cd3eSNetanel Belgazal
26801738cd3eSNetanel Belgazal memset(&ena_dev->rss, 0x0, sizeof(ena_dev->rss));
26811738cd3eSNetanel Belgazal }
26821738cd3eSNetanel Belgazal
ena_com_allocate_host_info(struct ena_com_dev * ena_dev)26831738cd3eSNetanel Belgazal int ena_com_allocate_host_info(struct ena_com_dev *ena_dev)
26841738cd3eSNetanel Belgazal {
26851738cd3eSNetanel Belgazal struct ena_host_attribute *host_attr = &ena_dev->host_attr;
26861738cd3eSNetanel Belgazal
2687*26668c2dSDavid Arinzon host_attr->host_info = dma_alloc_coherent(ena_dev->dmadev, SZ_4K,
26881738cd3eSNetanel Belgazal &host_attr->host_info_dma_addr, GFP_KERNEL);
26891738cd3eSNetanel Belgazal if (unlikely(!host_attr->host_info))
26901738cd3eSNetanel Belgazal return -ENOMEM;
26911738cd3eSNetanel Belgazal
2692bd791175SArthur Kiyanovski host_attr->host_info->ena_spec_version = ((ENA_COMMON_SPEC_VERSION_MAJOR <<
2693bd791175SArthur Kiyanovski ENA_REGS_VERSION_MAJOR_VERSION_SHIFT) |
2694095f2f1fSArthur Kiyanovski (ENA_COMMON_SPEC_VERSION_MINOR));
2695095f2f1fSArthur Kiyanovski
26961738cd3eSNetanel Belgazal return 0;
26971738cd3eSNetanel Belgazal }
26981738cd3eSNetanel Belgazal
ena_com_allocate_debug_area(struct ena_com_dev * ena_dev,u32 debug_area_size)26991738cd3eSNetanel Belgazal int ena_com_allocate_debug_area(struct ena_com_dev *ena_dev,
27001738cd3eSNetanel Belgazal u32 debug_area_size)
27011738cd3eSNetanel Belgazal {
27021738cd3eSNetanel Belgazal struct ena_host_attribute *host_attr = &ena_dev->host_attr;
27031738cd3eSNetanel Belgazal
27041738cd3eSNetanel Belgazal host_attr->debug_area_virt_addr =
2705750afb08SLuis Chamberlain dma_alloc_coherent(ena_dev->dmadev, debug_area_size,
2706bf2746e8SShay Agroskin &host_attr->debug_area_dma_addr, GFP_KERNEL);
27071738cd3eSNetanel Belgazal if (unlikely(!host_attr->debug_area_virt_addr)) {
27081738cd3eSNetanel Belgazal host_attr->debug_area_size = 0;
27091738cd3eSNetanel Belgazal return -ENOMEM;
27101738cd3eSNetanel Belgazal }
27111738cd3eSNetanel Belgazal
27121738cd3eSNetanel Belgazal host_attr->debug_area_size = debug_area_size;
27131738cd3eSNetanel Belgazal
27141738cd3eSNetanel Belgazal return 0;
27151738cd3eSNetanel Belgazal }
27161738cd3eSNetanel Belgazal
ena_com_delete_host_info(struct ena_com_dev * ena_dev)27171738cd3eSNetanel Belgazal void ena_com_delete_host_info(struct ena_com_dev *ena_dev)
27181738cd3eSNetanel Belgazal {
27191738cd3eSNetanel Belgazal struct ena_host_attribute *host_attr = &ena_dev->host_attr;
27201738cd3eSNetanel Belgazal
27211738cd3eSNetanel Belgazal if (host_attr->host_info) {
27221738cd3eSNetanel Belgazal dma_free_coherent(ena_dev->dmadev, SZ_4K, host_attr->host_info,
27231738cd3eSNetanel Belgazal host_attr->host_info_dma_addr);
27241738cd3eSNetanel Belgazal host_attr->host_info = NULL;
27251738cd3eSNetanel Belgazal }
27261738cd3eSNetanel Belgazal }
27271738cd3eSNetanel Belgazal
ena_com_delete_debug_area(struct ena_com_dev * ena_dev)27281738cd3eSNetanel Belgazal void ena_com_delete_debug_area(struct ena_com_dev *ena_dev)
27291738cd3eSNetanel Belgazal {
27301738cd3eSNetanel Belgazal struct ena_host_attribute *host_attr = &ena_dev->host_attr;
27311738cd3eSNetanel Belgazal
27321738cd3eSNetanel Belgazal if (host_attr->debug_area_virt_addr) {
27331738cd3eSNetanel Belgazal dma_free_coherent(ena_dev->dmadev, host_attr->debug_area_size,
2734*26668c2dSDavid Arinzon host_attr->debug_area_virt_addr, host_attr->debug_area_dma_addr);
27351738cd3eSNetanel Belgazal host_attr->debug_area_virt_addr = NULL;
27361738cd3eSNetanel Belgazal }
27371738cd3eSNetanel Belgazal }
27381738cd3eSNetanel Belgazal
ena_com_set_host_attributes(struct ena_com_dev * ena_dev)27391738cd3eSNetanel Belgazal int ena_com_set_host_attributes(struct ena_com_dev *ena_dev)
27401738cd3eSNetanel Belgazal {
27411738cd3eSNetanel Belgazal struct ena_host_attribute *host_attr = &ena_dev->host_attr;
27421738cd3eSNetanel Belgazal struct ena_com_admin_queue *admin_queue;
27431738cd3eSNetanel Belgazal struct ena_admin_set_feat_cmd cmd;
27441738cd3eSNetanel Belgazal struct ena_admin_set_feat_resp resp;
27451738cd3eSNetanel Belgazal
27461738cd3eSNetanel Belgazal int ret;
27471738cd3eSNetanel Belgazal
2748dd8427a7SNetanel Belgazal /* Host attribute config is called before ena_com_get_dev_attr_feat
2749dd8427a7SNetanel Belgazal * so ena_com can't check if the feature is supported.
2750dd8427a7SNetanel Belgazal */
27511738cd3eSNetanel Belgazal
27521738cd3eSNetanel Belgazal memset(&cmd, 0x0, sizeof(cmd));
27531738cd3eSNetanel Belgazal admin_queue = &ena_dev->admin_queue;
27541738cd3eSNetanel Belgazal
27551738cd3eSNetanel Belgazal cmd.aq_common_descriptor.opcode = ENA_ADMIN_SET_FEATURE;
27561738cd3eSNetanel Belgazal cmd.feat_common.feature_id = ENA_ADMIN_HOST_ATTR_CONFIG;
27571738cd3eSNetanel Belgazal
27581738cd3eSNetanel Belgazal ret = ena_com_mem_addr_set(ena_dev,
27591738cd3eSNetanel Belgazal &cmd.u.host_attr.debug_ba,
27601738cd3eSNetanel Belgazal host_attr->debug_area_dma_addr);
27611738cd3eSNetanel Belgazal if (unlikely(ret)) {
2762da580ca8SShay Agroskin netdev_err(ena_dev->net_device, "Memory address set failed\n");
27631738cd3eSNetanel Belgazal return ret;
27641738cd3eSNetanel Belgazal }
27651738cd3eSNetanel Belgazal
27661738cd3eSNetanel Belgazal ret = ena_com_mem_addr_set(ena_dev,
27671738cd3eSNetanel Belgazal &cmd.u.host_attr.os_info_ba,
27681738cd3eSNetanel Belgazal host_attr->host_info_dma_addr);
27691738cd3eSNetanel Belgazal if (unlikely(ret)) {
2770da580ca8SShay Agroskin netdev_err(ena_dev->net_device, "Memory address set failed\n");
27711738cd3eSNetanel Belgazal return ret;
27721738cd3eSNetanel Belgazal }
27731738cd3eSNetanel Belgazal
27741738cd3eSNetanel Belgazal cmd.u.host_attr.debug_area_size = host_attr->debug_area_size;
27751738cd3eSNetanel Belgazal
27761738cd3eSNetanel Belgazal ret = ena_com_execute_admin_command(admin_queue,
27771738cd3eSNetanel Belgazal (struct ena_admin_aq_entry *)&cmd,
27781738cd3eSNetanel Belgazal sizeof(cmd),
27791738cd3eSNetanel Belgazal (struct ena_admin_acq_entry *)&resp,
27801738cd3eSNetanel Belgazal sizeof(resp));
27811738cd3eSNetanel Belgazal
27821738cd3eSNetanel Belgazal if (unlikely(ret))
2783*26668c2dSDavid Arinzon netdev_err(ena_dev->net_device, "Failed to set host attributes: %d\n", ret);
27841738cd3eSNetanel Belgazal
27851738cd3eSNetanel Belgazal return ret;
27861738cd3eSNetanel Belgazal }
27871738cd3eSNetanel Belgazal
27881738cd3eSNetanel Belgazal /* Interrupt moderation */
ena_com_interrupt_moderation_supported(struct ena_com_dev * ena_dev)27891738cd3eSNetanel Belgazal bool ena_com_interrupt_moderation_supported(struct ena_com_dev *ena_dev)
27901738cd3eSNetanel Belgazal {
27911738cd3eSNetanel Belgazal return ena_com_check_supported_feature_id(ena_dev,
27921738cd3eSNetanel Belgazal ENA_ADMIN_INTERRUPT_MODERATION);
27931738cd3eSNetanel Belgazal }
27941738cd3eSNetanel Belgazal
ena_com_update_nonadaptive_moderation_interval(struct ena_com_dev * ena_dev,u32 coalesce_usecs,u32 intr_delay_resolution,u32 * intr_moder_interval)2795da580ca8SShay Agroskin static int ena_com_update_nonadaptive_moderation_interval(struct ena_com_dev *ena_dev,
2796da580ca8SShay Agroskin u32 coalesce_usecs,
279757e3a5f2SArthur Kiyanovski u32 intr_delay_resolution,
279857e3a5f2SArthur Kiyanovski u32 *intr_moder_interval)
27991738cd3eSNetanel Belgazal {
280057e3a5f2SArthur Kiyanovski if (!intr_delay_resolution) {
2801*26668c2dSDavid Arinzon netdev_err(ena_dev->net_device, "Illegal interrupt delay granularity value\n");
28021738cd3eSNetanel Belgazal return -EFAULT;
28031738cd3eSNetanel Belgazal }
28041738cd3eSNetanel Belgazal
280557e3a5f2SArthur Kiyanovski *intr_moder_interval = coalesce_usecs / intr_delay_resolution;
28061738cd3eSNetanel Belgazal
28071738cd3eSNetanel Belgazal return 0;
28081738cd3eSNetanel Belgazal }
28091738cd3eSNetanel Belgazal
ena_com_update_nonadaptive_moderation_interval_tx(struct ena_com_dev * ena_dev,u32 tx_coalesce_usecs)281057e3a5f2SArthur Kiyanovski int ena_com_update_nonadaptive_moderation_interval_tx(struct ena_com_dev *ena_dev,
281157e3a5f2SArthur Kiyanovski u32 tx_coalesce_usecs)
281257e3a5f2SArthur Kiyanovski {
2813da580ca8SShay Agroskin return ena_com_update_nonadaptive_moderation_interval(ena_dev,
2814da580ca8SShay Agroskin tx_coalesce_usecs,
281557e3a5f2SArthur Kiyanovski ena_dev->intr_delay_resolution,
281657e3a5f2SArthur Kiyanovski &ena_dev->intr_moder_tx_interval);
281757e3a5f2SArthur Kiyanovski }
281857e3a5f2SArthur Kiyanovski
ena_com_update_nonadaptive_moderation_interval_rx(struct ena_com_dev * ena_dev,u32 rx_coalesce_usecs)28191738cd3eSNetanel Belgazal int ena_com_update_nonadaptive_moderation_interval_rx(struct ena_com_dev *ena_dev,
28201738cd3eSNetanel Belgazal u32 rx_coalesce_usecs)
28211738cd3eSNetanel Belgazal {
2822da580ca8SShay Agroskin return ena_com_update_nonadaptive_moderation_interval(ena_dev,
2823da580ca8SShay Agroskin rx_coalesce_usecs,
282457e3a5f2SArthur Kiyanovski ena_dev->intr_delay_resolution,
282557e3a5f2SArthur Kiyanovski &ena_dev->intr_moder_rx_interval);
28261738cd3eSNetanel Belgazal }
28271738cd3eSNetanel Belgazal
ena_com_init_interrupt_moderation(struct ena_com_dev * ena_dev)28281738cd3eSNetanel Belgazal int ena_com_init_interrupt_moderation(struct ena_com_dev *ena_dev)
28291738cd3eSNetanel Belgazal {
28301738cd3eSNetanel Belgazal struct ena_admin_get_feat_resp get_resp;
28311738cd3eSNetanel Belgazal u16 delay_resolution;
28321738cd3eSNetanel Belgazal int rc;
28331738cd3eSNetanel Belgazal
28341738cd3eSNetanel Belgazal rc = ena_com_get_feature(ena_dev, &get_resp,
2835ba8ef506SArthur Kiyanovski ENA_ADMIN_INTERRUPT_MODERATION, 0);
28361738cd3eSNetanel Belgazal
28371738cd3eSNetanel Belgazal if (rc) {
2838d1497638SNetanel Belgazal if (rc == -EOPNOTSUPP) {
2839*26668c2dSDavid Arinzon netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n",
28401738cd3eSNetanel Belgazal ENA_ADMIN_INTERRUPT_MODERATION);
28411738cd3eSNetanel Belgazal rc = 0;
28421738cd3eSNetanel Belgazal } else {
2843da580ca8SShay Agroskin netdev_err(ena_dev->net_device,
2844*26668c2dSDavid Arinzon "Failed to get interrupt moderation admin cmd. rc: %d\n", rc);
28451738cd3eSNetanel Belgazal }
28461738cd3eSNetanel Belgazal
28471738cd3eSNetanel Belgazal /* no moderation supported, disable adaptive support */
28481738cd3eSNetanel Belgazal ena_com_disable_adaptive_moderation(ena_dev);
28491738cd3eSNetanel Belgazal return rc;
28501738cd3eSNetanel Belgazal }
28511738cd3eSNetanel Belgazal
28521738cd3eSNetanel Belgazal /* if moderation is supported by device we set adaptive moderation */
28531738cd3eSNetanel Belgazal delay_resolution = get_resp.u.intr_moderation.intr_delay_resolution;
28541738cd3eSNetanel Belgazal ena_com_update_intr_delay_resolution(ena_dev, delay_resolution);
285578cb421dSSameeh Jubran
2856282faf61SArthur Kiyanovski /* Disable adaptive moderation by default - can be enabled later */
285778cb421dSSameeh Jubran ena_com_disable_adaptive_moderation(ena_dev);
28581738cd3eSNetanel Belgazal
28591738cd3eSNetanel Belgazal return 0;
28601738cd3eSNetanel Belgazal }
28611738cd3eSNetanel Belgazal
ena_com_get_nonadaptive_moderation_interval_tx(struct ena_com_dev * ena_dev)28621738cd3eSNetanel Belgazal unsigned int ena_com_get_nonadaptive_moderation_interval_tx(struct ena_com_dev *ena_dev)
28631738cd3eSNetanel Belgazal {
28641738cd3eSNetanel Belgazal return ena_dev->intr_moder_tx_interval;
28651738cd3eSNetanel Belgazal }
28661738cd3eSNetanel Belgazal
ena_com_get_nonadaptive_moderation_interval_rx(struct ena_com_dev * ena_dev)28671738cd3eSNetanel Belgazal unsigned int ena_com_get_nonadaptive_moderation_interval_rx(struct ena_com_dev *ena_dev)
28681738cd3eSNetanel Belgazal {
286915619e72SArthur Kiyanovski return ena_dev->intr_moder_rx_interval;
28701738cd3eSNetanel Belgazal }
28711738cd3eSNetanel Belgazal
ena_com_config_dev_mode(struct ena_com_dev * ena_dev,struct ena_admin_feature_llq_desc * llq_features,struct ena_llq_configurations * llq_default_cfg)2872689b2bdaSArthur Kiyanovski int ena_com_config_dev_mode(struct ena_com_dev *ena_dev,
2873689b2bdaSArthur Kiyanovski struct ena_admin_feature_llq_desc *llq_features,
2874689b2bdaSArthur Kiyanovski struct ena_llq_configurations *llq_default_cfg)
2875689b2bdaSArthur Kiyanovski {
2876cdf449ecSSameeh Jubran struct ena_com_llq_info *llq_info = &ena_dev->llq_info;
2877689b2bdaSArthur Kiyanovski int rc;
2878689b2bdaSArthur Kiyanovski
2879689b2bdaSArthur Kiyanovski if (!llq_features->max_llq_num) {
2880689b2bdaSArthur Kiyanovski ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST;
2881689b2bdaSArthur Kiyanovski return 0;
2882689b2bdaSArthur Kiyanovski }
2883689b2bdaSArthur Kiyanovski
2884689b2bdaSArthur Kiyanovski rc = ena_com_config_llq_info(ena_dev, llq_features, llq_default_cfg);
2885689b2bdaSArthur Kiyanovski if (rc)
2886689b2bdaSArthur Kiyanovski return rc;
2887689b2bdaSArthur Kiyanovski
2888cdf449ecSSameeh Jubran ena_dev->tx_max_header_size = llq_info->desc_list_entry_size -
2889cdf449ecSSameeh Jubran (llq_info->descs_num_before_header * sizeof(struct ena_eth_io_tx_desc));
2890689b2bdaSArthur Kiyanovski
2891cdf449ecSSameeh Jubran if (unlikely(ena_dev->tx_max_header_size == 0)) {
2892*26668c2dSDavid Arinzon netdev_err(ena_dev->net_device, "The size of the LLQ entry is smaller than needed\n");
2893689b2bdaSArthur Kiyanovski return -EINVAL;
2894689b2bdaSArthur Kiyanovski }
2895689b2bdaSArthur Kiyanovski
2896689b2bdaSArthur Kiyanovski ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_DEV;
2897689b2bdaSArthur Kiyanovski
2898689b2bdaSArthur Kiyanovski return 0;
2899689b2bdaSArthur Kiyanovski }
2900