1316485Sdavidcs/* 2316485Sdavidcs * Copyright (c) 2017-2018 Cavium, Inc. 3316485Sdavidcs * All rights reserved. 4316485Sdavidcs * 5316485Sdavidcs * Redistribution and use in source and binary forms, with or without 6316485Sdavidcs * modification, are permitted provided that the following conditions 7316485Sdavidcs * are met: 8316485Sdavidcs * 9316485Sdavidcs * 1. Redistributions of source code must retain the above copyright 10316485Sdavidcs * notice, this list of conditions and the following disclaimer. 11316485Sdavidcs * 2. Redistributions in binary form must reproduce the above copyright 12316485Sdavidcs * notice, this list of conditions and the following disclaimer in the 13316485Sdavidcs * documentation and/or other materials provided with the distribution. 14316485Sdavidcs * 15316485Sdavidcs * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16316485Sdavidcs * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17316485Sdavidcs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18316485Sdavidcs * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19316485Sdavidcs * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20316485Sdavidcs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21316485Sdavidcs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22316485Sdavidcs * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23316485Sdavidcs * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24316485Sdavidcs * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25316485Sdavidcs * POSSIBILITY OF SUCH DAMAGE. 26316485Sdavidcs */ 27316485Sdavidcs 28316485Sdavidcs/* 29316485Sdavidcs * File : ecore_init_ops.c 30316485Sdavidcs */ 31316485Sdavidcs#include <sys/cdefs.h> 32316485Sdavidcs__FBSDID("$FreeBSD: stable/11/sys/dev/qlnx/qlnxe/ecore_init_ops.c 337517 2018-08-09 01:17:35Z davidcs $"); 33316485Sdavidcs 34316485Sdavidcs/* include the precompiled configuration values - only once */ 35316485Sdavidcs#include "bcm_osal.h" 36316485Sdavidcs#include "ecore_hsi_common.h" 37316485Sdavidcs#include "ecore.h" 38316485Sdavidcs#include "ecore_hw.h" 39316485Sdavidcs#include "ecore_status.h" 40316485Sdavidcs#include "ecore_rt_defs.h" 41316485Sdavidcs#include "ecore_init_fw_funcs.h" 42316485Sdavidcs 43316485Sdavidcs#ifndef CONFIG_ECORE_BINARY_FW 44316485Sdavidcs#ifdef CONFIG_ECORE_ZIPPED_FW 45316485Sdavidcs#include "ecore_init_values_zipped.h" 46316485Sdavidcs#else 47316485Sdavidcs#include "ecore_init_values.h" 48316485Sdavidcs#endif 49316485Sdavidcs#endif 50316485Sdavidcs 51316485Sdavidcs#include "ecore_iro_values.h" 52316485Sdavidcs#include "ecore_sriov.h" 53316485Sdavidcs#include "ecore_gtt_values.h" 54316485Sdavidcs#include "reg_addr.h" 55316485Sdavidcs#include "ecore_init_ops.h" 56316485Sdavidcs 57316485Sdavidcs#define ECORE_INIT_MAX_POLL_COUNT 100 58316485Sdavidcs#define ECORE_INIT_POLL_PERIOD_US 500 59316485Sdavidcs 60316485Sdavidcsvoid ecore_init_iro_array(struct ecore_dev *p_dev) 61316485Sdavidcs{ 62316485Sdavidcs p_dev->iro_arr = iro_arr; 63316485Sdavidcs} 64316485Sdavidcs 65316485Sdavidcs/* Runtime configuration helpers */ 66316485Sdavidcsvoid ecore_init_clear_rt_data(struct ecore_hwfn *p_hwfn) 67316485Sdavidcs{ 68316485Sdavidcs int i; 69316485Sdavidcs 70316485Sdavidcs for (i = 0; i < RUNTIME_ARRAY_SIZE; i++) 71316485Sdavidcs p_hwfn->rt_data.b_valid[i] = false; 72316485Sdavidcs} 73316485Sdavidcs 74316485Sdavidcsvoid ecore_init_store_rt_reg(struct ecore_hwfn *p_hwfn, 75316485Sdavidcs u32 rt_offset, u32 val) 76316485Sdavidcs{ 77320164Sdavidcs if (rt_offset >= RUNTIME_ARRAY_SIZE) { 78320164Sdavidcs DP_ERR(p_hwfn, 79320164Sdavidcs "Avoid storing %u in rt_data at index %u since RUNTIME_ARRAY_SIZE is %u!\n", 80320164Sdavidcs val, rt_offset, RUNTIME_ARRAY_SIZE); 81320164Sdavidcs return; 82320164Sdavidcs } 83320164Sdavidcs 84316485Sdavidcs p_hwfn->rt_data.init_val[rt_offset] = val; 85316485Sdavidcs p_hwfn->rt_data.b_valid[rt_offset] = true; 86316485Sdavidcs} 87316485Sdavidcs 88316485Sdavidcsvoid ecore_init_store_rt_agg(struct ecore_hwfn *p_hwfn, 89316485Sdavidcs u32 rt_offset, u32 *p_val, 90316485Sdavidcs osal_size_t size) 91316485Sdavidcs{ 92316485Sdavidcs osal_size_t i; 93316485Sdavidcs 94320164Sdavidcs if ((rt_offset + size - 1) >= RUNTIME_ARRAY_SIZE) { 95320164Sdavidcs DP_ERR(p_hwfn, 96320164Sdavidcs "Avoid storing values in rt_data at indices %u-%u since RUNTIME_ARRAY_SIZE is %u!\n", 97320164Sdavidcs rt_offset, (u32)(rt_offset + size - 1), 98320164Sdavidcs RUNTIME_ARRAY_SIZE); 99320164Sdavidcs return; 100320164Sdavidcs } 101320164Sdavidcs 102316485Sdavidcs for (i = 0; i < size / sizeof(u32); i++) { 103316485Sdavidcs p_hwfn->rt_data.init_val[rt_offset + i] = p_val[i]; 104316485Sdavidcs p_hwfn->rt_data.b_valid[rt_offset + i] = true; 105316485Sdavidcs 106316485Sdavidcs } 107316485Sdavidcs} 108316485Sdavidcs 109316485Sdavidcsstatic enum _ecore_status_t ecore_init_rt(struct ecore_hwfn *p_hwfn, 110316485Sdavidcs struct ecore_ptt *p_ptt, 111316485Sdavidcs u32 addr, 112316485Sdavidcs u16 rt_offset, 113316485Sdavidcs u16 size, 114316485Sdavidcs bool b_must_dmae) 115316485Sdavidcs{ 116316485Sdavidcs u32 *p_init_val = &p_hwfn->rt_data.init_val[rt_offset]; 117316485Sdavidcs bool *p_valid = &p_hwfn->rt_data.b_valid[rt_offset]; 118316485Sdavidcs u16 i, segment; 119316485Sdavidcs enum _ecore_status_t rc = ECORE_SUCCESS; 120316485Sdavidcs 121316485Sdavidcs /* Since not all RT entries are initialized, go over the RT and 122316485Sdavidcs * for each segment of initialized values use DMA. 123316485Sdavidcs */ 124316485Sdavidcs for (i = 0; i < size; i++) { 125316485Sdavidcs if (!p_valid[i]) 126316485Sdavidcs continue; 127316485Sdavidcs 128316485Sdavidcs /* In case there isn't any wide-bus configuration here, 129316485Sdavidcs * simply write the data instead of using dmae. 130316485Sdavidcs */ 131316485Sdavidcs if (!b_must_dmae) { 132316485Sdavidcs ecore_wr(p_hwfn, p_ptt, addr + (i << 2), 133316485Sdavidcs p_init_val[i]); 134316485Sdavidcs continue; 135316485Sdavidcs } 136316485Sdavidcs 137316485Sdavidcs /* Start of a new segment */ 138316485Sdavidcs for (segment = 1; i + segment < size; segment++) 139316485Sdavidcs if (!p_valid[i + segment]) 140316485Sdavidcs break; 141316485Sdavidcs 142316485Sdavidcs rc = ecore_dmae_host2grc(p_hwfn, p_ptt, 143316485Sdavidcs (osal_uintptr_t)(p_init_val + i), 144337517Sdavidcs addr + (i << 2), segment, 145337517Sdavidcs OSAL_NULL /* default parameters */); 146316485Sdavidcs if (rc != ECORE_SUCCESS) 147316485Sdavidcs return rc; 148316485Sdavidcs 149316485Sdavidcs /* Jump over the entire segment, including invalid entry */ 150316485Sdavidcs i += segment; 151316485Sdavidcs } 152316485Sdavidcs 153316485Sdavidcs return rc; 154316485Sdavidcs} 155316485Sdavidcs 156316485Sdavidcsenum _ecore_status_t ecore_init_alloc(struct ecore_hwfn *p_hwfn) 157316485Sdavidcs{ 158316485Sdavidcs struct ecore_rt_data *rt_data = &p_hwfn->rt_data; 159316485Sdavidcs 160316485Sdavidcs if (IS_VF(p_hwfn->p_dev)) 161316485Sdavidcs return ECORE_SUCCESS; 162316485Sdavidcs 163316485Sdavidcs rt_data->b_valid = OSAL_ZALLOC(p_hwfn->p_dev, GFP_KERNEL, 164316485Sdavidcs sizeof(bool) * RUNTIME_ARRAY_SIZE); 165316485Sdavidcs if (!rt_data->b_valid) 166316485Sdavidcs return ECORE_NOMEM; 167316485Sdavidcs 168316485Sdavidcs rt_data->init_val = OSAL_ZALLOC(p_hwfn->p_dev, GFP_KERNEL, 169316485Sdavidcs sizeof(u32) * RUNTIME_ARRAY_SIZE); 170316485Sdavidcs if (!rt_data->init_val) { 171316485Sdavidcs OSAL_FREE(p_hwfn->p_dev, rt_data->b_valid); 172316485Sdavidcs rt_data->b_valid = OSAL_NULL; 173316485Sdavidcs return ECORE_NOMEM; 174316485Sdavidcs } 175316485Sdavidcs 176316485Sdavidcs return ECORE_SUCCESS; 177316485Sdavidcs} 178316485Sdavidcs 179316485Sdavidcsvoid ecore_init_free(struct ecore_hwfn *p_hwfn) 180316485Sdavidcs{ 181316485Sdavidcs OSAL_FREE(p_hwfn->p_dev, p_hwfn->rt_data.init_val); 182316485Sdavidcs p_hwfn->rt_data.init_val = OSAL_NULL; 183316485Sdavidcs OSAL_FREE(p_hwfn->p_dev, p_hwfn->rt_data.b_valid); 184316485Sdavidcs p_hwfn->rt_data.b_valid = OSAL_NULL; 185316485Sdavidcs} 186316485Sdavidcs 187316485Sdavidcsstatic enum _ecore_status_t ecore_init_array_dmae(struct ecore_hwfn *p_hwfn, 188316485Sdavidcs struct ecore_ptt *p_ptt, 189316485Sdavidcs u32 addr, u32 dmae_data_offset, 190316485Sdavidcs u32 size, const u32 *p_buf, 191316485Sdavidcs bool b_must_dmae, bool b_can_dmae) 192316485Sdavidcs{ 193316485Sdavidcs enum _ecore_status_t rc = ECORE_SUCCESS; 194316485Sdavidcs 195316485Sdavidcs /* Perform DMAE only for lengthy enough sections or for wide-bus */ 196316485Sdavidcs#ifndef ASIC_ONLY 197316485Sdavidcs if ((CHIP_REV_IS_SLOW(p_hwfn->p_dev) && (size < 16)) || 198316485Sdavidcs !b_can_dmae || (!b_must_dmae && (size < 16))) { 199316485Sdavidcs#else 200316485Sdavidcs if (!b_can_dmae || (!b_must_dmae && (size < 16))) { 201316485Sdavidcs#endif 202316485Sdavidcs const u32 *data = p_buf + dmae_data_offset; 203316485Sdavidcs u32 i; 204316485Sdavidcs 205316485Sdavidcs for (i = 0; i < size; i++) 206316485Sdavidcs ecore_wr(p_hwfn, p_ptt, addr + (i << 2), data[i]); 207316485Sdavidcs } else { 208337517Sdavidcs rc = ecore_dmae_host2grc(p_hwfn, p_ptt, 209337517Sdavidcs (osal_uintptr_t)(p_buf + 210337517Sdavidcs dmae_data_offset), 211337517Sdavidcs addr, size, 212337517Sdavidcs OSAL_NULL /* default parameters */); 213316485Sdavidcs } 214316485Sdavidcs 215316485Sdavidcs return rc; 216316485Sdavidcs} 217316485Sdavidcs 218316485Sdavidcsstatic enum _ecore_status_t ecore_init_fill_dmae(struct ecore_hwfn *p_hwfn, 219316485Sdavidcs struct ecore_ptt *p_ptt, 220320164Sdavidcs u32 addr, u32 fill_count) 221316485Sdavidcs{ 222316485Sdavidcs static u32 zero_buffer[DMAE_MAX_RW_SIZE]; 223337517Sdavidcs struct ecore_dmae_params params; 224316485Sdavidcs 225316485Sdavidcs OSAL_MEMSET(zero_buffer, 0, sizeof(u32) * DMAE_MAX_RW_SIZE); 226316485Sdavidcs 227337517Sdavidcs OSAL_MEMSET(¶ms, 0, sizeof(params)); 228337517Sdavidcs params.flags = ECORE_DMAE_FLAG_RW_REPL_SRC; 229316485Sdavidcs return ecore_dmae_host2grc(p_hwfn, p_ptt, 230316485Sdavidcs (osal_uintptr_t)(&(zero_buffer[0])), 231337517Sdavidcs addr, fill_count, ¶ms); 232316485Sdavidcs} 233316485Sdavidcs 234316485Sdavidcsstatic void ecore_init_fill(struct ecore_hwfn *p_hwfn, 235316485Sdavidcs struct ecore_ptt *p_ptt, 236316485Sdavidcs u32 addr, u32 fill, u32 fill_count) 237316485Sdavidcs{ 238316485Sdavidcs u32 i; 239316485Sdavidcs 240316485Sdavidcs for (i = 0; i < fill_count; i++, addr += sizeof(u32)) 241316485Sdavidcs ecore_wr(p_hwfn, p_ptt, addr, fill); 242316485Sdavidcs} 243316485Sdavidcs 244316485Sdavidcs 245316485Sdavidcsstatic enum _ecore_status_t ecore_init_cmd_array(struct ecore_hwfn *p_hwfn, 246316485Sdavidcs struct ecore_ptt *p_ptt, 247316485Sdavidcs struct init_write_op *cmd, 248316485Sdavidcs bool b_must_dmae, 249316485Sdavidcs bool b_can_dmae) 250316485Sdavidcs{ 251316485Sdavidcs u32 dmae_array_offset = OSAL_LE32_TO_CPU(cmd->args.array_offset); 252316485Sdavidcs u32 data = OSAL_LE32_TO_CPU(cmd->data); 253316485Sdavidcs u32 addr = GET_FIELD(data, INIT_WRITE_OP_ADDRESS) << 2; 254316485Sdavidcs#ifdef CONFIG_ECORE_ZIPPED_FW 255316485Sdavidcs u32 offset, output_len, input_len, max_size; 256316485Sdavidcs#endif 257316485Sdavidcs struct ecore_dev *p_dev = p_hwfn->p_dev; 258316485Sdavidcs union init_array_hdr *hdr; 259316485Sdavidcs const u32 *array_data; 260316485Sdavidcs enum _ecore_status_t rc = ECORE_SUCCESS; 261316485Sdavidcs u32 size; 262316485Sdavidcs 263316485Sdavidcs array_data = p_dev->fw_data->arr_data; 264316485Sdavidcs 265316485Sdavidcs hdr = (union init_array_hdr *) (array_data + 266316485Sdavidcs dmae_array_offset); 267316485Sdavidcs data = OSAL_LE32_TO_CPU(hdr->raw.data); 268316485Sdavidcs switch (GET_FIELD(data, INIT_ARRAY_RAW_HDR_TYPE)) { 269316485Sdavidcs case INIT_ARR_ZIPPED: 270316485Sdavidcs#ifdef CONFIG_ECORE_ZIPPED_FW 271316485Sdavidcs offset = dmae_array_offset + 1; 272316485Sdavidcs input_len = GET_FIELD(data, 273316485Sdavidcs INIT_ARRAY_ZIPPED_HDR_ZIPPED_SIZE); 274316485Sdavidcs max_size = MAX_ZIPPED_SIZE * 4; 275316485Sdavidcs OSAL_MEMSET(p_hwfn->unzip_buf, 0, max_size); 276316485Sdavidcs 277316485Sdavidcs output_len = OSAL_UNZIP_DATA(p_hwfn, input_len, 278316485Sdavidcs (u8 *)&array_data[offset], 279316485Sdavidcs max_size, (u8 *)p_hwfn->unzip_buf); 280316485Sdavidcs if (output_len) { 281316485Sdavidcs rc = ecore_init_array_dmae(p_hwfn, p_ptt, addr, 0, 282316485Sdavidcs output_len, 283316485Sdavidcs p_hwfn->unzip_buf, 284316485Sdavidcs b_must_dmae, b_can_dmae); 285316485Sdavidcs } else { 286316485Sdavidcs DP_NOTICE(p_hwfn, true, 287316485Sdavidcs "Failed to unzip dmae data\n"); 288316485Sdavidcs rc = ECORE_INVAL; 289316485Sdavidcs } 290316485Sdavidcs#else 291316485Sdavidcs DP_NOTICE(p_hwfn, true, 292316485Sdavidcs "Using zipped firmware without config enabled\n"); 293316485Sdavidcs rc = ECORE_INVAL; 294316485Sdavidcs#endif 295316485Sdavidcs break; 296316485Sdavidcs case INIT_ARR_PATTERN: 297316485Sdavidcs { 298316485Sdavidcs u32 repeats = GET_FIELD(data, 299316485Sdavidcs INIT_ARRAY_PATTERN_HDR_REPETITIONS); 300316485Sdavidcs u32 i; 301316485Sdavidcs 302316485Sdavidcs size = GET_FIELD(data, 303316485Sdavidcs INIT_ARRAY_PATTERN_HDR_PATTERN_SIZE); 304316485Sdavidcs 305316485Sdavidcs for (i = 0; i < repeats; i++, addr += size << 2) { 306316485Sdavidcs rc = ecore_init_array_dmae(p_hwfn, p_ptt, addr, 307316485Sdavidcs dmae_array_offset + 1, 308316485Sdavidcs size, array_data, 309316485Sdavidcs b_must_dmae, b_can_dmae); 310316485Sdavidcs if (rc) 311316485Sdavidcs break; 312316485Sdavidcs } 313316485Sdavidcs break; 314316485Sdavidcs } 315316485Sdavidcs case INIT_ARR_STANDARD: 316316485Sdavidcs size = GET_FIELD(data, 317316485Sdavidcs INIT_ARRAY_STANDARD_HDR_SIZE); 318316485Sdavidcs rc = ecore_init_array_dmae(p_hwfn, p_ptt, addr, 319316485Sdavidcs dmae_array_offset + 1, 320316485Sdavidcs size, array_data, 321316485Sdavidcs b_must_dmae, b_can_dmae); 322316485Sdavidcs break; 323316485Sdavidcs } 324316485Sdavidcs 325316485Sdavidcs return rc; 326316485Sdavidcs} 327316485Sdavidcs 328316485Sdavidcs/* init_ops write command */ 329316485Sdavidcsstatic enum _ecore_status_t ecore_init_cmd_wr(struct ecore_hwfn *p_hwfn, 330316485Sdavidcs struct ecore_ptt *p_ptt, 331316485Sdavidcs struct init_write_op *p_cmd, 332316485Sdavidcs bool b_can_dmae) 333316485Sdavidcs{ 334316485Sdavidcs u32 data = OSAL_LE32_TO_CPU(p_cmd->data); 335316485Sdavidcs bool b_must_dmae = GET_FIELD(data, INIT_WRITE_OP_WIDE_BUS); 336316485Sdavidcs u32 addr = GET_FIELD(data, INIT_WRITE_OP_ADDRESS) << 2; 337316485Sdavidcs enum _ecore_status_t rc = ECORE_SUCCESS; 338316485Sdavidcs 339316485Sdavidcs /* Sanitize */ 340316485Sdavidcs if (b_must_dmae && !b_can_dmae) { 341316485Sdavidcs DP_NOTICE(p_hwfn, true, 342316485Sdavidcs "Need to write to %08x for Wide-bus but DMAE isn't allowed\n", 343316485Sdavidcs addr); 344316485Sdavidcs return ECORE_INVAL; 345316485Sdavidcs } 346316485Sdavidcs 347316485Sdavidcs switch (GET_FIELD(data, INIT_WRITE_OP_SOURCE)) { 348316485Sdavidcs case INIT_SRC_INLINE: 349316485Sdavidcs data = OSAL_LE32_TO_CPU(p_cmd->args.inline_val); 350316485Sdavidcs ecore_wr(p_hwfn, p_ptt, addr, data); 351316485Sdavidcs break; 352316485Sdavidcs case INIT_SRC_ZEROS: 353316485Sdavidcs data = OSAL_LE32_TO_CPU(p_cmd->args.zeros_count); 354316485Sdavidcs if (b_must_dmae || (b_can_dmae && (data >= 64))) 355320164Sdavidcs rc = ecore_init_fill_dmae(p_hwfn, p_ptt, addr, data); 356316485Sdavidcs else 357316485Sdavidcs ecore_init_fill(p_hwfn, p_ptt, addr, 0, data); 358316485Sdavidcs break; 359316485Sdavidcs case INIT_SRC_ARRAY: 360316485Sdavidcs rc = ecore_init_cmd_array(p_hwfn, p_ptt, p_cmd, 361316485Sdavidcs b_must_dmae, b_can_dmae); 362316485Sdavidcs break; 363316485Sdavidcs case INIT_SRC_RUNTIME: 364337517Sdavidcs rc = ecore_init_rt(p_hwfn, p_ptt, addr, 365337517Sdavidcs OSAL_LE16_TO_CPU(p_cmd->args.runtime.offset), 366337517Sdavidcs OSAL_LE16_TO_CPU(p_cmd->args.runtime.size), 367337517Sdavidcs b_must_dmae); 368316485Sdavidcs break; 369316485Sdavidcs } 370316485Sdavidcs 371316485Sdavidcs return rc; 372316485Sdavidcs} 373316485Sdavidcs 374316485Sdavidcsstatic OSAL_INLINE bool comp_eq(u32 val, u32 expected_val) 375316485Sdavidcs{ 376316485Sdavidcs return (val == expected_val); 377316485Sdavidcs} 378316485Sdavidcs 379316485Sdavidcsstatic OSAL_INLINE bool comp_and(u32 val, u32 expected_val) 380316485Sdavidcs{ 381316485Sdavidcs return (val & expected_val) == expected_val; 382316485Sdavidcs} 383316485Sdavidcs 384316485Sdavidcsstatic OSAL_INLINE bool comp_or(u32 val, u32 expected_val) 385316485Sdavidcs{ 386316485Sdavidcs return (val | expected_val) > 0; 387316485Sdavidcs} 388316485Sdavidcs 389316485Sdavidcs/* init_ops read/poll commands */ 390316485Sdavidcsstatic void ecore_init_cmd_rd(struct ecore_hwfn *p_hwfn, 391316485Sdavidcs struct ecore_ptt *p_ptt, 392316485Sdavidcs struct init_read_op *cmd) 393316485Sdavidcs{ 394316485Sdavidcs bool (*comp_check)(u32 val, u32 expected_val); 395316485Sdavidcs u32 delay = ECORE_INIT_POLL_PERIOD_US, val; 396316485Sdavidcs u32 data, addr, poll; 397316485Sdavidcs int i; 398316485Sdavidcs 399316485Sdavidcs data = OSAL_LE32_TO_CPU(cmd->op_data); 400316485Sdavidcs addr = GET_FIELD(data, INIT_READ_OP_ADDRESS) << 2; 401316485Sdavidcs poll = GET_FIELD(data, INIT_READ_OP_POLL_TYPE); 402316485Sdavidcs 403316485Sdavidcs#ifndef ASIC_ONLY 404316485Sdavidcs if (CHIP_REV_IS_EMUL(p_hwfn->p_dev)) 405316485Sdavidcs delay *= 100; 406316485Sdavidcs#endif 407316485Sdavidcs 408316485Sdavidcs val = ecore_rd(p_hwfn, p_ptt, addr); 409316485Sdavidcs 410316485Sdavidcs if (poll == INIT_POLL_NONE) 411316485Sdavidcs return; 412316485Sdavidcs 413316485Sdavidcs switch (poll) { 414316485Sdavidcs case INIT_POLL_EQ: 415316485Sdavidcs comp_check = comp_eq; 416316485Sdavidcs break; 417316485Sdavidcs case INIT_POLL_OR: 418316485Sdavidcs comp_check = comp_or; 419316485Sdavidcs break; 420316485Sdavidcs case INIT_POLL_AND: 421316485Sdavidcs comp_check = comp_and; 422316485Sdavidcs break; 423316485Sdavidcs default: 424316485Sdavidcs DP_ERR(p_hwfn, "Invalid poll comparison type %08x\n", 425316485Sdavidcs cmd->op_data); 426316485Sdavidcs return; 427316485Sdavidcs } 428316485Sdavidcs 429316485Sdavidcs data = OSAL_LE32_TO_CPU(cmd->expected_val); 430316485Sdavidcs for (i = 0; 431316485Sdavidcs i < ECORE_INIT_MAX_POLL_COUNT && !comp_check(val, data); 432316485Sdavidcs i++) { 433316485Sdavidcs OSAL_UDELAY(delay); 434316485Sdavidcs val = ecore_rd(p_hwfn, p_ptt, addr); 435316485Sdavidcs } 436316485Sdavidcs 437316485Sdavidcs if (i == ECORE_INIT_MAX_POLL_COUNT) 438337517Sdavidcs DP_ERR(p_hwfn, "Timeout when polling reg: 0x%08x [ Waiting-for: %08x Got: %08x (comparison %08x)]\n", 439316485Sdavidcs addr, 440316485Sdavidcs OSAL_LE32_TO_CPU(cmd->expected_val), val, 441316485Sdavidcs OSAL_LE32_TO_CPU(cmd->op_data)); 442316485Sdavidcs} 443316485Sdavidcs 444337517Sdavidcs/* init_ops callbacks entry point */ 445337517Sdavidcsstatic enum _ecore_status_t ecore_init_cmd_cb(struct ecore_hwfn *p_hwfn, 446337517Sdavidcs struct ecore_ptt *p_ptt, 447337517Sdavidcs struct init_callback_op *p_cmd) 448337517Sdavidcs{ 449337517Sdavidcs enum _ecore_status_t rc; 450337517Sdavidcs 451337517Sdavidcs switch (p_cmd->callback_id) { 452337517Sdavidcs case DMAE_READY_CB: 453337517Sdavidcs rc = ecore_dmae_sanity(p_hwfn, p_ptt, "engine_phase"); 454337517Sdavidcs break; 455337517Sdavidcs default: 456337517Sdavidcs DP_NOTICE(p_hwfn, false, "Unexpected init op callback ID %d\n", 457337517Sdavidcs p_cmd->callback_id); 458337517Sdavidcs return ECORE_INVAL; 459337517Sdavidcs } 460337517Sdavidcs 461337517Sdavidcs return rc; 462337517Sdavidcs} 463337517Sdavidcs 464316485Sdavidcsstatic u8 ecore_init_cmd_mode_match(struct ecore_hwfn *p_hwfn, 465316485Sdavidcs u16 *p_offset, int modes) 466316485Sdavidcs{ 467316485Sdavidcs struct ecore_dev *p_dev = p_hwfn->p_dev; 468316485Sdavidcs const u8 *modes_tree_buf; 469316485Sdavidcs u8 arg1, arg2, tree_val; 470316485Sdavidcs 471316485Sdavidcs modes_tree_buf = p_dev->fw_data->modes_tree_buf; 472316485Sdavidcs tree_val = modes_tree_buf[(*p_offset)++]; 473316485Sdavidcs switch(tree_val) { 474316485Sdavidcs case INIT_MODE_OP_NOT: 475316485Sdavidcs return ecore_init_cmd_mode_match(p_hwfn, p_offset, modes) ^ 1; 476316485Sdavidcs case INIT_MODE_OP_OR: 477316485Sdavidcs arg1 = ecore_init_cmd_mode_match(p_hwfn, p_offset, modes); 478316485Sdavidcs arg2 = ecore_init_cmd_mode_match(p_hwfn, p_offset, modes); 479316485Sdavidcs return arg1 | arg2; 480316485Sdavidcs case INIT_MODE_OP_AND: 481316485Sdavidcs arg1 = ecore_init_cmd_mode_match(p_hwfn, p_offset, modes); 482316485Sdavidcs arg2 = ecore_init_cmd_mode_match(p_hwfn, p_offset, modes); 483316485Sdavidcs return arg1 & arg2; 484316485Sdavidcs default: 485316485Sdavidcs tree_val -= MAX_INIT_MODE_OPS; 486316485Sdavidcs return (modes & (1 << tree_val)) ? 1 : 0; 487316485Sdavidcs } 488316485Sdavidcs} 489316485Sdavidcs 490316485Sdavidcsstatic u32 ecore_init_cmd_mode(struct ecore_hwfn *p_hwfn, 491316485Sdavidcs struct init_if_mode_op *p_cmd, int modes) 492316485Sdavidcs{ 493316485Sdavidcs u16 offset = OSAL_LE16_TO_CPU(p_cmd->modes_buf_offset); 494316485Sdavidcs 495316485Sdavidcs if (ecore_init_cmd_mode_match(p_hwfn, &offset, modes)) 496316485Sdavidcs return 0; 497316485Sdavidcs else 498316485Sdavidcs return GET_FIELD(OSAL_LE32_TO_CPU(p_cmd->op_data), 499316485Sdavidcs INIT_IF_MODE_OP_CMD_OFFSET); 500316485Sdavidcs} 501316485Sdavidcs 502320164Sdavidcsstatic u32 ecore_init_cmd_phase(struct init_if_phase_op *p_cmd, 503316485Sdavidcs u32 phase, u32 phase_id) 504316485Sdavidcs{ 505316485Sdavidcs u32 data = OSAL_LE32_TO_CPU(p_cmd->phase_data); 506337517Sdavidcs u32 op_data = OSAL_LE32_TO_CPU(p_cmd->op_data); 507316485Sdavidcs 508316485Sdavidcs if (!(GET_FIELD(data, INIT_IF_PHASE_OP_PHASE) == phase && 509316485Sdavidcs (GET_FIELD(data, INIT_IF_PHASE_OP_PHASE_ID) == ANY_PHASE_ID || 510316485Sdavidcs GET_FIELD(data, INIT_IF_PHASE_OP_PHASE_ID) == phase_id))) 511337517Sdavidcs return GET_FIELD(op_data, INIT_IF_PHASE_OP_CMD_OFFSET); 512316485Sdavidcs else 513316485Sdavidcs return 0; 514316485Sdavidcs} 515316485Sdavidcs 516316485Sdavidcsenum _ecore_status_t ecore_init_run(struct ecore_hwfn *p_hwfn, 517316485Sdavidcs struct ecore_ptt *p_ptt, 518316485Sdavidcs int phase, 519316485Sdavidcs int phase_id, 520316485Sdavidcs int modes) 521316485Sdavidcs{ 522316485Sdavidcs struct ecore_dev *p_dev = p_hwfn->p_dev; 523316485Sdavidcs u32 cmd_num, num_init_ops; 524316485Sdavidcs union init_op *init_ops; 525316485Sdavidcs bool b_dmae = false; 526316485Sdavidcs enum _ecore_status_t rc = ECORE_SUCCESS; 527316485Sdavidcs 528316485Sdavidcs num_init_ops = p_dev->fw_data->init_ops_size; 529316485Sdavidcs init_ops = p_dev->fw_data->init_ops; 530316485Sdavidcs 531316485Sdavidcs#ifdef CONFIG_ECORE_ZIPPED_FW 532316485Sdavidcs p_hwfn->unzip_buf = OSAL_ZALLOC(p_hwfn->p_dev, GFP_ATOMIC, 533316485Sdavidcs MAX_ZIPPED_SIZE * 4); 534316485Sdavidcs if (!p_hwfn->unzip_buf) { 535316485Sdavidcs DP_NOTICE(p_hwfn, true, "Failed to allocate unzip buffer\n"); 536316485Sdavidcs return ECORE_NOMEM; 537316485Sdavidcs } 538316485Sdavidcs#endif 539316485Sdavidcs 540316485Sdavidcs for (cmd_num = 0; cmd_num < num_init_ops; cmd_num++) { 541316485Sdavidcs union init_op *cmd = &init_ops[cmd_num]; 542316485Sdavidcs u32 data = OSAL_LE32_TO_CPU(cmd->raw.op_data); 543316485Sdavidcs 544316485Sdavidcs switch (GET_FIELD(data, INIT_CALLBACK_OP_OP)) { 545316485Sdavidcs case INIT_OP_WRITE: 546316485Sdavidcs rc = ecore_init_cmd_wr(p_hwfn, p_ptt, &cmd->write, 547316485Sdavidcs b_dmae); 548316485Sdavidcs break; 549316485Sdavidcs 550316485Sdavidcs case INIT_OP_READ: 551316485Sdavidcs ecore_init_cmd_rd(p_hwfn, p_ptt, &cmd->read); 552316485Sdavidcs break; 553316485Sdavidcs 554316485Sdavidcs case INIT_OP_IF_MODE: 555316485Sdavidcs cmd_num += ecore_init_cmd_mode(p_hwfn, &cmd->if_mode, 556316485Sdavidcs modes); 557316485Sdavidcs break; 558316485Sdavidcs case INIT_OP_IF_PHASE: 559320164Sdavidcs cmd_num += ecore_init_cmd_phase(&cmd->if_phase, phase, 560320164Sdavidcs phase_id); 561316485Sdavidcs b_dmae = GET_FIELD(data, 562316485Sdavidcs INIT_IF_PHASE_OP_DMAE_ENABLE); 563316485Sdavidcs break; 564316485Sdavidcs case INIT_OP_DELAY: 565316485Sdavidcs /* ecore_init_run is always invoked from 566316485Sdavidcs * sleep-able context 567316485Sdavidcs */ 568316485Sdavidcs OSAL_UDELAY(cmd->delay.delay); 569316485Sdavidcs break; 570316485Sdavidcs 571316485Sdavidcs case INIT_OP_CALLBACK: 572337517Sdavidcs rc = ecore_init_cmd_cb(p_hwfn, p_ptt, &cmd->callback); 573316485Sdavidcs break; 574316485Sdavidcs } 575316485Sdavidcs 576316485Sdavidcs if (rc) 577316485Sdavidcs break; 578316485Sdavidcs } 579316485Sdavidcs#ifdef CONFIG_ECORE_ZIPPED_FW 580316485Sdavidcs OSAL_FREE(p_hwfn->p_dev, p_hwfn->unzip_buf); 581316485Sdavidcs p_hwfn->unzip_buf = OSAL_NULL; 582316485Sdavidcs#endif 583316485Sdavidcs return rc; 584316485Sdavidcs} 585316485Sdavidcs 586320164Sdavidcsvoid ecore_gtt_init(struct ecore_hwfn *p_hwfn, 587320164Sdavidcs struct ecore_ptt *p_ptt) 588316485Sdavidcs{ 589316485Sdavidcs u32 gtt_base; 590316485Sdavidcs u32 i; 591316485Sdavidcs 592316485Sdavidcs#ifndef ASIC_ONLY 593316485Sdavidcs if (CHIP_REV_IS_SLOW(p_hwfn->p_dev)) { 594316485Sdavidcs /* This is done by MFW on ASIC; regardless, this should only 595316485Sdavidcs * be done once per chip [i.e., common]. Implementation is 596316485Sdavidcs * not too bright, but it should work on the simple FPGA/EMUL 597316485Sdavidcs * scenarios. 598316485Sdavidcs */ 599316485Sdavidcs static bool initialized = false; 600316485Sdavidcs int poll_cnt = 500; 601316485Sdavidcs u32 val; 602316485Sdavidcs 603316485Sdavidcs /* initialize PTT/GTT (poll for completion) */ 604316485Sdavidcs if (!initialized) { 605320164Sdavidcs ecore_wr(p_hwfn, p_ptt, 606316485Sdavidcs PGLUE_B_REG_START_INIT_PTT_GTT, 1); 607316485Sdavidcs initialized = true; 608316485Sdavidcs } 609316485Sdavidcs 610316485Sdavidcs do { 611316485Sdavidcs /* ptt might be overrided by HW until this is done */ 612316485Sdavidcs OSAL_UDELAY(10); 613316485Sdavidcs ecore_ptt_invalidate(p_hwfn); 614320164Sdavidcs val = ecore_rd(p_hwfn, p_ptt, 615316485Sdavidcs PGLUE_B_REG_INIT_DONE_PTT_GTT); 616316485Sdavidcs } while ((val != 1) && --poll_cnt); 617316485Sdavidcs 618316485Sdavidcs if (!poll_cnt) 619316485Sdavidcs DP_ERR(p_hwfn, "PGLUE_B_REG_INIT_DONE didn't complete\n"); 620316485Sdavidcs } 621316485Sdavidcs#endif 622316485Sdavidcs 623316485Sdavidcs /* Set the global windows */ 624316485Sdavidcs gtt_base = PXP_PF_WINDOW_ADMIN_START + PXP_PF_WINDOW_ADMIN_GLOBAL_START; 625316485Sdavidcs 626316485Sdavidcs for (i = 0; i < OSAL_ARRAY_SIZE(pxp_global_win); i++) 627316485Sdavidcs if (pxp_global_win[i]) 628316485Sdavidcs REG_WR(p_hwfn, gtt_base + i * PXP_GLOBAL_ENTRY_SIZE, 629316485Sdavidcs pxp_global_win[i]); 630316485Sdavidcs} 631316485Sdavidcs 632316485Sdavidcsenum _ecore_status_t ecore_init_fw_data(struct ecore_dev *p_dev, 633320164Sdavidcs#ifdef CONFIG_ECORE_BINARY_FW 634320164Sdavidcs const u8 *fw_data) 635320164Sdavidcs#else 636320164Sdavidcs const u8 OSAL_UNUSED *fw_data) 637320164Sdavidcs#endif 638316485Sdavidcs{ 639316485Sdavidcs struct ecore_fw_data *fw = p_dev->fw_data; 640316485Sdavidcs 641316485Sdavidcs#ifdef CONFIG_ECORE_BINARY_FW 642316485Sdavidcs struct bin_buffer_hdr *buf_hdr; 643316485Sdavidcs u32 offset, len; 644316485Sdavidcs 645320164Sdavidcs if (!fw_data) { 646316485Sdavidcs DP_NOTICE(p_dev, true, "Invalid fw data\n"); 647316485Sdavidcs return ECORE_INVAL; 648316485Sdavidcs } 649316485Sdavidcs 650320164Sdavidcs buf_hdr = (struct bin_buffer_hdr *)fw_data; 651316485Sdavidcs 652316485Sdavidcs offset = buf_hdr[BIN_BUF_INIT_FW_VER_INFO].offset; 653320164Sdavidcs fw->fw_ver_info = (struct fw_ver_info *)(fw_data + offset); 654316485Sdavidcs 655316485Sdavidcs offset = buf_hdr[BIN_BUF_INIT_CMD].offset; 656320164Sdavidcs fw->init_ops = (union init_op *)(fw_data + offset); 657316485Sdavidcs 658316485Sdavidcs offset = buf_hdr[BIN_BUF_INIT_VAL].offset; 659320164Sdavidcs fw->arr_data = (u32 *)(fw_data + offset); 660316485Sdavidcs 661316485Sdavidcs offset = buf_hdr[BIN_BUF_INIT_MODE_TREE].offset; 662320164Sdavidcs fw->modes_tree_buf = (u8 *)(fw_data + offset); 663316485Sdavidcs len = buf_hdr[BIN_BUF_INIT_CMD].length; 664316485Sdavidcs fw->init_ops_size = len / sizeof(struct init_raw_op); 665316485Sdavidcs#else 666316485Sdavidcs fw->init_ops = (union init_op *)init_ops; 667316485Sdavidcs fw->arr_data = (u32 *)init_val; 668316485Sdavidcs fw->modes_tree_buf = (u8 *)modes_tree_buf; 669316485Sdavidcs fw->init_ops_size = init_ops_size; 670316485Sdavidcs#endif 671316485Sdavidcs 672316485Sdavidcs return ECORE_SUCCESS; 673316485Sdavidcs} 674