114b24e2bSVaishali Kulkarni /*
214b24e2bSVaishali Kulkarni * CDDL HEADER START
314b24e2bSVaishali Kulkarni *
414b24e2bSVaishali Kulkarni * The contents of this file are subject to the terms of the
514b24e2bSVaishali Kulkarni * Common Development and Distribution License, v.1, (the "License").
614b24e2bSVaishali Kulkarni * You may not use this file except in compliance with the License.
714b24e2bSVaishali Kulkarni *
814b24e2bSVaishali Kulkarni * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
914b24e2bSVaishali Kulkarni * or http://opensource.org/licenses/CDDL-1.0.
1014b24e2bSVaishali Kulkarni * See the License for the specific language governing permissions
1114b24e2bSVaishali Kulkarni * and limitations under the License.
1214b24e2bSVaishali Kulkarni *
1314b24e2bSVaishali Kulkarni * When distributing Covered Code, include this CDDL HEADER in each
1414b24e2bSVaishali Kulkarni * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1514b24e2bSVaishali Kulkarni * If applicable, add the following below this CDDL HEADER, with the
1614b24e2bSVaishali Kulkarni * fields enclosed by brackets "[]" replaced with your own identifying
1714b24e2bSVaishali Kulkarni * information: Portions Copyright [yyyy] [name of copyright owner]
1814b24e2bSVaishali Kulkarni *
1914b24e2bSVaishali Kulkarni * CDDL HEADER END
2014b24e2bSVaishali Kulkarni */
2114b24e2bSVaishali Kulkarni
2214b24e2bSVaishali Kulkarni /*
2314b24e2bSVaishali Kulkarni * Copyright 2014-2017 Cavium, Inc.
2414b24e2bSVaishali Kulkarni * The contents of this file are subject to the terms of the Common Development
2514b24e2bSVaishali Kulkarni * and Distribution License, v.1, (the "License").
2614b24e2bSVaishali Kulkarni
2714b24e2bSVaishali Kulkarni * You may not use this file except in compliance with the License.
2814b24e2bSVaishali Kulkarni
2914b24e2bSVaishali Kulkarni * You can obtain a copy of the License at available
3014b24e2bSVaishali Kulkarni * at http://opensource.org/licenses/CDDL-1.0
3114b24e2bSVaishali Kulkarni
3214b24e2bSVaishali Kulkarni * See the License for the specific language governing permissions and
3314b24e2bSVaishali Kulkarni * limitations under the License.
3414b24e2bSVaishali Kulkarni */
3514b24e2bSVaishali Kulkarni
3614b24e2bSVaishali Kulkarni #include "bcm_osal.h"
3714b24e2bSVaishali Kulkarni #include "ecore_hsi_common.h"
3814b24e2bSVaishali Kulkarni #include "ecore_status.h"
3914b24e2bSVaishali Kulkarni #include "ecore.h"
4014b24e2bSVaishali Kulkarni #include "ecore_hw.h"
4114b24e2bSVaishali Kulkarni #include "reg_addr.h"
4214b24e2bSVaishali Kulkarni #include "ecore_utils.h"
4314b24e2bSVaishali Kulkarni #include "ecore_iov_api.h"
4414b24e2bSVaishali Kulkarni
4514b24e2bSVaishali Kulkarni #ifndef ASIC_ONLY
4614b24e2bSVaishali Kulkarni #define ECORE_EMUL_FACTOR 2000
4714b24e2bSVaishali Kulkarni #define ECORE_FPGA_FACTOR 200
4814b24e2bSVaishali Kulkarni #endif
4914b24e2bSVaishali Kulkarni
5014b24e2bSVaishali Kulkarni #define ECORE_BAR_ACQUIRE_TIMEOUT 1000
5114b24e2bSVaishali Kulkarni
5214b24e2bSVaishali Kulkarni /* Invalid values */
5314b24e2bSVaishali Kulkarni #define ECORE_BAR_INVALID_OFFSET (OSAL_CPU_TO_LE32(-1))
5414b24e2bSVaishali Kulkarni
5514b24e2bSVaishali Kulkarni struct ecore_ptt {
5614b24e2bSVaishali Kulkarni osal_list_entry_t list_entry;
5714b24e2bSVaishali Kulkarni unsigned int idx;
5814b24e2bSVaishali Kulkarni struct pxp_ptt_entry pxp;
5914b24e2bSVaishali Kulkarni u8 hwfn_id;
6014b24e2bSVaishali Kulkarni };
6114b24e2bSVaishali Kulkarni
6214b24e2bSVaishali Kulkarni struct ecore_ptt_pool {
6314b24e2bSVaishali Kulkarni osal_list_t free_list;
6414b24e2bSVaishali Kulkarni osal_spinlock_t lock; /* ptt synchronized access */
6514b24e2bSVaishali Kulkarni struct ecore_ptt ptts[PXP_EXTERNAL_BAR_PF_WINDOW_NUM];
6614b24e2bSVaishali Kulkarni };
6714b24e2bSVaishali Kulkarni
ecore_ptt_pool_alloc(struct ecore_hwfn * p_hwfn)6814b24e2bSVaishali Kulkarni enum _ecore_status_t ecore_ptt_pool_alloc(struct ecore_hwfn *p_hwfn)
6914b24e2bSVaishali Kulkarni {
7014b24e2bSVaishali Kulkarni struct ecore_ptt_pool *p_pool = OSAL_ALLOC(p_hwfn->p_dev,
7114b24e2bSVaishali Kulkarni GFP_KERNEL,
7214b24e2bSVaishali Kulkarni sizeof(*p_pool));
7314b24e2bSVaishali Kulkarni int i;
7414b24e2bSVaishali Kulkarni
7514b24e2bSVaishali Kulkarni if (!p_pool)
7614b24e2bSVaishali Kulkarni return ECORE_NOMEM;
7714b24e2bSVaishali Kulkarni
7814b24e2bSVaishali Kulkarni OSAL_LIST_INIT(&p_pool->free_list);
7914b24e2bSVaishali Kulkarni for (i = 0; i < PXP_EXTERNAL_BAR_PF_WINDOW_NUM; i++) {
8014b24e2bSVaishali Kulkarni p_pool->ptts[i].idx = i;
8114b24e2bSVaishali Kulkarni p_pool->ptts[i].pxp.offset = ECORE_BAR_INVALID_OFFSET;
8214b24e2bSVaishali Kulkarni p_pool->ptts[i].pxp.pretend.control = 0;
8314b24e2bSVaishali Kulkarni p_pool->ptts[i].hwfn_id = p_hwfn->my_id;
8414b24e2bSVaishali Kulkarni
8514b24e2bSVaishali Kulkarni /* There are special PTT entries that are taken only by design.
8614b24e2bSVaishali Kulkarni * The rest are added ot the list for general usage.
8714b24e2bSVaishali Kulkarni */
8814b24e2bSVaishali Kulkarni if (i >= RESERVED_PTT_MAX)
8914b24e2bSVaishali Kulkarni OSAL_LIST_PUSH_HEAD(&p_pool->ptts[i].list_entry,
9014b24e2bSVaishali Kulkarni &p_pool->free_list);
9114b24e2bSVaishali Kulkarni }
9214b24e2bSVaishali Kulkarni
9314b24e2bSVaishali Kulkarni p_hwfn->p_ptt_pool = p_pool;
9414b24e2bSVaishali Kulkarni OSAL_SPIN_LOCK_ALLOC(p_hwfn, &p_pool->lock);
9514b24e2bSVaishali Kulkarni OSAL_SPIN_LOCK_INIT(&p_pool->lock);
9614b24e2bSVaishali Kulkarni
9714b24e2bSVaishali Kulkarni return ECORE_SUCCESS;
9814b24e2bSVaishali Kulkarni }
9914b24e2bSVaishali Kulkarni
ecore_ptt_invalidate(struct ecore_hwfn * p_hwfn)10014b24e2bSVaishali Kulkarni void ecore_ptt_invalidate(struct ecore_hwfn *p_hwfn)
10114b24e2bSVaishali Kulkarni {
10214b24e2bSVaishali Kulkarni struct ecore_ptt *p_ptt;
10314b24e2bSVaishali Kulkarni int i;
10414b24e2bSVaishali Kulkarni
10514b24e2bSVaishali Kulkarni for (i = 0; i < PXP_EXTERNAL_BAR_PF_WINDOW_NUM; i++) {
10614b24e2bSVaishali Kulkarni p_ptt = &p_hwfn->p_ptt_pool->ptts[i];
10714b24e2bSVaishali Kulkarni p_ptt->pxp.offset = ECORE_BAR_INVALID_OFFSET;
10814b24e2bSVaishali Kulkarni }
10914b24e2bSVaishali Kulkarni }
11014b24e2bSVaishali Kulkarni
ecore_ptt_pool_free(struct ecore_hwfn * p_hwfn)11114b24e2bSVaishali Kulkarni void ecore_ptt_pool_free(struct ecore_hwfn *p_hwfn)
11214b24e2bSVaishali Kulkarni {
11314b24e2bSVaishali Kulkarni #ifndef __EXTRACT__LINUX__
11414b24e2bSVaishali Kulkarni if (p_hwfn->p_ptt_pool)
11514b24e2bSVaishali Kulkarni OSAL_SPIN_LOCK_DEALLOC(&p_hwfn->p_ptt_pool->lock);
11614b24e2bSVaishali Kulkarni #endif
11714b24e2bSVaishali Kulkarni OSAL_FREE(p_hwfn->p_dev, p_hwfn->p_ptt_pool);
11814b24e2bSVaishali Kulkarni p_hwfn->p_ptt_pool = OSAL_NULL;
11914b24e2bSVaishali Kulkarni }
12014b24e2bSVaishali Kulkarni
ecore_ptt_acquire(struct ecore_hwfn * p_hwfn)12114b24e2bSVaishali Kulkarni struct ecore_ptt *ecore_ptt_acquire(struct ecore_hwfn *p_hwfn)
12214b24e2bSVaishali Kulkarni {
12314b24e2bSVaishali Kulkarni struct ecore_ptt *p_ptt;
12414b24e2bSVaishali Kulkarni unsigned int i;
12514b24e2bSVaishali Kulkarni
12614b24e2bSVaishali Kulkarni /* Take the free PTT from the list */
12714b24e2bSVaishali Kulkarni for (i = 0; i < ECORE_BAR_ACQUIRE_TIMEOUT; i++) {
12814b24e2bSVaishali Kulkarni OSAL_SPIN_LOCK(&p_hwfn->p_ptt_pool->lock);
12914b24e2bSVaishali Kulkarni
13014b24e2bSVaishali Kulkarni if (!OSAL_LIST_IS_EMPTY(&p_hwfn->p_ptt_pool->free_list)) {
13114b24e2bSVaishali Kulkarni p_ptt = OSAL_LIST_FIRST_ENTRY(&p_hwfn->p_ptt_pool->free_list,
13214b24e2bSVaishali Kulkarni struct ecore_ptt, list_entry);
13314b24e2bSVaishali Kulkarni OSAL_LIST_REMOVE_ENTRY(&p_ptt->list_entry,
13414b24e2bSVaishali Kulkarni &p_hwfn->p_ptt_pool->free_list);
13514b24e2bSVaishali Kulkarni
13614b24e2bSVaishali Kulkarni OSAL_SPIN_UNLOCK(&p_hwfn->p_ptt_pool->lock);
13714b24e2bSVaishali Kulkarni
13814b24e2bSVaishali Kulkarni DP_VERBOSE(p_hwfn, ECORE_MSG_HW,
13914b24e2bSVaishali Kulkarni "allocated ptt %d\n", p_ptt->idx);
14014b24e2bSVaishali Kulkarni
14114b24e2bSVaishali Kulkarni return p_ptt;
14214b24e2bSVaishali Kulkarni }
14314b24e2bSVaishali Kulkarni
14414b24e2bSVaishali Kulkarni OSAL_SPIN_UNLOCK(&p_hwfn->p_ptt_pool->lock);
14514b24e2bSVaishali Kulkarni OSAL_MSLEEP(1);
14614b24e2bSVaishali Kulkarni }
14714b24e2bSVaishali Kulkarni
14814b24e2bSVaishali Kulkarni DP_NOTICE(p_hwfn, true, "PTT acquire timeout - failed to allocate PTT\n");
14914b24e2bSVaishali Kulkarni return OSAL_NULL;
15014b24e2bSVaishali Kulkarni }
15114b24e2bSVaishali Kulkarni
ecore_ptt_release(struct ecore_hwfn * p_hwfn,struct ecore_ptt * p_ptt)15214b24e2bSVaishali Kulkarni void ecore_ptt_release(struct ecore_hwfn *p_hwfn,
15314b24e2bSVaishali Kulkarni struct ecore_ptt *p_ptt) {
15414b24e2bSVaishali Kulkarni /* This PTT should not be set to pretend if it is being released */
15514b24e2bSVaishali Kulkarni /* TODO - add some pretend sanity checks, to make sure pretend isn't set on this ptt */
15614b24e2bSVaishali Kulkarni
15714b24e2bSVaishali Kulkarni OSAL_SPIN_LOCK(&p_hwfn->p_ptt_pool->lock);
15814b24e2bSVaishali Kulkarni OSAL_LIST_PUSH_HEAD(&p_ptt->list_entry, &p_hwfn->p_ptt_pool->free_list);
15914b24e2bSVaishali Kulkarni OSAL_SPIN_UNLOCK(&p_hwfn->p_ptt_pool->lock);
16014b24e2bSVaishali Kulkarni }
16114b24e2bSVaishali Kulkarni
ecore_ptt_get_hw_addr(struct ecore_hwfn * p_hwfn,struct ecore_ptt * p_ptt)16214b24e2bSVaishali Kulkarni u32 ecore_ptt_get_hw_addr(struct ecore_hwfn *p_hwfn,
16314b24e2bSVaishali Kulkarni struct ecore_ptt *p_ptt)
16414b24e2bSVaishali Kulkarni {
16514b24e2bSVaishali Kulkarni /* The HW is using DWORDS and we need to translate it to Bytes */
16614b24e2bSVaishali Kulkarni return OSAL_LE32_TO_CPU(p_ptt->pxp.offset) << 2;
16714b24e2bSVaishali Kulkarni }
16814b24e2bSVaishali Kulkarni
ecore_ptt_config_addr(struct ecore_ptt * p_ptt)16914b24e2bSVaishali Kulkarni static u32 ecore_ptt_config_addr(struct ecore_ptt *p_ptt)
17014b24e2bSVaishali Kulkarni {
17114b24e2bSVaishali Kulkarni return PXP_PF_WINDOW_ADMIN_PER_PF_START +
17214b24e2bSVaishali Kulkarni p_ptt->idx * sizeof(struct pxp_ptt_entry);
17314b24e2bSVaishali Kulkarni }
17414b24e2bSVaishali Kulkarni
ecore_ptt_get_bar_addr(struct ecore_ptt * p_ptt)17514b24e2bSVaishali Kulkarni u32 ecore_ptt_get_bar_addr(struct ecore_ptt *p_ptt)
17614b24e2bSVaishali Kulkarni {
17714b24e2bSVaishali Kulkarni return PXP_EXTERNAL_BAR_PF_WINDOW_START +
17814b24e2bSVaishali Kulkarni p_ptt->idx * PXP_EXTERNAL_BAR_PF_WINDOW_SINGLE_SIZE;
17914b24e2bSVaishali Kulkarni }
18014b24e2bSVaishali Kulkarni
ecore_ptt_set_win(struct ecore_hwfn * p_hwfn,struct ecore_ptt * p_ptt,u32 new_hw_addr)18114b24e2bSVaishali Kulkarni void ecore_ptt_set_win(struct ecore_hwfn *p_hwfn,
18214b24e2bSVaishali Kulkarni struct ecore_ptt *p_ptt,
18314b24e2bSVaishali Kulkarni u32 new_hw_addr)
18414b24e2bSVaishali Kulkarni {
18514b24e2bSVaishali Kulkarni u32 prev_hw_addr;
18614b24e2bSVaishali Kulkarni
18714b24e2bSVaishali Kulkarni prev_hw_addr = ecore_ptt_get_hw_addr(p_hwfn, p_ptt);
18814b24e2bSVaishali Kulkarni
18914b24e2bSVaishali Kulkarni if (new_hw_addr == prev_hw_addr)
19014b24e2bSVaishali Kulkarni return;
19114b24e2bSVaishali Kulkarni
19214b24e2bSVaishali Kulkarni /* Update PTT entery in admin window */
19314b24e2bSVaishali Kulkarni DP_VERBOSE(p_hwfn, ECORE_MSG_HW,
19414b24e2bSVaishali Kulkarni "Updating PTT entry %d to offset 0x%x\n",
19514b24e2bSVaishali Kulkarni p_ptt->idx, new_hw_addr);
19614b24e2bSVaishali Kulkarni
19714b24e2bSVaishali Kulkarni /* The HW is using DWORDS and the address is in Bytes */
19814b24e2bSVaishali Kulkarni p_ptt->pxp.offset = OSAL_CPU_TO_LE32(new_hw_addr >> 2);
19914b24e2bSVaishali Kulkarni
20014b24e2bSVaishali Kulkarni REG_WR(p_hwfn,
20114b24e2bSVaishali Kulkarni ecore_ptt_config_addr(p_ptt) +
202*04443fdeSToomas Soome offsetof(struct pxp_ptt_entry, offset),
20314b24e2bSVaishali Kulkarni OSAL_LE32_TO_CPU(p_ptt->pxp.offset));
20414b24e2bSVaishali Kulkarni }
20514b24e2bSVaishali Kulkarni
ecore_set_ptt(struct ecore_hwfn * p_hwfn,struct ecore_ptt * p_ptt,u32 hw_addr)20614b24e2bSVaishali Kulkarni static u32 ecore_set_ptt(struct ecore_hwfn *p_hwfn,
20714b24e2bSVaishali Kulkarni struct ecore_ptt *p_ptt,
20814b24e2bSVaishali Kulkarni u32 hw_addr)
20914b24e2bSVaishali Kulkarni {
21014b24e2bSVaishali Kulkarni u32 win_hw_addr = ecore_ptt_get_hw_addr(p_hwfn, p_ptt);
21114b24e2bSVaishali Kulkarni u32 offset;
21214b24e2bSVaishali Kulkarni
21314b24e2bSVaishali Kulkarni offset = hw_addr - win_hw_addr;
21414b24e2bSVaishali Kulkarni
21514b24e2bSVaishali Kulkarni if (p_ptt->hwfn_id != p_hwfn->my_id)
21614b24e2bSVaishali Kulkarni DP_NOTICE(p_hwfn, true,
21714b24e2bSVaishali Kulkarni "ptt[%d] of hwfn[%02x] is used by hwfn[%02x]!\n",
21814b24e2bSVaishali Kulkarni p_ptt->idx, p_ptt->hwfn_id, p_hwfn->my_id);
21914b24e2bSVaishali Kulkarni
22014b24e2bSVaishali Kulkarni /* Verify the address is within the window */
22114b24e2bSVaishali Kulkarni if (hw_addr < win_hw_addr ||
22214b24e2bSVaishali Kulkarni offset >= PXP_EXTERNAL_BAR_PF_WINDOW_SINGLE_SIZE) {
22314b24e2bSVaishali Kulkarni ecore_ptt_set_win(p_hwfn, p_ptt, hw_addr);
22414b24e2bSVaishali Kulkarni offset = 0;
22514b24e2bSVaishali Kulkarni }
22614b24e2bSVaishali Kulkarni
22714b24e2bSVaishali Kulkarni return ecore_ptt_get_bar_addr(p_ptt) + offset;
22814b24e2bSVaishali Kulkarni }
22914b24e2bSVaishali Kulkarni
ecore_get_reserved_ptt(struct ecore_hwfn * p_hwfn,enum reserved_ptts ptt_idx)23014b24e2bSVaishali Kulkarni struct ecore_ptt *ecore_get_reserved_ptt(struct ecore_hwfn *p_hwfn,
23114b24e2bSVaishali Kulkarni enum reserved_ptts ptt_idx)
23214b24e2bSVaishali Kulkarni {
23314b24e2bSVaishali Kulkarni if (ptt_idx >= RESERVED_PTT_MAX) {
23414b24e2bSVaishali Kulkarni DP_NOTICE(p_hwfn, true,
23514b24e2bSVaishali Kulkarni "Requested PTT %d is out of range\n", ptt_idx);
23614b24e2bSVaishali Kulkarni return OSAL_NULL;
23714b24e2bSVaishali Kulkarni }
23814b24e2bSVaishali Kulkarni
23914b24e2bSVaishali Kulkarni return &p_hwfn->p_ptt_pool->ptts[ptt_idx];
24014b24e2bSVaishali Kulkarni }
24114b24e2bSVaishali Kulkarni
ecore_is_reg_fifo_empty(struct ecore_hwfn * p_hwfn,struct ecore_ptt * p_ptt)24214b24e2bSVaishali Kulkarni static bool ecore_is_reg_fifo_empty(struct ecore_hwfn *p_hwfn,
24314b24e2bSVaishali Kulkarni struct ecore_ptt *p_ptt)
24414b24e2bSVaishali Kulkarni {
24514b24e2bSVaishali Kulkarni bool is_empty = true;
24614b24e2bSVaishali Kulkarni u32 bar_addr;
24714b24e2bSVaishali Kulkarni
24814b24e2bSVaishali Kulkarni if (!p_hwfn->p_dev->chk_reg_fifo)
24914b24e2bSVaishali Kulkarni goto out;
25014b24e2bSVaishali Kulkarni
25114b24e2bSVaishali Kulkarni /* ecore_rd() cannot be used here since it calls this function */
25214b24e2bSVaishali Kulkarni bar_addr = ecore_set_ptt(p_hwfn, p_ptt, GRC_REG_TRACE_FIFO_VALID_DATA);
25314b24e2bSVaishali Kulkarni is_empty = REG_RD(p_hwfn, bar_addr) == 0;
25414b24e2bSVaishali Kulkarni
25514b24e2bSVaishali Kulkarni #ifndef ASIC_ONLY
25614b24e2bSVaishali Kulkarni if (CHIP_REV_IS_SLOW(p_hwfn->p_dev))
25714b24e2bSVaishali Kulkarni OSAL_UDELAY(100);
25814b24e2bSVaishali Kulkarni #endif
25914b24e2bSVaishali Kulkarni
26014b24e2bSVaishali Kulkarni out:
26114b24e2bSVaishali Kulkarni return is_empty;
26214b24e2bSVaishali Kulkarni }
26314b24e2bSVaishali Kulkarni
ecore_wr(struct ecore_hwfn * p_hwfn,struct ecore_ptt * p_ptt,u32 hw_addr,u32 val)26414b24e2bSVaishali Kulkarni void ecore_wr(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt, u32 hw_addr,
26514b24e2bSVaishali Kulkarni u32 val)
26614b24e2bSVaishali Kulkarni {
26714b24e2bSVaishali Kulkarni bool prev_fifo_err;
26814b24e2bSVaishali Kulkarni u32 bar_addr;
26914b24e2bSVaishali Kulkarni
27014b24e2bSVaishali Kulkarni prev_fifo_err = !ecore_is_reg_fifo_empty(p_hwfn, p_ptt);
27114b24e2bSVaishali Kulkarni
27214b24e2bSVaishali Kulkarni bar_addr = ecore_set_ptt(p_hwfn, p_ptt, hw_addr);
27314b24e2bSVaishali Kulkarni REG_WR(p_hwfn, bar_addr, val);
27414b24e2bSVaishali Kulkarni DP_VERBOSE(p_hwfn, ECORE_MSG_HW,
27514b24e2bSVaishali Kulkarni "bar_addr 0x%x, hw_addr 0x%x, val 0x%x\n",
27614b24e2bSVaishali Kulkarni bar_addr, hw_addr, val);
27714b24e2bSVaishali Kulkarni
27814b24e2bSVaishali Kulkarni #ifndef ASIC_ONLY
27914b24e2bSVaishali Kulkarni if (CHIP_REV_IS_SLOW(p_hwfn->p_dev))
28014b24e2bSVaishali Kulkarni OSAL_UDELAY(100);
28114b24e2bSVaishali Kulkarni #endif
28214b24e2bSVaishali Kulkarni
28314b24e2bSVaishali Kulkarni OSAL_WARN(!prev_fifo_err && !ecore_is_reg_fifo_empty(p_hwfn, p_ptt),
28414b24e2bSVaishali Kulkarni "reg_fifo error was caused by a call to ecore_wr(0x%x, 0x%x)\n",
28514b24e2bSVaishali Kulkarni hw_addr, val);
28614b24e2bSVaishali Kulkarni }
28714b24e2bSVaishali Kulkarni
ecore_rd(struct ecore_hwfn * p_hwfn,struct ecore_ptt * p_ptt,u32 hw_addr)28814b24e2bSVaishali Kulkarni u32 ecore_rd(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt, u32 hw_addr)
28914b24e2bSVaishali Kulkarni {
29014b24e2bSVaishali Kulkarni bool prev_fifo_err;
29114b24e2bSVaishali Kulkarni u32 bar_addr, val;
29214b24e2bSVaishali Kulkarni
29314b24e2bSVaishali Kulkarni prev_fifo_err = !ecore_is_reg_fifo_empty(p_hwfn, p_ptt);
29414b24e2bSVaishali Kulkarni
29514b24e2bSVaishali Kulkarni bar_addr = ecore_set_ptt(p_hwfn, p_ptt, hw_addr);
29614b24e2bSVaishali Kulkarni val = REG_RD(p_hwfn, bar_addr);
29714b24e2bSVaishali Kulkarni
29814b24e2bSVaishali Kulkarni DP_VERBOSE(p_hwfn, ECORE_MSG_HW,
29914b24e2bSVaishali Kulkarni "bar_addr 0x%x, hw_addr 0x%x, val 0x%x\n",
30014b24e2bSVaishali Kulkarni bar_addr, hw_addr, val);
30114b24e2bSVaishali Kulkarni
30214b24e2bSVaishali Kulkarni #ifndef ASIC_ONLY
30314b24e2bSVaishali Kulkarni if (CHIP_REV_IS_SLOW(p_hwfn->p_dev))
30414b24e2bSVaishali Kulkarni OSAL_UDELAY(100);
30514b24e2bSVaishali Kulkarni #endif
30614b24e2bSVaishali Kulkarni
30714b24e2bSVaishali Kulkarni OSAL_WARN(!prev_fifo_err && !ecore_is_reg_fifo_empty(p_hwfn, p_ptt),
30814b24e2bSVaishali Kulkarni "reg_fifo error was caused by a call to ecore_rd(0x%x)\n",
30914b24e2bSVaishali Kulkarni hw_addr);
31014b24e2bSVaishali Kulkarni
31114b24e2bSVaishali Kulkarni return val;
31214b24e2bSVaishali Kulkarni }
31314b24e2bSVaishali Kulkarni
ecore_memcpy_hw(struct ecore_hwfn * p_hwfn,struct ecore_ptt * p_ptt,void * addr,u32 hw_addr,osal_size_t n,bool to_device)31414b24e2bSVaishali Kulkarni static void ecore_memcpy_hw(struct ecore_hwfn *p_hwfn,
31514b24e2bSVaishali Kulkarni struct ecore_ptt *p_ptt,
31614b24e2bSVaishali Kulkarni void *addr,
31714b24e2bSVaishali Kulkarni u32 hw_addr,
31814b24e2bSVaishali Kulkarni osal_size_t n,
31914b24e2bSVaishali Kulkarni bool to_device)
32014b24e2bSVaishali Kulkarni {
32114b24e2bSVaishali Kulkarni u32 dw_count, *host_addr, hw_offset;
32214b24e2bSVaishali Kulkarni osal_size_t quota, done = 0;
32314b24e2bSVaishali Kulkarni u32 OSAL_IOMEM *reg_addr;
32414b24e2bSVaishali Kulkarni
32514b24e2bSVaishali Kulkarni while (done < n) {
32614b24e2bSVaishali Kulkarni quota = OSAL_MIN_T(osal_size_t, n - done,
32714b24e2bSVaishali Kulkarni PXP_EXTERNAL_BAR_PF_WINDOW_SINGLE_SIZE);
32814b24e2bSVaishali Kulkarni
32914b24e2bSVaishali Kulkarni if (IS_PF(p_hwfn->p_dev)) {
33014b24e2bSVaishali Kulkarni ecore_ptt_set_win(p_hwfn, p_ptt, hw_addr + done);
33114b24e2bSVaishali Kulkarni hw_offset = ecore_ptt_get_bar_addr(p_ptt);
33214b24e2bSVaishali Kulkarni } else {
33314b24e2bSVaishali Kulkarni hw_offset = hw_addr + done;
33414b24e2bSVaishali Kulkarni }
33514b24e2bSVaishali Kulkarni
33614b24e2bSVaishali Kulkarni dw_count = quota / 4;
33714b24e2bSVaishali Kulkarni host_addr = (u32 *)((u8 *)addr + done);
33814b24e2bSVaishali Kulkarni reg_addr = (u32 OSAL_IOMEM *)OSAL_REG_ADDR(p_hwfn, hw_offset);
33914b24e2bSVaishali Kulkarni
34014b24e2bSVaishali Kulkarni if (to_device)
34114b24e2bSVaishali Kulkarni while (dw_count--)
34214b24e2bSVaishali Kulkarni DIRECT_REG_WR(p_hwfn, reg_addr++, *host_addr++);
34314b24e2bSVaishali Kulkarni else
34414b24e2bSVaishali Kulkarni while (dw_count--)
34514b24e2bSVaishali Kulkarni *host_addr++ = DIRECT_REG_RD(p_hwfn,
34614b24e2bSVaishali Kulkarni reg_addr++);
34714b24e2bSVaishali Kulkarni
34814b24e2bSVaishali Kulkarni done += quota;
34914b24e2bSVaishali Kulkarni }
35014b24e2bSVaishali Kulkarni }
35114b24e2bSVaishali Kulkarni
ecore_memcpy_from(struct ecore_hwfn * p_hwfn,struct ecore_ptt * p_ptt,void * dest,u32 hw_addr,osal_size_t n)35214b24e2bSVaishali Kulkarni void ecore_memcpy_from(struct ecore_hwfn *p_hwfn,
35314b24e2bSVaishali Kulkarni struct ecore_ptt *p_ptt,
35414b24e2bSVaishali Kulkarni void *dest, u32 hw_addr, osal_size_t n)
35514b24e2bSVaishali Kulkarni {
35614b24e2bSVaishali Kulkarni DP_VERBOSE(p_hwfn, ECORE_MSG_HW,
35714b24e2bSVaishali Kulkarni "hw_addr 0x%x, dest %p hw_addr 0x%x, size %lu\n",
35814b24e2bSVaishali Kulkarni hw_addr, dest, hw_addr, (unsigned long) n);
35914b24e2bSVaishali Kulkarni
36014b24e2bSVaishali Kulkarni ecore_memcpy_hw(p_hwfn, p_ptt, dest, hw_addr, n, false);
36114b24e2bSVaishali Kulkarni }
36214b24e2bSVaishali Kulkarni
ecore_memcpy_to(struct ecore_hwfn * p_hwfn,struct ecore_ptt * p_ptt,u32 hw_addr,void * src,osal_size_t n)36314b24e2bSVaishali Kulkarni void ecore_memcpy_to(struct ecore_hwfn *p_hwfn,
36414b24e2bSVaishali Kulkarni struct ecore_ptt *p_ptt,
36514b24e2bSVaishali Kulkarni u32 hw_addr, void *src, osal_size_t n)
36614b24e2bSVaishali Kulkarni {
36714b24e2bSVaishali Kulkarni DP_VERBOSE(p_hwfn, ECORE_MSG_HW,
36814b24e2bSVaishali Kulkarni "hw_addr 0x%x, hw_addr 0x%x, src %p size %lu\n",
36914b24e2bSVaishali Kulkarni hw_addr, hw_addr, src, (unsigned long)n);
37014b24e2bSVaishali Kulkarni
37114b24e2bSVaishali Kulkarni ecore_memcpy_hw(p_hwfn, p_ptt, src, hw_addr, n, true);
37214b24e2bSVaishali Kulkarni }
37314b24e2bSVaishali Kulkarni
ecore_fid_pretend(struct ecore_hwfn * p_hwfn,struct ecore_ptt * p_ptt,u16 fid)37414b24e2bSVaishali Kulkarni void ecore_fid_pretend(struct ecore_hwfn *p_hwfn,
37514b24e2bSVaishali Kulkarni struct ecore_ptt *p_ptt, u16 fid)
37614b24e2bSVaishali Kulkarni {
37714b24e2bSVaishali Kulkarni u16 control = 0;
37814b24e2bSVaishali Kulkarni
37914b24e2bSVaishali Kulkarni SET_FIELD(control, PXP_PRETEND_CMD_IS_CONCRETE, 1);
38014b24e2bSVaishali Kulkarni SET_FIELD(control, PXP_PRETEND_CMD_PRETEND_FUNCTION, 1);
38114b24e2bSVaishali Kulkarni
38214b24e2bSVaishali Kulkarni /* Every pretend undos previous pretends, including
38314b24e2bSVaishali Kulkarni * previous port pretend.
38414b24e2bSVaishali Kulkarni */
38514b24e2bSVaishali Kulkarni SET_FIELD(control, PXP_PRETEND_CMD_PORT, 0);
38614b24e2bSVaishali Kulkarni SET_FIELD(control, PXP_PRETEND_CMD_USE_PORT, 0);
38714b24e2bSVaishali Kulkarni SET_FIELD(control, PXP_PRETEND_CMD_PRETEND_PORT, 1);
38814b24e2bSVaishali Kulkarni
38914b24e2bSVaishali Kulkarni if (!GET_FIELD(fid, PXP_CONCRETE_FID_VFVALID))
39014b24e2bSVaishali Kulkarni fid = GET_FIELD(fid, PXP_CONCRETE_FID_PFID);
39114b24e2bSVaishali Kulkarni
39214b24e2bSVaishali Kulkarni p_ptt->pxp.pretend.control = OSAL_CPU_TO_LE16(control);
39314b24e2bSVaishali Kulkarni p_ptt->pxp.pretend.fid.concrete_fid.fid = OSAL_CPU_TO_LE16(fid);
39414b24e2bSVaishali Kulkarni
39514b24e2bSVaishali Kulkarni REG_WR(p_hwfn,
39614b24e2bSVaishali Kulkarni ecore_ptt_config_addr(p_ptt) +
397*04443fdeSToomas Soome offsetof(struct pxp_ptt_entry, pretend),
39814b24e2bSVaishali Kulkarni *(u32 *)&p_ptt->pxp.pretend);
39914b24e2bSVaishali Kulkarni }
40014b24e2bSVaishali Kulkarni
ecore_port_pretend(struct ecore_hwfn * p_hwfn,struct ecore_ptt * p_ptt,u8 port_id)40114b24e2bSVaishali Kulkarni void ecore_port_pretend(struct ecore_hwfn *p_hwfn,
40214b24e2bSVaishali Kulkarni struct ecore_ptt *p_ptt, u8 port_id)
40314b24e2bSVaishali Kulkarni {
40414b24e2bSVaishali Kulkarni u16 control = 0;
40514b24e2bSVaishali Kulkarni
40614b24e2bSVaishali Kulkarni SET_FIELD(control, PXP_PRETEND_CMD_PORT, port_id);
40714b24e2bSVaishali Kulkarni SET_FIELD(control, PXP_PRETEND_CMD_USE_PORT, 1);
40814b24e2bSVaishali Kulkarni SET_FIELD(control, PXP_PRETEND_CMD_PRETEND_PORT, 1);
40914b24e2bSVaishali Kulkarni p_ptt->pxp.pretend.control = OSAL_CPU_TO_LE16(control);
41014b24e2bSVaishali Kulkarni
41114b24e2bSVaishali Kulkarni REG_WR(p_hwfn,
41214b24e2bSVaishali Kulkarni ecore_ptt_config_addr(p_ptt) +
413*04443fdeSToomas Soome offsetof(struct pxp_ptt_entry, pretend),
41414b24e2bSVaishali Kulkarni *(u32 *)&p_ptt->pxp.pretend);
41514b24e2bSVaishali Kulkarni }
41614b24e2bSVaishali Kulkarni
ecore_port_unpretend(struct ecore_hwfn * p_hwfn,struct ecore_ptt * p_ptt)41714b24e2bSVaishali Kulkarni void ecore_port_unpretend(struct ecore_hwfn *p_hwfn,
41814b24e2bSVaishali Kulkarni struct ecore_ptt *p_ptt)
41914b24e2bSVaishali Kulkarni {
42014b24e2bSVaishali Kulkarni u16 control = 0;
42114b24e2bSVaishali Kulkarni
42214b24e2bSVaishali Kulkarni SET_FIELD(control, PXP_PRETEND_CMD_PORT, 0);
42314b24e2bSVaishali Kulkarni SET_FIELD(control, PXP_PRETEND_CMD_USE_PORT, 0);
42414b24e2bSVaishali Kulkarni SET_FIELD(control, PXP_PRETEND_CMD_PRETEND_PORT, 1);
42514b24e2bSVaishali Kulkarni
42614b24e2bSVaishali Kulkarni p_ptt->pxp.pretend.control = OSAL_CPU_TO_LE16(control);
42714b24e2bSVaishali Kulkarni
42814b24e2bSVaishali Kulkarni REG_WR(p_hwfn,
42914b24e2bSVaishali Kulkarni ecore_ptt_config_addr(p_ptt) +
430*04443fdeSToomas Soome offsetof(struct pxp_ptt_entry, pretend),
43114b24e2bSVaishali Kulkarni *(u32 *)&p_ptt->pxp.pretend);
43214b24e2bSVaishali Kulkarni }
43314b24e2bSVaishali Kulkarni
ecore_vfid_to_concrete(struct ecore_hwfn * p_hwfn,u8 vfid)43414b24e2bSVaishali Kulkarni u32 ecore_vfid_to_concrete(struct ecore_hwfn *p_hwfn, u8 vfid)
43514b24e2bSVaishali Kulkarni {
43614b24e2bSVaishali Kulkarni u32 concrete_fid = 0;
43714b24e2bSVaishali Kulkarni
43814b24e2bSVaishali Kulkarni SET_FIELD(concrete_fid, PXP_CONCRETE_FID_PFID, p_hwfn->rel_pf_id);
43914b24e2bSVaishali Kulkarni SET_FIELD(concrete_fid, PXP_CONCRETE_FID_VFID, vfid);
44014b24e2bSVaishali Kulkarni SET_FIELD(concrete_fid, PXP_CONCRETE_FID_VFVALID, 1);
44114b24e2bSVaishali Kulkarni
44214b24e2bSVaishali Kulkarni return concrete_fid;
44314b24e2bSVaishali Kulkarni }
44414b24e2bSVaishali Kulkarni
44514b24e2bSVaishali Kulkarni #if 0
44614b24e2bSVaishali Kulkarni /* Ecore HW lock
44714b24e2bSVaishali Kulkarni * =============
44814b24e2bSVaishali Kulkarni * Although the implemention is ready, today we don't have any flow that
44914b24e2bSVaishali Kulkarni * utliizes said locks - and we want to keep it this way.
45014b24e2bSVaishali Kulkarni * If this changes, this needs to be revisted.
45114b24e2bSVaishali Kulkarni */
45214b24e2bSVaishali Kulkarni #define HW_LOCK_MAX_RETRIES 1000
45314b24e2bSVaishali Kulkarni enum _ecore_status_t ecore_hw_lock(struct ecore_hwfn *p_hwfn,
45414b24e2bSVaishali Kulkarni struct ecore_ptt *p_ptt,
45514b24e2bSVaishali Kulkarni u8 resource,
45614b24e2bSVaishali Kulkarni bool block)
45714b24e2bSVaishali Kulkarni {
45814b24e2bSVaishali Kulkarni u32 cnt, lock_status, hw_lock_cntr_reg;
45914b24e2bSVaishali Kulkarni enum _ecore_status_t ecore_status;
46014b24e2bSVaishali Kulkarni
46114b24e2bSVaishali Kulkarni /* Locate the proper lock register for this function.
46214b24e2bSVaishali Kulkarni * Note This code assumes all the H/W lock registers are sequential
46314b24e2bSVaishali Kulkarni * in memory.
46414b24e2bSVaishali Kulkarni */
46514b24e2bSVaishali Kulkarni hw_lock_cntr_reg = MISCS_REG_DRIVER_CONTROL_0 +
46614b24e2bSVaishali Kulkarni p_hwfn->rel_pf_id *
46714b24e2bSVaishali Kulkarni MISCS_REG_DRIVER_CONTROL_0_SIZE * sizeof(u32);
46814b24e2bSVaishali Kulkarni
46914b24e2bSVaishali Kulkarni /* Validate that the resource is not already taken */
47014b24e2bSVaishali Kulkarni lock_status = ecore_rd(p_hwfn, p_ptt, hw_lock_cntr_reg);
47114b24e2bSVaishali Kulkarni
47214b24e2bSVaishali Kulkarni if (lock_status & resource) {
47314b24e2bSVaishali Kulkarni DP_NOTICE(p_hwfn, true,
47414b24e2bSVaishali Kulkarni "Resource already locked: lock_status=0x%x resource=0x%x\n",
47514b24e2bSVaishali Kulkarni lock_status, resource);
47614b24e2bSVaishali Kulkarni
47714b24e2bSVaishali Kulkarni return ECORE_BUSY;
47814b24e2bSVaishali Kulkarni }
47914b24e2bSVaishali Kulkarni
48014b24e2bSVaishali Kulkarni /* Register for the lock */
48114b24e2bSVaishali Kulkarni ecore_wr(p_hwfn, p_ptt, hw_lock_cntr_reg + sizeof(u32), resource);
48214b24e2bSVaishali Kulkarni
48314b24e2bSVaishali Kulkarni /* Try for 5 seconds every 5ms */
48414b24e2bSVaishali Kulkarni for (cnt = 0; cnt < HW_LOCK_MAX_RETRIES; cnt++) {
48514b24e2bSVaishali Kulkarni lock_status = ecore_rd(p_hwfn, p_ptt, hw_lock_cntr_reg);
48614b24e2bSVaishali Kulkarni
48714b24e2bSVaishali Kulkarni if (lock_status & resource)
48814b24e2bSVaishali Kulkarni return ECORE_SUCCESS;
48914b24e2bSVaishali Kulkarni
49014b24e2bSVaishali Kulkarni if (!block) {
49114b24e2bSVaishali Kulkarni ecore_status = ECORE_BUSY;
49214b24e2bSVaishali Kulkarni break;
49314b24e2bSVaishali Kulkarni }
49414b24e2bSVaishali Kulkarni
49514b24e2bSVaishali Kulkarni OSAL_MSLEEP(5);
49614b24e2bSVaishali Kulkarni }
49714b24e2bSVaishali Kulkarni
49814b24e2bSVaishali Kulkarni if (cnt == HW_LOCK_MAX_RETRIES) {
49914b24e2bSVaishali Kulkarni DP_NOTICE(p_hwfn, true, "Lock timeout resource=0x%x\n",
50014b24e2bSVaishali Kulkarni resource);
50114b24e2bSVaishali Kulkarni ecore_status = ECORE_TIMEOUT;
50214b24e2bSVaishali Kulkarni }
50314b24e2bSVaishali Kulkarni
50414b24e2bSVaishali Kulkarni /* Clear the pending request */
50514b24e2bSVaishali Kulkarni ecore_wr(p_hwfn, p_ptt, hw_lock_cntr_reg, resource);
50614b24e2bSVaishali Kulkarni
50714b24e2bSVaishali Kulkarni return ecore_status;
50814b24e2bSVaishali Kulkarni }
50914b24e2bSVaishali Kulkarni
51014b24e2bSVaishali Kulkarni enum _ecore_status_t ecore_hw_unlock(struct ecore_hwfn *p_hwfn,
51114b24e2bSVaishali Kulkarni struct ecore_ptt *p_ptt,
51214b24e2bSVaishali Kulkarni u8 resource)
51314b24e2bSVaishali Kulkarni {
51414b24e2bSVaishali Kulkarni u32 lock_status, hw_lock_cntr_reg;
51514b24e2bSVaishali Kulkarni
51614b24e2bSVaishali Kulkarni /* Locate the proper lock register for this function.
51714b24e2bSVaishali Kulkarni * Note This code assumes all the H/W lock registers are sequential
51814b24e2bSVaishali Kulkarni * in memory.
51914b24e2bSVaishali Kulkarni */
52014b24e2bSVaishali Kulkarni hw_lock_cntr_reg = MISCS_REG_DRIVER_CONTROL_0 +
52114b24e2bSVaishali Kulkarni p_hwfn->rel_pf_id *
52214b24e2bSVaishali Kulkarni MISCS_REG_DRIVER_CONTROL_0_SIZE * sizeof(u32);
52314b24e2bSVaishali Kulkarni
52414b24e2bSVaishali Kulkarni /* Validate that the resource is currently taken */
52514b24e2bSVaishali Kulkarni lock_status = ecore_rd(p_hwfn, p_ptt, hw_lock_cntr_reg);
52614b24e2bSVaishali Kulkarni
52714b24e2bSVaishali Kulkarni if (!(lock_status & resource)) {
52814b24e2bSVaishali Kulkarni DP_NOTICE(p_hwfn, true,
52914b24e2bSVaishali Kulkarni "resource 0x%x was not taken (lock status 0x%x)\n",
53014b24e2bSVaishali Kulkarni resource, lock_status);
53114b24e2bSVaishali Kulkarni
53214b24e2bSVaishali Kulkarni return ECORE_NODEV;
53314b24e2bSVaishali Kulkarni }
53414b24e2bSVaishali Kulkarni
53514b24e2bSVaishali Kulkarni /* clear lock for resource */
53614b24e2bSVaishali Kulkarni ecore_wr(p_hwfn, p_ptt, hw_lock_cntr_reg, resource);
53714b24e2bSVaishali Kulkarni return ECORE_SUCCESS;
53814b24e2bSVaishali Kulkarni }
53914b24e2bSVaishali Kulkarni #endif /* HW locks logic */
54014b24e2bSVaishali Kulkarni
54114b24e2bSVaishali Kulkarni /* DMAE */
ecore_dmae_opcode(struct ecore_hwfn * p_hwfn,const u8 is_src_type_grc,const u8 is_dst_type_grc,struct ecore_dmae_params * p_params)54214b24e2bSVaishali Kulkarni static void ecore_dmae_opcode(struct ecore_hwfn *p_hwfn,
54314b24e2bSVaishali Kulkarni const u8 is_src_type_grc,
54414b24e2bSVaishali Kulkarni const u8 is_dst_type_grc,
54514b24e2bSVaishali Kulkarni struct ecore_dmae_params *p_params)
54614b24e2bSVaishali Kulkarni {
54714b24e2bSVaishali Kulkarni u16 opcode_b = 0;
54814b24e2bSVaishali Kulkarni u32 opcode = 0;
54914b24e2bSVaishali Kulkarni
55014b24e2bSVaishali Kulkarni /* Whether the source is the PCIe or the GRC.
55114b24e2bSVaishali Kulkarni * 0- The source is the PCIe
55214b24e2bSVaishali Kulkarni * 1- The source is the GRC.
55314b24e2bSVaishali Kulkarni */
55414b24e2bSVaishali Kulkarni opcode |= (is_src_type_grc ? DMAE_CMD_SRC_MASK_GRC
55514b24e2bSVaishali Kulkarni : DMAE_CMD_SRC_MASK_PCIE) <<
55614b24e2bSVaishali Kulkarni DMAE_CMD_SRC_SHIFT;
55714b24e2bSVaishali Kulkarni opcode |= (p_hwfn->rel_pf_id & DMAE_CMD_SRC_PF_ID_MASK) <<
55814b24e2bSVaishali Kulkarni DMAE_CMD_SRC_PF_ID_SHIFT;
55914b24e2bSVaishali Kulkarni
56014b24e2bSVaishali Kulkarni /* The destination of the DMA can be: 0-None 1-PCIe 2-GRC 3-None */
56114b24e2bSVaishali Kulkarni opcode |= (is_dst_type_grc ? DMAE_CMD_DST_MASK_GRC
56214b24e2bSVaishali Kulkarni : DMAE_CMD_DST_MASK_PCIE) <<
56314b24e2bSVaishali Kulkarni DMAE_CMD_DST_SHIFT;
56414b24e2bSVaishali Kulkarni opcode |= (p_hwfn->rel_pf_id & DMAE_CMD_DST_PF_ID_MASK) <<
56514b24e2bSVaishali Kulkarni DMAE_CMD_DST_PF_ID_SHIFT;
56614b24e2bSVaishali Kulkarni
56714b24e2bSVaishali Kulkarni /* DMAE_E4_TODO need to check which value to specifiy here. */
56814b24e2bSVaishali Kulkarni /* opcode |= (!b_complete_to_host)<< DMAE_CMD_C_DST_SHIFT;*/
56914b24e2bSVaishali Kulkarni
57014b24e2bSVaishali Kulkarni /* Whether to write a completion word to the completion destination:
57114b24e2bSVaishali Kulkarni * 0-Do not write a completion word
57214b24e2bSVaishali Kulkarni * 1-Write the completion word
57314b24e2bSVaishali Kulkarni */
57414b24e2bSVaishali Kulkarni opcode |= DMAE_CMD_COMP_WORD_EN_MASK << DMAE_CMD_COMP_WORD_EN_SHIFT;
57514b24e2bSVaishali Kulkarni opcode |= DMAE_CMD_SRC_ADDR_RESET_MASK <<
57614b24e2bSVaishali Kulkarni DMAE_CMD_SRC_ADDR_RESET_SHIFT;
57714b24e2bSVaishali Kulkarni
57814b24e2bSVaishali Kulkarni if (p_params->flags & ECORE_DMAE_FLAG_COMPLETION_DST)
57914b24e2bSVaishali Kulkarni opcode |= 1 << DMAE_CMD_COMP_FUNC_SHIFT;
58014b24e2bSVaishali Kulkarni
58114b24e2bSVaishali Kulkarni /* swapping mode 3 - big endian there should be a define ifdefed in
58214b24e2bSVaishali Kulkarni * the HSI somewhere. Since it is currently
58314b24e2bSVaishali Kulkarni */
58414b24e2bSVaishali Kulkarni opcode |= DMAE_CMD_ENDIANITY << DMAE_CMD_ENDIANITY_MODE_SHIFT;
58514b24e2bSVaishali Kulkarni
58614b24e2bSVaishali Kulkarni opcode |= p_hwfn->port_id << DMAE_CMD_PORT_ID_SHIFT;
58714b24e2bSVaishali Kulkarni
58814b24e2bSVaishali Kulkarni /* reset source address in next go */
58914b24e2bSVaishali Kulkarni opcode |= DMAE_CMD_SRC_ADDR_RESET_MASK <<
59014b24e2bSVaishali Kulkarni DMAE_CMD_SRC_ADDR_RESET_SHIFT;
59114b24e2bSVaishali Kulkarni
59214b24e2bSVaishali Kulkarni /* reset dest address in next go */
59314b24e2bSVaishali Kulkarni opcode |= DMAE_CMD_DST_ADDR_RESET_MASK <<
59414b24e2bSVaishali Kulkarni DMAE_CMD_DST_ADDR_RESET_SHIFT;
59514b24e2bSVaishali Kulkarni
59614b24e2bSVaishali Kulkarni /* SRC/DST VFID: all 1's - pf, otherwise VF id */
59714b24e2bSVaishali Kulkarni if (p_params->flags & ECORE_DMAE_FLAG_VF_SRC) {
59814b24e2bSVaishali Kulkarni opcode |= (1 << DMAE_CMD_SRC_VF_ID_VALID_SHIFT);
59914b24e2bSVaishali Kulkarni opcode_b |= (p_params->src_vfid << DMAE_CMD_SRC_VF_ID_SHIFT);
60014b24e2bSVaishali Kulkarni } else {
60114b24e2bSVaishali Kulkarni opcode_b |= (DMAE_CMD_SRC_VF_ID_MASK <<
60214b24e2bSVaishali Kulkarni DMAE_CMD_SRC_VF_ID_SHIFT);
60314b24e2bSVaishali Kulkarni }
60414b24e2bSVaishali Kulkarni if (p_params->flags & ECORE_DMAE_FLAG_VF_DST) {
60514b24e2bSVaishali Kulkarni opcode |= 1 << DMAE_CMD_DST_VF_ID_VALID_SHIFT;
60614b24e2bSVaishali Kulkarni opcode_b |= p_params->dst_vfid << DMAE_CMD_DST_VF_ID_SHIFT;
60714b24e2bSVaishali Kulkarni } else {
60814b24e2bSVaishali Kulkarni opcode_b |= DMAE_CMD_DST_VF_ID_MASK <<
60914b24e2bSVaishali Kulkarni DMAE_CMD_DST_VF_ID_SHIFT;
61014b24e2bSVaishali Kulkarni }
61114b24e2bSVaishali Kulkarni
61214b24e2bSVaishali Kulkarni p_hwfn->dmae_info.p_dmae_cmd->opcode = OSAL_CPU_TO_LE32(opcode);
61314b24e2bSVaishali Kulkarni p_hwfn->dmae_info.p_dmae_cmd->opcode_b = OSAL_CPU_TO_LE16(opcode_b);
61414b24e2bSVaishali Kulkarni }
61514b24e2bSVaishali Kulkarni
ecore_dmae_idx_to_go_cmd(u8 idx)61614b24e2bSVaishali Kulkarni static u32 ecore_dmae_idx_to_go_cmd(u8 idx)
61714b24e2bSVaishali Kulkarni {
61814b24e2bSVaishali Kulkarni OSAL_BUILD_BUG_ON((DMAE_REG_GO_C31 - DMAE_REG_GO_C0) !=
61914b24e2bSVaishali Kulkarni 31 * 4);
62014b24e2bSVaishali Kulkarni
62114b24e2bSVaishali Kulkarni /* All the DMAE 'go' registers form an array in internal memory */
62214b24e2bSVaishali Kulkarni return DMAE_REG_GO_C0 + (idx << 2);
62314b24e2bSVaishali Kulkarni }
62414b24e2bSVaishali Kulkarni
ecore_dmae_post_command(struct ecore_hwfn * p_hwfn,struct ecore_ptt * p_ptt)62514b24e2bSVaishali Kulkarni static enum _ecore_status_t ecore_dmae_post_command(struct ecore_hwfn *p_hwfn,
62614b24e2bSVaishali Kulkarni struct ecore_ptt *p_ptt)
62714b24e2bSVaishali Kulkarni {
62814b24e2bSVaishali Kulkarni struct dmae_cmd *p_command = p_hwfn->dmae_info.p_dmae_cmd;
62914b24e2bSVaishali Kulkarni u8 idx_cmd = p_hwfn->dmae_info.channel, i;
63014b24e2bSVaishali Kulkarni enum _ecore_status_t ecore_status = ECORE_SUCCESS;
63114b24e2bSVaishali Kulkarni
63214b24e2bSVaishali Kulkarni /* verify address is not OSAL_NULL */
63314b24e2bSVaishali Kulkarni if ((((!p_command->dst_addr_lo) && (!p_command->dst_addr_hi)) ||
63414b24e2bSVaishali Kulkarni ((!p_command->src_addr_lo) && (!p_command->src_addr_hi)))) {
63514b24e2bSVaishali Kulkarni DP_NOTICE(p_hwfn, true,
63614b24e2bSVaishali Kulkarni "source or destination address 0 idx_cmd=%d\n"
63714b24e2bSVaishali Kulkarni "opcode = [0x%08x,0x%04x] len=0x%x src=0x%x:%x dst=0x%x:%x\n",
63814b24e2bSVaishali Kulkarni idx_cmd,
63914b24e2bSVaishali Kulkarni OSAL_LE32_TO_CPU(p_command->opcode),
64014b24e2bSVaishali Kulkarni OSAL_LE16_TO_CPU(p_command->opcode_b),
64114b24e2bSVaishali Kulkarni OSAL_LE16_TO_CPU(p_command->length_dw),
64214b24e2bSVaishali Kulkarni OSAL_LE32_TO_CPU(p_command->src_addr_hi),
64314b24e2bSVaishali Kulkarni OSAL_LE32_TO_CPU(p_command->src_addr_lo),
64414b24e2bSVaishali Kulkarni OSAL_LE32_TO_CPU(p_command->dst_addr_hi),
64514b24e2bSVaishali Kulkarni OSAL_LE32_TO_CPU(p_command->dst_addr_lo));
64614b24e2bSVaishali Kulkarni
64714b24e2bSVaishali Kulkarni return ECORE_INVAL;
64814b24e2bSVaishali Kulkarni }
64914b24e2bSVaishali Kulkarni
65014b24e2bSVaishali Kulkarni DP_VERBOSE(p_hwfn, ECORE_MSG_HW,
65114b24e2bSVaishali Kulkarni "Posting DMAE command [idx %d]: opcode = [0x%08x,0x%04x] len=0x%x src=0x%x:%x dst=0x%x:%x\n",
65214b24e2bSVaishali Kulkarni idx_cmd,
65314b24e2bSVaishali Kulkarni OSAL_LE32_TO_CPU(p_command->opcode),
65414b24e2bSVaishali Kulkarni OSAL_LE16_TO_CPU(p_command->opcode_b),
65514b24e2bSVaishali Kulkarni OSAL_LE16_TO_CPU(p_command->length_dw),
65614b24e2bSVaishali Kulkarni OSAL_LE32_TO_CPU(p_command->src_addr_hi),
65714b24e2bSVaishali Kulkarni OSAL_LE32_TO_CPU(p_command->src_addr_lo),
65814b24e2bSVaishali Kulkarni OSAL_LE32_TO_CPU(p_command->dst_addr_hi),
65914b24e2bSVaishali Kulkarni OSAL_LE32_TO_CPU(p_command->dst_addr_lo));
66014b24e2bSVaishali Kulkarni
66114b24e2bSVaishali Kulkarni /* Copy the command to DMAE - need to do it before every call
66214b24e2bSVaishali Kulkarni * for source/dest address no reset.
66314b24e2bSVaishali Kulkarni * The number of commands have been increased to 16 (previous was 14)
66414b24e2bSVaishali Kulkarni * The first 9 DWs are the command registers, the 10 DW is the
66514b24e2bSVaishali Kulkarni * GO register, and
66614b24e2bSVaishali Kulkarni * the rest are result registers (which are read only by the client).
66714b24e2bSVaishali Kulkarni */
66814b24e2bSVaishali Kulkarni for (i = 0; i < DMAE_CMD_SIZE; i++) {
66914b24e2bSVaishali Kulkarni u32 data = (i < DMAE_CMD_SIZE_TO_FILL) ?
67014b24e2bSVaishali Kulkarni *(((u32 *)p_command) + i) : 0;
67114b24e2bSVaishali Kulkarni
67214b24e2bSVaishali Kulkarni ecore_wr(p_hwfn, p_ptt,
67314b24e2bSVaishali Kulkarni DMAE_REG_CMD_MEM +
67414b24e2bSVaishali Kulkarni (idx_cmd * DMAE_CMD_SIZE * sizeof(u32)) +
67514b24e2bSVaishali Kulkarni (i * sizeof(u32)), data);
67614b24e2bSVaishali Kulkarni }
67714b24e2bSVaishali Kulkarni
67814b24e2bSVaishali Kulkarni ecore_wr(p_hwfn, p_ptt,
67914b24e2bSVaishali Kulkarni ecore_dmae_idx_to_go_cmd(idx_cmd),
68014b24e2bSVaishali Kulkarni DMAE_GO_VALUE);
68114b24e2bSVaishali Kulkarni
68214b24e2bSVaishali Kulkarni return ecore_status;
68314b24e2bSVaishali Kulkarni }
68414b24e2bSVaishali Kulkarni
ecore_dmae_info_alloc(struct ecore_hwfn * p_hwfn)68514b24e2bSVaishali Kulkarni enum _ecore_status_t ecore_dmae_info_alloc(struct ecore_hwfn *p_hwfn)
68614b24e2bSVaishali Kulkarni {
68714b24e2bSVaishali Kulkarni dma_addr_t *p_addr = &p_hwfn->dmae_info.completion_word_phys_addr;
68814b24e2bSVaishali Kulkarni struct dmae_cmd **p_cmd = &p_hwfn->dmae_info.p_dmae_cmd;
68914b24e2bSVaishali Kulkarni u32 **p_buff = &p_hwfn->dmae_info.p_intermediate_buffer;
69014b24e2bSVaishali Kulkarni u32 **p_comp = &p_hwfn->dmae_info.p_completion_word;
69114b24e2bSVaishali Kulkarni
69214b24e2bSVaishali Kulkarni *p_comp = OSAL_DMA_ALLOC_COHERENT(p_hwfn->p_dev, p_addr, sizeof(u32));
69314b24e2bSVaishali Kulkarni if (*p_comp == OSAL_NULL) {
69414b24e2bSVaishali Kulkarni DP_NOTICE(p_hwfn, true,
69514b24e2bSVaishali Kulkarni "Failed to allocate `p_completion_word'\n");
69614b24e2bSVaishali Kulkarni goto err;
69714b24e2bSVaishali Kulkarni }
69814b24e2bSVaishali Kulkarni
69914b24e2bSVaishali Kulkarni p_addr = &p_hwfn->dmae_info.dmae_cmd_phys_addr;
70014b24e2bSVaishali Kulkarni *p_cmd = OSAL_DMA_ALLOC_COHERENT(p_hwfn->p_dev, p_addr,
70114b24e2bSVaishali Kulkarni sizeof(struct dmae_cmd));
70214b24e2bSVaishali Kulkarni if (*p_cmd == OSAL_NULL) {
70314b24e2bSVaishali Kulkarni DP_NOTICE(p_hwfn, true,
70414b24e2bSVaishali Kulkarni "Failed to allocate `struct dmae_cmd'\n");
70514b24e2bSVaishali Kulkarni goto err;
70614b24e2bSVaishali Kulkarni }
70714b24e2bSVaishali Kulkarni
70814b24e2bSVaishali Kulkarni p_addr = &p_hwfn->dmae_info.intermediate_buffer_phys_addr;
70914b24e2bSVaishali Kulkarni *p_buff = OSAL_DMA_ALLOC_COHERENT(p_hwfn->p_dev, p_addr,
71014b24e2bSVaishali Kulkarni sizeof(u32) * DMAE_MAX_RW_SIZE);
71114b24e2bSVaishali Kulkarni if (*p_buff == OSAL_NULL) {
71214b24e2bSVaishali Kulkarni DP_NOTICE(p_hwfn, true,
71314b24e2bSVaishali Kulkarni "Failed to allocate `intermediate_buffer'\n");
71414b24e2bSVaishali Kulkarni goto err;
71514b24e2bSVaishali Kulkarni }
71614b24e2bSVaishali Kulkarni
71714b24e2bSVaishali Kulkarni p_hwfn->dmae_info.channel = p_hwfn->rel_pf_id;
71814b24e2bSVaishali Kulkarni
71914b24e2bSVaishali Kulkarni return ECORE_SUCCESS;
72014b24e2bSVaishali Kulkarni err:
72114b24e2bSVaishali Kulkarni ecore_dmae_info_free(p_hwfn);
72214b24e2bSVaishali Kulkarni return ECORE_NOMEM;
72314b24e2bSVaishali Kulkarni }
72414b24e2bSVaishali Kulkarni
ecore_dmae_info_free(struct ecore_hwfn * p_hwfn)72514b24e2bSVaishali Kulkarni void ecore_dmae_info_free(struct ecore_hwfn *p_hwfn)
72614b24e2bSVaishali Kulkarni {
72714b24e2bSVaishali Kulkarni dma_addr_t p_phys;
72814b24e2bSVaishali Kulkarni
72914b24e2bSVaishali Kulkarni /* Just make sure no one is in the middle */
73014b24e2bSVaishali Kulkarni OSAL_MUTEX_ACQUIRE(&p_hwfn->dmae_info.mutex);
73114b24e2bSVaishali Kulkarni
73214b24e2bSVaishali Kulkarni if (p_hwfn->dmae_info.p_completion_word != OSAL_NULL) {
73314b24e2bSVaishali Kulkarni p_phys = p_hwfn->dmae_info.completion_word_phys_addr;
73414b24e2bSVaishali Kulkarni OSAL_DMA_FREE_COHERENT(p_hwfn->p_dev,
73514b24e2bSVaishali Kulkarni p_hwfn->dmae_info.p_completion_word,
73614b24e2bSVaishali Kulkarni p_phys, sizeof(u32));
73714b24e2bSVaishali Kulkarni p_hwfn->dmae_info.p_completion_word = OSAL_NULL;
73814b24e2bSVaishali Kulkarni }
73914b24e2bSVaishali Kulkarni
74014b24e2bSVaishali Kulkarni if (p_hwfn->dmae_info.p_dmae_cmd != OSAL_NULL) {
74114b24e2bSVaishali Kulkarni p_phys = p_hwfn->dmae_info.dmae_cmd_phys_addr;
74214b24e2bSVaishali Kulkarni OSAL_DMA_FREE_COHERENT(p_hwfn->p_dev,
74314b24e2bSVaishali Kulkarni p_hwfn->dmae_info.p_dmae_cmd,
74414b24e2bSVaishali Kulkarni p_phys, sizeof(struct dmae_cmd));
74514b24e2bSVaishali Kulkarni p_hwfn->dmae_info.p_dmae_cmd = OSAL_NULL;
74614b24e2bSVaishali Kulkarni }
74714b24e2bSVaishali Kulkarni
74814b24e2bSVaishali Kulkarni if (p_hwfn->dmae_info.p_intermediate_buffer != OSAL_NULL) {
74914b24e2bSVaishali Kulkarni p_phys = p_hwfn->dmae_info.intermediate_buffer_phys_addr;
75014b24e2bSVaishali Kulkarni OSAL_DMA_FREE_COHERENT(p_hwfn->p_dev,
75114b24e2bSVaishali Kulkarni p_hwfn->dmae_info.p_intermediate_buffer,
75214b24e2bSVaishali Kulkarni p_phys, sizeof(u32) * DMAE_MAX_RW_SIZE);
75314b24e2bSVaishali Kulkarni p_hwfn->dmae_info.p_intermediate_buffer = OSAL_NULL;
75414b24e2bSVaishali Kulkarni }
75514b24e2bSVaishali Kulkarni
75614b24e2bSVaishali Kulkarni OSAL_MUTEX_RELEASE(&p_hwfn->dmae_info.mutex);
75714b24e2bSVaishali Kulkarni }
75814b24e2bSVaishali Kulkarni
75914b24e2bSVaishali Kulkarni static enum _ecore_status_t
ecore_dmae_operation_wait(struct ecore_hwfn * p_hwfn)76014b24e2bSVaishali Kulkarni ecore_dmae_operation_wait(struct ecore_hwfn *p_hwfn)
76114b24e2bSVaishali Kulkarni {
76214b24e2bSVaishali Kulkarni u32 wait_cnt_limit = 10000, wait_cnt = 0;
76314b24e2bSVaishali Kulkarni enum _ecore_status_t ecore_status = ECORE_SUCCESS;
76414b24e2bSVaishali Kulkarni
76514b24e2bSVaishali Kulkarni #ifndef ASIC_ONLY
76614b24e2bSVaishali Kulkarni u32 factor = (CHIP_REV_IS_EMUL(p_hwfn->p_dev) ?
76714b24e2bSVaishali Kulkarni ECORE_EMUL_FACTOR :
76814b24e2bSVaishali Kulkarni (CHIP_REV_IS_FPGA(p_hwfn->p_dev) ?
76914b24e2bSVaishali Kulkarni ECORE_FPGA_FACTOR : 1));
77014b24e2bSVaishali Kulkarni
77114b24e2bSVaishali Kulkarni wait_cnt_limit *= factor;
77214b24e2bSVaishali Kulkarni #endif
77314b24e2bSVaishali Kulkarni
77414b24e2bSVaishali Kulkarni /* DMAE_E4_TODO : TODO check if we have to call any other function
77514b24e2bSVaishali Kulkarni * other than BARRIER to sync the completion_word since we are not
77614b24e2bSVaishali Kulkarni * using the volatile keyword for this
77714b24e2bSVaishali Kulkarni */
77814b24e2bSVaishali Kulkarni OSAL_BARRIER(p_hwfn->p_dev);
77914b24e2bSVaishali Kulkarni while (*p_hwfn->dmae_info.p_completion_word != DMAE_COMPLETION_VAL) {
78014b24e2bSVaishali Kulkarni OSAL_UDELAY(DMAE_MIN_WAIT_TIME);
78114b24e2bSVaishali Kulkarni if (++wait_cnt > wait_cnt_limit) {
78214b24e2bSVaishali Kulkarni DP_NOTICE(p_hwfn->p_dev, ECORE_MSG_HW,
78314b24e2bSVaishali Kulkarni "Timed-out waiting for operation to complete. Completion word is 0x%08x expected 0x%08x.\n",
78414b24e2bSVaishali Kulkarni *(p_hwfn->dmae_info.p_completion_word),
78514b24e2bSVaishali Kulkarni DMAE_COMPLETION_VAL);
78614b24e2bSVaishali Kulkarni ecore_status = ECORE_TIMEOUT;
78714b24e2bSVaishali Kulkarni break;
78814b24e2bSVaishali Kulkarni }
78914b24e2bSVaishali Kulkarni
79014b24e2bSVaishali Kulkarni /* to sync the completion_word since we are not
79114b24e2bSVaishali Kulkarni * using the volatile keyword for p_completion_word
79214b24e2bSVaishali Kulkarni */
79314b24e2bSVaishali Kulkarni OSAL_BARRIER(p_hwfn->p_dev);
79414b24e2bSVaishali Kulkarni }
79514b24e2bSVaishali Kulkarni
79614b24e2bSVaishali Kulkarni if (ecore_status == ECORE_SUCCESS)
79714b24e2bSVaishali Kulkarni *p_hwfn->dmae_info.p_completion_word = 0;
79814b24e2bSVaishali Kulkarni
79914b24e2bSVaishali Kulkarni return ecore_status;
80014b24e2bSVaishali Kulkarni }
80114b24e2bSVaishali Kulkarni
ecore_dmae_execute_sub_operation(struct ecore_hwfn * p_hwfn,struct ecore_ptt * p_ptt,u64 src_addr,u64 dst_addr,u8 src_type,u8 dst_type,u32 length_dw)80214b24e2bSVaishali Kulkarni static enum _ecore_status_t ecore_dmae_execute_sub_operation(struct ecore_hwfn *p_hwfn,
80314b24e2bSVaishali Kulkarni struct ecore_ptt *p_ptt,
80414b24e2bSVaishali Kulkarni u64 src_addr,
80514b24e2bSVaishali Kulkarni u64 dst_addr,
80614b24e2bSVaishali Kulkarni u8 src_type,
80714b24e2bSVaishali Kulkarni u8 dst_type,
80814b24e2bSVaishali Kulkarni u32 length_dw)
80914b24e2bSVaishali Kulkarni {
81014b24e2bSVaishali Kulkarni dma_addr_t phys = p_hwfn->dmae_info.intermediate_buffer_phys_addr;
81114b24e2bSVaishali Kulkarni struct dmae_cmd *cmd = p_hwfn->dmae_info.p_dmae_cmd;
81214b24e2bSVaishali Kulkarni enum _ecore_status_t ecore_status = ECORE_SUCCESS;
81314b24e2bSVaishali Kulkarni
81414b24e2bSVaishali Kulkarni switch (src_type) {
81514b24e2bSVaishali Kulkarni case ECORE_DMAE_ADDRESS_GRC:
81614b24e2bSVaishali Kulkarni case ECORE_DMAE_ADDRESS_HOST_PHYS:
81714b24e2bSVaishali Kulkarni cmd->src_addr_hi = OSAL_CPU_TO_LE32(DMA_HI(src_addr));
81814b24e2bSVaishali Kulkarni cmd->src_addr_lo = OSAL_CPU_TO_LE32(DMA_LO(src_addr));
81914b24e2bSVaishali Kulkarni break;
82014b24e2bSVaishali Kulkarni /* for virtual source addresses we use the intermediate buffer. */
82114b24e2bSVaishali Kulkarni case ECORE_DMAE_ADDRESS_HOST_VIRT:
82214b24e2bSVaishali Kulkarni cmd->src_addr_hi = OSAL_CPU_TO_LE32(DMA_HI(phys));
82314b24e2bSVaishali Kulkarni cmd->src_addr_lo = OSAL_CPU_TO_LE32(DMA_LO(phys));
82414b24e2bSVaishali Kulkarni OSAL_MEMCPY(&(p_hwfn->dmae_info.p_intermediate_buffer[0]),
82514b24e2bSVaishali Kulkarni (void *)(osal_uintptr_t)src_addr,
82614b24e2bSVaishali Kulkarni length_dw * sizeof(u32));
82714b24e2bSVaishali Kulkarni break;
82814b24e2bSVaishali Kulkarni default:
82914b24e2bSVaishali Kulkarni return ECORE_INVAL;
83014b24e2bSVaishali Kulkarni }
83114b24e2bSVaishali Kulkarni
83214b24e2bSVaishali Kulkarni switch (dst_type) {
83314b24e2bSVaishali Kulkarni case ECORE_DMAE_ADDRESS_GRC:
83414b24e2bSVaishali Kulkarni case ECORE_DMAE_ADDRESS_HOST_PHYS:
83514b24e2bSVaishali Kulkarni cmd->dst_addr_hi = OSAL_CPU_TO_LE32(DMA_HI(dst_addr));
83614b24e2bSVaishali Kulkarni cmd->dst_addr_lo = OSAL_CPU_TO_LE32(DMA_LO(dst_addr));
83714b24e2bSVaishali Kulkarni break;
83814b24e2bSVaishali Kulkarni /* for virtual destination addresses we use the intermediate buffer. */
83914b24e2bSVaishali Kulkarni case ECORE_DMAE_ADDRESS_HOST_VIRT:
84014b24e2bSVaishali Kulkarni cmd->dst_addr_hi = OSAL_CPU_TO_LE32(DMA_HI(phys));
84114b24e2bSVaishali Kulkarni cmd->dst_addr_lo = OSAL_CPU_TO_LE32(DMA_LO(phys));
84214b24e2bSVaishali Kulkarni break;
84314b24e2bSVaishali Kulkarni default:
84414b24e2bSVaishali Kulkarni return ECORE_INVAL;
84514b24e2bSVaishali Kulkarni }
84614b24e2bSVaishali Kulkarni
84714b24e2bSVaishali Kulkarni cmd->length_dw = OSAL_CPU_TO_LE16((u16)length_dw);
84814b24e2bSVaishali Kulkarni #ifndef __EXTRACT__LINUX__
84914b24e2bSVaishali Kulkarni if (src_type == ECORE_DMAE_ADDRESS_HOST_VIRT ||
85014b24e2bSVaishali Kulkarni src_type == ECORE_DMAE_ADDRESS_HOST_PHYS)
85114b24e2bSVaishali Kulkarni OSAL_DMA_SYNC(p_hwfn->p_dev,
85214b24e2bSVaishali Kulkarni (void *)HILO_U64(cmd->src_addr_hi,
85314b24e2bSVaishali Kulkarni cmd->src_addr_lo),
85414b24e2bSVaishali Kulkarni length_dw * sizeof(u32), false);
85514b24e2bSVaishali Kulkarni #endif
85614b24e2bSVaishali Kulkarni
85714b24e2bSVaishali Kulkarni ecore_dmae_post_command(p_hwfn, p_ptt);
85814b24e2bSVaishali Kulkarni
85914b24e2bSVaishali Kulkarni ecore_status = ecore_dmae_operation_wait(p_hwfn);
86014b24e2bSVaishali Kulkarni
86114b24e2bSVaishali Kulkarni #ifndef __EXTRACT__LINUX__
86214b24e2bSVaishali Kulkarni /* TODO - is it true ? */
86314b24e2bSVaishali Kulkarni if (src_type == ECORE_DMAE_ADDRESS_HOST_VIRT ||
86414b24e2bSVaishali Kulkarni src_type == ECORE_DMAE_ADDRESS_HOST_PHYS)
86514b24e2bSVaishali Kulkarni OSAL_DMA_SYNC(p_hwfn->p_dev,
86614b24e2bSVaishali Kulkarni (void *)HILO_U64(cmd->src_addr_hi,
86714b24e2bSVaishali Kulkarni cmd->src_addr_lo),
86814b24e2bSVaishali Kulkarni length_dw * sizeof(u32), true);
86914b24e2bSVaishali Kulkarni #endif
87014b24e2bSVaishali Kulkarni
87114b24e2bSVaishali Kulkarni if (ecore_status != ECORE_SUCCESS) {
87214b24e2bSVaishali Kulkarni DP_NOTICE(p_hwfn, ECORE_MSG_HW,
87314b24e2bSVaishali Kulkarni "Wait Failed. source_addr 0x%llx, grc_addr 0x%llx, size_in_dwords 0x%x, intermediate buffer 0x%llx.\n",
87414b24e2bSVaishali Kulkarni src_addr, dst_addr, length_dw,
87514b24e2bSVaishali Kulkarni (u64)p_hwfn->dmae_info.intermediate_buffer_phys_addr);
87614b24e2bSVaishali Kulkarni return ecore_status;
87714b24e2bSVaishali Kulkarni }
87814b24e2bSVaishali Kulkarni
87914b24e2bSVaishali Kulkarni if (dst_type == ECORE_DMAE_ADDRESS_HOST_VIRT)
88014b24e2bSVaishali Kulkarni OSAL_MEMCPY((void *)(osal_uintptr_t)(dst_addr),
88114b24e2bSVaishali Kulkarni &p_hwfn->dmae_info.p_intermediate_buffer[0],
88214b24e2bSVaishali Kulkarni length_dw * sizeof(u32));
88314b24e2bSVaishali Kulkarni
88414b24e2bSVaishali Kulkarni return ECORE_SUCCESS;
88514b24e2bSVaishali Kulkarni }
88614b24e2bSVaishali Kulkarni
ecore_dmae_execute_command(struct ecore_hwfn * p_hwfn,struct ecore_ptt * p_ptt,u64 src_addr,u64 dst_addr,u8 src_type,u8 dst_type,u32 size_in_dwords,struct ecore_dmae_params * p_params)88714b24e2bSVaishali Kulkarni static enum _ecore_status_t ecore_dmae_execute_command(struct ecore_hwfn *p_hwfn,
88814b24e2bSVaishali Kulkarni struct ecore_ptt *p_ptt,
88914b24e2bSVaishali Kulkarni u64 src_addr, u64 dst_addr,
89014b24e2bSVaishali Kulkarni u8 src_type, u8 dst_type,
89114b24e2bSVaishali Kulkarni u32 size_in_dwords,
89214b24e2bSVaishali Kulkarni struct ecore_dmae_params *p_params)
89314b24e2bSVaishali Kulkarni {
89414b24e2bSVaishali Kulkarni dma_addr_t phys = p_hwfn->dmae_info.completion_word_phys_addr;
89514b24e2bSVaishali Kulkarni u16 length_cur = 0, i = 0, cnt_split = 0, length_mod = 0;
89614b24e2bSVaishali Kulkarni struct dmae_cmd *cmd = p_hwfn->dmae_info.p_dmae_cmd;
89714b24e2bSVaishali Kulkarni u64 src_addr_split = 0, dst_addr_split = 0;
89814b24e2bSVaishali Kulkarni u16 length_limit = DMAE_MAX_RW_SIZE;
89914b24e2bSVaishali Kulkarni enum _ecore_status_t ecore_status = ECORE_SUCCESS;
90014b24e2bSVaishali Kulkarni u32 offset = 0;
90114b24e2bSVaishali Kulkarni
90214b24e2bSVaishali Kulkarni if (p_hwfn->p_dev->recov_in_prog) {
90314b24e2bSVaishali Kulkarni DP_VERBOSE(p_hwfn, ECORE_MSG_HW,
90414b24e2bSVaishali Kulkarni "Recovery is in progress. Avoid DMAE transaction [{src: addr 0x%llx, type %d}, {dst: addr 0x%llx, type %d}, size %d].\n",
90514b24e2bSVaishali Kulkarni src_addr, src_type, dst_addr, dst_type,
90614b24e2bSVaishali Kulkarni size_in_dwords);
90714b24e2bSVaishali Kulkarni /* Return success to let the flow to be completed successfully
90814b24e2bSVaishali Kulkarni * w/o any error handling.
90914b24e2bSVaishali Kulkarni */
91014b24e2bSVaishali Kulkarni return ECORE_SUCCESS;
91114b24e2bSVaishali Kulkarni }
91214b24e2bSVaishali Kulkarni
91314b24e2bSVaishali Kulkarni ecore_dmae_opcode(p_hwfn,
91414b24e2bSVaishali Kulkarni (src_type == ECORE_DMAE_ADDRESS_GRC),
91514b24e2bSVaishali Kulkarni (dst_type == ECORE_DMAE_ADDRESS_GRC),
91614b24e2bSVaishali Kulkarni p_params);
91714b24e2bSVaishali Kulkarni
91814b24e2bSVaishali Kulkarni cmd->comp_addr_lo = OSAL_CPU_TO_LE32(DMA_LO(phys));
91914b24e2bSVaishali Kulkarni cmd->comp_addr_hi = OSAL_CPU_TO_LE32(DMA_HI(phys));
92014b24e2bSVaishali Kulkarni cmd->comp_val = OSAL_CPU_TO_LE32(DMAE_COMPLETION_VAL);
92114b24e2bSVaishali Kulkarni
92214b24e2bSVaishali Kulkarni /* Check if the grc_addr is valid like < MAX_GRC_OFFSET */
92314b24e2bSVaishali Kulkarni cnt_split = size_in_dwords / length_limit;
92414b24e2bSVaishali Kulkarni length_mod = size_in_dwords % length_limit;
92514b24e2bSVaishali Kulkarni
92614b24e2bSVaishali Kulkarni src_addr_split = src_addr;
92714b24e2bSVaishali Kulkarni dst_addr_split = dst_addr;
92814b24e2bSVaishali Kulkarni
92914b24e2bSVaishali Kulkarni for (i = 0; i <= cnt_split; i++) {
93014b24e2bSVaishali Kulkarni offset = length_limit * i;
93114b24e2bSVaishali Kulkarni
93214b24e2bSVaishali Kulkarni if (!(p_params->flags & ECORE_DMAE_FLAG_RW_REPL_SRC)) {
93314b24e2bSVaishali Kulkarni if (src_type == ECORE_DMAE_ADDRESS_GRC)
93414b24e2bSVaishali Kulkarni src_addr_split = src_addr + offset;
93514b24e2bSVaishali Kulkarni else
93614b24e2bSVaishali Kulkarni src_addr_split = src_addr + (offset*4);
93714b24e2bSVaishali Kulkarni }
93814b24e2bSVaishali Kulkarni
93914b24e2bSVaishali Kulkarni if (dst_type == ECORE_DMAE_ADDRESS_GRC)
94014b24e2bSVaishali Kulkarni dst_addr_split = dst_addr + offset;
94114b24e2bSVaishali Kulkarni else
94214b24e2bSVaishali Kulkarni dst_addr_split = dst_addr + (offset*4);
94314b24e2bSVaishali Kulkarni
94414b24e2bSVaishali Kulkarni length_cur = (cnt_split == i) ? length_mod : length_limit;
94514b24e2bSVaishali Kulkarni
94614b24e2bSVaishali Kulkarni /* might be zero on last iteration */
94714b24e2bSVaishali Kulkarni if (!length_cur)
94814b24e2bSVaishali Kulkarni continue;
94914b24e2bSVaishali Kulkarni
95014b24e2bSVaishali Kulkarni ecore_status = ecore_dmae_execute_sub_operation(p_hwfn,
95114b24e2bSVaishali Kulkarni p_ptt,
95214b24e2bSVaishali Kulkarni src_addr_split,
95314b24e2bSVaishali Kulkarni dst_addr_split,
95414b24e2bSVaishali Kulkarni src_type,
95514b24e2bSVaishali Kulkarni dst_type,
95614b24e2bSVaishali Kulkarni length_cur);
95714b24e2bSVaishali Kulkarni if (ecore_status != ECORE_SUCCESS) {
95814b24e2bSVaishali Kulkarni DP_NOTICE(p_hwfn, false,
95914b24e2bSVaishali Kulkarni "ecore_dmae_execute_sub_operation Failed with error 0x%x. source_addr 0x%llx, destination addr 0x%llx, size_in_dwords 0x%x\n",
96014b24e2bSVaishali Kulkarni ecore_status, src_addr, dst_addr, length_cur);
96114b24e2bSVaishali Kulkarni
96214b24e2bSVaishali Kulkarni ecore_hw_err_notify(p_hwfn, ECORE_HW_ERR_DMAE_FAIL);
96314b24e2bSVaishali Kulkarni break;
96414b24e2bSVaishali Kulkarni }
96514b24e2bSVaishali Kulkarni }
96614b24e2bSVaishali Kulkarni
96714b24e2bSVaishali Kulkarni return ecore_status;
96814b24e2bSVaishali Kulkarni }
96914b24e2bSVaishali Kulkarni
ecore_dmae_host2grc(struct ecore_hwfn * p_hwfn,struct ecore_ptt * p_ptt,u64 source_addr,u32 grc_addr,u32 size_in_dwords,u32 flags)97014b24e2bSVaishali Kulkarni enum _ecore_status_t ecore_dmae_host2grc(struct ecore_hwfn *p_hwfn,
97114b24e2bSVaishali Kulkarni struct ecore_ptt *p_ptt,
97214b24e2bSVaishali Kulkarni u64 source_addr,
97314b24e2bSVaishali Kulkarni u32 grc_addr,
97414b24e2bSVaishali Kulkarni u32 size_in_dwords,
97514b24e2bSVaishali Kulkarni u32 flags)
97614b24e2bSVaishali Kulkarni {
97714b24e2bSVaishali Kulkarni u32 grc_addr_in_dw = grc_addr / sizeof(u32);
97814b24e2bSVaishali Kulkarni struct ecore_dmae_params params;
97914b24e2bSVaishali Kulkarni enum _ecore_status_t rc;
98014b24e2bSVaishali Kulkarni
98114b24e2bSVaishali Kulkarni OSAL_MEMSET(¶ms, 0, sizeof(struct ecore_dmae_params));
98214b24e2bSVaishali Kulkarni params.flags = flags;
98314b24e2bSVaishali Kulkarni
98414b24e2bSVaishali Kulkarni OSAL_MUTEX_ACQUIRE(&p_hwfn->dmae_info.mutex);
98514b24e2bSVaishali Kulkarni
98614b24e2bSVaishali Kulkarni rc = ecore_dmae_execute_command(p_hwfn, p_ptt, source_addr,
98714b24e2bSVaishali Kulkarni grc_addr_in_dw,
98814b24e2bSVaishali Kulkarni ECORE_DMAE_ADDRESS_HOST_VIRT,
98914b24e2bSVaishali Kulkarni ECORE_DMAE_ADDRESS_GRC,
99014b24e2bSVaishali Kulkarni size_in_dwords, ¶ms);
99114b24e2bSVaishali Kulkarni
99214b24e2bSVaishali Kulkarni OSAL_MUTEX_RELEASE(&p_hwfn->dmae_info.mutex);
99314b24e2bSVaishali Kulkarni
99414b24e2bSVaishali Kulkarni return rc;
99514b24e2bSVaishali Kulkarni }
99614b24e2bSVaishali Kulkarni
ecore_dmae_grc2host(struct ecore_hwfn * p_hwfn,struct ecore_ptt * p_ptt,u32 grc_addr,dma_addr_t dest_addr,u32 size_in_dwords,u32 flags)99714b24e2bSVaishali Kulkarni enum _ecore_status_t ecore_dmae_grc2host(struct ecore_hwfn *p_hwfn,
99814b24e2bSVaishali Kulkarni struct ecore_ptt *p_ptt,
99914b24e2bSVaishali Kulkarni u32 grc_addr,
100014b24e2bSVaishali Kulkarni dma_addr_t dest_addr,
100114b24e2bSVaishali Kulkarni u32 size_in_dwords,
100214b24e2bSVaishali Kulkarni u32 flags)
100314b24e2bSVaishali Kulkarni {
100414b24e2bSVaishali Kulkarni u32 grc_addr_in_dw = grc_addr / sizeof(u32);
100514b24e2bSVaishali Kulkarni struct ecore_dmae_params params;
100614b24e2bSVaishali Kulkarni enum _ecore_status_t rc;
100714b24e2bSVaishali Kulkarni
100814b24e2bSVaishali Kulkarni OSAL_MEMSET(¶ms, 0, sizeof(struct ecore_dmae_params));
100914b24e2bSVaishali Kulkarni params.flags = flags;
101014b24e2bSVaishali Kulkarni
101114b24e2bSVaishali Kulkarni OSAL_MUTEX_ACQUIRE(&(p_hwfn->dmae_info.mutex));
101214b24e2bSVaishali Kulkarni
101314b24e2bSVaishali Kulkarni rc = ecore_dmae_execute_command(p_hwfn, p_ptt, grc_addr_in_dw,
101414b24e2bSVaishali Kulkarni dest_addr, ECORE_DMAE_ADDRESS_GRC,
101514b24e2bSVaishali Kulkarni ECORE_DMAE_ADDRESS_HOST_VIRT,
101614b24e2bSVaishali Kulkarni size_in_dwords, ¶ms);
101714b24e2bSVaishali Kulkarni
101814b24e2bSVaishali Kulkarni OSAL_MUTEX_RELEASE(&(p_hwfn->dmae_info.mutex));
101914b24e2bSVaishali Kulkarni
102014b24e2bSVaishali Kulkarni return rc;
102114b24e2bSVaishali Kulkarni }
102214b24e2bSVaishali Kulkarni
ecore_dmae_host2host(struct ecore_hwfn * p_hwfn,struct ecore_ptt * p_ptt,dma_addr_t source_addr,dma_addr_t dest_addr,u32 size_in_dwords,struct ecore_dmae_params * p_params)102314b24e2bSVaishali Kulkarni enum _ecore_status_t ecore_dmae_host2host(struct ecore_hwfn *p_hwfn,
102414b24e2bSVaishali Kulkarni struct ecore_ptt *p_ptt,
102514b24e2bSVaishali Kulkarni dma_addr_t source_addr,
102614b24e2bSVaishali Kulkarni dma_addr_t dest_addr,
102714b24e2bSVaishali Kulkarni u32 size_in_dwords,
102814b24e2bSVaishali Kulkarni struct ecore_dmae_params *p_params)
102914b24e2bSVaishali Kulkarni {
103014b24e2bSVaishali Kulkarni enum _ecore_status_t rc;
103114b24e2bSVaishali Kulkarni
103214b24e2bSVaishali Kulkarni OSAL_MUTEX_ACQUIRE(&p_hwfn->dmae_info.mutex);
103314b24e2bSVaishali Kulkarni
103414b24e2bSVaishali Kulkarni rc = ecore_dmae_execute_command(p_hwfn, p_ptt, source_addr,
103514b24e2bSVaishali Kulkarni dest_addr,
103614b24e2bSVaishali Kulkarni ECORE_DMAE_ADDRESS_HOST_PHYS,
103714b24e2bSVaishali Kulkarni ECORE_DMAE_ADDRESS_HOST_PHYS,
103814b24e2bSVaishali Kulkarni size_in_dwords,
103914b24e2bSVaishali Kulkarni p_params);
104014b24e2bSVaishali Kulkarni
104114b24e2bSVaishali Kulkarni OSAL_MUTEX_RELEASE(&p_hwfn->dmae_info.mutex);
104214b24e2bSVaishali Kulkarni
104314b24e2bSVaishali Kulkarni return rc;
104414b24e2bSVaishali Kulkarni }
104514b24e2bSVaishali Kulkarni
ecore_hw_err_notify(struct ecore_hwfn * p_hwfn,enum ecore_hw_err_type err_type)104614b24e2bSVaishali Kulkarni void ecore_hw_err_notify(struct ecore_hwfn *p_hwfn,
104714b24e2bSVaishali Kulkarni enum ecore_hw_err_type err_type)
104814b24e2bSVaishali Kulkarni {
104914b24e2bSVaishali Kulkarni /* Fan failure cannot be masked by handling of another HW error */
105014b24e2bSVaishali Kulkarni if (p_hwfn->p_dev->recov_in_prog && err_type != ECORE_HW_ERR_FAN_FAIL) {
105114b24e2bSVaishali Kulkarni DP_VERBOSE(p_hwfn, ECORE_MSG_DRV,
105214b24e2bSVaishali Kulkarni "Recovery is in progress. Avoid notifying about HW error %d.\n",
105314b24e2bSVaishali Kulkarni err_type);
105414b24e2bSVaishali Kulkarni return;
105514b24e2bSVaishali Kulkarni }
105614b24e2bSVaishali Kulkarni
105714b24e2bSVaishali Kulkarni OSAL_HW_ERROR_OCCURRED(p_hwfn, err_type);
105814b24e2bSVaishali Kulkarni }
1059