qla_misc.c revision 229423
1227064Sbz/* 2227064Sbz * Copyright (c) 2010-2011 Qlogic Corporation 3227064Sbz * All rights reserved. 4227064Sbz * 5227064Sbz * Redistribution and use in source and binary forms, with or without 6227064Sbz * modification, are permitted provided that the following conditions 7227064Sbz * are met: 8227064Sbz * 9227064Sbz * 1. Redistributions of source code must retain the above copyright 10227064Sbz * notice, this list of conditions and the following disclaimer. 11227064Sbz * 2. Redistributions in binary form must reproduce the above copyright 12227064Sbz * notice, this list of conditions and the following disclaimer in the 13227064Sbz * documentation and/or other materials provided with the distribution. 14227064Sbz * 15227064Sbz * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16227064Sbz * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17227064Sbz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18227064Sbz * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19227064Sbz * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20227064Sbz * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21227064Sbz * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22227064Sbz * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23227064Sbz * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24227064Sbz * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25227064Sbz * POSSIBILITY OF SUCH DAMAGE. 26227064Sbz */ 27227064Sbz/* 28227064Sbz * File : qla_misc.c 29227064Sbz * Author : David C Somayajulu, Qlogic Corporation, Aliso Viejo, CA 92656. 30227064Sbz */ 31227064Sbz 32227064Sbz#include <sys/cdefs.h> 33227064Sbz__FBSDID("$FreeBSD: head/sys/dev/qlxgb/qla_misc.c 229423 2012-01-03 20:51:26Z dim $"); 34227064Sbz 35227064Sbz#include "qla_os.h" 36227064Sbz#include "qla_reg.h" 37227064Sbz#include "qla_hw.h" 38227064Sbz#include "qla_def.h" 39227064Sbz#include "qla_reg.h" 40227064Sbz#include "qla_inline.h" 41227064Sbz#include "qla_glbl.h" 42227064Sbz#include "qla_dbg.h" 43227064Sbz 44227064Sbz/* 45227064Sbz * structure encapsulating the value to read/write to offchip memory 46227064Sbz */ 47227064Sbztypedef struct _offchip_mem_val { 48227064Sbz uint32_t data_lo; 49227064Sbz uint32_t data_hi; 50227064Sbz uint32_t data_ulo; 51227064Sbz uint32_t data_uhi; 52227064Sbz} offchip_mem_val_t; 53227064Sbz 54227064Sbz#define Q8_ADDR_UNDEFINED 0xFFFFFFFF 55227064Sbz 56227064Sbz/* 57227064Sbz * The index to this table is Bits 20-27 of the indirect register address 58227064Sbz */ 59227064Sbzstatic uint32_t indirect_to_base_map[] = 60227064Sbz { 61227064Sbz Q8_ADDR_UNDEFINED, /* 0x00 */ 62227064Sbz 0x77300000, /* 0x01 */ 63227064Sbz 0x29500000, /* 0x02 */ 64227064Sbz 0x2A500000, /* 0x03 */ 65227064Sbz Q8_ADDR_UNDEFINED, /* 0x04 */ 66227064Sbz 0x0D000000, /* 0x05 */ 67227064Sbz 0x1B100000, /* 0x06 */ 68227064Sbz 0x0E600000, /* 0x07 */ 69227064Sbz 0x0E000000, /* 0x08 */ 70227064Sbz 0x0E100000, /* 0x09 */ 71227064Sbz 0x0E200000, /* 0x0A */ 72227064Sbz 0x0E300000, /* 0x0B */ 73227064Sbz 0x42000000, /* 0x0C */ 74227064Sbz 0x41700000, /* 0x0D */ 75227064Sbz 0x42100000, /* 0x0E */ 76227064Sbz 0x34B00000, /* 0x0F */ 77227064Sbz 0x40500000, /* 0x10 */ 78227064Sbz 0x34000000, /* 0x11 */ 79227064Sbz 0x34100000, /* 0x12 */ 80227064Sbz 0x34200000, /* 0x13 */ 81227064Sbz 0x34300000, /* 0x14 */ 82227064Sbz 0x34500000, /* 0x15 */ 83227064Sbz 0x34400000, /* 0x16 */ 84227064Sbz 0x3C000000, /* 0x17 */ 85227064Sbz 0x3C100000, /* 0x18 */ 86227064Sbz 0x3C200000, /* 0x19 */ 87227064Sbz 0x3C300000, /* 0x1A */ 88227064Sbz Q8_ADDR_UNDEFINED, /* 0x1B */ 89227064Sbz 0x3C400000, /* 0x1C */ 90227064Sbz 0x41000000, /* 0x1D */ 91227064Sbz Q8_ADDR_UNDEFINED, /* 0x1E */ 92227064Sbz 0x0D100000, /* 0x1F */ 93227064Sbz Q8_ADDR_UNDEFINED, /* 0x20 */ 94227064Sbz 0x77300000, /* 0x21 */ 95227064Sbz 0x41600000, /* 0x22 */ 96227064Sbz Q8_ADDR_UNDEFINED, /* 0x23 */ 97227064Sbz Q8_ADDR_UNDEFINED, /* 0x24 */ 98227064Sbz Q8_ADDR_UNDEFINED, /* 0x25 */ 99227064Sbz Q8_ADDR_UNDEFINED, /* 0x26 */ 100227064Sbz Q8_ADDR_UNDEFINED, /* 0x27 */ 101227064Sbz 0x41700000, /* 0x28 */ 102227064Sbz Q8_ADDR_UNDEFINED, /* 0x29 */ 103227064Sbz 0x08900000, /* 0x2A */ 104227064Sbz 0x70A00000, /* 0x2B */ 105227064Sbz 0x70B00000, /* 0x2C */ 106227064Sbz 0x70C00000, /* 0x2D */ 107227064Sbz 0x08D00000, /* 0x2E */ 108227064Sbz 0x08E00000, /* 0x2F */ 109227064Sbz 0x70F00000, /* 0x30 */ 110227064Sbz 0x40500000, /* 0x31 */ 111227064Sbz 0x42000000, /* 0x32 */ 112227064Sbz 0x42100000, /* 0x33 */ 113227064Sbz Q8_ADDR_UNDEFINED, /* 0x34 */ 114227064Sbz 0x08800000, /* 0x35 */ 115227064Sbz 0x09100000, /* 0x36 */ 116227064Sbz 0x71200000, /* 0x37 */ 117227064Sbz 0x40600000, /* 0x38 */ 118227064Sbz Q8_ADDR_UNDEFINED, /* 0x39 */ 119227064Sbz 0x71800000, /* 0x3A */ 120227064Sbz 0x19900000, /* 0x3B */ 121227064Sbz 0x1A900000, /* 0x3C */ 122227064Sbz Q8_ADDR_UNDEFINED, /* 0x3D */ 123227064Sbz 0x34600000, /* 0x3E */ 124227064Sbz Q8_ADDR_UNDEFINED, /* 0x3F */ 125227064Sbz }; 126227064Sbz 127227064Sbz/* 128227064Sbz * Address Translation Table for CRB to offsets from PCI BAR0 129227064Sbz */ 130227064Sbztypedef struct _crb_to_pci { 131227064Sbz uint32_t crb_addr; 132227064Sbz uint32_t pci_addr; 133227064Sbz} crb_to_pci_t; 134227064Sbz 135227064Sbzstatic crb_to_pci_t crbinit_to_pciaddr[] = { 136227064Sbz {(0x088 << 20), (0x035 << 20)}, 137227064Sbz {(0x089 << 20), (0x02A << 20)}, 138227064Sbz {(0x08D << 20), (0x02E << 20)}, 139227064Sbz {(0x08E << 20), (0x02F << 20)}, 140227064Sbz {(0x0C6 << 20), (0x023 << 20)}, 141227064Sbz {(0x0C7 << 20), (0x024 << 20)}, 142227064Sbz {(0x0C8 << 20), (0x025 << 20)}, 143227064Sbz {(0x0D0 << 20), (0x005 << 20)}, 144227064Sbz {(0x0D1 << 20), (0x01F << 20)}, 145227064Sbz {(0x0E0 << 20), (0x008 << 20)}, 146227064Sbz {(0x0E1 << 20), (0x009 << 20)}, 147227064Sbz {(0x0E2 << 20), (0x00A << 20)}, 148227064Sbz {(0x0E3 << 20), (0x00B << 20)}, 149227064Sbz {(0x0E6 << 20), (0x007 << 20)}, 150227064Sbz {(0x199 << 20), (0x03B << 20)}, 151227064Sbz {(0x1B1 << 20), (0x006 << 20)}, 152227064Sbz {(0x295 << 20), (0x002 << 20)}, 153227064Sbz {(0x29A << 20), (0x000 << 20)}, 154227064Sbz {(0x2A5 << 20), (0x003 << 20)}, 155227064Sbz {(0x340 << 20), (0x011 << 20)}, 156227064Sbz {(0x341 << 20), (0x012 << 20)}, 157227064Sbz {(0x342 << 20), (0x013 << 20)}, 158227064Sbz {(0x343 << 20), (0x014 << 20)}, 159227064Sbz {(0x344 << 20), (0x016 << 20)}, 160227064Sbz {(0x345 << 20), (0x015 << 20)}, 161227064Sbz {(0x3C0 << 20), (0x017 << 20)}, 162227064Sbz {(0x3C1 << 20), (0x018 << 20)}, 163227064Sbz {(0x3C2 << 20), (0x019 << 20)}, 164227064Sbz {(0x3C3 << 20), (0x01A << 20)}, 165227064Sbz {(0x3C4 << 20), (0x01C << 20)}, 166227064Sbz {(0x3C5 << 20), (0x01B << 20)}, 167227064Sbz {(0x405 << 20), (0x031 << 20)}, 168227064Sbz {(0x406 << 20), (0x038 << 20)}, 169227064Sbz {(0x410 << 20), (0x01D << 20)}, 170227064Sbz {(0x416 << 20), (0x022 << 20)}, 171227064Sbz {(0x417 << 20), (0x028 << 20)}, 172227064Sbz {(0x420 << 20), (0x032 << 20)}, 173227064Sbz {(0x421 << 20), (0x033 << 20)}, 174227064Sbz {(0x700 << 20), (0x00C << 20)}, 175227064Sbz {(0x701 << 20), (0x00D << 20)}, 176227064Sbz {(0x702 << 20), (0x00E << 20)}, 177227064Sbz {(0x703 << 20), (0x00F << 20)}, 178227064Sbz {(0x704 << 20), (0x010 << 20)}, 179227064Sbz {(0x70A << 20), (0x02B << 20)}, 180227064Sbz {(0x70B << 20), (0x02C << 20)}, 181227064Sbz {(0x70C << 20), (0x02D << 20)}, 182227064Sbz {(0x70F << 20), (0x030 << 20)}, 183227064Sbz {(0x718 << 20), (0x03A << 20)}, 184227064Sbz {(0x758 << 20), (0x026 << 20)}, 185227064Sbz {(0x759 << 20), (0x027 << 20)}, 186227064Sbz {(0x773 << 20), (0x001 << 20)} 187227064Sbz}; 188227064Sbz 189227064Sbz#define Q8_INVALID_ADDRESS (-1) 190227064Sbz#define Q8_ADDR_MASK (0xFFF << 20) 191227064Sbz 192227064Sbztypedef struct _addr_val { 193227064Sbz uint32_t addr; 194227064Sbz uint32_t value; 195227064Sbz uint32_t pci_addr; 196227064Sbz uint32_t ind_addr; 197227064Sbz} addr_val_t; 198227064Sbz 199227064Sbz/* 200227064Sbz * Name: qla_rdwr_indreg32 201227064Sbz * Function: Read/Write an Indirect Register 202227064Sbz */ 203227064Sbzint 204227064Sbzqla_rdwr_indreg32(qla_host_t *ha, uint32_t addr, uint32_t *val, uint32_t rd) 205227064Sbz{ 206227064Sbz uint32_t offset; 207227064Sbz int count = 100; 208227064Sbz 209227064Sbz offset = (addr & 0xFFF00000) >> 20; 210227064Sbz 211227064Sbz if (offset > 0x3F) { 212227064Sbz device_printf(ha->pci_dev, "%s: invalid addr 0x%08x\n", 213227064Sbz __func__, addr); 214227064Sbz return -1; 215227064Sbz } 216227064Sbz 217227064Sbz offset = indirect_to_base_map[offset]; 218227064Sbz if (offset == Q8_ADDR_UNDEFINED) { 219227064Sbz device_printf(ha->pci_dev, "%s: undefined map 0x%08x\n", 220227064Sbz __func__, addr); 221227064Sbz return -1; 222227064Sbz } 223227064Sbz 224227064Sbz offset = offset | (addr & 0x000F0000); 225227064Sbz 226227064Sbz if (qla_sem_lock(ha, Q8_SEM7_LOCK, 0, 0)) { 227227064Sbz device_printf(ha->pci_dev, "%s: SEM7_LOCK failed\n", __func__); 228227064Sbz return (-1); 229227064Sbz } 230227064Sbz 231227064Sbz WRITE_OFFSET32(ha, Q8_CRB_WINDOW_2M, offset); 232227064Sbz 233227064Sbz while (offset != (READ_OFFSET32(ha, Q8_CRB_WINDOW_2M))) { 234227064Sbz count--; 235227064Sbz if (!count) { 236227064Sbz qla_sem_unlock(ha, Q8_SEM7_UNLOCK); 237227064Sbz return -1; 238227064Sbz } 239227064Sbz 240227064Sbz qla_mdelay(__func__, 1); 241227064Sbz } 242227064Sbz 243227064Sbz if (rd) { 244227064Sbz *val = READ_OFFSET32(ha, ((addr & 0xFFFF) | 0x1E0000)); 245227064Sbz } else { 246227064Sbz WRITE_OFFSET32(ha, ((addr & 0xFFFF) | 0x1E0000), *val); 247227064Sbz } 248227064Sbz 249227064Sbz qla_sem_unlock(ha, Q8_SEM7_UNLOCK); 250227064Sbz return 0; 251227064Sbz} 252227064Sbz 253227064Sbz/* 254227064Sbz * Name: qla_rdwr_offchip_mem 255227064Sbz * Function: Read/Write OffChip Memory 256227064Sbz */ 257227064Sbzstatic int 258227064Sbzqla_rdwr_offchip_mem(qla_host_t *ha, uint64_t addr, offchip_mem_val_t *val, 259227064Sbz uint32_t rd) 260227064Sbz{ 261227064Sbz uint32_t count = 100; 262227064Sbz uint32_t data; 263227064Sbz 264227064Sbz WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_ADDR_LO, (uint32_t)addr); 265227064Sbz WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_ADDR_HI, (uint32_t)(addr >> 32)); 266227064Sbz 267227064Sbz if (!rd) { 268227064Sbz WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_WRDATA_LO, val->data_lo); 269227064Sbz WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_WRDATA_HI, val->data_hi); 270227064Sbz WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_WRDATA_ULO, val->data_ulo); 271227064Sbz WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_WRDATA_UHI, val->data_uhi); 272227064Sbz WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_CTRL, 0x07); /* Write */ 273227064Sbz } else { 274227064Sbz WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_CTRL, 0x03); /* Read */ 275227064Sbz } 276227064Sbz 277227064Sbz while (count--) { 278227064Sbz data = READ_OFFSET32(ha, Q8_MIU_TEST_AGT_CTRL); 279227064Sbz if (!(data & BIT_3)) { 280227064Sbz if (rd) { 281227064Sbz val->data_lo = READ_OFFSET32(ha, \ 282227064Sbz Q8_MIU_TEST_AGT_RDDATA_LO); 283227064Sbz val->data_hi = READ_OFFSET32(ha, \ 284227064Sbz Q8_MIU_TEST_AGT_RDDATA_HI); 285227064Sbz val->data_ulo = READ_OFFSET32(ha, \ 286227064Sbz Q8_MIU_TEST_AGT_RDDATA_ULO); 287227064Sbz val->data_uhi = READ_OFFSET32(ha, \ 288227064Sbz Q8_MIU_TEST_AGT_RDDATA_UHI); 289227064Sbz } 290227064Sbz return 0; 291227064Sbz } else 292227064Sbz qla_mdelay(__func__, 1); 293227064Sbz } 294227064Sbz 295227064Sbz device_printf(ha->pci_dev, "%s: failed[0x%08x]\n", __func__, data); 296227064Sbz return (-1); 297227064Sbz} 298227064Sbz 299227064Sbz/* 300227064Sbz * Name: qla_rd_flash32 301227064Sbz * Function: Read Flash Memory 302227064Sbz */ 303227064Sbzint 304227064Sbzqla_rd_flash32(qla_host_t *ha, uint32_t addr, uint32_t *data) 305227064Sbz{ 306227064Sbz uint32_t val; 307227064Sbz uint32_t count = 100; 308227064Sbz 309227064Sbz if (qla_sem_lock(ha, Q8_SEM2_LOCK, 0, 0)) { 310227064Sbz device_printf(ha->pci_dev, "%s: SEM2_LOCK failed\n", __func__); 311227064Sbz return (-1); 312227064Sbz } 313227064Sbz WRITE_OFFSET32(ha, Q8_ROM_LOCKID, 0xa5a5a5a5); 314227064Sbz 315227064Sbz val = addr; 316227064Sbz qla_rdwr_indreg32(ha, Q8_ROM_ADDRESS, &val, 0); 317227064Sbz val = 0; 318227064Sbz qla_rdwr_indreg32(ha, Q8_ROM_DUMMY_BYTE_COUNT, &val, 0); 319227064Sbz val = 3; 320227064Sbz qla_rdwr_indreg32(ha, Q8_ROM_ADDR_BYTE_COUNT, &val, 0); 321227064Sbz 322227064Sbz QLA_USEC_DELAY(100); 323227064Sbz 324227064Sbz val = ROM_OPCODE_FAST_RD; 325227064Sbz qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0); 326227064Sbz 327227064Sbz while (!((val = READ_OFFSET32(ha, Q8_ROM_STATUS)) & BIT_1)) { 328227064Sbz count--; 329227064Sbz if (!count) { 330227064Sbz qla_sem_unlock(ha, Q8_SEM7_UNLOCK); 331227064Sbz return -1; 332227064Sbz } 333227064Sbz } 334227064Sbz 335227064Sbz val = 0; 336227064Sbz qla_rdwr_indreg32(ha, Q8_ROM_DUMMY_BYTE_COUNT, &val, 0); 337227064Sbz qla_rdwr_indreg32(ha, Q8_ROM_ADDR_BYTE_COUNT, &val, 0); 338227064Sbz 339227064Sbz QLA_USEC_DELAY(100); 340227064Sbz 341227064Sbz qla_rdwr_indreg32(ha, Q8_ROM_RD_DATA, data, 1); 342227064Sbz 343227064Sbz qla_sem_unlock(ha, Q8_SEM2_UNLOCK); 344227064Sbz return 0; 345227064Sbz} 346227064Sbz 347227064Sbz/* 348227064Sbz * Name: qla_int_to_pci_addr_map 349227064Sbz * Function: Convert's Internal(CRB) Address to Indirect Address 350227064Sbz */ 351227064Sbzstatic uint32_t 352227064Sbzqla_int_to_pci_addr_map(qla_host_t *ha, uint32_t int_addr) 353227064Sbz{ 354227064Sbz uint32_t crb_to_pci_table_size, i; 355227064Sbz uint32_t addr; 356227064Sbz 357227064Sbz crb_to_pci_table_size = sizeof(crbinit_to_pciaddr)/sizeof(crb_to_pci_t); 358227064Sbz addr = int_addr & Q8_ADDR_MASK; 359227064Sbz 360227064Sbz for (i = 0; i < crb_to_pci_table_size; i++) { 361227064Sbz if (crbinit_to_pciaddr[i].crb_addr == addr) { 362227064Sbz addr = (int_addr & ~Q8_ADDR_MASK) | 363227064Sbz crbinit_to_pciaddr[i].pci_addr; 364227064Sbz return (addr); 365227064Sbz } 366227064Sbz } 367227064Sbz return (Q8_INVALID_ADDRESS); 368227064Sbz} 369227064Sbz 370227064Sbz/* 371227064Sbz * Name: qla_filter_pci_addr 372227064Sbz * Function: Filter's out Indirect Addresses which are not writeable 373227064Sbz */ 374227064Sbzstatic uint32_t 375227064Sbzqla_filter_pci_addr(qla_host_t *ha, uint32_t addr) 376227064Sbz{ 377227064Sbz if ((addr == Q8_INVALID_ADDRESS) || 378227064Sbz (addr == 0x00112040) || 379227064Sbz (addr == 0x00112048) || 380227064Sbz ((addr & 0xFFFF0FFF) == 0x001100C4) || 381227064Sbz ((addr & 0xFFFF0FFF) == 0x001100C8) || 382227064Sbz ((addr & 0x0FF00000) == 0x00200000) || 383227064Sbz (addr == 0x022021FC) || 384227064Sbz (addr == 0x0330001C) || 385227064Sbz (addr == 0x03300024) || 386227064Sbz (addr == 0x033000A8) || 387227064Sbz (addr == 0x033000C8) || 388227064Sbz (addr == 0x033000BC) || 389227064Sbz ((addr & 0x0FF00000) == 0x03A00000) || 390227064Sbz (addr == 0x03B0001C)) 391227064Sbz return (Q8_INVALID_ADDRESS); 392227064Sbz else 393227064Sbz return (addr); 394227064Sbz} 395227064Sbz 396227064Sbz/* 397227064Sbz * Name: qla_crb_init 398227064Sbz * Function: CRB Initialization - first step in the initialization after reset 399227064Sbz * Essentially reads the address/value pairs from address = 0x00 and 400227064Sbz * writes the value into address in the addr/value pair. 401227064Sbz */ 402227064Sbzstatic int 403227064Sbzqla_crb_init(qla_host_t *ha) 404227064Sbz{ 405227064Sbz uint32_t val, sig; 406227064Sbz uint32_t offset, count, i; 407227064Sbz addr_val_t *addr_val_map, *avmap; 408227064Sbz 409227064Sbz qla_rd_flash32(ha, 0, &sig); 410229423Sdim QL_DPRINT2((ha->pci_dev, "%s: val[0] = 0x%08x\n", __func__, sig)); 411227064Sbz 412227064Sbz qla_rd_flash32(ha, 4, &val); 413227064Sbz QL_DPRINT2((ha->pci_dev, "%s: val[4] = 0x%08x\n", __func__, val)); 414227064Sbz 415227064Sbz count = val >> 16; 416227064Sbz offset = val & 0xFFFF; 417227064Sbz offset = offset << 2; 418227064Sbz 419227064Sbz QL_DPRINT2((ha->pci_dev, "%s: [sig,val]=[0x%08x, 0x%08x] %d pairs\n", 420227064Sbz __func__, sig, val, count)); 421227064Sbz 422227064Sbz addr_val_map = avmap = malloc((sizeof(addr_val_t) * count), 423227064Sbz M_QLA8XXXBUF, M_NOWAIT); 424227064Sbz 425227064Sbz if (addr_val_map == NULL) { 426227064Sbz device_printf(ha->pci_dev, "%s: malloc failed\n", __func__); 427227064Sbz return (-1); 428227064Sbz } 429227064Sbz memset(avmap, 0, (sizeof(addr_val_t) * count)); 430227064Sbz 431227064Sbz count = count << 1; 432227064Sbz for (i = 0; i < count; ) { 433227064Sbz qla_rd_flash32(ha, (offset + (i * 4)), &avmap->value); 434227064Sbz i++; 435227064Sbz qla_rd_flash32(ha, (offset + (i * 4)), &avmap->addr); 436227064Sbz i++; 437227064Sbz 438227064Sbz avmap->pci_addr = qla_int_to_pci_addr_map(ha, avmap->addr); 439227064Sbz avmap->ind_addr = qla_filter_pci_addr(ha, avmap->pci_addr); 440227064Sbz 441227064Sbz QL_DPRINT2((ha->pci_dev, 442227064Sbz "%s: [0x%02x][0x%08x:0x%08x:0x%08x] 0x%08x\n", 443227064Sbz __func__, (i >> 1), avmap->addr, avmap->pci_addr, 444227064Sbz avmap->ind_addr, avmap->value)); 445227064Sbz 446227064Sbz if (avmap->ind_addr != Q8_INVALID_ADDRESS) { 447227064Sbz qla_rdwr_indreg32(ha, avmap->ind_addr, &avmap->value,0); 448227064Sbz qla_mdelay(__func__, 1); 449227064Sbz } 450227064Sbz avmap++; 451227064Sbz } 452227064Sbz 453227064Sbz free (addr_val_map, M_QLA8XXXBUF); 454227064Sbz return (0); 455227064Sbz} 456227064Sbz 457227064Sbz/* 458227064Sbz * Name: qla_init_peg_regs 459227064Sbz * Function: Protocol Engine Register Initialization 460227064Sbz */ 461227064Sbzstatic void 462227064Sbzqla_init_peg_regs(qla_host_t *ha) 463227064Sbz{ 464227064Sbz WRITE_OFFSET32(ha, Q8_PEG_D_RESET1, 0x001E); 465227064Sbz WRITE_OFFSET32(ha, Q8_PEG_D_RESET2, 0x0008); 466227064Sbz WRITE_OFFSET32(ha, Q8_PEG_I_RESET, 0x0008); 467227064Sbz WRITE_OFFSET32(ha, Q8_PEG_0_CLR1, 0x0000); 468227064Sbz WRITE_OFFSET32(ha, Q8_PEG_0_CLR2, 0x0000); 469227064Sbz WRITE_OFFSET32(ha, Q8_PEG_1_CLR1, 0x0000); 470227064Sbz WRITE_OFFSET32(ha, Q8_PEG_1_CLR2, 0x0000); 471227064Sbz WRITE_OFFSET32(ha, Q8_PEG_2_CLR1, 0x0000); 472227064Sbz WRITE_OFFSET32(ha, Q8_PEG_2_CLR2, 0x0000); 473227064Sbz WRITE_OFFSET32(ha, Q8_PEG_3_CLR1, 0x0000); 474227064Sbz WRITE_OFFSET32(ha, Q8_PEG_3_CLR2, 0x0000); 475227064Sbz WRITE_OFFSET32(ha, Q8_PEG_4_CLR1, 0x0000); 476227064Sbz WRITE_OFFSET32(ha, Q8_PEG_4_CLR2, 0x0000); 477227064Sbz} 478227064Sbz 479227064Sbz/* 480227064Sbz * Name: qla_load_fw_from_flash 481227064Sbz * Function: Reads the Bootloader from Flash and Loads into Offchip Memory 482227064Sbz */ 483227064Sbzstatic void 484227064Sbzqla_load_fw_from_flash(qla_host_t *ha) 485227064Sbz{ 486227064Sbz uint64_t mem_off = 0x10000; 487227064Sbz uint32_t flash_off = 0x10000; 488227064Sbz uint32_t count; 489227064Sbz offchip_mem_val_t val; 490227064Sbz 491227064Sbz 492227064Sbz /* only bootloader needs to be loaded into memory */ 493227064Sbz for (count = 0; count < 0x20000 ; ) { 494227064Sbz qla_rd_flash32(ha, flash_off, &val.data_lo); 495227064Sbz count = count + 4; 496227064Sbz flash_off = flash_off + 4; 497227064Sbz 498227064Sbz qla_rd_flash32(ha, flash_off, &val.data_hi); 499227064Sbz count = count + 4; 500227064Sbz flash_off = flash_off + 4; 501227064Sbz 502227064Sbz qla_rd_flash32(ha, flash_off, &val.data_ulo); 503227064Sbz count = count + 4; 504227064Sbz flash_off = flash_off + 4; 505227064Sbz 506227064Sbz qla_rd_flash32(ha, flash_off, &val.data_uhi); 507227064Sbz count = count + 4; 508227064Sbz flash_off = flash_off + 4; 509227064Sbz 510227064Sbz qla_rdwr_offchip_mem(ha, mem_off, &val, 0); 511227064Sbz 512227064Sbz mem_off = mem_off + 16; 513227064Sbz } 514227064Sbz return; 515227064Sbz} 516227064Sbz 517227064Sbz/* 518227064Sbz * Name: qla_init_from_flash 519227064Sbz * Function: Performs Initialization which consists of the following sequence 520227064Sbz * - reset 521227064Sbz * - CRB Init 522227064Sbz * - Peg Init 523227064Sbz * - Read the Bootloader from Flash and Load into Offchip Memory 524227064Sbz * - Kick start the bootloader which loads the rest of the firmware 525227064Sbz * and performs the remaining steps in the initialization process. 526227064Sbz */ 527227064Sbzstatic int 528227064Sbzqla_init_from_flash(qla_host_t *ha) 529227064Sbz{ 530227064Sbz uint32_t delay = 300; 531227064Sbz uint32_t data; 532227064Sbz 533227064Sbz qla_hw_reset(ha); 534227064Sbz qla_mdelay(__func__, 100); 535227064Sbz 536227064Sbz qla_crb_init(ha); 537227064Sbz qla_mdelay(__func__, 10); 538227064Sbz 539227064Sbz qla_init_peg_regs(ha); 540227064Sbz qla_mdelay(__func__, 10); 541227064Sbz 542227064Sbz qla_load_fw_from_flash(ha); 543227064Sbz 544227064Sbz WRITE_OFFSET32(ha, Q8_CMDPEG_STATE, 0x00000000); 545227064Sbz WRITE_OFFSET32(ha, Q8_PEG_0_RESET, 0x00001020); 546227064Sbz WRITE_OFFSET32(ha, Q8_ASIC_RESET, 0x0080001E); 547227064Sbz qla_mdelay(__func__, 100); 548227064Sbz 549227064Sbz do { 550227064Sbz data = READ_OFFSET32(ha, Q8_CMDPEG_STATE); 551227064Sbz 552227064Sbz QL_DPRINT2((ha->pci_dev, "%s: func[%d] cmdpegstate 0x%08x\n", 553227064Sbz __func__, ha->pci_func, data)); 554227064Sbz if (data == CMDPEG_PHAN_INIT_COMPLETE) { 555227064Sbz QL_DPRINT2((ha->pci_dev, 556227064Sbz "%s: func[%d] init complete\n", 557227064Sbz __func__, ha->pci_func)); 558227064Sbz return(0); 559227064Sbz } 560227064Sbz qla_mdelay(__func__, 100); 561227064Sbz } while (delay--); 562227064Sbz 563227064Sbz device_printf(ha->pci_dev, 564227064Sbz "%s: func[%d] Q8_PEG_HALT_STATUS1[0x%08x] STATUS2[0x%08x]" 565227064Sbz " HEARTBEAT[0x%08x] RCVPEG_STATE[0x%08x]" 566227064Sbz " CMDPEG_STATE[0x%08x]\n", 567227064Sbz __func__, ha->pci_func, 568227064Sbz (READ_OFFSET32(ha, Q8_PEG_HALT_STATUS1)), 569227064Sbz (READ_OFFSET32(ha, Q8_PEG_HALT_STATUS2)), 570227064Sbz (READ_OFFSET32(ha, Q8_FIRMWARE_HEARTBEAT)), 571227064Sbz (READ_OFFSET32(ha, Q8_RCVPEG_STATE)), data); 572227064Sbz 573227064Sbz return (-1); 574227064Sbz} 575227064Sbz 576227064Sbz/* 577227064Sbz * Name: qla_init_hw 578227064Sbz * Function: Initializes P3+ hardware. 579227064Sbz */ 580227064Sbzint 581227064Sbzqla_init_hw(qla_host_t *ha) 582227064Sbz{ 583227064Sbz device_t dev; 584227064Sbz int ret = 0; 585227064Sbz uint32_t val, delay = 300; 586227064Sbz 587227064Sbz dev = ha->pci_dev; 588227064Sbz 589227064Sbz QL_DPRINT1((dev, "%s: enter\n", __func__)); 590227064Sbz 591227064Sbz qla_mdelay(__func__, 100); 592227064Sbz 593227064Sbz if (ha->pci_func & 0x1) { 594227064Sbz while ((ha->pci_func & 0x1) && delay--) { 595227064Sbz val = READ_OFFSET32(ha, Q8_CMDPEG_STATE); 596227064Sbz 597227064Sbz if (val == CMDPEG_PHAN_INIT_COMPLETE) { 598227064Sbz QL_DPRINT2((dev, 599227064Sbz "%s: func = %d init complete\n", 600227064Sbz __func__, ha->pci_func)); 601227064Sbz qla_mdelay(__func__, 100); 602227064Sbz goto qla_init_exit; 603227064Sbz } 604227064Sbz qla_mdelay(__func__, 100); 605227064Sbz } 606227064Sbz return (-1); 607227064Sbz } 608227064Sbz 609227064Sbz val = READ_OFFSET32(ha, Q8_CMDPEG_STATE); 610227064Sbz 611227064Sbz if (val != CMDPEG_PHAN_INIT_COMPLETE) { 612227064Sbz ret = qla_init_from_flash(ha); 613227064Sbz qla_mdelay(__func__, 100); 614227064Sbz } 615227064Sbz 616227064Sbzqla_init_exit: 617227064Sbz ha->fw_ver_major = READ_OFFSET32(ha, Q8_FW_VER_MAJOR); 618227064Sbz ha->fw_ver_minor = READ_OFFSET32(ha, Q8_FW_VER_MINOR); 619227064Sbz ha->fw_ver_sub = READ_OFFSET32(ha, Q8_FW_VER_SUB); 620227064Sbz ha->fw_ver_build = READ_OFFSET32(ha, Q8_FW_VER_BUILD); 621227064Sbz 622227064Sbz return (ret); 623227064Sbz} 624227064Sbz 625