10bc7cf6fSBjoern A. Zeeb /* 2*088fc971SDavid C Somayajulu * Copyright (c) 2011-2013 Qlogic Corporation 30bc7cf6fSBjoern A. Zeeb * All rights reserved. 40bc7cf6fSBjoern A. Zeeb * 50bc7cf6fSBjoern A. Zeeb * Redistribution and use in source and binary forms, with or without 60bc7cf6fSBjoern A. Zeeb * modification, are permitted provided that the following conditions 70bc7cf6fSBjoern A. Zeeb * are met: 80bc7cf6fSBjoern A. Zeeb * 90bc7cf6fSBjoern A. Zeeb * 1. Redistributions of source code must retain the above copyright 100bc7cf6fSBjoern A. Zeeb * notice, this list of conditions and the following disclaimer. 110bc7cf6fSBjoern A. Zeeb * 2. Redistributions in binary form must reproduce the above copyright 120bc7cf6fSBjoern A. Zeeb * notice, this list of conditions and the following disclaimer in the 130bc7cf6fSBjoern A. Zeeb * documentation and/or other materials provided with the distribution. 140bc7cf6fSBjoern A. Zeeb * 150bc7cf6fSBjoern A. Zeeb * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 160bc7cf6fSBjoern A. Zeeb * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 170bc7cf6fSBjoern A. Zeeb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 180bc7cf6fSBjoern A. Zeeb * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 190bc7cf6fSBjoern A. Zeeb * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 200bc7cf6fSBjoern A. Zeeb * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 210bc7cf6fSBjoern A. Zeeb * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 220bc7cf6fSBjoern A. Zeeb * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 230bc7cf6fSBjoern A. Zeeb * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 240bc7cf6fSBjoern A. Zeeb * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 250bc7cf6fSBjoern A. Zeeb * POSSIBILITY OF SUCH DAMAGE. 260bc7cf6fSBjoern A. Zeeb */ 270bc7cf6fSBjoern A. Zeeb /* 280bc7cf6fSBjoern A. Zeeb * File : qla_misc.c 290bc7cf6fSBjoern A. Zeeb * Author : David C Somayajulu, Qlogic Corporation, Aliso Viejo, CA 92656. 300bc7cf6fSBjoern A. Zeeb */ 310bc7cf6fSBjoern A. Zeeb 320bc7cf6fSBjoern A. Zeeb #include <sys/cdefs.h> 330bc7cf6fSBjoern A. Zeeb __FBSDID("$FreeBSD$"); 340bc7cf6fSBjoern A. Zeeb 350bc7cf6fSBjoern A. Zeeb #include "qla_os.h" 360bc7cf6fSBjoern A. Zeeb #include "qla_reg.h" 370bc7cf6fSBjoern A. Zeeb #include "qla_hw.h" 380bc7cf6fSBjoern A. Zeeb #include "qla_def.h" 390bc7cf6fSBjoern A. Zeeb #include "qla_reg.h" 400bc7cf6fSBjoern A. Zeeb #include "qla_inline.h" 410bc7cf6fSBjoern A. Zeeb #include "qla_glbl.h" 420bc7cf6fSBjoern A. Zeeb #include "qla_dbg.h" 430bc7cf6fSBjoern A. Zeeb 440bc7cf6fSBjoern A. Zeeb /* 450bc7cf6fSBjoern A. Zeeb * structure encapsulating the value to read/write to offchip memory 460bc7cf6fSBjoern A. Zeeb */ 470bc7cf6fSBjoern A. Zeeb typedef struct _offchip_mem_val { 480bc7cf6fSBjoern A. Zeeb uint32_t data_lo; 490bc7cf6fSBjoern A. Zeeb uint32_t data_hi; 500bc7cf6fSBjoern A. Zeeb uint32_t data_ulo; 510bc7cf6fSBjoern A. Zeeb uint32_t data_uhi; 520bc7cf6fSBjoern A. Zeeb } offchip_mem_val_t; 530bc7cf6fSBjoern A. Zeeb 540bc7cf6fSBjoern A. Zeeb #define Q8_ADDR_UNDEFINED 0xFFFFFFFF 550bc7cf6fSBjoern A. Zeeb 560bc7cf6fSBjoern A. Zeeb /* 570bc7cf6fSBjoern A. Zeeb * The index to this table is Bits 20-27 of the indirect register address 580bc7cf6fSBjoern A. Zeeb */ 590bc7cf6fSBjoern A. Zeeb static uint32_t indirect_to_base_map[] = 600bc7cf6fSBjoern A. Zeeb { 610bc7cf6fSBjoern A. Zeeb Q8_ADDR_UNDEFINED, /* 0x00 */ 620bc7cf6fSBjoern A. Zeeb 0x77300000, /* 0x01 */ 630bc7cf6fSBjoern A. Zeeb 0x29500000, /* 0x02 */ 640bc7cf6fSBjoern A. Zeeb 0x2A500000, /* 0x03 */ 650bc7cf6fSBjoern A. Zeeb Q8_ADDR_UNDEFINED, /* 0x04 */ 660bc7cf6fSBjoern A. Zeeb 0x0D000000, /* 0x05 */ 670bc7cf6fSBjoern A. Zeeb 0x1B100000, /* 0x06 */ 680bc7cf6fSBjoern A. Zeeb 0x0E600000, /* 0x07 */ 690bc7cf6fSBjoern A. Zeeb 0x0E000000, /* 0x08 */ 700bc7cf6fSBjoern A. Zeeb 0x0E100000, /* 0x09 */ 710bc7cf6fSBjoern A. Zeeb 0x0E200000, /* 0x0A */ 720bc7cf6fSBjoern A. Zeeb 0x0E300000, /* 0x0B */ 730bc7cf6fSBjoern A. Zeeb 0x42000000, /* 0x0C */ 740bc7cf6fSBjoern A. Zeeb 0x41700000, /* 0x0D */ 750bc7cf6fSBjoern A. Zeeb 0x42100000, /* 0x0E */ 760bc7cf6fSBjoern A. Zeeb 0x34B00000, /* 0x0F */ 770bc7cf6fSBjoern A. Zeeb 0x40500000, /* 0x10 */ 780bc7cf6fSBjoern A. Zeeb 0x34000000, /* 0x11 */ 790bc7cf6fSBjoern A. Zeeb 0x34100000, /* 0x12 */ 800bc7cf6fSBjoern A. Zeeb 0x34200000, /* 0x13 */ 810bc7cf6fSBjoern A. Zeeb 0x34300000, /* 0x14 */ 820bc7cf6fSBjoern A. Zeeb 0x34500000, /* 0x15 */ 830bc7cf6fSBjoern A. Zeeb 0x34400000, /* 0x16 */ 840bc7cf6fSBjoern A. Zeeb 0x3C000000, /* 0x17 */ 850bc7cf6fSBjoern A. Zeeb 0x3C100000, /* 0x18 */ 860bc7cf6fSBjoern A. Zeeb 0x3C200000, /* 0x19 */ 870bc7cf6fSBjoern A. Zeeb 0x3C300000, /* 0x1A */ 880bc7cf6fSBjoern A. Zeeb Q8_ADDR_UNDEFINED, /* 0x1B */ 890bc7cf6fSBjoern A. Zeeb 0x3C400000, /* 0x1C */ 900bc7cf6fSBjoern A. Zeeb 0x41000000, /* 0x1D */ 910bc7cf6fSBjoern A. Zeeb Q8_ADDR_UNDEFINED, /* 0x1E */ 920bc7cf6fSBjoern A. Zeeb 0x0D100000, /* 0x1F */ 930bc7cf6fSBjoern A. Zeeb Q8_ADDR_UNDEFINED, /* 0x20 */ 940bc7cf6fSBjoern A. Zeeb 0x77300000, /* 0x21 */ 950bc7cf6fSBjoern A. Zeeb 0x41600000, /* 0x22 */ 960bc7cf6fSBjoern A. Zeeb Q8_ADDR_UNDEFINED, /* 0x23 */ 970bc7cf6fSBjoern A. Zeeb Q8_ADDR_UNDEFINED, /* 0x24 */ 980bc7cf6fSBjoern A. Zeeb Q8_ADDR_UNDEFINED, /* 0x25 */ 990bc7cf6fSBjoern A. Zeeb Q8_ADDR_UNDEFINED, /* 0x26 */ 1000bc7cf6fSBjoern A. Zeeb Q8_ADDR_UNDEFINED, /* 0x27 */ 1010bc7cf6fSBjoern A. Zeeb 0x41700000, /* 0x28 */ 1020bc7cf6fSBjoern A. Zeeb Q8_ADDR_UNDEFINED, /* 0x29 */ 1030bc7cf6fSBjoern A. Zeeb 0x08900000, /* 0x2A */ 1040bc7cf6fSBjoern A. Zeeb 0x70A00000, /* 0x2B */ 1050bc7cf6fSBjoern A. Zeeb 0x70B00000, /* 0x2C */ 1060bc7cf6fSBjoern A. Zeeb 0x70C00000, /* 0x2D */ 1070bc7cf6fSBjoern A. Zeeb 0x08D00000, /* 0x2E */ 1080bc7cf6fSBjoern A. Zeeb 0x08E00000, /* 0x2F */ 1090bc7cf6fSBjoern A. Zeeb 0x70F00000, /* 0x30 */ 1100bc7cf6fSBjoern A. Zeeb 0x40500000, /* 0x31 */ 1110bc7cf6fSBjoern A. Zeeb 0x42000000, /* 0x32 */ 1120bc7cf6fSBjoern A. Zeeb 0x42100000, /* 0x33 */ 1130bc7cf6fSBjoern A. Zeeb Q8_ADDR_UNDEFINED, /* 0x34 */ 1140bc7cf6fSBjoern A. Zeeb 0x08800000, /* 0x35 */ 1150bc7cf6fSBjoern A. Zeeb 0x09100000, /* 0x36 */ 1160bc7cf6fSBjoern A. Zeeb 0x71200000, /* 0x37 */ 1170bc7cf6fSBjoern A. Zeeb 0x40600000, /* 0x38 */ 1180bc7cf6fSBjoern A. Zeeb Q8_ADDR_UNDEFINED, /* 0x39 */ 1190bc7cf6fSBjoern A. Zeeb 0x71800000, /* 0x3A */ 1200bc7cf6fSBjoern A. Zeeb 0x19900000, /* 0x3B */ 1210bc7cf6fSBjoern A. Zeeb 0x1A900000, /* 0x3C */ 1220bc7cf6fSBjoern A. Zeeb Q8_ADDR_UNDEFINED, /* 0x3D */ 1230bc7cf6fSBjoern A. Zeeb 0x34600000, /* 0x3E */ 1240bc7cf6fSBjoern A. Zeeb Q8_ADDR_UNDEFINED, /* 0x3F */ 1250bc7cf6fSBjoern A. Zeeb }; 1260bc7cf6fSBjoern A. Zeeb 1270bc7cf6fSBjoern A. Zeeb /* 1280bc7cf6fSBjoern A. Zeeb * Address Translation Table for CRB to offsets from PCI BAR0 1290bc7cf6fSBjoern A. Zeeb */ 1300bc7cf6fSBjoern A. Zeeb typedef struct _crb_to_pci { 1310bc7cf6fSBjoern A. Zeeb uint32_t crb_addr; 1320bc7cf6fSBjoern A. Zeeb uint32_t pci_addr; 1330bc7cf6fSBjoern A. Zeeb } crb_to_pci_t; 1340bc7cf6fSBjoern A. Zeeb 1350bc7cf6fSBjoern A. Zeeb static crb_to_pci_t crbinit_to_pciaddr[] = { 1360bc7cf6fSBjoern A. Zeeb {(0x088 << 20), (0x035 << 20)}, 1370bc7cf6fSBjoern A. Zeeb {(0x089 << 20), (0x02A << 20)}, 1380bc7cf6fSBjoern A. Zeeb {(0x08D << 20), (0x02E << 20)}, 1390bc7cf6fSBjoern A. Zeeb {(0x08E << 20), (0x02F << 20)}, 1400bc7cf6fSBjoern A. Zeeb {(0x0C6 << 20), (0x023 << 20)}, 1410bc7cf6fSBjoern A. Zeeb {(0x0C7 << 20), (0x024 << 20)}, 1420bc7cf6fSBjoern A. Zeeb {(0x0C8 << 20), (0x025 << 20)}, 1430bc7cf6fSBjoern A. Zeeb {(0x0D0 << 20), (0x005 << 20)}, 1440bc7cf6fSBjoern A. Zeeb {(0x0D1 << 20), (0x01F << 20)}, 1450bc7cf6fSBjoern A. Zeeb {(0x0E0 << 20), (0x008 << 20)}, 1460bc7cf6fSBjoern A. Zeeb {(0x0E1 << 20), (0x009 << 20)}, 1470bc7cf6fSBjoern A. Zeeb {(0x0E2 << 20), (0x00A << 20)}, 1480bc7cf6fSBjoern A. Zeeb {(0x0E3 << 20), (0x00B << 20)}, 1490bc7cf6fSBjoern A. Zeeb {(0x0E6 << 20), (0x007 << 20)}, 1500bc7cf6fSBjoern A. Zeeb {(0x199 << 20), (0x03B << 20)}, 1510bc7cf6fSBjoern A. Zeeb {(0x1B1 << 20), (0x006 << 20)}, 1520bc7cf6fSBjoern A. Zeeb {(0x295 << 20), (0x002 << 20)}, 1530bc7cf6fSBjoern A. Zeeb {(0x29A << 20), (0x000 << 20)}, 1540bc7cf6fSBjoern A. Zeeb {(0x2A5 << 20), (0x003 << 20)}, 1550bc7cf6fSBjoern A. Zeeb {(0x340 << 20), (0x011 << 20)}, 1560bc7cf6fSBjoern A. Zeeb {(0x341 << 20), (0x012 << 20)}, 1570bc7cf6fSBjoern A. Zeeb {(0x342 << 20), (0x013 << 20)}, 1580bc7cf6fSBjoern A. Zeeb {(0x343 << 20), (0x014 << 20)}, 1590bc7cf6fSBjoern A. Zeeb {(0x344 << 20), (0x016 << 20)}, 1600bc7cf6fSBjoern A. Zeeb {(0x345 << 20), (0x015 << 20)}, 1610bc7cf6fSBjoern A. Zeeb {(0x3C0 << 20), (0x017 << 20)}, 1620bc7cf6fSBjoern A. Zeeb {(0x3C1 << 20), (0x018 << 20)}, 1630bc7cf6fSBjoern A. Zeeb {(0x3C2 << 20), (0x019 << 20)}, 1640bc7cf6fSBjoern A. Zeeb {(0x3C3 << 20), (0x01A << 20)}, 1650bc7cf6fSBjoern A. Zeeb {(0x3C4 << 20), (0x01C << 20)}, 1660bc7cf6fSBjoern A. Zeeb {(0x3C5 << 20), (0x01B << 20)}, 1670bc7cf6fSBjoern A. Zeeb {(0x405 << 20), (0x031 << 20)}, 1680bc7cf6fSBjoern A. Zeeb {(0x406 << 20), (0x038 << 20)}, 1690bc7cf6fSBjoern A. Zeeb {(0x410 << 20), (0x01D << 20)}, 1700bc7cf6fSBjoern A. Zeeb {(0x416 << 20), (0x022 << 20)}, 1710bc7cf6fSBjoern A. Zeeb {(0x417 << 20), (0x028 << 20)}, 1720bc7cf6fSBjoern A. Zeeb {(0x420 << 20), (0x032 << 20)}, 1730bc7cf6fSBjoern A. Zeeb {(0x421 << 20), (0x033 << 20)}, 1740bc7cf6fSBjoern A. Zeeb {(0x700 << 20), (0x00C << 20)}, 1750bc7cf6fSBjoern A. Zeeb {(0x701 << 20), (0x00D << 20)}, 1760bc7cf6fSBjoern A. Zeeb {(0x702 << 20), (0x00E << 20)}, 1770bc7cf6fSBjoern A. Zeeb {(0x703 << 20), (0x00F << 20)}, 1780bc7cf6fSBjoern A. Zeeb {(0x704 << 20), (0x010 << 20)}, 1790bc7cf6fSBjoern A. Zeeb {(0x70A << 20), (0x02B << 20)}, 1800bc7cf6fSBjoern A. Zeeb {(0x70B << 20), (0x02C << 20)}, 1810bc7cf6fSBjoern A. Zeeb {(0x70C << 20), (0x02D << 20)}, 1820bc7cf6fSBjoern A. Zeeb {(0x70F << 20), (0x030 << 20)}, 1830bc7cf6fSBjoern A. Zeeb {(0x718 << 20), (0x03A << 20)}, 1840bc7cf6fSBjoern A. Zeeb {(0x758 << 20), (0x026 << 20)}, 1850bc7cf6fSBjoern A. Zeeb {(0x759 << 20), (0x027 << 20)}, 1860bc7cf6fSBjoern A. Zeeb {(0x773 << 20), (0x001 << 20)} 1870bc7cf6fSBjoern A. Zeeb }; 1880bc7cf6fSBjoern A. Zeeb 1890bc7cf6fSBjoern A. Zeeb #define Q8_INVALID_ADDRESS (-1) 1900bc7cf6fSBjoern A. Zeeb #define Q8_ADDR_MASK (0xFFF << 20) 1910bc7cf6fSBjoern A. Zeeb 1920bc7cf6fSBjoern A. Zeeb typedef struct _addr_val { 1930bc7cf6fSBjoern A. Zeeb uint32_t addr; 1940bc7cf6fSBjoern A. Zeeb uint32_t value; 1950bc7cf6fSBjoern A. Zeeb uint32_t pci_addr; 1960bc7cf6fSBjoern A. Zeeb uint32_t ind_addr; 1970bc7cf6fSBjoern A. Zeeb } addr_val_t; 1980bc7cf6fSBjoern A. Zeeb 1990bc7cf6fSBjoern A. Zeeb /* 2000bc7cf6fSBjoern A. Zeeb * Name: qla_rdwr_indreg32 2010bc7cf6fSBjoern A. Zeeb * Function: Read/Write an Indirect Register 2020bc7cf6fSBjoern A. Zeeb */ 2030bc7cf6fSBjoern A. Zeeb int 2040bc7cf6fSBjoern A. Zeeb qla_rdwr_indreg32(qla_host_t *ha, uint32_t addr, uint32_t *val, uint32_t rd) 2050bc7cf6fSBjoern A. Zeeb { 2060bc7cf6fSBjoern A. Zeeb uint32_t offset; 2070bc7cf6fSBjoern A. Zeeb int count = 100; 2080bc7cf6fSBjoern A. Zeeb 2090bc7cf6fSBjoern A. Zeeb offset = (addr & 0xFFF00000) >> 20; 2100bc7cf6fSBjoern A. Zeeb 2110bc7cf6fSBjoern A. Zeeb if (offset > 0x3F) { 2120bc7cf6fSBjoern A. Zeeb device_printf(ha->pci_dev, "%s: invalid addr 0x%08x\n", 2130bc7cf6fSBjoern A. Zeeb __func__, addr); 2140bc7cf6fSBjoern A. Zeeb return -1; 2150bc7cf6fSBjoern A. Zeeb } 2160bc7cf6fSBjoern A. Zeeb 2170bc7cf6fSBjoern A. Zeeb offset = indirect_to_base_map[offset]; 2180bc7cf6fSBjoern A. Zeeb if (offset == Q8_ADDR_UNDEFINED) { 2190bc7cf6fSBjoern A. Zeeb device_printf(ha->pci_dev, "%s: undefined map 0x%08x\n", 2200bc7cf6fSBjoern A. Zeeb __func__, addr); 2210bc7cf6fSBjoern A. Zeeb return -1; 2220bc7cf6fSBjoern A. Zeeb } 2230bc7cf6fSBjoern A. Zeeb 2240bc7cf6fSBjoern A. Zeeb offset = offset | (addr & 0x000F0000); 2250bc7cf6fSBjoern A. Zeeb 2260bc7cf6fSBjoern A. Zeeb if (qla_sem_lock(ha, Q8_SEM7_LOCK, 0, 0)) { 2270bc7cf6fSBjoern A. Zeeb device_printf(ha->pci_dev, "%s: SEM7_LOCK failed\n", __func__); 2280bc7cf6fSBjoern A. Zeeb return (-1); 2290bc7cf6fSBjoern A. Zeeb } 2300bc7cf6fSBjoern A. Zeeb 2310bc7cf6fSBjoern A. Zeeb WRITE_OFFSET32(ha, Q8_CRB_WINDOW_2M, offset); 2320bc7cf6fSBjoern A. Zeeb 2330bc7cf6fSBjoern A. Zeeb while (offset != (READ_OFFSET32(ha, Q8_CRB_WINDOW_2M))) { 2340bc7cf6fSBjoern A. Zeeb count--; 2350bc7cf6fSBjoern A. Zeeb if (!count) { 2360bc7cf6fSBjoern A. Zeeb qla_sem_unlock(ha, Q8_SEM7_UNLOCK); 2370bc7cf6fSBjoern A. Zeeb return -1; 2380bc7cf6fSBjoern A. Zeeb } 2390bc7cf6fSBjoern A. Zeeb 2400bc7cf6fSBjoern A. Zeeb qla_mdelay(__func__, 1); 2410bc7cf6fSBjoern A. Zeeb } 2420bc7cf6fSBjoern A. Zeeb 2430bc7cf6fSBjoern A. Zeeb if (rd) { 2440bc7cf6fSBjoern A. Zeeb *val = READ_OFFSET32(ha, ((addr & 0xFFFF) | 0x1E0000)); 2450bc7cf6fSBjoern A. Zeeb } else { 2460bc7cf6fSBjoern A. Zeeb WRITE_OFFSET32(ha, ((addr & 0xFFFF) | 0x1E0000), *val); 2470bc7cf6fSBjoern A. Zeeb } 2480bc7cf6fSBjoern A. Zeeb 2490bc7cf6fSBjoern A. Zeeb qla_sem_unlock(ha, Q8_SEM7_UNLOCK); 2500bc7cf6fSBjoern A. Zeeb return 0; 2510bc7cf6fSBjoern A. Zeeb } 2520bc7cf6fSBjoern A. Zeeb 2530bc7cf6fSBjoern A. Zeeb /* 2540bc7cf6fSBjoern A. Zeeb * Name: qla_rdwr_offchip_mem 2550bc7cf6fSBjoern A. Zeeb * Function: Read/Write OffChip Memory 2560bc7cf6fSBjoern A. Zeeb */ 2570bc7cf6fSBjoern A. Zeeb static int 2580bc7cf6fSBjoern A. Zeeb qla_rdwr_offchip_mem(qla_host_t *ha, uint64_t addr, offchip_mem_val_t *val, 2590bc7cf6fSBjoern A. Zeeb uint32_t rd) 2600bc7cf6fSBjoern A. Zeeb { 2610bc7cf6fSBjoern A. Zeeb uint32_t count = 100; 2620bc7cf6fSBjoern A. Zeeb uint32_t data; 2630bc7cf6fSBjoern A. Zeeb 2640bc7cf6fSBjoern A. Zeeb WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_ADDR_LO, (uint32_t)addr); 2650bc7cf6fSBjoern A. Zeeb WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_ADDR_HI, (uint32_t)(addr >> 32)); 2660bc7cf6fSBjoern A. Zeeb 2670bc7cf6fSBjoern A. Zeeb if (!rd) { 2680bc7cf6fSBjoern A. Zeeb WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_WRDATA_LO, val->data_lo); 2690bc7cf6fSBjoern A. Zeeb WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_WRDATA_HI, val->data_hi); 2700bc7cf6fSBjoern A. Zeeb WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_WRDATA_ULO, val->data_ulo); 2710bc7cf6fSBjoern A. Zeeb WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_WRDATA_UHI, val->data_uhi); 2720bc7cf6fSBjoern A. Zeeb WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_CTRL, 0x07); /* Write */ 2730bc7cf6fSBjoern A. Zeeb } else { 2740bc7cf6fSBjoern A. Zeeb WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_CTRL, 0x03); /* Read */ 2750bc7cf6fSBjoern A. Zeeb } 2760bc7cf6fSBjoern A. Zeeb 2770bc7cf6fSBjoern A. Zeeb while (count--) { 2780bc7cf6fSBjoern A. Zeeb data = READ_OFFSET32(ha, Q8_MIU_TEST_AGT_CTRL); 2790bc7cf6fSBjoern A. Zeeb if (!(data & BIT_3)) { 2800bc7cf6fSBjoern A. Zeeb if (rd) { 2810bc7cf6fSBjoern A. Zeeb val->data_lo = READ_OFFSET32(ha, \ 2820bc7cf6fSBjoern A. Zeeb Q8_MIU_TEST_AGT_RDDATA_LO); 2830bc7cf6fSBjoern A. Zeeb val->data_hi = READ_OFFSET32(ha, \ 2840bc7cf6fSBjoern A. Zeeb Q8_MIU_TEST_AGT_RDDATA_HI); 2850bc7cf6fSBjoern A. Zeeb val->data_ulo = READ_OFFSET32(ha, \ 2860bc7cf6fSBjoern A. Zeeb Q8_MIU_TEST_AGT_RDDATA_ULO); 2870bc7cf6fSBjoern A. Zeeb val->data_uhi = READ_OFFSET32(ha, \ 2880bc7cf6fSBjoern A. Zeeb Q8_MIU_TEST_AGT_RDDATA_UHI); 2890bc7cf6fSBjoern A. Zeeb } 2900bc7cf6fSBjoern A. Zeeb return 0; 2910bc7cf6fSBjoern A. Zeeb } else 2920bc7cf6fSBjoern A. Zeeb qla_mdelay(__func__, 1); 2930bc7cf6fSBjoern A. Zeeb } 2940bc7cf6fSBjoern A. Zeeb 2950bc7cf6fSBjoern A. Zeeb device_printf(ha->pci_dev, "%s: failed[0x%08x]\n", __func__, data); 2960bc7cf6fSBjoern A. Zeeb return (-1); 2970bc7cf6fSBjoern A. Zeeb } 2980bc7cf6fSBjoern A. Zeeb 2990bc7cf6fSBjoern A. Zeeb /* 3000bc7cf6fSBjoern A. Zeeb * Name: qla_rd_flash32 3010bc7cf6fSBjoern A. Zeeb * Function: Read Flash Memory 3020bc7cf6fSBjoern A. Zeeb */ 3030bc7cf6fSBjoern A. Zeeb int 3040bc7cf6fSBjoern A. Zeeb qla_rd_flash32(qla_host_t *ha, uint32_t addr, uint32_t *data) 3050bc7cf6fSBjoern A. Zeeb { 3060bc7cf6fSBjoern A. Zeeb uint32_t val; 3070bc7cf6fSBjoern A. Zeeb uint32_t count = 100; 3080bc7cf6fSBjoern A. Zeeb 3090bc7cf6fSBjoern A. Zeeb if (qla_sem_lock(ha, Q8_SEM2_LOCK, 0, 0)) { 3100bc7cf6fSBjoern A. Zeeb device_printf(ha->pci_dev, "%s: SEM2_LOCK failed\n", __func__); 3110bc7cf6fSBjoern A. Zeeb return (-1); 3120bc7cf6fSBjoern A. Zeeb } 3130bc7cf6fSBjoern A. Zeeb WRITE_OFFSET32(ha, Q8_ROM_LOCKID, 0xa5a5a5a5); 3140bc7cf6fSBjoern A. Zeeb 3150bc7cf6fSBjoern A. Zeeb val = addr; 3160bc7cf6fSBjoern A. Zeeb qla_rdwr_indreg32(ha, Q8_ROM_ADDRESS, &val, 0); 3170bc7cf6fSBjoern A. Zeeb val = 0; 3180bc7cf6fSBjoern A. Zeeb qla_rdwr_indreg32(ha, Q8_ROM_DUMMY_BYTE_COUNT, &val, 0); 3190bc7cf6fSBjoern A. Zeeb val = 3; 3200bc7cf6fSBjoern A. Zeeb qla_rdwr_indreg32(ha, Q8_ROM_ADDR_BYTE_COUNT, &val, 0); 3210bc7cf6fSBjoern A. Zeeb 3220bc7cf6fSBjoern A. Zeeb QLA_USEC_DELAY(100); 3230bc7cf6fSBjoern A. Zeeb 3240bc7cf6fSBjoern A. Zeeb val = ROM_OPCODE_FAST_RD; 3250bc7cf6fSBjoern A. Zeeb qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0); 3260bc7cf6fSBjoern A. Zeeb 3270bc7cf6fSBjoern A. Zeeb while (!((val = READ_OFFSET32(ha, Q8_ROM_STATUS)) & BIT_1)) { 3280bc7cf6fSBjoern A. Zeeb count--; 3290bc7cf6fSBjoern A. Zeeb if (!count) { 3300bc7cf6fSBjoern A. Zeeb qla_sem_unlock(ha, Q8_SEM7_UNLOCK); 3310bc7cf6fSBjoern A. Zeeb return -1; 3320bc7cf6fSBjoern A. Zeeb } 3330bc7cf6fSBjoern A. Zeeb } 3340bc7cf6fSBjoern A. Zeeb 3350bc7cf6fSBjoern A. Zeeb val = 0; 3360bc7cf6fSBjoern A. Zeeb qla_rdwr_indreg32(ha, Q8_ROM_DUMMY_BYTE_COUNT, &val, 0); 3370bc7cf6fSBjoern A. Zeeb qla_rdwr_indreg32(ha, Q8_ROM_ADDR_BYTE_COUNT, &val, 0); 3380bc7cf6fSBjoern A. Zeeb 3390bc7cf6fSBjoern A. Zeeb QLA_USEC_DELAY(100); 3400bc7cf6fSBjoern A. Zeeb 3410bc7cf6fSBjoern A. Zeeb qla_rdwr_indreg32(ha, Q8_ROM_RD_DATA, data, 1); 3420bc7cf6fSBjoern A. Zeeb 3430bc7cf6fSBjoern A. Zeeb qla_sem_unlock(ha, Q8_SEM2_UNLOCK); 3440bc7cf6fSBjoern A. Zeeb return 0; 3450bc7cf6fSBjoern A. Zeeb } 3460bc7cf6fSBjoern A. Zeeb 347*088fc971SDavid C Somayajulu static int 348*088fc971SDavid C Somayajulu qla_p3p_sem_lock2(qla_host_t *ha) 349*088fc971SDavid C Somayajulu { 350*088fc971SDavid C Somayajulu if (qla_sem_lock(ha, Q8_SEM2_LOCK, 0, 0)) { 351*088fc971SDavid C Somayajulu device_printf(ha->pci_dev, "%s: SEM2_LOCK failed\n", __func__); 352*088fc971SDavid C Somayajulu return (-1); 353*088fc971SDavid C Somayajulu } 354*088fc971SDavid C Somayajulu WRITE_OFFSET32(ha, Q8_ROM_LOCKID, 0xa5a5a5a5); 355*088fc971SDavid C Somayajulu return (0); 356*088fc971SDavid C Somayajulu } 357*088fc971SDavid C Somayajulu 3580bc7cf6fSBjoern A. Zeeb /* 3590bc7cf6fSBjoern A. Zeeb * Name: qla_int_to_pci_addr_map 3600bc7cf6fSBjoern A. Zeeb * Function: Convert's Internal(CRB) Address to Indirect Address 3610bc7cf6fSBjoern A. Zeeb */ 3620bc7cf6fSBjoern A. Zeeb static uint32_t 3630bc7cf6fSBjoern A. Zeeb qla_int_to_pci_addr_map(qla_host_t *ha, uint32_t int_addr) 3640bc7cf6fSBjoern A. Zeeb { 3650bc7cf6fSBjoern A. Zeeb uint32_t crb_to_pci_table_size, i; 3660bc7cf6fSBjoern A. Zeeb uint32_t addr; 3670bc7cf6fSBjoern A. Zeeb 3680bc7cf6fSBjoern A. Zeeb crb_to_pci_table_size = sizeof(crbinit_to_pciaddr)/sizeof(crb_to_pci_t); 3690bc7cf6fSBjoern A. Zeeb addr = int_addr & Q8_ADDR_MASK; 3700bc7cf6fSBjoern A. Zeeb 3710bc7cf6fSBjoern A. Zeeb for (i = 0; i < crb_to_pci_table_size; i++) { 3720bc7cf6fSBjoern A. Zeeb if (crbinit_to_pciaddr[i].crb_addr == addr) { 3730bc7cf6fSBjoern A. Zeeb addr = (int_addr & ~Q8_ADDR_MASK) | 3740bc7cf6fSBjoern A. Zeeb crbinit_to_pciaddr[i].pci_addr; 3750bc7cf6fSBjoern A. Zeeb return (addr); 3760bc7cf6fSBjoern A. Zeeb } 3770bc7cf6fSBjoern A. Zeeb } 3780bc7cf6fSBjoern A. Zeeb return (Q8_INVALID_ADDRESS); 3790bc7cf6fSBjoern A. Zeeb } 3800bc7cf6fSBjoern A. Zeeb 3810bc7cf6fSBjoern A. Zeeb /* 3820bc7cf6fSBjoern A. Zeeb * Name: qla_filter_pci_addr 3830bc7cf6fSBjoern A. Zeeb * Function: Filter's out Indirect Addresses which are not writeable 3840bc7cf6fSBjoern A. Zeeb */ 3850bc7cf6fSBjoern A. Zeeb static uint32_t 3860bc7cf6fSBjoern A. Zeeb qla_filter_pci_addr(qla_host_t *ha, uint32_t addr) 3870bc7cf6fSBjoern A. Zeeb { 3880bc7cf6fSBjoern A. Zeeb if ((addr == Q8_INVALID_ADDRESS) || 3890bc7cf6fSBjoern A. Zeeb (addr == 0x00112040) || 3900bc7cf6fSBjoern A. Zeeb (addr == 0x00112048) || 3910bc7cf6fSBjoern A. Zeeb ((addr & 0xFFFF0FFF) == 0x001100C4) || 3920bc7cf6fSBjoern A. Zeeb ((addr & 0xFFFF0FFF) == 0x001100C8) || 3930bc7cf6fSBjoern A. Zeeb ((addr & 0x0FF00000) == 0x00200000) || 3940bc7cf6fSBjoern A. Zeeb (addr == 0x022021FC) || 3950bc7cf6fSBjoern A. Zeeb (addr == 0x0330001C) || 3960bc7cf6fSBjoern A. Zeeb (addr == 0x03300024) || 3970bc7cf6fSBjoern A. Zeeb (addr == 0x033000A8) || 3980bc7cf6fSBjoern A. Zeeb (addr == 0x033000C8) || 3990bc7cf6fSBjoern A. Zeeb (addr == 0x033000BC) || 4000bc7cf6fSBjoern A. Zeeb ((addr & 0x0FF00000) == 0x03A00000) || 4010bc7cf6fSBjoern A. Zeeb (addr == 0x03B0001C)) 4020bc7cf6fSBjoern A. Zeeb return (Q8_INVALID_ADDRESS); 4030bc7cf6fSBjoern A. Zeeb else 4040bc7cf6fSBjoern A. Zeeb return (addr); 4050bc7cf6fSBjoern A. Zeeb } 4060bc7cf6fSBjoern A. Zeeb 4070bc7cf6fSBjoern A. Zeeb /* 4080bc7cf6fSBjoern A. Zeeb * Name: qla_crb_init 4090bc7cf6fSBjoern A. Zeeb * Function: CRB Initialization - first step in the initialization after reset 4100bc7cf6fSBjoern A. Zeeb * Essentially reads the address/value pairs from address = 0x00 and 4110bc7cf6fSBjoern A. Zeeb * writes the value into address in the addr/value pair. 4120bc7cf6fSBjoern A. Zeeb */ 4130bc7cf6fSBjoern A. Zeeb static int 4140bc7cf6fSBjoern A. Zeeb qla_crb_init(qla_host_t *ha) 4150bc7cf6fSBjoern A. Zeeb { 416*088fc971SDavid C Somayajulu uint32_t val = 0, sig = 0; 4170bc7cf6fSBjoern A. Zeeb uint32_t offset, count, i; 4180bc7cf6fSBjoern A. Zeeb addr_val_t *addr_val_map, *avmap; 4190bc7cf6fSBjoern A. Zeeb 4200bc7cf6fSBjoern A. Zeeb qla_rd_flash32(ha, 0, &sig); 4217c864d7dSDimitry Andric QL_DPRINT2((ha->pci_dev, "%s: val[0] = 0x%08x\n", __func__, sig)); 4220bc7cf6fSBjoern A. Zeeb 4230bc7cf6fSBjoern A. Zeeb qla_rd_flash32(ha, 4, &val); 4240bc7cf6fSBjoern A. Zeeb QL_DPRINT2((ha->pci_dev, "%s: val[4] = 0x%08x\n", __func__, val)); 4250bc7cf6fSBjoern A. Zeeb 4260bc7cf6fSBjoern A. Zeeb count = val >> 16; 4270bc7cf6fSBjoern A. Zeeb offset = val & 0xFFFF; 4280bc7cf6fSBjoern A. Zeeb offset = offset << 2; 4290bc7cf6fSBjoern A. Zeeb 4300bc7cf6fSBjoern A. Zeeb QL_DPRINT2((ha->pci_dev, "%s: [sig,val]=[0x%08x, 0x%08x] %d pairs\n", 4310bc7cf6fSBjoern A. Zeeb __func__, sig, val, count)); 4320bc7cf6fSBjoern A. Zeeb 4330bc7cf6fSBjoern A. Zeeb addr_val_map = avmap = malloc((sizeof(addr_val_t) * count), 4340bc7cf6fSBjoern A. Zeeb M_QLA8XXXBUF, M_NOWAIT); 4350bc7cf6fSBjoern A. Zeeb 4360bc7cf6fSBjoern A. Zeeb if (addr_val_map == NULL) { 4370bc7cf6fSBjoern A. Zeeb device_printf(ha->pci_dev, "%s: malloc failed\n", __func__); 4380bc7cf6fSBjoern A. Zeeb return (-1); 4390bc7cf6fSBjoern A. Zeeb } 4400bc7cf6fSBjoern A. Zeeb memset(avmap, 0, (sizeof(addr_val_t) * count)); 4410bc7cf6fSBjoern A. Zeeb 4420bc7cf6fSBjoern A. Zeeb count = count << 1; 4430bc7cf6fSBjoern A. Zeeb for (i = 0; i < count; ) { 4440bc7cf6fSBjoern A. Zeeb qla_rd_flash32(ha, (offset + (i * 4)), &avmap->value); 4450bc7cf6fSBjoern A. Zeeb i++; 4460bc7cf6fSBjoern A. Zeeb qla_rd_flash32(ha, (offset + (i * 4)), &avmap->addr); 4470bc7cf6fSBjoern A. Zeeb i++; 4480bc7cf6fSBjoern A. Zeeb 4490bc7cf6fSBjoern A. Zeeb avmap->pci_addr = qla_int_to_pci_addr_map(ha, avmap->addr); 4500bc7cf6fSBjoern A. Zeeb avmap->ind_addr = qla_filter_pci_addr(ha, avmap->pci_addr); 4510bc7cf6fSBjoern A. Zeeb 4520bc7cf6fSBjoern A. Zeeb QL_DPRINT2((ha->pci_dev, 4530bc7cf6fSBjoern A. Zeeb "%s: [0x%02x][0x%08x:0x%08x:0x%08x] 0x%08x\n", 4540bc7cf6fSBjoern A. Zeeb __func__, (i >> 1), avmap->addr, avmap->pci_addr, 4550bc7cf6fSBjoern A. Zeeb avmap->ind_addr, avmap->value)); 4560bc7cf6fSBjoern A. Zeeb 4570bc7cf6fSBjoern A. Zeeb if (avmap->ind_addr != Q8_INVALID_ADDRESS) { 4580bc7cf6fSBjoern A. Zeeb qla_rdwr_indreg32(ha, avmap->ind_addr, &avmap->value,0); 4590bc7cf6fSBjoern A. Zeeb qla_mdelay(__func__, 1); 4600bc7cf6fSBjoern A. Zeeb } 4610bc7cf6fSBjoern A. Zeeb avmap++; 4620bc7cf6fSBjoern A. Zeeb } 4630bc7cf6fSBjoern A. Zeeb 4640bc7cf6fSBjoern A. Zeeb free (addr_val_map, M_QLA8XXXBUF); 4650bc7cf6fSBjoern A. Zeeb return (0); 4660bc7cf6fSBjoern A. Zeeb } 4670bc7cf6fSBjoern A. Zeeb 4680bc7cf6fSBjoern A. Zeeb /* 4690bc7cf6fSBjoern A. Zeeb * Name: qla_init_peg_regs 4700bc7cf6fSBjoern A. Zeeb * Function: Protocol Engine Register Initialization 4710bc7cf6fSBjoern A. Zeeb */ 4720bc7cf6fSBjoern A. Zeeb static void 4730bc7cf6fSBjoern A. Zeeb qla_init_peg_regs(qla_host_t *ha) 4740bc7cf6fSBjoern A. Zeeb { 4750bc7cf6fSBjoern A. Zeeb WRITE_OFFSET32(ha, Q8_PEG_D_RESET1, 0x001E); 4760bc7cf6fSBjoern A. Zeeb WRITE_OFFSET32(ha, Q8_PEG_D_RESET2, 0x0008); 4770bc7cf6fSBjoern A. Zeeb WRITE_OFFSET32(ha, Q8_PEG_I_RESET, 0x0008); 4780bc7cf6fSBjoern A. Zeeb WRITE_OFFSET32(ha, Q8_PEG_0_CLR1, 0x0000); 4790bc7cf6fSBjoern A. Zeeb WRITE_OFFSET32(ha, Q8_PEG_0_CLR2, 0x0000); 4800bc7cf6fSBjoern A. Zeeb WRITE_OFFSET32(ha, Q8_PEG_1_CLR1, 0x0000); 4810bc7cf6fSBjoern A. Zeeb WRITE_OFFSET32(ha, Q8_PEG_1_CLR2, 0x0000); 4820bc7cf6fSBjoern A. Zeeb WRITE_OFFSET32(ha, Q8_PEG_2_CLR1, 0x0000); 4830bc7cf6fSBjoern A. Zeeb WRITE_OFFSET32(ha, Q8_PEG_2_CLR2, 0x0000); 4840bc7cf6fSBjoern A. Zeeb WRITE_OFFSET32(ha, Q8_PEG_3_CLR1, 0x0000); 4850bc7cf6fSBjoern A. Zeeb WRITE_OFFSET32(ha, Q8_PEG_3_CLR2, 0x0000); 4860bc7cf6fSBjoern A. Zeeb WRITE_OFFSET32(ha, Q8_PEG_4_CLR1, 0x0000); 4870bc7cf6fSBjoern A. Zeeb WRITE_OFFSET32(ha, Q8_PEG_4_CLR2, 0x0000); 4880bc7cf6fSBjoern A. Zeeb } 4890bc7cf6fSBjoern A. Zeeb 4900bc7cf6fSBjoern A. Zeeb /* 4910bc7cf6fSBjoern A. Zeeb * Name: qla_load_fw_from_flash 4920bc7cf6fSBjoern A. Zeeb * Function: Reads the Bootloader from Flash and Loads into Offchip Memory 4930bc7cf6fSBjoern A. Zeeb */ 4940bc7cf6fSBjoern A. Zeeb static void 4950bc7cf6fSBjoern A. Zeeb qla_load_fw_from_flash(qla_host_t *ha) 4960bc7cf6fSBjoern A. Zeeb { 4970bc7cf6fSBjoern A. Zeeb uint64_t mem_off = 0x10000; 4980bc7cf6fSBjoern A. Zeeb uint32_t flash_off = 0x10000; 4990bc7cf6fSBjoern A. Zeeb uint32_t count; 5000bc7cf6fSBjoern A. Zeeb offchip_mem_val_t val; 5010bc7cf6fSBjoern A. Zeeb 5020bc7cf6fSBjoern A. Zeeb 5030bc7cf6fSBjoern A. Zeeb /* only bootloader needs to be loaded into memory */ 5040bc7cf6fSBjoern A. Zeeb for (count = 0; count < 0x20000 ; ) { 5050bc7cf6fSBjoern A. Zeeb qla_rd_flash32(ha, flash_off, &val.data_lo); 5060bc7cf6fSBjoern A. Zeeb count = count + 4; 5070bc7cf6fSBjoern A. Zeeb flash_off = flash_off + 4; 5080bc7cf6fSBjoern A. Zeeb 5090bc7cf6fSBjoern A. Zeeb qla_rd_flash32(ha, flash_off, &val.data_hi); 5100bc7cf6fSBjoern A. Zeeb count = count + 4; 5110bc7cf6fSBjoern A. Zeeb flash_off = flash_off + 4; 5120bc7cf6fSBjoern A. Zeeb 5130bc7cf6fSBjoern A. Zeeb qla_rd_flash32(ha, flash_off, &val.data_ulo); 5140bc7cf6fSBjoern A. Zeeb count = count + 4; 5150bc7cf6fSBjoern A. Zeeb flash_off = flash_off + 4; 5160bc7cf6fSBjoern A. Zeeb 5170bc7cf6fSBjoern A. Zeeb qla_rd_flash32(ha, flash_off, &val.data_uhi); 5180bc7cf6fSBjoern A. Zeeb count = count + 4; 5190bc7cf6fSBjoern A. Zeeb flash_off = flash_off + 4; 5200bc7cf6fSBjoern A. Zeeb 5210bc7cf6fSBjoern A. Zeeb qla_rdwr_offchip_mem(ha, mem_off, &val, 0); 5220bc7cf6fSBjoern A. Zeeb 5230bc7cf6fSBjoern A. Zeeb mem_off = mem_off + 16; 5240bc7cf6fSBjoern A. Zeeb } 5250bc7cf6fSBjoern A. Zeeb return; 5260bc7cf6fSBjoern A. Zeeb } 5270bc7cf6fSBjoern A. Zeeb 5280bc7cf6fSBjoern A. Zeeb /* 5290bc7cf6fSBjoern A. Zeeb * Name: qla_init_from_flash 5300bc7cf6fSBjoern A. Zeeb * Function: Performs Initialization which consists of the following sequence 5310bc7cf6fSBjoern A. Zeeb * - reset 5320bc7cf6fSBjoern A. Zeeb * - CRB Init 5330bc7cf6fSBjoern A. Zeeb * - Peg Init 5340bc7cf6fSBjoern A. Zeeb * - Read the Bootloader from Flash and Load into Offchip Memory 5350bc7cf6fSBjoern A. Zeeb * - Kick start the bootloader which loads the rest of the firmware 5360bc7cf6fSBjoern A. Zeeb * and performs the remaining steps in the initialization process. 5370bc7cf6fSBjoern A. Zeeb */ 5380bc7cf6fSBjoern A. Zeeb static int 5390bc7cf6fSBjoern A. Zeeb qla_init_from_flash(qla_host_t *ha) 5400bc7cf6fSBjoern A. Zeeb { 5410bc7cf6fSBjoern A. Zeeb uint32_t delay = 300; 5420bc7cf6fSBjoern A. Zeeb uint32_t data; 5430bc7cf6fSBjoern A. Zeeb 5440bc7cf6fSBjoern A. Zeeb qla_hw_reset(ha); 5450bc7cf6fSBjoern A. Zeeb qla_mdelay(__func__, 100); 5460bc7cf6fSBjoern A. Zeeb 5470bc7cf6fSBjoern A. Zeeb qla_crb_init(ha); 5480bc7cf6fSBjoern A. Zeeb qla_mdelay(__func__, 10); 5490bc7cf6fSBjoern A. Zeeb 5500bc7cf6fSBjoern A. Zeeb qla_init_peg_regs(ha); 5510bc7cf6fSBjoern A. Zeeb qla_mdelay(__func__, 10); 5520bc7cf6fSBjoern A. Zeeb 5530bc7cf6fSBjoern A. Zeeb qla_load_fw_from_flash(ha); 5540bc7cf6fSBjoern A. Zeeb 5550bc7cf6fSBjoern A. Zeeb WRITE_OFFSET32(ha, Q8_CMDPEG_STATE, 0x00000000); 5560bc7cf6fSBjoern A. Zeeb WRITE_OFFSET32(ha, Q8_PEG_0_RESET, 0x00001020); 5570bc7cf6fSBjoern A. Zeeb WRITE_OFFSET32(ha, Q8_ASIC_RESET, 0x0080001E); 5580bc7cf6fSBjoern A. Zeeb qla_mdelay(__func__, 100); 5590bc7cf6fSBjoern A. Zeeb 5600bc7cf6fSBjoern A. Zeeb do { 5610bc7cf6fSBjoern A. Zeeb data = READ_OFFSET32(ha, Q8_CMDPEG_STATE); 5620bc7cf6fSBjoern A. Zeeb 5630bc7cf6fSBjoern A. Zeeb QL_DPRINT2((ha->pci_dev, "%s: func[%d] cmdpegstate 0x%08x\n", 5640bc7cf6fSBjoern A. Zeeb __func__, ha->pci_func, data)); 5650bc7cf6fSBjoern A. Zeeb if (data == CMDPEG_PHAN_INIT_COMPLETE) { 5660bc7cf6fSBjoern A. Zeeb QL_DPRINT2((ha->pci_dev, 5670bc7cf6fSBjoern A. Zeeb "%s: func[%d] init complete\n", 5680bc7cf6fSBjoern A. Zeeb __func__, ha->pci_func)); 5690bc7cf6fSBjoern A. Zeeb return(0); 5700bc7cf6fSBjoern A. Zeeb } 5710bc7cf6fSBjoern A. Zeeb qla_mdelay(__func__, 100); 5720bc7cf6fSBjoern A. Zeeb } while (delay--); 5730bc7cf6fSBjoern A. Zeeb 5740bc7cf6fSBjoern A. Zeeb device_printf(ha->pci_dev, 5750bc7cf6fSBjoern A. Zeeb "%s: func[%d] Q8_PEG_HALT_STATUS1[0x%08x] STATUS2[0x%08x]" 5760bc7cf6fSBjoern A. Zeeb " HEARTBEAT[0x%08x] RCVPEG_STATE[0x%08x]" 5770bc7cf6fSBjoern A. Zeeb " CMDPEG_STATE[0x%08x]\n", 5780bc7cf6fSBjoern A. Zeeb __func__, ha->pci_func, 5790bc7cf6fSBjoern A. Zeeb (READ_OFFSET32(ha, Q8_PEG_HALT_STATUS1)), 5800bc7cf6fSBjoern A. Zeeb (READ_OFFSET32(ha, Q8_PEG_HALT_STATUS2)), 5810bc7cf6fSBjoern A. Zeeb (READ_OFFSET32(ha, Q8_FIRMWARE_HEARTBEAT)), 5820bc7cf6fSBjoern A. Zeeb (READ_OFFSET32(ha, Q8_RCVPEG_STATE)), data); 5830bc7cf6fSBjoern A. Zeeb 5840bc7cf6fSBjoern A. Zeeb return (-1); 5850bc7cf6fSBjoern A. Zeeb } 5860bc7cf6fSBjoern A. Zeeb 5870bc7cf6fSBjoern A. Zeeb /* 5880bc7cf6fSBjoern A. Zeeb * Name: qla_init_hw 5890bc7cf6fSBjoern A. Zeeb * Function: Initializes P3+ hardware. 5900bc7cf6fSBjoern A. Zeeb */ 5910bc7cf6fSBjoern A. Zeeb int 5920bc7cf6fSBjoern A. Zeeb qla_init_hw(qla_host_t *ha) 5930bc7cf6fSBjoern A. Zeeb { 5940bc7cf6fSBjoern A. Zeeb device_t dev; 5950bc7cf6fSBjoern A. Zeeb int ret = 0; 5960bc7cf6fSBjoern A. Zeeb uint32_t val, delay = 300; 5970bc7cf6fSBjoern A. Zeeb 5980bc7cf6fSBjoern A. Zeeb dev = ha->pci_dev; 5990bc7cf6fSBjoern A. Zeeb 6000bc7cf6fSBjoern A. Zeeb QL_DPRINT1((dev, "%s: enter\n", __func__)); 6010bc7cf6fSBjoern A. Zeeb 6020bc7cf6fSBjoern A. Zeeb qla_mdelay(__func__, 100); 6030bc7cf6fSBjoern A. Zeeb 6040bc7cf6fSBjoern A. Zeeb if (ha->pci_func & 0x1) { 6050bc7cf6fSBjoern A. Zeeb while ((ha->pci_func & 0x1) && delay--) { 6060bc7cf6fSBjoern A. Zeeb val = READ_OFFSET32(ha, Q8_CMDPEG_STATE); 6070bc7cf6fSBjoern A. Zeeb 6080bc7cf6fSBjoern A. Zeeb if (val == CMDPEG_PHAN_INIT_COMPLETE) { 6090bc7cf6fSBjoern A. Zeeb QL_DPRINT2((dev, 6100bc7cf6fSBjoern A. Zeeb "%s: func = %d init complete\n", 6110bc7cf6fSBjoern A. Zeeb __func__, ha->pci_func)); 6120bc7cf6fSBjoern A. Zeeb qla_mdelay(__func__, 100); 6130bc7cf6fSBjoern A. Zeeb goto qla_init_exit; 6140bc7cf6fSBjoern A. Zeeb } 6150bc7cf6fSBjoern A. Zeeb qla_mdelay(__func__, 100); 6160bc7cf6fSBjoern A. Zeeb } 6170bc7cf6fSBjoern A. Zeeb return (-1); 6180bc7cf6fSBjoern A. Zeeb } 6190bc7cf6fSBjoern A. Zeeb 6200bc7cf6fSBjoern A. Zeeb val = READ_OFFSET32(ha, Q8_CMDPEG_STATE); 6210bc7cf6fSBjoern A. Zeeb 6220bc7cf6fSBjoern A. Zeeb if (val != CMDPEG_PHAN_INIT_COMPLETE) { 6230bc7cf6fSBjoern A. Zeeb ret = qla_init_from_flash(ha); 6240bc7cf6fSBjoern A. Zeeb qla_mdelay(__func__, 100); 625*088fc971SDavid C Somayajulu } else { 626*088fc971SDavid C Somayajulu ha->fw_ver_major = READ_OFFSET32(ha, Q8_FW_VER_MAJOR); 627*088fc971SDavid C Somayajulu ha->fw_ver_minor = READ_OFFSET32(ha, Q8_FW_VER_MINOR); 628*088fc971SDavid C Somayajulu ha->fw_ver_sub = READ_OFFSET32(ha, Q8_FW_VER_SUB); 629*088fc971SDavid C Somayajulu 630*088fc971SDavid C Somayajulu if (qla_rd_flash32(ha, 0x100004, &val) == 0) { 631*088fc971SDavid C Somayajulu 632*088fc971SDavid C Somayajulu if (((val & 0xFF) != ha->fw_ver_major) || 633*088fc971SDavid C Somayajulu (((val >> 8) & 0xFF) != ha->fw_ver_minor) || 634*088fc971SDavid C Somayajulu (((val >> 16) & 0xFF) != ha->fw_ver_sub)) { 635*088fc971SDavid C Somayajulu 636*088fc971SDavid C Somayajulu ret = qla_init_from_flash(ha); 637*088fc971SDavid C Somayajulu qla_mdelay(__func__, 100); 638*088fc971SDavid C Somayajulu } 639*088fc971SDavid C Somayajulu } 6400bc7cf6fSBjoern A. Zeeb } 6410bc7cf6fSBjoern A. Zeeb 6420bc7cf6fSBjoern A. Zeeb qla_init_exit: 6430bc7cf6fSBjoern A. Zeeb ha->fw_ver_major = READ_OFFSET32(ha, Q8_FW_VER_MAJOR); 6440bc7cf6fSBjoern A. Zeeb ha->fw_ver_minor = READ_OFFSET32(ha, Q8_FW_VER_MINOR); 6450bc7cf6fSBjoern A. Zeeb ha->fw_ver_sub = READ_OFFSET32(ha, Q8_FW_VER_SUB); 6460bc7cf6fSBjoern A. Zeeb ha->fw_ver_build = READ_OFFSET32(ha, Q8_FW_VER_BUILD); 6470bc7cf6fSBjoern A. Zeeb 6480bc7cf6fSBjoern A. Zeeb return (ret); 6490bc7cf6fSBjoern A. Zeeb } 6500bc7cf6fSBjoern A. Zeeb 651*088fc971SDavid C Somayajulu static int 652*088fc971SDavid C Somayajulu qla_wait_for_flash_busy(qla_host_t *ha) 653*088fc971SDavid C Somayajulu { 654*088fc971SDavid C Somayajulu uint32_t count = 100; 655*088fc971SDavid C Somayajulu uint32_t val; 656*088fc971SDavid C Somayajulu 657*088fc971SDavid C Somayajulu QLA_USEC_DELAY(100); 658*088fc971SDavid C Somayajulu 659*088fc971SDavid C Somayajulu while (count--) { 660*088fc971SDavid C Somayajulu val = READ_OFFSET32(ha, Q8_ROM_STATUS); 661*088fc971SDavid C Somayajulu 662*088fc971SDavid C Somayajulu if (val & BIT_1) 663*088fc971SDavid C Somayajulu return 0; 664*088fc971SDavid C Somayajulu qla_mdelay(__func__, 1); 665*088fc971SDavid C Somayajulu } 666*088fc971SDavid C Somayajulu return -1; 667*088fc971SDavid C Somayajulu } 668*088fc971SDavid C Somayajulu 669*088fc971SDavid C Somayajulu static int 670*088fc971SDavid C Somayajulu qla_flash_write_enable(qla_host_t *ha) 671*088fc971SDavid C Somayajulu { 672*088fc971SDavid C Somayajulu uint32_t val, rval; 673*088fc971SDavid C Somayajulu 674*088fc971SDavid C Somayajulu val = 0; 675*088fc971SDavid C Somayajulu qla_rdwr_indreg32(ha, Q8_ROM_ADDR_BYTE_COUNT, &val, 0); 676*088fc971SDavid C Somayajulu 677*088fc971SDavid C Somayajulu val = ROM_OPCODE_WR_ENABLE; 678*088fc971SDavid C Somayajulu qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0); 679*088fc971SDavid C Somayajulu 680*088fc971SDavid C Somayajulu rval = qla_wait_for_flash_busy(ha); 681*088fc971SDavid C Somayajulu 682*088fc971SDavid C Somayajulu if (rval) 683*088fc971SDavid C Somayajulu device_printf(ha->pci_dev, "%s: failed \n", __func__); 684*088fc971SDavid C Somayajulu 685*088fc971SDavid C Somayajulu return (rval); 686*088fc971SDavid C Somayajulu } 687*088fc971SDavid C Somayajulu 688*088fc971SDavid C Somayajulu static int 689*088fc971SDavid C Somayajulu qla_flash_unprotect(qla_host_t *ha) 690*088fc971SDavid C Somayajulu { 691*088fc971SDavid C Somayajulu uint32_t val, rval; 692*088fc971SDavid C Somayajulu 693*088fc971SDavid C Somayajulu if (qla_flash_write_enable(ha) != 0) 694*088fc971SDavid C Somayajulu return(-1); 695*088fc971SDavid C Somayajulu 696*088fc971SDavid C Somayajulu val = 0; 697*088fc971SDavid C Somayajulu qla_rdwr_indreg32(ha, Q8_ROM_WR_DATA, &val, 0); 698*088fc971SDavid C Somayajulu 699*088fc971SDavid C Somayajulu val = ROM_OPCODE_WR_STATUS_REG; 700*088fc971SDavid C Somayajulu qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0); 701*088fc971SDavid C Somayajulu 702*088fc971SDavid C Somayajulu rval = qla_wait_for_flash_busy(ha); 703*088fc971SDavid C Somayajulu 704*088fc971SDavid C Somayajulu if (rval) { 705*088fc971SDavid C Somayajulu device_printf(ha->pci_dev, "%s: failed \n", __func__); 706*088fc971SDavid C Somayajulu return rval; 707*088fc971SDavid C Somayajulu } 708*088fc971SDavid C Somayajulu 709*088fc971SDavid C Somayajulu if (qla_flash_write_enable(ha) != 0) 710*088fc971SDavid C Somayajulu return(-1); 711*088fc971SDavid C Somayajulu 712*088fc971SDavid C Somayajulu val = 0; 713*088fc971SDavid C Somayajulu qla_rdwr_indreg32(ha, Q8_ROM_WR_DATA, &val, 0); 714*088fc971SDavid C Somayajulu 715*088fc971SDavid C Somayajulu val = ROM_OPCODE_WR_STATUS_REG; 716*088fc971SDavid C Somayajulu qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0); 717*088fc971SDavid C Somayajulu 718*088fc971SDavid C Somayajulu rval = qla_wait_for_flash_busy(ha); 719*088fc971SDavid C Somayajulu 720*088fc971SDavid C Somayajulu if (rval) 721*088fc971SDavid C Somayajulu device_printf(ha->pci_dev, "%s: failed \n", __func__); 722*088fc971SDavid C Somayajulu 723*088fc971SDavid C Somayajulu return rval; 724*088fc971SDavid C Somayajulu } 725*088fc971SDavid C Somayajulu 726*088fc971SDavid C Somayajulu static int 727*088fc971SDavid C Somayajulu qla_flash_protect(qla_host_t *ha) 728*088fc971SDavid C Somayajulu { 729*088fc971SDavid C Somayajulu uint32_t val, rval; 730*088fc971SDavid C Somayajulu 731*088fc971SDavid C Somayajulu if (qla_flash_write_enable(ha) != 0) 732*088fc971SDavid C Somayajulu return(-1); 733*088fc971SDavid C Somayajulu 734*088fc971SDavid C Somayajulu val = 0x9C; 735*088fc971SDavid C Somayajulu qla_rdwr_indreg32(ha, Q8_ROM_WR_DATA, &val, 0); 736*088fc971SDavid C Somayajulu 737*088fc971SDavid C Somayajulu val = ROM_OPCODE_WR_STATUS_REG; 738*088fc971SDavid C Somayajulu qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0); 739*088fc971SDavid C Somayajulu 740*088fc971SDavid C Somayajulu rval = qla_wait_for_flash_busy(ha); 741*088fc971SDavid C Somayajulu 742*088fc971SDavid C Somayajulu if (rval) 743*088fc971SDavid C Somayajulu device_printf(ha->pci_dev, "%s: failed \n", __func__); 744*088fc971SDavid C Somayajulu 745*088fc971SDavid C Somayajulu return rval; 746*088fc971SDavid C Somayajulu } 747*088fc971SDavid C Somayajulu 748*088fc971SDavid C Somayajulu static uint32_t 749*088fc971SDavid C Somayajulu qla_flash_get_status(qla_host_t *ha) 750*088fc971SDavid C Somayajulu { 751*088fc971SDavid C Somayajulu uint32_t count = 1000; 752*088fc971SDavid C Somayajulu uint32_t val, rval; 753*088fc971SDavid C Somayajulu 754*088fc971SDavid C Somayajulu while (count--) { 755*088fc971SDavid C Somayajulu val = 0; 756*088fc971SDavid C Somayajulu qla_rdwr_indreg32(ha, Q8_ROM_ADDR_BYTE_COUNT, &val, 0); 757*088fc971SDavid C Somayajulu 758*088fc971SDavid C Somayajulu val = ROM_OPCODE_RD_STATUS_REG; 759*088fc971SDavid C Somayajulu qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0); 760*088fc971SDavid C Somayajulu 761*088fc971SDavid C Somayajulu rval = qla_wait_for_flash_busy(ha); 762*088fc971SDavid C Somayajulu 763*088fc971SDavid C Somayajulu if (rval == 0) { 764*088fc971SDavid C Somayajulu qla_rdwr_indreg32(ha, Q8_ROM_RD_DATA, &val, 1); 765*088fc971SDavid C Somayajulu 766*088fc971SDavid C Somayajulu if ((val & BIT_0) == 0) 767*088fc971SDavid C Somayajulu return (val); 768*088fc971SDavid C Somayajulu } 769*088fc971SDavid C Somayajulu qla_mdelay(__func__, 1); 770*088fc971SDavid C Somayajulu } 771*088fc971SDavid C Somayajulu return -1; 772*088fc971SDavid C Somayajulu } 773*088fc971SDavid C Somayajulu 774*088fc971SDavid C Somayajulu static int 775*088fc971SDavid C Somayajulu qla_wait_for_flash_unprotect(qla_host_t *ha) 776*088fc971SDavid C Somayajulu { 777*088fc971SDavid C Somayajulu uint32_t delay = 1000; 778*088fc971SDavid C Somayajulu 779*088fc971SDavid C Somayajulu while (delay--) { 780*088fc971SDavid C Somayajulu 781*088fc971SDavid C Somayajulu if (qla_flash_get_status(ha) == 0) 782*088fc971SDavid C Somayajulu return 0; 783*088fc971SDavid C Somayajulu 784*088fc971SDavid C Somayajulu qla_mdelay(__func__, 1); 785*088fc971SDavid C Somayajulu } 786*088fc971SDavid C Somayajulu 787*088fc971SDavid C Somayajulu return -1; 788*088fc971SDavid C Somayajulu } 789*088fc971SDavid C Somayajulu 790*088fc971SDavid C Somayajulu static int 791*088fc971SDavid C Somayajulu qla_wait_for_flash_protect(qla_host_t *ha) 792*088fc971SDavid C Somayajulu { 793*088fc971SDavid C Somayajulu uint32_t delay = 1000; 794*088fc971SDavid C Somayajulu 795*088fc971SDavid C Somayajulu while (delay--) { 796*088fc971SDavid C Somayajulu 797*088fc971SDavid C Somayajulu if (qla_flash_get_status(ha) == 0x9C) 798*088fc971SDavid C Somayajulu return 0; 799*088fc971SDavid C Somayajulu 800*088fc971SDavid C Somayajulu qla_mdelay(__func__, 1); 801*088fc971SDavid C Somayajulu } 802*088fc971SDavid C Somayajulu 803*088fc971SDavid C Somayajulu return -1; 804*088fc971SDavid C Somayajulu } 805*088fc971SDavid C Somayajulu 806*088fc971SDavid C Somayajulu static int 807*088fc971SDavid C Somayajulu qla_erase_flash_sector(qla_host_t *ha, uint32_t start) 808*088fc971SDavid C Somayajulu { 809*088fc971SDavid C Somayajulu uint32_t val; 810*088fc971SDavid C Somayajulu int rval; 811*088fc971SDavid C Somayajulu 812*088fc971SDavid C Somayajulu if (qla_flash_write_enable(ha) != 0) 813*088fc971SDavid C Somayajulu return(-1); 814*088fc971SDavid C Somayajulu 815*088fc971SDavid C Somayajulu val = start; 816*088fc971SDavid C Somayajulu qla_rdwr_indreg32(ha, Q8_ROM_ADDRESS, &val, 0); 817*088fc971SDavid C Somayajulu 818*088fc971SDavid C Somayajulu val = 3; 819*088fc971SDavid C Somayajulu qla_rdwr_indreg32(ha, Q8_ROM_ADDR_BYTE_COUNT, &val, 0); 820*088fc971SDavid C Somayajulu 821*088fc971SDavid C Somayajulu val = ROM_OPCODE_SECTOR_ERASE; 822*088fc971SDavid C Somayajulu qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0); 823*088fc971SDavid C Somayajulu 824*088fc971SDavid C Somayajulu rval = qla_wait_for_flash_busy(ha); 825*088fc971SDavid C Somayajulu 826*088fc971SDavid C Somayajulu if (rval) 827*088fc971SDavid C Somayajulu device_printf(ha->pci_dev, "%s: failed \n", __func__); 828*088fc971SDavid C Somayajulu return rval; 829*088fc971SDavid C Somayajulu } 830*088fc971SDavid C Somayajulu 831*088fc971SDavid C Somayajulu #define Q8_FLASH_SECTOR_SIZE 0x10000 832*088fc971SDavid C Somayajulu int 833*088fc971SDavid C Somayajulu qla_erase_flash(qla_host_t *ha, uint32_t off, uint32_t size) 834*088fc971SDavid C Somayajulu { 835*088fc971SDavid C Somayajulu int rval = 0; 836*088fc971SDavid C Somayajulu uint32_t start; 837*088fc971SDavid C Somayajulu 838*088fc971SDavid C Somayajulu if (off & (Q8_FLASH_SECTOR_SIZE -1)) 839*088fc971SDavid C Somayajulu return -1; 840*088fc971SDavid C Somayajulu 841*088fc971SDavid C Somayajulu if ((rval = qla_p3p_sem_lock2(ha))) 842*088fc971SDavid C Somayajulu goto qla_erase_flash_exit; 843*088fc971SDavid C Somayajulu 844*088fc971SDavid C Somayajulu if ((rval = qla_flash_unprotect(ha))) 845*088fc971SDavid C Somayajulu goto qla_erase_flash_unlock_exit; 846*088fc971SDavid C Somayajulu 847*088fc971SDavid C Somayajulu if ((rval = qla_wait_for_flash_unprotect(ha))) 848*088fc971SDavid C Somayajulu goto qla_erase_flash_unlock_exit; 849*088fc971SDavid C Somayajulu 850*088fc971SDavid C Somayajulu for (start = off; start < (off + size); start = start + 0x10000) { 851*088fc971SDavid C Somayajulu if (qla_erase_flash_sector(ha, start)) { 852*088fc971SDavid C Somayajulu rval = -1; 853*088fc971SDavid C Somayajulu break; 854*088fc971SDavid C Somayajulu } 855*088fc971SDavid C Somayajulu } 856*088fc971SDavid C Somayajulu 857*088fc971SDavid C Somayajulu rval = qla_flash_protect(ha); 858*088fc971SDavid C Somayajulu 859*088fc971SDavid C Somayajulu qla_erase_flash_unlock_exit: 860*088fc971SDavid C Somayajulu qla_sem_unlock(ha, Q8_SEM2_UNLOCK); 861*088fc971SDavid C Somayajulu 862*088fc971SDavid C Somayajulu qla_erase_flash_exit: 863*088fc971SDavid C Somayajulu return (rval); 864*088fc971SDavid C Somayajulu } 865*088fc971SDavid C Somayajulu 866*088fc971SDavid C Somayajulu static int 867*088fc971SDavid C Somayajulu qla_flash_write32(qla_host_t *ha, uint32_t off, uint32_t data) 868*088fc971SDavid C Somayajulu { 869*088fc971SDavid C Somayajulu uint32_t val; 870*088fc971SDavid C Somayajulu int rval = 0; 871*088fc971SDavid C Somayajulu 872*088fc971SDavid C Somayajulu val = data; 873*088fc971SDavid C Somayajulu qla_rdwr_indreg32(ha, Q8_ROM_WR_DATA, &val, 0); 874*088fc971SDavid C Somayajulu 875*088fc971SDavid C Somayajulu val = off; 876*088fc971SDavid C Somayajulu qla_rdwr_indreg32(ha, Q8_ROM_ADDRESS, &val, 0); 877*088fc971SDavid C Somayajulu 878*088fc971SDavid C Somayajulu val = 3; 879*088fc971SDavid C Somayajulu qla_rdwr_indreg32(ha, Q8_ROM_ADDR_BYTE_COUNT, &val, 0); 880*088fc971SDavid C Somayajulu 881*088fc971SDavid C Somayajulu val = ROM_OPCODE_PROG_PAGE; 882*088fc971SDavid C Somayajulu qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0); 883*088fc971SDavid C Somayajulu 884*088fc971SDavid C Somayajulu rval = qla_wait_for_flash_busy(ha); 885*088fc971SDavid C Somayajulu 886*088fc971SDavid C Somayajulu if (rval) 887*088fc971SDavid C Somayajulu device_printf(ha->pci_dev, "%s: failed \n", __func__); 888*088fc971SDavid C Somayajulu 889*088fc971SDavid C Somayajulu return rval; 890*088fc971SDavid C Somayajulu } 891*088fc971SDavid C Somayajulu 892*088fc971SDavid C Somayajulu static int 893*088fc971SDavid C Somayajulu qla_flash_wait_for_write_complete(qla_host_t *ha) 894*088fc971SDavid C Somayajulu { 895*088fc971SDavid C Somayajulu uint32_t val, count = 1000; 896*088fc971SDavid C Somayajulu int rval = 0; 897*088fc971SDavid C Somayajulu 898*088fc971SDavid C Somayajulu while (count--) { 899*088fc971SDavid C Somayajulu 900*088fc971SDavid C Somayajulu val = 0; 901*088fc971SDavid C Somayajulu qla_rdwr_indreg32(ha, Q8_ROM_ADDR_BYTE_COUNT, &val, 0); 902*088fc971SDavid C Somayajulu 903*088fc971SDavid C Somayajulu val = ROM_OPCODE_RD_STATUS_REG; 904*088fc971SDavid C Somayajulu qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0); 905*088fc971SDavid C Somayajulu 906*088fc971SDavid C Somayajulu 907*088fc971SDavid C Somayajulu rval = qla_wait_for_flash_busy(ha); 908*088fc971SDavid C Somayajulu 909*088fc971SDavid C Somayajulu if (rval == 0) { 910*088fc971SDavid C Somayajulu qla_rdwr_indreg32(ha, Q8_ROM_RD_DATA, &val, 1); 911*088fc971SDavid C Somayajulu 912*088fc971SDavid C Somayajulu if ((val & BIT_0) == 0) 913*088fc971SDavid C Somayajulu return (0); 914*088fc971SDavid C Somayajulu } 915*088fc971SDavid C Somayajulu qla_mdelay(__func__, 1); 916*088fc971SDavid C Somayajulu } 917*088fc971SDavid C Somayajulu return -1; 918*088fc971SDavid C Somayajulu } 919*088fc971SDavid C Somayajulu 920*088fc971SDavid C Somayajulu static int 921*088fc971SDavid C Somayajulu qla_flash_write(qla_host_t *ha, uint32_t off, uint32_t data) 922*088fc971SDavid C Somayajulu { 923*088fc971SDavid C Somayajulu if (qla_flash_write_enable(ha) != 0) 924*088fc971SDavid C Somayajulu return(-1); 925*088fc971SDavid C Somayajulu 926*088fc971SDavid C Somayajulu if (qla_flash_write32(ha, off, data) != 0) 927*088fc971SDavid C Somayajulu return -1; 928*088fc971SDavid C Somayajulu 929*088fc971SDavid C Somayajulu if (qla_flash_wait_for_write_complete(ha)) 930*088fc971SDavid C Somayajulu return -1; 931*088fc971SDavid C Somayajulu 932*088fc971SDavid C Somayajulu return 0; 933*088fc971SDavid C Somayajulu } 934*088fc971SDavid C Somayajulu 935*088fc971SDavid C Somayajulu 936*088fc971SDavid C Somayajulu static int 937*088fc971SDavid C Somayajulu qla_flash_write_pattern(qla_host_t *ha, uint32_t off, uint32_t size, 938*088fc971SDavid C Somayajulu uint32_t pattern) 939*088fc971SDavid C Somayajulu { 940*088fc971SDavid C Somayajulu int rval = 0; 941*088fc971SDavid C Somayajulu uint32_t start; 942*088fc971SDavid C Somayajulu 943*088fc971SDavid C Somayajulu 944*088fc971SDavid C Somayajulu if ((rval = qla_p3p_sem_lock2(ha))) 945*088fc971SDavid C Somayajulu goto qla_wr_pattern_exit; 946*088fc971SDavid C Somayajulu 947*088fc971SDavid C Somayajulu if ((rval = qla_flash_unprotect(ha))) 948*088fc971SDavid C Somayajulu goto qla_wr_pattern_unlock_exit; 949*088fc971SDavid C Somayajulu 950*088fc971SDavid C Somayajulu if ((rval = qla_wait_for_flash_unprotect(ha))) 951*088fc971SDavid C Somayajulu goto qla_wr_pattern_unlock_exit; 952*088fc971SDavid C Somayajulu 953*088fc971SDavid C Somayajulu for (start = off; start < (off + size); start = start + 4) { 954*088fc971SDavid C Somayajulu if (qla_flash_write(ha, start, pattern)) { 955*088fc971SDavid C Somayajulu rval = -1; 956*088fc971SDavid C Somayajulu break; 957*088fc971SDavid C Somayajulu } 958*088fc971SDavid C Somayajulu } 959*088fc971SDavid C Somayajulu 960*088fc971SDavid C Somayajulu rval = qla_flash_protect(ha); 961*088fc971SDavid C Somayajulu 962*088fc971SDavid C Somayajulu if (rval == 0) 963*088fc971SDavid C Somayajulu rval = qla_wait_for_flash_protect(ha); 964*088fc971SDavid C Somayajulu 965*088fc971SDavid C Somayajulu qla_wr_pattern_unlock_exit: 966*088fc971SDavid C Somayajulu qla_sem_unlock(ha, Q8_SEM2_UNLOCK); 967*088fc971SDavid C Somayajulu 968*088fc971SDavid C Somayajulu qla_wr_pattern_exit: 969*088fc971SDavid C Somayajulu return (rval); 970*088fc971SDavid C Somayajulu } 971*088fc971SDavid C Somayajulu 972*088fc971SDavid C Somayajulu static int 973*088fc971SDavid C Somayajulu qla_flash_write_data(qla_host_t *ha, uint32_t off, uint32_t size, 974*088fc971SDavid C Somayajulu void *data) 975*088fc971SDavid C Somayajulu { 976*088fc971SDavid C Somayajulu int rval = 0; 977*088fc971SDavid C Somayajulu uint32_t start; 978*088fc971SDavid C Somayajulu uint32_t *data32 = data; 979*088fc971SDavid C Somayajulu 980*088fc971SDavid C Somayajulu 981*088fc971SDavid C Somayajulu if ((rval = qla_p3p_sem_lock2(ha))) 982*088fc971SDavid C Somayajulu goto qla_wr_pattern_exit; 983*088fc971SDavid C Somayajulu 984*088fc971SDavid C Somayajulu if ((rval = qla_flash_unprotect(ha))) 985*088fc971SDavid C Somayajulu goto qla_wr_pattern_unlock_exit; 986*088fc971SDavid C Somayajulu 987*088fc971SDavid C Somayajulu if ((rval = qla_wait_for_flash_unprotect(ha))) 988*088fc971SDavid C Somayajulu goto qla_wr_pattern_unlock_exit; 989*088fc971SDavid C Somayajulu 990*088fc971SDavid C Somayajulu for (start = off; start < (off + size); start = start + 4) { 991*088fc971SDavid C Somayajulu 992*088fc971SDavid C Somayajulu if (*data32 != 0xFFFFFFFF) { 993*088fc971SDavid C Somayajulu if (qla_flash_write(ha, start, *data32)) { 994*088fc971SDavid C Somayajulu rval = -1; 995*088fc971SDavid C Somayajulu break; 996*088fc971SDavid C Somayajulu } 997*088fc971SDavid C Somayajulu } 998*088fc971SDavid C Somayajulu data32++; 999*088fc971SDavid C Somayajulu } 1000*088fc971SDavid C Somayajulu 1001*088fc971SDavid C Somayajulu rval = qla_flash_protect(ha); 1002*088fc971SDavid C Somayajulu 1003*088fc971SDavid C Somayajulu if (rval == 0) 1004*088fc971SDavid C Somayajulu rval = qla_wait_for_flash_protect(ha); 1005*088fc971SDavid C Somayajulu 1006*088fc971SDavid C Somayajulu qla_wr_pattern_unlock_exit: 1007*088fc971SDavid C Somayajulu qla_sem_unlock(ha, Q8_SEM2_UNLOCK); 1008*088fc971SDavid C Somayajulu 1009*088fc971SDavid C Somayajulu qla_wr_pattern_exit: 1010*088fc971SDavid C Somayajulu return (rval); 1011*088fc971SDavid C Somayajulu } 1012*088fc971SDavid C Somayajulu 1013*088fc971SDavid C Somayajulu int 1014*088fc971SDavid C Somayajulu qla_wr_flash_buffer(qla_host_t *ha, uint32_t off, uint32_t size, void *buf, 1015*088fc971SDavid C Somayajulu uint32_t pattern) 1016*088fc971SDavid C Somayajulu { 1017*088fc971SDavid C Somayajulu int rval = 0; 1018*088fc971SDavid C Somayajulu void *data; 1019*088fc971SDavid C Somayajulu 1020*088fc971SDavid C Somayajulu 1021*088fc971SDavid C Somayajulu if (size == 0) 1022*088fc971SDavid C Somayajulu return 0; 1023*088fc971SDavid C Somayajulu 1024*088fc971SDavid C Somayajulu size = size << 2; 1025*088fc971SDavid C Somayajulu 1026*088fc971SDavid C Somayajulu if (buf == NULL) { 1027*088fc971SDavid C Somayajulu rval = qla_flash_write_pattern(ha, off, size, pattern); 1028*088fc971SDavid C Somayajulu return (rval); 1029*088fc971SDavid C Somayajulu } 1030*088fc971SDavid C Somayajulu 1031*088fc971SDavid C Somayajulu if ((data = malloc(size, M_QLA8XXXBUF, M_NOWAIT)) == NULL) { 1032*088fc971SDavid C Somayajulu device_printf(ha->pci_dev, "%s: malloc failed \n", __func__); 1033*088fc971SDavid C Somayajulu rval = -1; 1034*088fc971SDavid C Somayajulu goto qla_wr_flash_buffer_exit; 1035*088fc971SDavid C Somayajulu } 1036*088fc971SDavid C Somayajulu 1037*088fc971SDavid C Somayajulu if ((rval = copyin(buf, data, size))) { 1038*088fc971SDavid C Somayajulu device_printf(ha->pci_dev, "%s copyin failed\n", __func__); 1039*088fc971SDavid C Somayajulu goto qla_wr_flash_buffer_free_exit; 1040*088fc971SDavid C Somayajulu } 1041*088fc971SDavid C Somayajulu 1042*088fc971SDavid C Somayajulu rval = qla_flash_write_data(ha, off, size, data); 1043*088fc971SDavid C Somayajulu 1044*088fc971SDavid C Somayajulu qla_wr_flash_buffer_free_exit: 1045*088fc971SDavid C Somayajulu free(data, M_QLA8XXXBUF); 1046*088fc971SDavid C Somayajulu 1047*088fc971SDavid C Somayajulu qla_wr_flash_buffer_exit: 1048*088fc971SDavid C Somayajulu return (rval); 1049*088fc971SDavid C Somayajulu } 1050*088fc971SDavid C Somayajulu 1051