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 
774