1a3667aaeSNaresh Kumar Inna /* 2a3667aaeSNaresh Kumar Inna * This file is part of the Chelsio FCoE driver for Linux. 3a3667aaeSNaresh Kumar Inna * 4a3667aaeSNaresh Kumar Inna * Copyright (c) 2008-2012 Chelsio Communications, Inc. All rights reserved. 5a3667aaeSNaresh Kumar Inna * 6a3667aaeSNaresh Kumar Inna * This software is available to you under a choice of one of two 7a3667aaeSNaresh Kumar Inna * licenses. You may choose to be licensed under the terms of the GNU 8a3667aaeSNaresh Kumar Inna * General Public License (GPL) Version 2, available from the file 9a3667aaeSNaresh Kumar Inna * COPYING in the main directory of this source tree, or the 10a3667aaeSNaresh Kumar Inna * OpenIB.org BSD license below: 11a3667aaeSNaresh Kumar Inna * 12a3667aaeSNaresh Kumar Inna * Redistribution and use in source and binary forms, with or 13a3667aaeSNaresh Kumar Inna * without modification, are permitted provided that the following 14a3667aaeSNaresh Kumar Inna * conditions are met: 15a3667aaeSNaresh Kumar Inna * 16a3667aaeSNaresh Kumar Inna * - Redistributions of source code must retain the above 17a3667aaeSNaresh Kumar Inna * copyright notice, this list of conditions and the following 18a3667aaeSNaresh Kumar Inna * disclaimer. 19a3667aaeSNaresh Kumar Inna * 20a3667aaeSNaresh Kumar Inna * - Redistributions in binary form must reproduce the above 21a3667aaeSNaresh Kumar Inna * copyright notice, this list of conditions and the following 22a3667aaeSNaresh Kumar Inna * disclaimer in the documentation and/or other materials 23a3667aaeSNaresh Kumar Inna * provided with the distribution. 24a3667aaeSNaresh Kumar Inna * 25a3667aaeSNaresh Kumar Inna * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26a3667aaeSNaresh Kumar Inna * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27a3667aaeSNaresh Kumar Inna * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28a3667aaeSNaresh Kumar Inna * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29a3667aaeSNaresh Kumar Inna * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30a3667aaeSNaresh Kumar Inna * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31a3667aaeSNaresh Kumar Inna * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32a3667aaeSNaresh Kumar Inna * SOFTWARE. 33a3667aaeSNaresh Kumar Inna */ 34a3667aaeSNaresh Kumar Inna 35a3667aaeSNaresh Kumar Inna #include <linux/pci.h> 36a3667aaeSNaresh Kumar Inna #include <linux/pci_regs.h> 37a3667aaeSNaresh Kumar Inna #include <linux/firmware.h> 38a3667aaeSNaresh Kumar Inna #include <linux/stddef.h> 39a3667aaeSNaresh Kumar Inna #include <linux/delay.h> 40a3667aaeSNaresh Kumar Inna #include <linux/string.h> 41a3667aaeSNaresh Kumar Inna #include <linux/compiler.h> 42a3667aaeSNaresh Kumar Inna #include <linux/jiffies.h> 43a3667aaeSNaresh Kumar Inna #include <linux/kernel.h> 44a3667aaeSNaresh Kumar Inna #include <linux/log2.h> 45a3667aaeSNaresh Kumar Inna 46a3667aaeSNaresh Kumar Inna #include "csio_hw.h" 47a3667aaeSNaresh Kumar Inna #include "csio_lnode.h" 48a3667aaeSNaresh Kumar Inna #include "csio_rnode.h" 49a3667aaeSNaresh Kumar Inna 50a3667aaeSNaresh Kumar Inna int csio_force_master; 51a3667aaeSNaresh Kumar Inna int csio_dbg_level = 0xFEFF; 52a3667aaeSNaresh Kumar Inna unsigned int csio_port_mask = 0xf; 53a3667aaeSNaresh Kumar Inna 54a3667aaeSNaresh Kumar Inna /* Default FW event queue entries. */ 55a3667aaeSNaresh Kumar Inna static uint32_t csio_evtq_sz = CSIO_EVTQ_SIZE; 56a3667aaeSNaresh Kumar Inna 57a3667aaeSNaresh Kumar Inna /* Default MSI param level */ 58a3667aaeSNaresh Kumar Inna int csio_msi = 2; 59a3667aaeSNaresh Kumar Inna 60a3667aaeSNaresh Kumar Inna /* FCoE function instances */ 61a3667aaeSNaresh Kumar Inna static int dev_num; 62a3667aaeSNaresh Kumar Inna 63a3667aaeSNaresh Kumar Inna /* FCoE Adapter types & its description */ 647cc16380SArvind Bhushan static const struct csio_adap_desc csio_t4_fcoe_adapters[] = { 65a3667aaeSNaresh Kumar Inna {"T440-Dbg 10G", "Chelsio T440-Dbg 10G [FCoE]"}, 66a3667aaeSNaresh Kumar Inna {"T420-CR 10G", "Chelsio T420-CR 10G [FCoE]"}, 67a3667aaeSNaresh Kumar Inna {"T422-CR 10G/1G", "Chelsio T422-CR 10G/1G [FCoE]"}, 68a3667aaeSNaresh Kumar Inna {"T440-CR 10G", "Chelsio T440-CR 10G [FCoE]"}, 69a3667aaeSNaresh Kumar Inna {"T420-BCH 10G", "Chelsio T420-BCH 10G [FCoE]"}, 70a3667aaeSNaresh Kumar Inna {"T440-BCH 10G", "Chelsio T440-BCH 10G [FCoE]"}, 71a3667aaeSNaresh Kumar Inna {"T440-CH 10G", "Chelsio T440-CH 10G [FCoE]"}, 72a3667aaeSNaresh Kumar Inna {"T420-SO 10G", "Chelsio T420-SO 10G [FCoE]"}, 73a3667aaeSNaresh Kumar Inna {"T420-CX4 10G", "Chelsio T420-CX4 10G [FCoE]"}, 74a3667aaeSNaresh Kumar Inna {"T420-BT 10G", "Chelsio T420-BT 10G [FCoE]"}, 75a3667aaeSNaresh Kumar Inna {"T404-BT 1G", "Chelsio T404-BT 1G [FCoE]"}, 76a3667aaeSNaresh Kumar Inna {"B420-SR 10G", "Chelsio B420-SR 10G [FCoE]"}, 77a3667aaeSNaresh Kumar Inna {"B404-BT 1G", "Chelsio B404-BT 1G [FCoE]"}, 78a3667aaeSNaresh Kumar Inna {"T480-CR 10G", "Chelsio T480-CR 10G [FCoE]"}, 79a3667aaeSNaresh Kumar Inna {"T440-LP-CR 10G", "Chelsio T440-LP-CR 10G [FCoE]"}, 807cc16380SArvind Bhushan {"AMSTERDAM 10G", "Chelsio AMSTERDAM 10G [FCoE]"}, 817cc16380SArvind Bhushan {"HUAWEI T480 10G", "Chelsio HUAWEI T480 10G [FCoE]"}, 827cc16380SArvind Bhushan {"HUAWEI T440 10G", "Chelsio HUAWEI T440 10G [FCoE]"}, 837cc16380SArvind Bhushan {"HUAWEI STG 10G", "Chelsio HUAWEI STG 10G [FCoE]"}, 847cc16380SArvind Bhushan {"ACROMAG XAUI 10G", "Chelsio ACROMAG XAUI 10G [FCoE]"}, 857cc16380SArvind Bhushan {"ACROMAG SFP+ 10G", "Chelsio ACROMAG SFP+ 10G [FCoE]"}, 867cc16380SArvind Bhushan {"QUANTA SFP+ 10G", "Chelsio QUANTA SFP+ 10G [FCoE]"}, 877cc16380SArvind Bhushan {"HUAWEI 10Gbase-T", "Chelsio HUAWEI 10Gbase-T [FCoE]"}, 887cc16380SArvind Bhushan {"HUAWEI T4TOE 10G", "Chelsio HUAWEI T4TOE 10G [FCoE]"} 897cc16380SArvind Bhushan }; 907cc16380SArvind Bhushan 917cc16380SArvind Bhushan static const struct csio_adap_desc csio_t5_fcoe_adapters[] = { 927cc16380SArvind Bhushan {"T580-Dbg 10G", "Chelsio T580-Dbg 10G [FCoE]"}, 937cc16380SArvind Bhushan {"T520-CR 10G", "Chelsio T520-CR 10G [FCoE]"}, 947cc16380SArvind Bhushan {"T522-CR 10G/1G", "Chelsio T452-CR 10G/1G [FCoE]"}, 957cc16380SArvind Bhushan {"T540-CR 10G", "Chelsio T540-CR 10G [FCoE]"}, 967cc16380SArvind Bhushan {"T520-BCH 10G", "Chelsio T520-BCH 10G [FCoE]"}, 977cc16380SArvind Bhushan {"T540-BCH 10G", "Chelsio T540-BCH 10G [FCoE]"}, 987cc16380SArvind Bhushan {"T540-CH 10G", "Chelsio T540-CH 10G [FCoE]"}, 997cc16380SArvind Bhushan {"T520-SO 10G", "Chelsio T520-SO 10G [FCoE]"}, 1007cc16380SArvind Bhushan {"T520-CX4 10G", "Chelsio T520-CX4 10G [FCoE]"}, 1017cc16380SArvind Bhushan {"T520-BT 10G", "Chelsio T520-BT 10G [FCoE]"}, 1027cc16380SArvind Bhushan {"T504-BT 1G", "Chelsio T504-BT 1G [FCoE]"}, 1037cc16380SArvind Bhushan {"B520-SR 10G", "Chelsio B520-SR 10G [FCoE]"}, 1047cc16380SArvind Bhushan {"B504-BT 1G", "Chelsio B504-BT 1G [FCoE]"}, 1057cc16380SArvind Bhushan {"T580-CR 10G", "Chelsio T580-CR 10G [FCoE]"}, 1067cc16380SArvind Bhushan {"T540-LP-CR 10G", "Chelsio T540-LP-CR 10G [FCoE]"}, 1077cc16380SArvind Bhushan {"AMSTERDAM 10G", "Chelsio AMSTERDAM 10G [FCoE]"}, 1087cc16380SArvind Bhushan {"T580-LP-CR 40G", "Chelsio T580-LP-CR 40G [FCoE]"}, 1097cc16380SArvind Bhushan {"T520-LL-CR 10G", "Chelsio T520-LL-CR 10G [FCoE]"}, 1107cc16380SArvind Bhushan {"T560-CR 40G", "Chelsio T560-CR 40G [FCoE]"}, 1117cc16380SArvind Bhushan {"T580-CR 40G", "Chelsio T580-CR 40G [FCoE]"} 112a3667aaeSNaresh Kumar Inna }; 113a3667aaeSNaresh Kumar Inna 114a3667aaeSNaresh Kumar Inna static void csio_mgmtm_cleanup(struct csio_mgmtm *); 115a3667aaeSNaresh Kumar Inna static void csio_hw_mbm_cleanup(struct csio_hw *); 116a3667aaeSNaresh Kumar Inna 117a3667aaeSNaresh Kumar Inna /* State machine forward declarations */ 118a3667aaeSNaresh Kumar Inna static void csio_hws_uninit(struct csio_hw *, enum csio_hw_ev); 119a3667aaeSNaresh Kumar Inna static void csio_hws_configuring(struct csio_hw *, enum csio_hw_ev); 120a3667aaeSNaresh Kumar Inna static void csio_hws_initializing(struct csio_hw *, enum csio_hw_ev); 121a3667aaeSNaresh Kumar Inna static void csio_hws_ready(struct csio_hw *, enum csio_hw_ev); 122a3667aaeSNaresh Kumar Inna static void csio_hws_quiescing(struct csio_hw *, enum csio_hw_ev); 123a3667aaeSNaresh Kumar Inna static void csio_hws_quiesced(struct csio_hw *, enum csio_hw_ev); 124a3667aaeSNaresh Kumar Inna static void csio_hws_resetting(struct csio_hw *, enum csio_hw_ev); 125a3667aaeSNaresh Kumar Inna static void csio_hws_removing(struct csio_hw *, enum csio_hw_ev); 126a3667aaeSNaresh Kumar Inna static void csio_hws_pcierr(struct csio_hw *, enum csio_hw_ev); 127a3667aaeSNaresh Kumar Inna 128a3667aaeSNaresh Kumar Inna static void csio_hw_initialize(struct csio_hw *hw); 129a3667aaeSNaresh Kumar Inna static void csio_evtq_stop(struct csio_hw *hw); 130a3667aaeSNaresh Kumar Inna static void csio_evtq_start(struct csio_hw *hw); 131a3667aaeSNaresh Kumar Inna 132a3667aaeSNaresh Kumar Inna int csio_is_hw_ready(struct csio_hw *hw) 133a3667aaeSNaresh Kumar Inna { 134a3667aaeSNaresh Kumar Inna return csio_match_state(hw, csio_hws_ready); 135a3667aaeSNaresh Kumar Inna } 136a3667aaeSNaresh Kumar Inna 137a3667aaeSNaresh Kumar Inna int csio_is_hw_removing(struct csio_hw *hw) 138a3667aaeSNaresh Kumar Inna { 139a3667aaeSNaresh Kumar Inna return csio_match_state(hw, csio_hws_removing); 140a3667aaeSNaresh Kumar Inna } 141a3667aaeSNaresh Kumar Inna 142a3667aaeSNaresh Kumar Inna 143a3667aaeSNaresh Kumar Inna /* 144a3667aaeSNaresh Kumar Inna * csio_hw_wait_op_done_val - wait until an operation is completed 145a3667aaeSNaresh Kumar Inna * @hw: the HW module 146a3667aaeSNaresh Kumar Inna * @reg: the register to check for completion 147a3667aaeSNaresh Kumar Inna * @mask: a single-bit field within @reg that indicates completion 148a3667aaeSNaresh Kumar Inna * @polarity: the value of the field when the operation is completed 149a3667aaeSNaresh Kumar Inna * @attempts: number of check iterations 150a3667aaeSNaresh Kumar Inna * @delay: delay in usecs between iterations 151a3667aaeSNaresh Kumar Inna * @valp: where to store the value of the register at completion time 152a3667aaeSNaresh Kumar Inna * 153a3667aaeSNaresh Kumar Inna * Wait until an operation is completed by checking a bit in a register 154a3667aaeSNaresh Kumar Inna * up to @attempts times. If @valp is not NULL the value of the register 155a3667aaeSNaresh Kumar Inna * at the time it indicated completion is stored there. Returns 0 if the 156a3667aaeSNaresh Kumar Inna * operation completes and -EAGAIN otherwise. 157a3667aaeSNaresh Kumar Inna */ 1587cc16380SArvind Bhushan int 159a3667aaeSNaresh Kumar Inna csio_hw_wait_op_done_val(struct csio_hw *hw, int reg, uint32_t mask, 160a3667aaeSNaresh Kumar Inna int polarity, int attempts, int delay, uint32_t *valp) 161a3667aaeSNaresh Kumar Inna { 162a3667aaeSNaresh Kumar Inna uint32_t val; 163a3667aaeSNaresh Kumar Inna while (1) { 164a3667aaeSNaresh Kumar Inna val = csio_rd_reg32(hw, reg); 165a3667aaeSNaresh Kumar Inna 166a3667aaeSNaresh Kumar Inna if (!!(val & mask) == polarity) { 167a3667aaeSNaresh Kumar Inna if (valp) 168a3667aaeSNaresh Kumar Inna *valp = val; 169a3667aaeSNaresh Kumar Inna return 0; 170a3667aaeSNaresh Kumar Inna } 171a3667aaeSNaresh Kumar Inna 172a3667aaeSNaresh Kumar Inna if (--attempts == 0) 173a3667aaeSNaresh Kumar Inna return -EAGAIN; 174a3667aaeSNaresh Kumar Inna if (delay) 175a3667aaeSNaresh Kumar Inna udelay(delay); 176a3667aaeSNaresh Kumar Inna } 177a3667aaeSNaresh Kumar Inna } 178a3667aaeSNaresh Kumar Inna 1797cc16380SArvind Bhushan /* 1807cc16380SArvind Bhushan * csio_hw_tp_wr_bits_indirect - set/clear bits in an indirect TP register 1817cc16380SArvind Bhushan * @hw: the adapter 1827cc16380SArvind Bhushan * @addr: the indirect TP register address 1837cc16380SArvind Bhushan * @mask: specifies the field within the register to modify 1847cc16380SArvind Bhushan * @val: new value for the field 1857cc16380SArvind Bhushan * 1867cc16380SArvind Bhushan * Sets a field of an indirect TP register to the given value. 1877cc16380SArvind Bhushan */ 1887cc16380SArvind Bhushan void 1897cc16380SArvind Bhushan csio_hw_tp_wr_bits_indirect(struct csio_hw *hw, unsigned int addr, 1907cc16380SArvind Bhushan unsigned int mask, unsigned int val) 1917cc16380SArvind Bhushan { 1927cc16380SArvind Bhushan csio_wr_reg32(hw, addr, TP_PIO_ADDR); 1937cc16380SArvind Bhushan val |= csio_rd_reg32(hw, TP_PIO_DATA) & ~mask; 1947cc16380SArvind Bhushan csio_wr_reg32(hw, val, TP_PIO_DATA); 1957cc16380SArvind Bhushan } 1967cc16380SArvind Bhushan 197a3667aaeSNaresh Kumar Inna void 198a3667aaeSNaresh Kumar Inna csio_set_reg_field(struct csio_hw *hw, uint32_t reg, uint32_t mask, 199a3667aaeSNaresh Kumar Inna uint32_t value) 200a3667aaeSNaresh Kumar Inna { 201a3667aaeSNaresh Kumar Inna uint32_t val = csio_rd_reg32(hw, reg) & ~mask; 202a3667aaeSNaresh Kumar Inna 203a3667aaeSNaresh Kumar Inna csio_wr_reg32(hw, val | value, reg); 204a3667aaeSNaresh Kumar Inna /* Flush */ 205a3667aaeSNaresh Kumar Inna csio_rd_reg32(hw, reg); 206a3667aaeSNaresh Kumar Inna 207a3667aaeSNaresh Kumar Inna } 208a3667aaeSNaresh Kumar Inna 209a3667aaeSNaresh Kumar Inna static int 2105036f0a0SNaresh Kumar Inna csio_memory_write(struct csio_hw *hw, int mtype, u32 addr, u32 len, u32 *buf) 211a3667aaeSNaresh Kumar Inna { 2127cc16380SArvind Bhushan return hw->chip_ops->chip_memory_rw(hw, MEMWIN_CSIOSTOR, mtype, 2137cc16380SArvind Bhushan addr, len, buf, 0); 214a3667aaeSNaresh Kumar Inna } 215a3667aaeSNaresh Kumar Inna 216a3667aaeSNaresh Kumar Inna /* 217a3667aaeSNaresh Kumar Inna * EEPROM reads take a few tens of us while writes can take a bit over 5 ms. 218a3667aaeSNaresh Kumar Inna */ 219a3667aaeSNaresh Kumar Inna #define EEPROM_MAX_RD_POLL 40 220a3667aaeSNaresh Kumar Inna #define EEPROM_MAX_WR_POLL 6 221a3667aaeSNaresh Kumar Inna #define EEPROM_STAT_ADDR 0x7bfc 222a3667aaeSNaresh Kumar Inna #define VPD_BASE 0x400 223a3667aaeSNaresh Kumar Inna #define VPD_BASE_OLD 0 2247cc16380SArvind Bhushan #define VPD_LEN 1024 225a3667aaeSNaresh Kumar Inna #define VPD_INFO_FLD_HDR_SIZE 3 226a3667aaeSNaresh Kumar Inna 227a3667aaeSNaresh Kumar Inna /* 228a3667aaeSNaresh Kumar Inna * csio_hw_seeprom_read - read a serial EEPROM location 229a3667aaeSNaresh Kumar Inna * @hw: hw to read 230a3667aaeSNaresh Kumar Inna * @addr: EEPROM virtual address 231a3667aaeSNaresh Kumar Inna * @data: where to store the read data 232a3667aaeSNaresh Kumar Inna * 233a3667aaeSNaresh Kumar Inna * Read a 32-bit word from a location in serial EEPROM using the card's PCI 234a3667aaeSNaresh Kumar Inna * VPD capability. Note that this function must be called with a virtual 235a3667aaeSNaresh Kumar Inna * address. 236a3667aaeSNaresh Kumar Inna */ 237a3667aaeSNaresh Kumar Inna static int 238a3667aaeSNaresh Kumar Inna csio_hw_seeprom_read(struct csio_hw *hw, uint32_t addr, uint32_t *data) 239a3667aaeSNaresh Kumar Inna { 240a3667aaeSNaresh Kumar Inna uint16_t val = 0; 241a3667aaeSNaresh Kumar Inna int attempts = EEPROM_MAX_RD_POLL; 242a3667aaeSNaresh Kumar Inna uint32_t base = hw->params.pci.vpd_cap_addr; 243a3667aaeSNaresh Kumar Inna 244a3667aaeSNaresh Kumar Inna if (addr >= EEPROMVSIZE || (addr & 3)) 245a3667aaeSNaresh Kumar Inna return -EINVAL; 246a3667aaeSNaresh Kumar Inna 247a3667aaeSNaresh Kumar Inna pci_write_config_word(hw->pdev, base + PCI_VPD_ADDR, (uint16_t)addr); 248a3667aaeSNaresh Kumar Inna 249a3667aaeSNaresh Kumar Inna do { 250a3667aaeSNaresh Kumar Inna udelay(10); 251a3667aaeSNaresh Kumar Inna pci_read_config_word(hw->pdev, base + PCI_VPD_ADDR, &val); 252a3667aaeSNaresh Kumar Inna } while (!(val & PCI_VPD_ADDR_F) && --attempts); 253a3667aaeSNaresh Kumar Inna 254a3667aaeSNaresh Kumar Inna if (!(val & PCI_VPD_ADDR_F)) { 255a3667aaeSNaresh Kumar Inna csio_err(hw, "reading EEPROM address 0x%x failed\n", addr); 256a3667aaeSNaresh Kumar Inna return -EINVAL; 257a3667aaeSNaresh Kumar Inna } 258a3667aaeSNaresh Kumar Inna 259a3667aaeSNaresh Kumar Inna pci_read_config_dword(hw->pdev, base + PCI_VPD_DATA, data); 260a3667aaeSNaresh Kumar Inna *data = le32_to_cpu(*data); 2615036f0a0SNaresh Kumar Inna 262a3667aaeSNaresh Kumar Inna return 0; 263a3667aaeSNaresh Kumar Inna } 264a3667aaeSNaresh Kumar Inna 265a3667aaeSNaresh Kumar Inna /* 266a3667aaeSNaresh Kumar Inna * Partial EEPROM Vital Product Data structure. Includes only the ID and 267a3667aaeSNaresh Kumar Inna * VPD-R sections. 268a3667aaeSNaresh Kumar Inna */ 269a3667aaeSNaresh Kumar Inna struct t4_vpd_hdr { 270a3667aaeSNaresh Kumar Inna u8 id_tag; 271a3667aaeSNaresh Kumar Inna u8 id_len[2]; 272a3667aaeSNaresh Kumar Inna u8 id_data[ID_LEN]; 273a3667aaeSNaresh Kumar Inna u8 vpdr_tag; 274a3667aaeSNaresh Kumar Inna u8 vpdr_len[2]; 275a3667aaeSNaresh Kumar Inna }; 276a3667aaeSNaresh Kumar Inna 277a3667aaeSNaresh Kumar Inna /* 278a3667aaeSNaresh Kumar Inna * csio_hw_get_vpd_keyword_val - Locates an information field keyword in 279a3667aaeSNaresh Kumar Inna * the VPD 280a3667aaeSNaresh Kumar Inna * @v: Pointer to buffered vpd data structure 281a3667aaeSNaresh Kumar Inna * @kw: The keyword to search for 282a3667aaeSNaresh Kumar Inna * 283a3667aaeSNaresh Kumar Inna * Returns the value of the information field keyword or 284a3667aaeSNaresh Kumar Inna * -EINVAL otherwise. 285a3667aaeSNaresh Kumar Inna */ 286a3667aaeSNaresh Kumar Inna static int 287a3667aaeSNaresh Kumar Inna csio_hw_get_vpd_keyword_val(const struct t4_vpd_hdr *v, const char *kw) 288a3667aaeSNaresh Kumar Inna { 289a3667aaeSNaresh Kumar Inna int32_t i; 290a3667aaeSNaresh Kumar Inna int32_t offset , len; 291a3667aaeSNaresh Kumar Inna const uint8_t *buf = &v->id_tag; 292a3667aaeSNaresh Kumar Inna const uint8_t *vpdr_len = &v->vpdr_tag; 293a3667aaeSNaresh Kumar Inna offset = sizeof(struct t4_vpd_hdr); 294a3667aaeSNaresh Kumar Inna len = (uint16_t)vpdr_len[1] + ((uint16_t)vpdr_len[2] << 8); 295a3667aaeSNaresh Kumar Inna 296a3667aaeSNaresh Kumar Inna if (len + sizeof(struct t4_vpd_hdr) > VPD_LEN) 297a3667aaeSNaresh Kumar Inna return -EINVAL; 298a3667aaeSNaresh Kumar Inna 299a3667aaeSNaresh Kumar Inna for (i = offset; (i + VPD_INFO_FLD_HDR_SIZE) <= (offset + len);) { 300a3667aaeSNaresh Kumar Inna if (memcmp(buf + i , kw, 2) == 0) { 301a3667aaeSNaresh Kumar Inna i += VPD_INFO_FLD_HDR_SIZE; 302a3667aaeSNaresh Kumar Inna return i; 303a3667aaeSNaresh Kumar Inna } 304a3667aaeSNaresh Kumar Inna 305a3667aaeSNaresh Kumar Inna i += VPD_INFO_FLD_HDR_SIZE + buf[i+2]; 306a3667aaeSNaresh Kumar Inna } 307a3667aaeSNaresh Kumar Inna 308a3667aaeSNaresh Kumar Inna return -EINVAL; 309a3667aaeSNaresh Kumar Inna } 310a3667aaeSNaresh Kumar Inna 311a3667aaeSNaresh Kumar Inna static int 312a3667aaeSNaresh Kumar Inna csio_pci_capability(struct pci_dev *pdev, int cap, int *pos) 313a3667aaeSNaresh Kumar Inna { 314a3667aaeSNaresh Kumar Inna *pos = pci_find_capability(pdev, cap); 315a3667aaeSNaresh Kumar Inna if (*pos) 316a3667aaeSNaresh Kumar Inna return 0; 317a3667aaeSNaresh Kumar Inna 318a3667aaeSNaresh Kumar Inna return -1; 319a3667aaeSNaresh Kumar Inna } 320a3667aaeSNaresh Kumar Inna 321a3667aaeSNaresh Kumar Inna /* 322a3667aaeSNaresh Kumar Inna * csio_hw_get_vpd_params - read VPD parameters from VPD EEPROM 323a3667aaeSNaresh Kumar Inna * @hw: HW module 324a3667aaeSNaresh Kumar Inna * @p: where to store the parameters 325a3667aaeSNaresh Kumar Inna * 326a3667aaeSNaresh Kumar Inna * Reads card parameters stored in VPD EEPROM. 327a3667aaeSNaresh Kumar Inna */ 328a3667aaeSNaresh Kumar Inna static int 329a3667aaeSNaresh Kumar Inna csio_hw_get_vpd_params(struct csio_hw *hw, struct csio_vpd *p) 330a3667aaeSNaresh Kumar Inna { 331a3667aaeSNaresh Kumar Inna int i, ret, ec, sn, addr; 332a3667aaeSNaresh Kumar Inna uint8_t *vpd, csum; 333a3667aaeSNaresh Kumar Inna const struct t4_vpd_hdr *v; 334a3667aaeSNaresh Kumar Inna /* To get around compilation warning from strstrip */ 335a3667aaeSNaresh Kumar Inna char *s; 336a3667aaeSNaresh Kumar Inna 337a3667aaeSNaresh Kumar Inna if (csio_is_valid_vpd(hw)) 338a3667aaeSNaresh Kumar Inna return 0; 339a3667aaeSNaresh Kumar Inna 340a3667aaeSNaresh Kumar Inna ret = csio_pci_capability(hw->pdev, PCI_CAP_ID_VPD, 341a3667aaeSNaresh Kumar Inna &hw->params.pci.vpd_cap_addr); 342a3667aaeSNaresh Kumar Inna if (ret) 343a3667aaeSNaresh Kumar Inna return -EINVAL; 344a3667aaeSNaresh Kumar Inna 345a3667aaeSNaresh Kumar Inna vpd = kzalloc(VPD_LEN, GFP_ATOMIC); 346a3667aaeSNaresh Kumar Inna if (vpd == NULL) 347a3667aaeSNaresh Kumar Inna return -ENOMEM; 348a3667aaeSNaresh Kumar Inna 349a3667aaeSNaresh Kumar Inna /* 350a3667aaeSNaresh Kumar Inna * Card information normally starts at VPD_BASE but early cards had 351a3667aaeSNaresh Kumar Inna * it at 0. 352a3667aaeSNaresh Kumar Inna */ 353a3667aaeSNaresh Kumar Inna ret = csio_hw_seeprom_read(hw, VPD_BASE, (uint32_t *)(vpd)); 354a3667aaeSNaresh Kumar Inna addr = *vpd == 0x82 ? VPD_BASE : VPD_BASE_OLD; 355a3667aaeSNaresh Kumar Inna 356a3667aaeSNaresh Kumar Inna for (i = 0; i < VPD_LEN; i += 4) { 357a3667aaeSNaresh Kumar Inna ret = csio_hw_seeprom_read(hw, addr + i, (uint32_t *)(vpd + i)); 358a3667aaeSNaresh Kumar Inna if (ret) { 359a3667aaeSNaresh Kumar Inna kfree(vpd); 360a3667aaeSNaresh Kumar Inna return ret; 361a3667aaeSNaresh Kumar Inna } 362a3667aaeSNaresh Kumar Inna } 363a3667aaeSNaresh Kumar Inna 364a3667aaeSNaresh Kumar Inna /* Reset the VPD flag! */ 365a3667aaeSNaresh Kumar Inna hw->flags &= (~CSIO_HWF_VPD_VALID); 366a3667aaeSNaresh Kumar Inna 367a3667aaeSNaresh Kumar Inna v = (const struct t4_vpd_hdr *)vpd; 368a3667aaeSNaresh Kumar Inna 369a3667aaeSNaresh Kumar Inna #define FIND_VPD_KW(var, name) do { \ 370a3667aaeSNaresh Kumar Inna var = csio_hw_get_vpd_keyword_val(v, name); \ 371a3667aaeSNaresh Kumar Inna if (var < 0) { \ 372a3667aaeSNaresh Kumar Inna csio_err(hw, "missing VPD keyword " name "\n"); \ 373a3667aaeSNaresh Kumar Inna kfree(vpd); \ 374a3667aaeSNaresh Kumar Inna return -EINVAL; \ 375a3667aaeSNaresh Kumar Inna } \ 376a3667aaeSNaresh Kumar Inna } while (0) 377a3667aaeSNaresh Kumar Inna 378a3667aaeSNaresh Kumar Inna FIND_VPD_KW(i, "RV"); 379a3667aaeSNaresh Kumar Inna for (csum = 0; i >= 0; i--) 380a3667aaeSNaresh Kumar Inna csum += vpd[i]; 381a3667aaeSNaresh Kumar Inna 382a3667aaeSNaresh Kumar Inna if (csum) { 383a3667aaeSNaresh Kumar Inna csio_err(hw, "corrupted VPD EEPROM, actual csum %u\n", csum); 384a3667aaeSNaresh Kumar Inna kfree(vpd); 385a3667aaeSNaresh Kumar Inna return -EINVAL; 386a3667aaeSNaresh Kumar Inna } 387a3667aaeSNaresh Kumar Inna FIND_VPD_KW(ec, "EC"); 388a3667aaeSNaresh Kumar Inna FIND_VPD_KW(sn, "SN"); 389a3667aaeSNaresh Kumar Inna #undef FIND_VPD_KW 390a3667aaeSNaresh Kumar Inna 391a3667aaeSNaresh Kumar Inna memcpy(p->id, v->id_data, ID_LEN); 392a3667aaeSNaresh Kumar Inna s = strstrip(p->id); 393a3667aaeSNaresh Kumar Inna memcpy(p->ec, vpd + ec, EC_LEN); 394a3667aaeSNaresh Kumar Inna s = strstrip(p->ec); 395a3667aaeSNaresh Kumar Inna i = vpd[sn - VPD_INFO_FLD_HDR_SIZE + 2]; 396a3667aaeSNaresh Kumar Inna memcpy(p->sn, vpd + sn, min(i, SERNUM_LEN)); 397a3667aaeSNaresh Kumar Inna s = strstrip(p->sn); 398a3667aaeSNaresh Kumar Inna 399a3667aaeSNaresh Kumar Inna csio_valid_vpd_copied(hw); 400a3667aaeSNaresh Kumar Inna 401a3667aaeSNaresh Kumar Inna kfree(vpd); 402a3667aaeSNaresh Kumar Inna return 0; 403a3667aaeSNaresh Kumar Inna } 404a3667aaeSNaresh Kumar Inna 405a3667aaeSNaresh Kumar Inna /* 406a3667aaeSNaresh Kumar Inna * csio_hw_sf1_read - read data from the serial flash 407a3667aaeSNaresh Kumar Inna * @hw: the HW module 408a3667aaeSNaresh Kumar Inna * @byte_cnt: number of bytes to read 409a3667aaeSNaresh Kumar Inna * @cont: whether another operation will be chained 410a3667aaeSNaresh Kumar Inna * @lock: whether to lock SF for PL access only 411a3667aaeSNaresh Kumar Inna * @valp: where to store the read data 412a3667aaeSNaresh Kumar Inna * 413a3667aaeSNaresh Kumar Inna * Reads up to 4 bytes of data from the serial flash. The location of 414a3667aaeSNaresh Kumar Inna * the read needs to be specified prior to calling this by issuing the 415a3667aaeSNaresh Kumar Inna * appropriate commands to the serial flash. 416a3667aaeSNaresh Kumar Inna */ 417a3667aaeSNaresh Kumar Inna static int 418a3667aaeSNaresh Kumar Inna csio_hw_sf1_read(struct csio_hw *hw, uint32_t byte_cnt, int32_t cont, 419a3667aaeSNaresh Kumar Inna int32_t lock, uint32_t *valp) 420a3667aaeSNaresh Kumar Inna { 421a3667aaeSNaresh Kumar Inna int ret; 422a3667aaeSNaresh Kumar Inna 423a3667aaeSNaresh Kumar Inna if (!byte_cnt || byte_cnt > 4) 424a3667aaeSNaresh Kumar Inna return -EINVAL; 425a3667aaeSNaresh Kumar Inna if (csio_rd_reg32(hw, SF_OP) & SF_BUSY) 426a3667aaeSNaresh Kumar Inna return -EBUSY; 427a3667aaeSNaresh Kumar Inna 428a3667aaeSNaresh Kumar Inna cont = cont ? SF_CONT : 0; 429a3667aaeSNaresh Kumar Inna lock = lock ? SF_LOCK : 0; 430a3667aaeSNaresh Kumar Inna 431a3667aaeSNaresh Kumar Inna csio_wr_reg32(hw, lock | cont | BYTECNT(byte_cnt - 1), SF_OP); 432a3667aaeSNaresh Kumar Inna ret = csio_hw_wait_op_done_val(hw, SF_OP, SF_BUSY, 0, SF_ATTEMPTS, 433a3667aaeSNaresh Kumar Inna 10, NULL); 434a3667aaeSNaresh Kumar Inna if (!ret) 435a3667aaeSNaresh Kumar Inna *valp = csio_rd_reg32(hw, SF_DATA); 436a3667aaeSNaresh Kumar Inna return ret; 437a3667aaeSNaresh Kumar Inna } 438a3667aaeSNaresh Kumar Inna 439a3667aaeSNaresh Kumar Inna /* 440a3667aaeSNaresh Kumar Inna * csio_hw_sf1_write - write data to the serial flash 441a3667aaeSNaresh Kumar Inna * @hw: the HW module 442a3667aaeSNaresh Kumar Inna * @byte_cnt: number of bytes to write 443a3667aaeSNaresh Kumar Inna * @cont: whether another operation will be chained 444a3667aaeSNaresh Kumar Inna * @lock: whether to lock SF for PL access only 445a3667aaeSNaresh Kumar Inna * @val: value to write 446a3667aaeSNaresh Kumar Inna * 447a3667aaeSNaresh Kumar Inna * Writes up to 4 bytes of data to the serial flash. The location of 448a3667aaeSNaresh Kumar Inna * the write needs to be specified prior to calling this by issuing the 449a3667aaeSNaresh Kumar Inna * appropriate commands to the serial flash. 450a3667aaeSNaresh Kumar Inna */ 451a3667aaeSNaresh Kumar Inna static int 452a3667aaeSNaresh Kumar Inna csio_hw_sf1_write(struct csio_hw *hw, uint32_t byte_cnt, uint32_t cont, 453a3667aaeSNaresh Kumar Inna int32_t lock, uint32_t val) 454a3667aaeSNaresh Kumar Inna { 455a3667aaeSNaresh Kumar Inna if (!byte_cnt || byte_cnt > 4) 456a3667aaeSNaresh Kumar Inna return -EINVAL; 457a3667aaeSNaresh Kumar Inna if (csio_rd_reg32(hw, SF_OP) & SF_BUSY) 458a3667aaeSNaresh Kumar Inna return -EBUSY; 459a3667aaeSNaresh Kumar Inna 460a3667aaeSNaresh Kumar Inna cont = cont ? SF_CONT : 0; 461a3667aaeSNaresh Kumar Inna lock = lock ? SF_LOCK : 0; 462a3667aaeSNaresh Kumar Inna 463a3667aaeSNaresh Kumar Inna csio_wr_reg32(hw, val, SF_DATA); 464a3667aaeSNaresh Kumar Inna csio_wr_reg32(hw, cont | BYTECNT(byte_cnt - 1) | OP_WR | lock, SF_OP); 465a3667aaeSNaresh Kumar Inna 466a3667aaeSNaresh Kumar Inna return csio_hw_wait_op_done_val(hw, SF_OP, SF_BUSY, 0, SF_ATTEMPTS, 467a3667aaeSNaresh Kumar Inna 10, NULL); 468a3667aaeSNaresh Kumar Inna } 469a3667aaeSNaresh Kumar Inna 470a3667aaeSNaresh Kumar Inna /* 471a3667aaeSNaresh Kumar Inna * csio_hw_flash_wait_op - wait for a flash operation to complete 472a3667aaeSNaresh Kumar Inna * @hw: the HW module 473a3667aaeSNaresh Kumar Inna * @attempts: max number of polls of the status register 474a3667aaeSNaresh Kumar Inna * @delay: delay between polls in ms 475a3667aaeSNaresh Kumar Inna * 476a3667aaeSNaresh Kumar Inna * Wait for a flash operation to complete by polling the status register. 477a3667aaeSNaresh Kumar Inna */ 478a3667aaeSNaresh Kumar Inna static int 479a3667aaeSNaresh Kumar Inna csio_hw_flash_wait_op(struct csio_hw *hw, int32_t attempts, int32_t delay) 480a3667aaeSNaresh Kumar Inna { 481a3667aaeSNaresh Kumar Inna int ret; 482a3667aaeSNaresh Kumar Inna uint32_t status; 483a3667aaeSNaresh Kumar Inna 484a3667aaeSNaresh Kumar Inna while (1) { 485a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_write(hw, 1, 1, 1, SF_RD_STATUS); 486a3667aaeSNaresh Kumar Inna if (ret != 0) 487a3667aaeSNaresh Kumar Inna return ret; 488a3667aaeSNaresh Kumar Inna 489a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_read(hw, 1, 0, 1, &status); 490a3667aaeSNaresh Kumar Inna if (ret != 0) 491a3667aaeSNaresh Kumar Inna return ret; 492a3667aaeSNaresh Kumar Inna 493a3667aaeSNaresh Kumar Inna if (!(status & 1)) 494a3667aaeSNaresh Kumar Inna return 0; 495a3667aaeSNaresh Kumar Inna if (--attempts == 0) 496a3667aaeSNaresh Kumar Inna return -EAGAIN; 497a3667aaeSNaresh Kumar Inna if (delay) 498a3667aaeSNaresh Kumar Inna msleep(delay); 499a3667aaeSNaresh Kumar Inna } 500a3667aaeSNaresh Kumar Inna } 501a3667aaeSNaresh Kumar Inna 502a3667aaeSNaresh Kumar Inna /* 503a3667aaeSNaresh Kumar Inna * csio_hw_read_flash - read words from serial flash 504a3667aaeSNaresh Kumar Inna * @hw: the HW module 505a3667aaeSNaresh Kumar Inna * @addr: the start address for the read 506a3667aaeSNaresh Kumar Inna * @nwords: how many 32-bit words to read 507a3667aaeSNaresh Kumar Inna * @data: where to store the read data 508a3667aaeSNaresh Kumar Inna * @byte_oriented: whether to store data as bytes or as words 509a3667aaeSNaresh Kumar Inna * 510a3667aaeSNaresh Kumar Inna * Read the specified number of 32-bit words from the serial flash. 511a3667aaeSNaresh Kumar Inna * If @byte_oriented is set the read data is stored as a byte array 512a3667aaeSNaresh Kumar Inna * (i.e., big-endian), otherwise as 32-bit words in the platform's 513a3667aaeSNaresh Kumar Inna * natural endianess. 514a3667aaeSNaresh Kumar Inna */ 515a3667aaeSNaresh Kumar Inna static int 516a3667aaeSNaresh Kumar Inna csio_hw_read_flash(struct csio_hw *hw, uint32_t addr, uint32_t nwords, 517a3667aaeSNaresh Kumar Inna uint32_t *data, int32_t byte_oriented) 518a3667aaeSNaresh Kumar Inna { 519a3667aaeSNaresh Kumar Inna int ret; 520a3667aaeSNaresh Kumar Inna 521a3667aaeSNaresh Kumar Inna if (addr + nwords * sizeof(uint32_t) > hw->params.sf_size || (addr & 3)) 522a3667aaeSNaresh Kumar Inna return -EINVAL; 523a3667aaeSNaresh Kumar Inna 524a3667aaeSNaresh Kumar Inna addr = swab32(addr) | SF_RD_DATA_FAST; 525a3667aaeSNaresh Kumar Inna 526a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_write(hw, 4, 1, 0, addr); 527a3667aaeSNaresh Kumar Inna if (ret != 0) 528a3667aaeSNaresh Kumar Inna return ret; 529a3667aaeSNaresh Kumar Inna 530a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_read(hw, 1, 1, 0, data); 531a3667aaeSNaresh Kumar Inna if (ret != 0) 532a3667aaeSNaresh Kumar Inna return ret; 533a3667aaeSNaresh Kumar Inna 534a3667aaeSNaresh Kumar Inna for ( ; nwords; nwords--, data++) { 535a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_read(hw, 4, nwords > 1, nwords == 1, data); 536a3667aaeSNaresh Kumar Inna if (nwords == 1) 537a3667aaeSNaresh Kumar Inna csio_wr_reg32(hw, 0, SF_OP); /* unlock SF */ 538a3667aaeSNaresh Kumar Inna if (ret) 539a3667aaeSNaresh Kumar Inna return ret; 540a3667aaeSNaresh Kumar Inna if (byte_oriented) 541a3667aaeSNaresh Kumar Inna *data = htonl(*data); 542a3667aaeSNaresh Kumar Inna } 543a3667aaeSNaresh Kumar Inna return 0; 544a3667aaeSNaresh Kumar Inna } 545a3667aaeSNaresh Kumar Inna 546a3667aaeSNaresh Kumar Inna /* 547a3667aaeSNaresh Kumar Inna * csio_hw_write_flash - write up to a page of data to the serial flash 548a3667aaeSNaresh Kumar Inna * @hw: the hw 549a3667aaeSNaresh Kumar Inna * @addr: the start address to write 550a3667aaeSNaresh Kumar Inna * @n: length of data to write in bytes 551a3667aaeSNaresh Kumar Inna * @data: the data to write 552a3667aaeSNaresh Kumar Inna * 553a3667aaeSNaresh Kumar Inna * Writes up to a page of data (256 bytes) to the serial flash starting 554a3667aaeSNaresh Kumar Inna * at the given address. All the data must be written to the same page. 555a3667aaeSNaresh Kumar Inna */ 556a3667aaeSNaresh Kumar Inna static int 557a3667aaeSNaresh Kumar Inna csio_hw_write_flash(struct csio_hw *hw, uint32_t addr, 558a3667aaeSNaresh Kumar Inna uint32_t n, const uint8_t *data) 559a3667aaeSNaresh Kumar Inna { 560a3667aaeSNaresh Kumar Inna int ret = -EINVAL; 561a3667aaeSNaresh Kumar Inna uint32_t buf[64]; 562a3667aaeSNaresh Kumar Inna uint32_t i, c, left, val, offset = addr & 0xff; 563a3667aaeSNaresh Kumar Inna 564a3667aaeSNaresh Kumar Inna if (addr >= hw->params.sf_size || offset + n > SF_PAGE_SIZE) 565a3667aaeSNaresh Kumar Inna return -EINVAL; 566a3667aaeSNaresh Kumar Inna 567a3667aaeSNaresh Kumar Inna val = swab32(addr) | SF_PROG_PAGE; 568a3667aaeSNaresh Kumar Inna 569a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_write(hw, 1, 0, 1, SF_WR_ENABLE); 570a3667aaeSNaresh Kumar Inna if (ret != 0) 571a3667aaeSNaresh Kumar Inna goto unlock; 572a3667aaeSNaresh Kumar Inna 573a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_write(hw, 4, 1, 1, val); 574a3667aaeSNaresh Kumar Inna if (ret != 0) 575a3667aaeSNaresh Kumar Inna goto unlock; 576a3667aaeSNaresh Kumar Inna 577a3667aaeSNaresh Kumar Inna for (left = n; left; left -= c) { 578a3667aaeSNaresh Kumar Inna c = min(left, 4U); 579a3667aaeSNaresh Kumar Inna for (val = 0, i = 0; i < c; ++i) 580a3667aaeSNaresh Kumar Inna val = (val << 8) + *data++; 581a3667aaeSNaresh Kumar Inna 582a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_write(hw, c, c != left, 1, val); 583a3667aaeSNaresh Kumar Inna if (ret) 584a3667aaeSNaresh Kumar Inna goto unlock; 585a3667aaeSNaresh Kumar Inna } 586a3667aaeSNaresh Kumar Inna ret = csio_hw_flash_wait_op(hw, 8, 1); 587a3667aaeSNaresh Kumar Inna if (ret) 588a3667aaeSNaresh Kumar Inna goto unlock; 589a3667aaeSNaresh Kumar Inna 590a3667aaeSNaresh Kumar Inna csio_wr_reg32(hw, 0, SF_OP); /* unlock SF */ 591a3667aaeSNaresh Kumar Inna 592a3667aaeSNaresh Kumar Inna /* Read the page to verify the write succeeded */ 593a3667aaeSNaresh Kumar Inna ret = csio_hw_read_flash(hw, addr & ~0xff, ARRAY_SIZE(buf), buf, 1); 594a3667aaeSNaresh Kumar Inna if (ret) 595a3667aaeSNaresh Kumar Inna return ret; 596a3667aaeSNaresh Kumar Inna 597a3667aaeSNaresh Kumar Inna if (memcmp(data - n, (uint8_t *)buf + offset, n)) { 598a3667aaeSNaresh Kumar Inna csio_err(hw, 599a3667aaeSNaresh Kumar Inna "failed to correctly write the flash page at %#x\n", 600a3667aaeSNaresh Kumar Inna addr); 601a3667aaeSNaresh Kumar Inna return -EINVAL; 602a3667aaeSNaresh Kumar Inna } 603a3667aaeSNaresh Kumar Inna 604a3667aaeSNaresh Kumar Inna return 0; 605a3667aaeSNaresh Kumar Inna 606a3667aaeSNaresh Kumar Inna unlock: 607a3667aaeSNaresh Kumar Inna csio_wr_reg32(hw, 0, SF_OP); /* unlock SF */ 608a3667aaeSNaresh Kumar Inna return ret; 609a3667aaeSNaresh Kumar Inna } 610a3667aaeSNaresh Kumar Inna 611a3667aaeSNaresh Kumar Inna /* 612a3667aaeSNaresh Kumar Inna * csio_hw_flash_erase_sectors - erase a range of flash sectors 613a3667aaeSNaresh Kumar Inna * @hw: the HW module 614a3667aaeSNaresh Kumar Inna * @start: the first sector to erase 615a3667aaeSNaresh Kumar Inna * @end: the last sector to erase 616a3667aaeSNaresh Kumar Inna * 617a3667aaeSNaresh Kumar Inna * Erases the sectors in the given inclusive range. 618a3667aaeSNaresh Kumar Inna */ 619a3667aaeSNaresh Kumar Inna static int 620a3667aaeSNaresh Kumar Inna csio_hw_flash_erase_sectors(struct csio_hw *hw, int32_t start, int32_t end) 621a3667aaeSNaresh Kumar Inna { 622a3667aaeSNaresh Kumar Inna int ret = 0; 623a3667aaeSNaresh Kumar Inna 624a3667aaeSNaresh Kumar Inna while (start <= end) { 625a3667aaeSNaresh Kumar Inna 626a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_write(hw, 1, 0, 1, SF_WR_ENABLE); 627a3667aaeSNaresh Kumar Inna if (ret != 0) 628a3667aaeSNaresh Kumar Inna goto out; 629a3667aaeSNaresh Kumar Inna 630a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_write(hw, 4, 0, 1, 631a3667aaeSNaresh Kumar Inna SF_ERASE_SECTOR | (start << 8)); 632a3667aaeSNaresh Kumar Inna if (ret != 0) 633a3667aaeSNaresh Kumar Inna goto out; 634a3667aaeSNaresh Kumar Inna 635a3667aaeSNaresh Kumar Inna ret = csio_hw_flash_wait_op(hw, 14, 500); 636a3667aaeSNaresh Kumar Inna if (ret != 0) 637a3667aaeSNaresh Kumar Inna goto out; 638a3667aaeSNaresh Kumar Inna 639a3667aaeSNaresh Kumar Inna start++; 640a3667aaeSNaresh Kumar Inna } 641a3667aaeSNaresh Kumar Inna out: 642a3667aaeSNaresh Kumar Inna if (ret) 643a3667aaeSNaresh Kumar Inna csio_err(hw, "erase of flash sector %d failed, error %d\n", 644a3667aaeSNaresh Kumar Inna start, ret); 645a3667aaeSNaresh Kumar Inna csio_wr_reg32(hw, 0, SF_OP); /* unlock SF */ 646a3667aaeSNaresh Kumar Inna return 0; 647a3667aaeSNaresh Kumar Inna } 648a3667aaeSNaresh Kumar Inna 649a3667aaeSNaresh Kumar Inna static void 650a3667aaeSNaresh Kumar Inna csio_hw_print_fw_version(struct csio_hw *hw, char *str) 651a3667aaeSNaresh Kumar Inna { 652a3667aaeSNaresh Kumar Inna csio_info(hw, "%s: %u.%u.%u.%u\n", str, 653a3667aaeSNaresh Kumar Inna FW_HDR_FW_VER_MAJOR_GET(hw->fwrev), 654a3667aaeSNaresh Kumar Inna FW_HDR_FW_VER_MINOR_GET(hw->fwrev), 655a3667aaeSNaresh Kumar Inna FW_HDR_FW_VER_MICRO_GET(hw->fwrev), 656a3667aaeSNaresh Kumar Inna FW_HDR_FW_VER_BUILD_GET(hw->fwrev)); 657a3667aaeSNaresh Kumar Inna } 658a3667aaeSNaresh Kumar Inna 659a3667aaeSNaresh Kumar Inna /* 660a3667aaeSNaresh Kumar Inna * csio_hw_get_fw_version - read the firmware version 661a3667aaeSNaresh Kumar Inna * @hw: HW module 662a3667aaeSNaresh Kumar Inna * @vers: where to place the version 663a3667aaeSNaresh Kumar Inna * 664a3667aaeSNaresh Kumar Inna * Reads the FW version from flash. 665a3667aaeSNaresh Kumar Inna */ 666a3667aaeSNaresh Kumar Inna static int 667a3667aaeSNaresh Kumar Inna csio_hw_get_fw_version(struct csio_hw *hw, uint32_t *vers) 668a3667aaeSNaresh Kumar Inna { 669a3667aaeSNaresh Kumar Inna return csio_hw_read_flash(hw, FW_IMG_START + 670a3667aaeSNaresh Kumar Inna offsetof(struct fw_hdr, fw_ver), 1, 671a3667aaeSNaresh Kumar Inna vers, 0); 672a3667aaeSNaresh Kumar Inna } 673a3667aaeSNaresh Kumar Inna 674a3667aaeSNaresh Kumar Inna /* 675a3667aaeSNaresh Kumar Inna * csio_hw_get_tp_version - read the TP microcode version 676a3667aaeSNaresh Kumar Inna * @hw: HW module 677a3667aaeSNaresh Kumar Inna * @vers: where to place the version 678a3667aaeSNaresh Kumar Inna * 679a3667aaeSNaresh Kumar Inna * Reads the TP microcode version from flash. 680a3667aaeSNaresh Kumar Inna */ 681a3667aaeSNaresh Kumar Inna static int 682a3667aaeSNaresh Kumar Inna csio_hw_get_tp_version(struct csio_hw *hw, u32 *vers) 683a3667aaeSNaresh Kumar Inna { 684a3667aaeSNaresh Kumar Inna return csio_hw_read_flash(hw, FLASH_FW_START + 685a3667aaeSNaresh Kumar Inna offsetof(struct fw_hdr, tp_microcode_ver), 1, 686a3667aaeSNaresh Kumar Inna vers, 0); 687a3667aaeSNaresh Kumar Inna } 688a3667aaeSNaresh Kumar Inna 689a3667aaeSNaresh Kumar Inna /* 690a3667aaeSNaresh Kumar Inna * csio_hw_check_fw_version - check if the FW is compatible with 691a3667aaeSNaresh Kumar Inna * this driver 692a3667aaeSNaresh Kumar Inna * @hw: HW module 693a3667aaeSNaresh Kumar Inna * 694a3667aaeSNaresh Kumar Inna * Checks if an adapter's FW is compatible with the driver. Returns 0 695a3667aaeSNaresh Kumar Inna * if there's exact match, a negative error if the version could not be 696a3667aaeSNaresh Kumar Inna * read or there's a major/minor version mismatch/minor. 697a3667aaeSNaresh Kumar Inna */ 698a3667aaeSNaresh Kumar Inna static int 699a3667aaeSNaresh Kumar Inna csio_hw_check_fw_version(struct csio_hw *hw) 700a3667aaeSNaresh Kumar Inna { 701a3667aaeSNaresh Kumar Inna int ret, major, minor, micro; 702a3667aaeSNaresh Kumar Inna 703a3667aaeSNaresh Kumar Inna ret = csio_hw_get_fw_version(hw, &hw->fwrev); 704a3667aaeSNaresh Kumar Inna if (!ret) 705a3667aaeSNaresh Kumar Inna ret = csio_hw_get_tp_version(hw, &hw->tp_vers); 706a3667aaeSNaresh Kumar Inna if (ret) 707a3667aaeSNaresh Kumar Inna return ret; 708a3667aaeSNaresh Kumar Inna 709a3667aaeSNaresh Kumar Inna major = FW_HDR_FW_VER_MAJOR_GET(hw->fwrev); 710a3667aaeSNaresh Kumar Inna minor = FW_HDR_FW_VER_MINOR_GET(hw->fwrev); 711a3667aaeSNaresh Kumar Inna micro = FW_HDR_FW_VER_MICRO_GET(hw->fwrev); 712a3667aaeSNaresh Kumar Inna 7137cc16380SArvind Bhushan if (major != FW_VERSION_MAJOR(hw)) { /* major mismatch - fail */ 714a3667aaeSNaresh Kumar Inna csio_err(hw, "card FW has major version %u, driver wants %u\n", 7157cc16380SArvind Bhushan major, FW_VERSION_MAJOR(hw)); 716a3667aaeSNaresh Kumar Inna return -EINVAL; 717a3667aaeSNaresh Kumar Inna } 718a3667aaeSNaresh Kumar Inna 7197cc16380SArvind Bhushan if (minor == FW_VERSION_MINOR(hw) && micro == FW_VERSION_MICRO(hw)) 720a3667aaeSNaresh Kumar Inna return 0; /* perfect match */ 721a3667aaeSNaresh Kumar Inna 722a3667aaeSNaresh Kumar Inna /* Minor/micro version mismatch */ 723a3667aaeSNaresh Kumar Inna return -EINVAL; 724a3667aaeSNaresh Kumar Inna } 725a3667aaeSNaresh Kumar Inna 726a3667aaeSNaresh Kumar Inna /* 727a3667aaeSNaresh Kumar Inna * csio_hw_fw_dload - download firmware. 728a3667aaeSNaresh Kumar Inna * @hw: HW module 729a3667aaeSNaresh Kumar Inna * @fw_data: firmware image to write. 730a3667aaeSNaresh Kumar Inna * @size: image size 731a3667aaeSNaresh Kumar Inna * 732a3667aaeSNaresh Kumar Inna * Write the supplied firmware image to the card's serial flash. 733a3667aaeSNaresh Kumar Inna */ 734a3667aaeSNaresh Kumar Inna static int 735a3667aaeSNaresh Kumar Inna csio_hw_fw_dload(struct csio_hw *hw, uint8_t *fw_data, uint32_t size) 736a3667aaeSNaresh Kumar Inna { 737a3667aaeSNaresh Kumar Inna uint32_t csum; 738a3667aaeSNaresh Kumar Inna int32_t addr; 739a3667aaeSNaresh Kumar Inna int ret; 740a3667aaeSNaresh Kumar Inna uint32_t i; 741a3667aaeSNaresh Kumar Inna uint8_t first_page[SF_PAGE_SIZE]; 7425036f0a0SNaresh Kumar Inna const __be32 *p = (const __be32 *)fw_data; 743a3667aaeSNaresh Kumar Inna struct fw_hdr *hdr = (struct fw_hdr *)fw_data; 744a3667aaeSNaresh Kumar Inna uint32_t sf_sec_size; 745a3667aaeSNaresh Kumar Inna 746a3667aaeSNaresh Kumar Inna if ((!hw->params.sf_size) || (!hw->params.sf_nsec)) { 747a3667aaeSNaresh Kumar Inna csio_err(hw, "Serial Flash data invalid\n"); 748a3667aaeSNaresh Kumar Inna return -EINVAL; 749a3667aaeSNaresh Kumar Inna } 750a3667aaeSNaresh Kumar Inna 751a3667aaeSNaresh Kumar Inna if (!size) { 752a3667aaeSNaresh Kumar Inna csio_err(hw, "FW image has no data\n"); 753a3667aaeSNaresh Kumar Inna return -EINVAL; 754a3667aaeSNaresh Kumar Inna } 755a3667aaeSNaresh Kumar Inna 756a3667aaeSNaresh Kumar Inna if (size & 511) { 757a3667aaeSNaresh Kumar Inna csio_err(hw, "FW image size not multiple of 512 bytes\n"); 758a3667aaeSNaresh Kumar Inna return -EINVAL; 759a3667aaeSNaresh Kumar Inna } 760a3667aaeSNaresh Kumar Inna 761a3667aaeSNaresh Kumar Inna if (ntohs(hdr->len512) * 512 != size) { 762a3667aaeSNaresh Kumar Inna csio_err(hw, "FW image size differs from size in FW header\n"); 763a3667aaeSNaresh Kumar Inna return -EINVAL; 764a3667aaeSNaresh Kumar Inna } 765a3667aaeSNaresh Kumar Inna 766a3667aaeSNaresh Kumar Inna if (size > FW_MAX_SIZE) { 767a3667aaeSNaresh Kumar Inna csio_err(hw, "FW image too large, max is %u bytes\n", 768a3667aaeSNaresh Kumar Inna FW_MAX_SIZE); 769a3667aaeSNaresh Kumar Inna return -EINVAL; 770a3667aaeSNaresh Kumar Inna } 771a3667aaeSNaresh Kumar Inna 772a3667aaeSNaresh Kumar Inna for (csum = 0, i = 0; i < size / sizeof(csum); i++) 773a3667aaeSNaresh Kumar Inna csum += ntohl(p[i]); 774a3667aaeSNaresh Kumar Inna 775a3667aaeSNaresh Kumar Inna if (csum != 0xffffffff) { 776a3667aaeSNaresh Kumar Inna csio_err(hw, "corrupted firmware image, checksum %#x\n", csum); 777a3667aaeSNaresh Kumar Inna return -EINVAL; 778a3667aaeSNaresh Kumar Inna } 779a3667aaeSNaresh Kumar Inna 780a3667aaeSNaresh Kumar Inna sf_sec_size = hw->params.sf_size / hw->params.sf_nsec; 781a3667aaeSNaresh Kumar Inna i = DIV_ROUND_UP(size, sf_sec_size); /* # of sectors spanned */ 782a3667aaeSNaresh Kumar Inna 783a3667aaeSNaresh Kumar Inna csio_dbg(hw, "Erasing sectors... start:%d end:%d\n", 784a3667aaeSNaresh Kumar Inna FW_START_SEC, FW_START_SEC + i - 1); 785a3667aaeSNaresh Kumar Inna 786a3667aaeSNaresh Kumar Inna ret = csio_hw_flash_erase_sectors(hw, FW_START_SEC, 787a3667aaeSNaresh Kumar Inna FW_START_SEC + i - 1); 788a3667aaeSNaresh Kumar Inna if (ret) { 789a3667aaeSNaresh Kumar Inna csio_err(hw, "Flash Erase failed\n"); 790a3667aaeSNaresh Kumar Inna goto out; 791a3667aaeSNaresh Kumar Inna } 792a3667aaeSNaresh Kumar Inna 793a3667aaeSNaresh Kumar Inna /* 794a3667aaeSNaresh Kumar Inna * We write the correct version at the end so the driver can see a bad 795a3667aaeSNaresh Kumar Inna * version if the FW write fails. Start by writing a copy of the 796a3667aaeSNaresh Kumar Inna * first page with a bad version. 797a3667aaeSNaresh Kumar Inna */ 798a3667aaeSNaresh Kumar Inna memcpy(first_page, fw_data, SF_PAGE_SIZE); 799a3667aaeSNaresh Kumar Inna ((struct fw_hdr *)first_page)->fw_ver = htonl(0xffffffff); 800a3667aaeSNaresh Kumar Inna ret = csio_hw_write_flash(hw, FW_IMG_START, SF_PAGE_SIZE, first_page); 801a3667aaeSNaresh Kumar Inna if (ret) 802a3667aaeSNaresh Kumar Inna goto out; 803a3667aaeSNaresh Kumar Inna 804a3667aaeSNaresh Kumar Inna csio_dbg(hw, "Writing Flash .. start:%d end:%d\n", 805a3667aaeSNaresh Kumar Inna FW_IMG_START, FW_IMG_START + size); 806a3667aaeSNaresh Kumar Inna 807a3667aaeSNaresh Kumar Inna addr = FW_IMG_START; 808a3667aaeSNaresh Kumar Inna for (size -= SF_PAGE_SIZE; size; size -= SF_PAGE_SIZE) { 809a3667aaeSNaresh Kumar Inna addr += SF_PAGE_SIZE; 810a3667aaeSNaresh Kumar Inna fw_data += SF_PAGE_SIZE; 811a3667aaeSNaresh Kumar Inna ret = csio_hw_write_flash(hw, addr, SF_PAGE_SIZE, fw_data); 812a3667aaeSNaresh Kumar Inna if (ret) 813a3667aaeSNaresh Kumar Inna goto out; 814a3667aaeSNaresh Kumar Inna } 815a3667aaeSNaresh Kumar Inna 816a3667aaeSNaresh Kumar Inna ret = csio_hw_write_flash(hw, 817a3667aaeSNaresh Kumar Inna FW_IMG_START + 818a3667aaeSNaresh Kumar Inna offsetof(struct fw_hdr, fw_ver), 819a3667aaeSNaresh Kumar Inna sizeof(hdr->fw_ver), 820a3667aaeSNaresh Kumar Inna (const uint8_t *)&hdr->fw_ver); 821a3667aaeSNaresh Kumar Inna 822a3667aaeSNaresh Kumar Inna out: 823a3667aaeSNaresh Kumar Inna if (ret) 824a3667aaeSNaresh Kumar Inna csio_err(hw, "firmware download failed, error %d\n", ret); 825a3667aaeSNaresh Kumar Inna return ret; 826a3667aaeSNaresh Kumar Inna } 827a3667aaeSNaresh Kumar Inna 828a3667aaeSNaresh Kumar Inna static int 829a3667aaeSNaresh Kumar Inna csio_hw_get_flash_params(struct csio_hw *hw) 830a3667aaeSNaresh Kumar Inna { 831a3667aaeSNaresh Kumar Inna int ret; 832a3667aaeSNaresh Kumar Inna uint32_t info = 0; 833a3667aaeSNaresh Kumar Inna 834a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_write(hw, 1, 1, 0, SF_RD_ID); 835a3667aaeSNaresh Kumar Inna if (!ret) 836a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_read(hw, 3, 0, 1, &info); 837a3667aaeSNaresh Kumar Inna csio_wr_reg32(hw, 0, SF_OP); /* unlock SF */ 838a3667aaeSNaresh Kumar Inna if (ret != 0) 839a3667aaeSNaresh Kumar Inna return ret; 840a3667aaeSNaresh Kumar Inna 841a3667aaeSNaresh Kumar Inna if ((info & 0xff) != 0x20) /* not a Numonix flash */ 842a3667aaeSNaresh Kumar Inna return -EINVAL; 843a3667aaeSNaresh Kumar Inna info >>= 16; /* log2 of size */ 844a3667aaeSNaresh Kumar Inna if (info >= 0x14 && info < 0x18) 845a3667aaeSNaresh Kumar Inna hw->params.sf_nsec = 1 << (info - 16); 846a3667aaeSNaresh Kumar Inna else if (info == 0x18) 847a3667aaeSNaresh Kumar Inna hw->params.sf_nsec = 64; 848a3667aaeSNaresh Kumar Inna else 849a3667aaeSNaresh Kumar Inna return -EINVAL; 850a3667aaeSNaresh Kumar Inna hw->params.sf_size = 1 << info; 851a3667aaeSNaresh Kumar Inna 852a3667aaeSNaresh Kumar Inna return 0; 853a3667aaeSNaresh Kumar Inna } 854a3667aaeSNaresh Kumar Inna 855a3667aaeSNaresh Kumar Inna /*****************************************************************************/ 856a3667aaeSNaresh Kumar Inna /* HW State machine assists */ 857a3667aaeSNaresh Kumar Inna /*****************************************************************************/ 858a3667aaeSNaresh Kumar Inna 859a3667aaeSNaresh Kumar Inna static int 860a3667aaeSNaresh Kumar Inna csio_hw_dev_ready(struct csio_hw *hw) 861a3667aaeSNaresh Kumar Inna { 862a3667aaeSNaresh Kumar Inna uint32_t reg; 863a3667aaeSNaresh Kumar Inna int cnt = 6; 864a3667aaeSNaresh Kumar Inna 865a3667aaeSNaresh Kumar Inna while (((reg = csio_rd_reg32(hw, PL_WHOAMI)) == 0xFFFFFFFF) && 866a3667aaeSNaresh Kumar Inna (--cnt != 0)) 867a3667aaeSNaresh Kumar Inna mdelay(100); 868a3667aaeSNaresh Kumar Inna 869a3667aaeSNaresh Kumar Inna if ((cnt == 0) && (((int32_t)(SOURCEPF_GET(reg)) < 0) || 870a3667aaeSNaresh Kumar Inna (SOURCEPF_GET(reg) >= CSIO_MAX_PFN))) { 871a3667aaeSNaresh Kumar Inna csio_err(hw, "PL_WHOAMI returned 0x%x, cnt:%d\n", reg, cnt); 872a3667aaeSNaresh Kumar Inna return -EIO; 873a3667aaeSNaresh Kumar Inna } 874a3667aaeSNaresh Kumar Inna 875a3667aaeSNaresh Kumar Inna hw->pfn = SOURCEPF_GET(reg); 876a3667aaeSNaresh Kumar Inna 877a3667aaeSNaresh Kumar Inna return 0; 878a3667aaeSNaresh Kumar Inna } 879a3667aaeSNaresh Kumar Inna 880a3667aaeSNaresh Kumar Inna /* 881a3667aaeSNaresh Kumar Inna * csio_do_hello - Perform the HELLO FW Mailbox command and process response. 882a3667aaeSNaresh Kumar Inna * @hw: HW module 883a3667aaeSNaresh Kumar Inna * @state: Device state 884a3667aaeSNaresh Kumar Inna * 885a3667aaeSNaresh Kumar Inna * FW_HELLO_CMD has to be polled for completion. 886a3667aaeSNaresh Kumar Inna */ 887a3667aaeSNaresh Kumar Inna static int 888a3667aaeSNaresh Kumar Inna csio_do_hello(struct csio_hw *hw, enum csio_dev_state *state) 889a3667aaeSNaresh Kumar Inna { 890a3667aaeSNaresh Kumar Inna struct csio_mb *mbp; 891a3667aaeSNaresh Kumar Inna int rv = 0; 892a3667aaeSNaresh Kumar Inna enum csio_dev_master master; 893a3667aaeSNaresh Kumar Inna enum fw_retval retval; 894a3667aaeSNaresh Kumar Inna uint8_t mpfn; 895a3667aaeSNaresh Kumar Inna char state_str[16]; 896a3667aaeSNaresh Kumar Inna int retries = FW_CMD_HELLO_RETRIES; 897a3667aaeSNaresh Kumar Inna 898a3667aaeSNaresh Kumar Inna memset(state_str, 0, sizeof(state_str)); 899a3667aaeSNaresh Kumar Inna 900a3667aaeSNaresh Kumar Inna mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 901a3667aaeSNaresh Kumar Inna if (!mbp) { 902a3667aaeSNaresh Kumar Inna rv = -ENOMEM; 903a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_nomem); 904a3667aaeSNaresh Kumar Inna goto out; 905a3667aaeSNaresh Kumar Inna } 906a3667aaeSNaresh Kumar Inna 907a3667aaeSNaresh Kumar Inna master = csio_force_master ? CSIO_MASTER_MUST : CSIO_MASTER_MAY; 908a3667aaeSNaresh Kumar Inna 909a3667aaeSNaresh Kumar Inna retry: 910a3667aaeSNaresh Kumar Inna csio_mb_hello(hw, mbp, CSIO_MB_DEFAULT_TMO, hw->pfn, 911a3667aaeSNaresh Kumar Inna hw->pfn, master, NULL); 912a3667aaeSNaresh Kumar Inna 913a3667aaeSNaresh Kumar Inna rv = csio_mb_issue(hw, mbp); 914a3667aaeSNaresh Kumar Inna if (rv) { 915a3667aaeSNaresh Kumar Inna csio_err(hw, "failed to issue HELLO cmd. ret:%d.\n", rv); 916a3667aaeSNaresh Kumar Inna goto out_free_mb; 917a3667aaeSNaresh Kumar Inna } 918a3667aaeSNaresh Kumar Inna 919a3667aaeSNaresh Kumar Inna csio_mb_process_hello_rsp(hw, mbp, &retval, state, &mpfn); 920a3667aaeSNaresh Kumar Inna if (retval != FW_SUCCESS) { 921a3667aaeSNaresh Kumar Inna csio_err(hw, "HELLO cmd failed with ret: %d\n", retval); 922a3667aaeSNaresh Kumar Inna rv = -EINVAL; 923a3667aaeSNaresh Kumar Inna goto out_free_mb; 924a3667aaeSNaresh Kumar Inna } 925a3667aaeSNaresh Kumar Inna 926a3667aaeSNaresh Kumar Inna /* Firmware has designated us to be master */ 927a3667aaeSNaresh Kumar Inna if (hw->pfn == mpfn) { 928a3667aaeSNaresh Kumar Inna hw->flags |= CSIO_HWF_MASTER; 929a3667aaeSNaresh Kumar Inna } else if (*state == CSIO_DEV_STATE_UNINIT) { 930a3667aaeSNaresh Kumar Inna /* 931a3667aaeSNaresh Kumar Inna * If we're not the Master PF then we need to wait around for 932a3667aaeSNaresh Kumar Inna * the Master PF Driver to finish setting up the adapter. 933a3667aaeSNaresh Kumar Inna * 934a3667aaeSNaresh Kumar Inna * Note that we also do this wait if we're a non-Master-capable 935a3667aaeSNaresh Kumar Inna * PF and there is no current Master PF; a Master PF may show up 936a3667aaeSNaresh Kumar Inna * momentarily and we wouldn't want to fail pointlessly. (This 937a3667aaeSNaresh Kumar Inna * can happen when an OS loads lots of different drivers rapidly 938a3667aaeSNaresh Kumar Inna * at the same time). In this case, the Master PF returned by 939a3667aaeSNaresh Kumar Inna * the firmware will be PCIE_FW_MASTER_MASK so the test below 940a3667aaeSNaresh Kumar Inna * will work ... 941a3667aaeSNaresh Kumar Inna */ 942a3667aaeSNaresh Kumar Inna 943a3667aaeSNaresh Kumar Inna int waiting = FW_CMD_HELLO_TIMEOUT; 944a3667aaeSNaresh Kumar Inna 945a3667aaeSNaresh Kumar Inna /* 946a3667aaeSNaresh Kumar Inna * Wait for the firmware to either indicate an error or 947a3667aaeSNaresh Kumar Inna * initialized state. If we see either of these we bail out 948a3667aaeSNaresh Kumar Inna * and report the issue to the caller. If we exhaust the 949a3667aaeSNaresh Kumar Inna * "hello timeout" and we haven't exhausted our retries, try 950a3667aaeSNaresh Kumar Inna * again. Otherwise bail with a timeout error. 951a3667aaeSNaresh Kumar Inna */ 952a3667aaeSNaresh Kumar Inna for (;;) { 953a3667aaeSNaresh Kumar Inna uint32_t pcie_fw; 954a3667aaeSNaresh Kumar Inna 9557cc16380SArvind Bhushan spin_unlock_irq(&hw->lock); 956a3667aaeSNaresh Kumar Inna msleep(50); 9577cc16380SArvind Bhushan spin_lock_irq(&hw->lock); 958a3667aaeSNaresh Kumar Inna waiting -= 50; 959a3667aaeSNaresh Kumar Inna 960a3667aaeSNaresh Kumar Inna /* 961a3667aaeSNaresh Kumar Inna * If neither Error nor Initialialized are indicated 962a3667aaeSNaresh Kumar Inna * by the firmware keep waiting till we exaust our 963a3667aaeSNaresh Kumar Inna * timeout ... and then retry if we haven't exhausted 964a3667aaeSNaresh Kumar Inna * our retries ... 965a3667aaeSNaresh Kumar Inna */ 966a3667aaeSNaresh Kumar Inna pcie_fw = csio_rd_reg32(hw, PCIE_FW); 967a3667aaeSNaresh Kumar Inna if (!(pcie_fw & (PCIE_FW_ERR|PCIE_FW_INIT))) { 968a3667aaeSNaresh Kumar Inna if (waiting <= 0) { 969a3667aaeSNaresh Kumar Inna if (retries-- > 0) 970a3667aaeSNaresh Kumar Inna goto retry; 971a3667aaeSNaresh Kumar Inna 972a3667aaeSNaresh Kumar Inna rv = -ETIMEDOUT; 973a3667aaeSNaresh Kumar Inna break; 974a3667aaeSNaresh Kumar Inna } 975a3667aaeSNaresh Kumar Inna continue; 976a3667aaeSNaresh Kumar Inna } 977a3667aaeSNaresh Kumar Inna 978a3667aaeSNaresh Kumar Inna /* 979a3667aaeSNaresh Kumar Inna * We either have an Error or Initialized condition 980a3667aaeSNaresh Kumar Inna * report errors preferentially. 981a3667aaeSNaresh Kumar Inna */ 982a3667aaeSNaresh Kumar Inna if (state) { 983a3667aaeSNaresh Kumar Inna if (pcie_fw & PCIE_FW_ERR) { 984a3667aaeSNaresh Kumar Inna *state = CSIO_DEV_STATE_ERR; 985a3667aaeSNaresh Kumar Inna rv = -ETIMEDOUT; 986a3667aaeSNaresh Kumar Inna } else if (pcie_fw & PCIE_FW_INIT) 987a3667aaeSNaresh Kumar Inna *state = CSIO_DEV_STATE_INIT; 988a3667aaeSNaresh Kumar Inna } 989a3667aaeSNaresh Kumar Inna 990a3667aaeSNaresh Kumar Inna /* 991a3667aaeSNaresh Kumar Inna * If we arrived before a Master PF was selected and 992a3667aaeSNaresh Kumar Inna * there's not a valid Master PF, grab its identity 993a3667aaeSNaresh Kumar Inna * for our caller. 994a3667aaeSNaresh Kumar Inna */ 995a3667aaeSNaresh Kumar Inna if (mpfn == PCIE_FW_MASTER_MASK && 996a3667aaeSNaresh Kumar Inna (pcie_fw & PCIE_FW_MASTER_VLD)) 997a3667aaeSNaresh Kumar Inna mpfn = PCIE_FW_MASTER_GET(pcie_fw); 998a3667aaeSNaresh Kumar Inna break; 999a3667aaeSNaresh Kumar Inna } 1000a3667aaeSNaresh Kumar Inna hw->flags &= ~CSIO_HWF_MASTER; 1001a3667aaeSNaresh Kumar Inna } 1002a3667aaeSNaresh Kumar Inna 1003a3667aaeSNaresh Kumar Inna switch (*state) { 1004a3667aaeSNaresh Kumar Inna case CSIO_DEV_STATE_UNINIT: 1005a3667aaeSNaresh Kumar Inna strcpy(state_str, "Initializing"); 1006a3667aaeSNaresh Kumar Inna break; 1007a3667aaeSNaresh Kumar Inna case CSIO_DEV_STATE_INIT: 1008a3667aaeSNaresh Kumar Inna strcpy(state_str, "Initialized"); 1009a3667aaeSNaresh Kumar Inna break; 1010a3667aaeSNaresh Kumar Inna case CSIO_DEV_STATE_ERR: 1011a3667aaeSNaresh Kumar Inna strcpy(state_str, "Error"); 1012a3667aaeSNaresh Kumar Inna break; 1013a3667aaeSNaresh Kumar Inna default: 1014a3667aaeSNaresh Kumar Inna strcpy(state_str, "Unknown"); 1015a3667aaeSNaresh Kumar Inna break; 1016a3667aaeSNaresh Kumar Inna } 1017a3667aaeSNaresh Kumar Inna 1018a3667aaeSNaresh Kumar Inna if (hw->pfn == mpfn) 1019a3667aaeSNaresh Kumar Inna csio_info(hw, "PF: %d, Coming up as MASTER, HW state: %s\n", 1020a3667aaeSNaresh Kumar Inna hw->pfn, state_str); 1021a3667aaeSNaresh Kumar Inna else 1022a3667aaeSNaresh Kumar Inna csio_info(hw, 1023a3667aaeSNaresh Kumar Inna "PF: %d, Coming up as SLAVE, Master PF: %d, HW state: %s\n", 1024a3667aaeSNaresh Kumar Inna hw->pfn, mpfn, state_str); 1025a3667aaeSNaresh Kumar Inna 1026a3667aaeSNaresh Kumar Inna out_free_mb: 1027a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1028a3667aaeSNaresh Kumar Inna out: 1029a3667aaeSNaresh Kumar Inna return rv; 1030a3667aaeSNaresh Kumar Inna } 1031a3667aaeSNaresh Kumar Inna 1032a3667aaeSNaresh Kumar Inna /* 1033a3667aaeSNaresh Kumar Inna * csio_do_bye - Perform the BYE FW Mailbox command and process response. 1034a3667aaeSNaresh Kumar Inna * @hw: HW module 1035a3667aaeSNaresh Kumar Inna * 1036a3667aaeSNaresh Kumar Inna */ 1037a3667aaeSNaresh Kumar Inna static int 1038a3667aaeSNaresh Kumar Inna csio_do_bye(struct csio_hw *hw) 1039a3667aaeSNaresh Kumar Inna { 1040a3667aaeSNaresh Kumar Inna struct csio_mb *mbp; 1041a3667aaeSNaresh Kumar Inna enum fw_retval retval; 1042a3667aaeSNaresh Kumar Inna 1043a3667aaeSNaresh Kumar Inna mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 1044a3667aaeSNaresh Kumar Inna if (!mbp) { 1045a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_nomem); 1046a3667aaeSNaresh Kumar Inna return -ENOMEM; 1047a3667aaeSNaresh Kumar Inna } 1048a3667aaeSNaresh Kumar Inna 1049a3667aaeSNaresh Kumar Inna csio_mb_bye(hw, mbp, CSIO_MB_DEFAULT_TMO, NULL); 1050a3667aaeSNaresh Kumar Inna 1051a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 1052a3667aaeSNaresh Kumar Inna csio_err(hw, "Issue of BYE command failed\n"); 1053a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1054a3667aaeSNaresh Kumar Inna return -EINVAL; 1055a3667aaeSNaresh Kumar Inna } 1056a3667aaeSNaresh Kumar Inna 1057a3667aaeSNaresh Kumar Inna retval = csio_mb_fw_retval(mbp); 1058a3667aaeSNaresh Kumar Inna if (retval != FW_SUCCESS) { 1059a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1060a3667aaeSNaresh Kumar Inna return -EINVAL; 1061a3667aaeSNaresh Kumar Inna } 1062a3667aaeSNaresh Kumar Inna 1063a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1064a3667aaeSNaresh Kumar Inna 1065a3667aaeSNaresh Kumar Inna return 0; 1066a3667aaeSNaresh Kumar Inna } 1067a3667aaeSNaresh Kumar Inna 1068a3667aaeSNaresh Kumar Inna /* 1069a3667aaeSNaresh Kumar Inna * csio_do_reset- Perform the device reset. 1070a3667aaeSNaresh Kumar Inna * @hw: HW module 1071a3667aaeSNaresh Kumar Inna * @fw_rst: FW reset 1072a3667aaeSNaresh Kumar Inna * 1073a3667aaeSNaresh Kumar Inna * If fw_rst is set, issues FW reset mbox cmd otherwise 1074a3667aaeSNaresh Kumar Inna * does PIO reset. 1075a3667aaeSNaresh Kumar Inna * Performs reset of the function. 1076a3667aaeSNaresh Kumar Inna */ 1077a3667aaeSNaresh Kumar Inna static int 1078a3667aaeSNaresh Kumar Inna csio_do_reset(struct csio_hw *hw, bool fw_rst) 1079a3667aaeSNaresh Kumar Inna { 1080a3667aaeSNaresh Kumar Inna struct csio_mb *mbp; 1081a3667aaeSNaresh Kumar Inna enum fw_retval retval; 1082a3667aaeSNaresh Kumar Inna 1083a3667aaeSNaresh Kumar Inna if (!fw_rst) { 1084a3667aaeSNaresh Kumar Inna /* PIO reset */ 1085a3667aaeSNaresh Kumar Inna csio_wr_reg32(hw, PIORSTMODE | PIORST, PL_RST); 1086a3667aaeSNaresh Kumar Inna mdelay(2000); 1087a3667aaeSNaresh Kumar Inna return 0; 1088a3667aaeSNaresh Kumar Inna } 1089a3667aaeSNaresh Kumar Inna 1090a3667aaeSNaresh Kumar Inna mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 1091a3667aaeSNaresh Kumar Inna if (!mbp) { 1092a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_nomem); 1093a3667aaeSNaresh Kumar Inna return -ENOMEM; 1094a3667aaeSNaresh Kumar Inna } 1095a3667aaeSNaresh Kumar Inna 1096a3667aaeSNaresh Kumar Inna csio_mb_reset(hw, mbp, CSIO_MB_DEFAULT_TMO, 1097a3667aaeSNaresh Kumar Inna PIORSTMODE | PIORST, 0, NULL); 1098a3667aaeSNaresh Kumar Inna 1099a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 1100a3667aaeSNaresh Kumar Inna csio_err(hw, "Issue of RESET command failed.n"); 1101a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1102a3667aaeSNaresh Kumar Inna return -EINVAL; 1103a3667aaeSNaresh Kumar Inna } 1104a3667aaeSNaresh Kumar Inna 1105a3667aaeSNaresh Kumar Inna retval = csio_mb_fw_retval(mbp); 1106a3667aaeSNaresh Kumar Inna if (retval != FW_SUCCESS) { 1107a3667aaeSNaresh Kumar Inna csio_err(hw, "RESET cmd failed with ret:0x%x.\n", retval); 1108a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1109a3667aaeSNaresh Kumar Inna return -EINVAL; 1110a3667aaeSNaresh Kumar Inna } 1111a3667aaeSNaresh Kumar Inna 1112a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1113a3667aaeSNaresh Kumar Inna 1114a3667aaeSNaresh Kumar Inna return 0; 1115a3667aaeSNaresh Kumar Inna } 1116a3667aaeSNaresh Kumar Inna 1117a3667aaeSNaresh Kumar Inna static int 1118a3667aaeSNaresh Kumar Inna csio_hw_validate_caps(struct csio_hw *hw, struct csio_mb *mbp) 1119a3667aaeSNaresh Kumar Inna { 1120a3667aaeSNaresh Kumar Inna struct fw_caps_config_cmd *rsp = (struct fw_caps_config_cmd *)mbp->mb; 1121a3667aaeSNaresh Kumar Inna uint16_t caps; 1122a3667aaeSNaresh Kumar Inna 1123a3667aaeSNaresh Kumar Inna caps = ntohs(rsp->fcoecaps); 1124a3667aaeSNaresh Kumar Inna 1125a3667aaeSNaresh Kumar Inna if (!(caps & FW_CAPS_CONFIG_FCOE_INITIATOR)) { 1126a3667aaeSNaresh Kumar Inna csio_err(hw, "No FCoE Initiator capability in the firmware.\n"); 1127a3667aaeSNaresh Kumar Inna return -EINVAL; 1128a3667aaeSNaresh Kumar Inna } 1129a3667aaeSNaresh Kumar Inna 1130a3667aaeSNaresh Kumar Inna if (!(caps & FW_CAPS_CONFIG_FCOE_CTRL_OFLD)) { 1131a3667aaeSNaresh Kumar Inna csio_err(hw, "No FCoE Control Offload capability\n"); 1132a3667aaeSNaresh Kumar Inna return -EINVAL; 1133a3667aaeSNaresh Kumar Inna } 1134a3667aaeSNaresh Kumar Inna 1135a3667aaeSNaresh Kumar Inna return 0; 1136a3667aaeSNaresh Kumar Inna } 1137a3667aaeSNaresh Kumar Inna 1138a3667aaeSNaresh Kumar Inna /* 1139a3667aaeSNaresh Kumar Inna * csio_hw_fw_halt - issue a reset/halt to FW and put uP into RESET 1140a3667aaeSNaresh Kumar Inna * @hw: the HW module 1141a3667aaeSNaresh Kumar Inna * @mbox: mailbox to use for the FW RESET command (if desired) 1142a3667aaeSNaresh Kumar Inna * @force: force uP into RESET even if FW RESET command fails 1143a3667aaeSNaresh Kumar Inna * 1144a3667aaeSNaresh Kumar Inna * Issues a RESET command to firmware (if desired) with a HALT indication 1145a3667aaeSNaresh Kumar Inna * and then puts the microprocessor into RESET state. The RESET command 1146a3667aaeSNaresh Kumar Inna * will only be issued if a legitimate mailbox is provided (mbox <= 1147a3667aaeSNaresh Kumar Inna * PCIE_FW_MASTER_MASK). 1148a3667aaeSNaresh Kumar Inna * 1149a3667aaeSNaresh Kumar Inna * This is generally used in order for the host to safely manipulate the 1150a3667aaeSNaresh Kumar Inna * adapter without fear of conflicting with whatever the firmware might 1151a3667aaeSNaresh Kumar Inna * be doing. The only way out of this state is to RESTART the firmware 1152a3667aaeSNaresh Kumar Inna * ... 1153a3667aaeSNaresh Kumar Inna */ 1154a3667aaeSNaresh Kumar Inna static int 1155a3667aaeSNaresh Kumar Inna csio_hw_fw_halt(struct csio_hw *hw, uint32_t mbox, int32_t force) 1156a3667aaeSNaresh Kumar Inna { 1157a3667aaeSNaresh Kumar Inna enum fw_retval retval = 0; 1158a3667aaeSNaresh Kumar Inna 1159a3667aaeSNaresh Kumar Inna /* 1160a3667aaeSNaresh Kumar Inna * If a legitimate mailbox is provided, issue a RESET command 1161a3667aaeSNaresh Kumar Inna * with a HALT indication. 1162a3667aaeSNaresh Kumar Inna */ 1163a3667aaeSNaresh Kumar Inna if (mbox <= PCIE_FW_MASTER_MASK) { 1164a3667aaeSNaresh Kumar Inna struct csio_mb *mbp; 1165a3667aaeSNaresh Kumar Inna 1166a3667aaeSNaresh Kumar Inna mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 1167a3667aaeSNaresh Kumar Inna if (!mbp) { 1168a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_nomem); 1169a3667aaeSNaresh Kumar Inna return -ENOMEM; 1170a3667aaeSNaresh Kumar Inna } 1171a3667aaeSNaresh Kumar Inna 1172a3667aaeSNaresh Kumar Inna csio_mb_reset(hw, mbp, CSIO_MB_DEFAULT_TMO, 1173a3667aaeSNaresh Kumar Inna PIORSTMODE | PIORST, FW_RESET_CMD_HALT(1), 1174a3667aaeSNaresh Kumar Inna NULL); 1175a3667aaeSNaresh Kumar Inna 1176a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 1177a3667aaeSNaresh Kumar Inna csio_err(hw, "Issue of RESET command failed!\n"); 1178a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1179a3667aaeSNaresh Kumar Inna return -EINVAL; 1180a3667aaeSNaresh Kumar Inna } 1181a3667aaeSNaresh Kumar Inna 1182a3667aaeSNaresh Kumar Inna retval = csio_mb_fw_retval(mbp); 1183a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1184a3667aaeSNaresh Kumar Inna } 1185a3667aaeSNaresh Kumar Inna 1186a3667aaeSNaresh Kumar Inna /* 1187a3667aaeSNaresh Kumar Inna * Normally we won't complete the operation if the firmware RESET 1188a3667aaeSNaresh Kumar Inna * command fails but if our caller insists we'll go ahead and put the 1189a3667aaeSNaresh Kumar Inna * uP into RESET. This can be useful if the firmware is hung or even 1190a3667aaeSNaresh Kumar Inna * missing ... We'll have to take the risk of putting the uP into 1191a3667aaeSNaresh Kumar Inna * RESET without the cooperation of firmware in that case. 1192a3667aaeSNaresh Kumar Inna * 1193a3667aaeSNaresh Kumar Inna * We also force the firmware's HALT flag to be on in case we bypassed 1194a3667aaeSNaresh Kumar Inna * the firmware RESET command above or we're dealing with old firmware 1195a3667aaeSNaresh Kumar Inna * which doesn't have the HALT capability. This will serve as a flag 1196a3667aaeSNaresh Kumar Inna * for the incoming firmware to know that it's coming out of a HALT 1197a3667aaeSNaresh Kumar Inna * rather than a RESET ... if it's new enough to understand that ... 1198a3667aaeSNaresh Kumar Inna */ 1199a3667aaeSNaresh Kumar Inna if (retval == 0 || force) { 1200a3667aaeSNaresh Kumar Inna csio_set_reg_field(hw, CIM_BOOT_CFG, UPCRST, UPCRST); 1201a3667aaeSNaresh Kumar Inna csio_set_reg_field(hw, PCIE_FW, PCIE_FW_HALT, PCIE_FW_HALT); 1202a3667aaeSNaresh Kumar Inna } 1203a3667aaeSNaresh Kumar Inna 1204a3667aaeSNaresh Kumar Inna /* 1205a3667aaeSNaresh Kumar Inna * And we always return the result of the firmware RESET command 1206a3667aaeSNaresh Kumar Inna * even when we force the uP into RESET ... 1207a3667aaeSNaresh Kumar Inna */ 1208a3667aaeSNaresh Kumar Inna return retval ? -EINVAL : 0; 1209a3667aaeSNaresh Kumar Inna } 1210a3667aaeSNaresh Kumar Inna 1211a3667aaeSNaresh Kumar Inna /* 1212a3667aaeSNaresh Kumar Inna * csio_hw_fw_restart - restart the firmware by taking the uP out of RESET 1213a3667aaeSNaresh Kumar Inna * @hw: the HW module 1214a3667aaeSNaresh Kumar Inna * @reset: if we want to do a RESET to restart things 1215a3667aaeSNaresh Kumar Inna * 1216a3667aaeSNaresh Kumar Inna * Restart firmware previously halted by csio_hw_fw_halt(). On successful 1217a3667aaeSNaresh Kumar Inna * return the previous PF Master remains as the new PF Master and there 1218a3667aaeSNaresh Kumar Inna * is no need to issue a new HELLO command, etc. 1219a3667aaeSNaresh Kumar Inna * 1220a3667aaeSNaresh Kumar Inna * We do this in two ways: 1221a3667aaeSNaresh Kumar Inna * 1222a3667aaeSNaresh Kumar Inna * 1. If we're dealing with newer firmware we'll simply want to take 1223a3667aaeSNaresh Kumar Inna * the chip's microprocessor out of RESET. This will cause the 1224a3667aaeSNaresh Kumar Inna * firmware to start up from its start vector. And then we'll loop 1225a3667aaeSNaresh Kumar Inna * until the firmware indicates it's started again (PCIE_FW.HALT 1226a3667aaeSNaresh Kumar Inna * reset to 0) or we timeout. 1227a3667aaeSNaresh Kumar Inna * 1228a3667aaeSNaresh Kumar Inna * 2. If we're dealing with older firmware then we'll need to RESET 1229a3667aaeSNaresh Kumar Inna * the chip since older firmware won't recognize the PCIE_FW.HALT 1230a3667aaeSNaresh Kumar Inna * flag and automatically RESET itself on startup. 1231a3667aaeSNaresh Kumar Inna */ 1232a3667aaeSNaresh Kumar Inna static int 1233a3667aaeSNaresh Kumar Inna csio_hw_fw_restart(struct csio_hw *hw, uint32_t mbox, int32_t reset) 1234a3667aaeSNaresh Kumar Inna { 1235a3667aaeSNaresh Kumar Inna if (reset) { 1236a3667aaeSNaresh Kumar Inna /* 1237a3667aaeSNaresh Kumar Inna * Since we're directing the RESET instead of the firmware 1238a3667aaeSNaresh Kumar Inna * doing it automatically, we need to clear the PCIE_FW.HALT 1239a3667aaeSNaresh Kumar Inna * bit. 1240a3667aaeSNaresh Kumar Inna */ 1241a3667aaeSNaresh Kumar Inna csio_set_reg_field(hw, PCIE_FW, PCIE_FW_HALT, 0); 1242a3667aaeSNaresh Kumar Inna 1243a3667aaeSNaresh Kumar Inna /* 1244a3667aaeSNaresh Kumar Inna * If we've been given a valid mailbox, first try to get the 1245a3667aaeSNaresh Kumar Inna * firmware to do the RESET. If that works, great and we can 1246a3667aaeSNaresh Kumar Inna * return success. Otherwise, if we haven't been given a 1247a3667aaeSNaresh Kumar Inna * valid mailbox or the RESET command failed, fall back to 1248a3667aaeSNaresh Kumar Inna * hitting the chip with a hammer. 1249a3667aaeSNaresh Kumar Inna */ 1250a3667aaeSNaresh Kumar Inna if (mbox <= PCIE_FW_MASTER_MASK) { 1251a3667aaeSNaresh Kumar Inna csio_set_reg_field(hw, CIM_BOOT_CFG, UPCRST, 0); 1252a3667aaeSNaresh Kumar Inna msleep(100); 1253a3667aaeSNaresh Kumar Inna if (csio_do_reset(hw, true) == 0) 1254a3667aaeSNaresh Kumar Inna return 0; 1255a3667aaeSNaresh Kumar Inna } 1256a3667aaeSNaresh Kumar Inna 1257a3667aaeSNaresh Kumar Inna csio_wr_reg32(hw, PIORSTMODE | PIORST, PL_RST); 1258a3667aaeSNaresh Kumar Inna msleep(2000); 1259a3667aaeSNaresh Kumar Inna } else { 1260a3667aaeSNaresh Kumar Inna int ms; 1261a3667aaeSNaresh Kumar Inna 1262a3667aaeSNaresh Kumar Inna csio_set_reg_field(hw, CIM_BOOT_CFG, UPCRST, 0); 1263a3667aaeSNaresh Kumar Inna for (ms = 0; ms < FW_CMD_MAX_TIMEOUT; ) { 1264a3667aaeSNaresh Kumar Inna if (!(csio_rd_reg32(hw, PCIE_FW) & PCIE_FW_HALT)) 1265a3667aaeSNaresh Kumar Inna return 0; 1266a3667aaeSNaresh Kumar Inna msleep(100); 1267a3667aaeSNaresh Kumar Inna ms += 100; 1268a3667aaeSNaresh Kumar Inna } 1269a3667aaeSNaresh Kumar Inna return -ETIMEDOUT; 1270a3667aaeSNaresh Kumar Inna } 1271a3667aaeSNaresh Kumar Inna return 0; 1272a3667aaeSNaresh Kumar Inna } 1273a3667aaeSNaresh Kumar Inna 1274a3667aaeSNaresh Kumar Inna /* 1275a3667aaeSNaresh Kumar Inna * csio_hw_fw_upgrade - perform all of the steps necessary to upgrade FW 1276a3667aaeSNaresh Kumar Inna * @hw: the HW module 1277a3667aaeSNaresh Kumar Inna * @mbox: mailbox to use for the FW RESET command (if desired) 1278a3667aaeSNaresh Kumar Inna * @fw_data: the firmware image to write 1279a3667aaeSNaresh Kumar Inna * @size: image size 1280a3667aaeSNaresh Kumar Inna * @force: force upgrade even if firmware doesn't cooperate 1281a3667aaeSNaresh Kumar Inna * 1282a3667aaeSNaresh Kumar Inna * Perform all of the steps necessary for upgrading an adapter's 1283a3667aaeSNaresh Kumar Inna * firmware image. Normally this requires the cooperation of the 1284a3667aaeSNaresh Kumar Inna * existing firmware in order to halt all existing activities 1285a3667aaeSNaresh Kumar Inna * but if an invalid mailbox token is passed in we skip that step 1286a3667aaeSNaresh Kumar Inna * (though we'll still put the adapter microprocessor into RESET in 1287a3667aaeSNaresh Kumar Inna * that case). 1288a3667aaeSNaresh Kumar Inna * 1289a3667aaeSNaresh Kumar Inna * On successful return the new firmware will have been loaded and 1290a3667aaeSNaresh Kumar Inna * the adapter will have been fully RESET losing all previous setup 1291a3667aaeSNaresh Kumar Inna * state. On unsuccessful return the adapter may be completely hosed ... 1292a3667aaeSNaresh Kumar Inna * positive errno indicates that the adapter is ~probably~ intact, a 1293a3667aaeSNaresh Kumar Inna * negative errno indicates that things are looking bad ... 1294a3667aaeSNaresh Kumar Inna */ 1295a3667aaeSNaresh Kumar Inna static int 1296a3667aaeSNaresh Kumar Inna csio_hw_fw_upgrade(struct csio_hw *hw, uint32_t mbox, 1297a3667aaeSNaresh Kumar Inna const u8 *fw_data, uint32_t size, int32_t force) 1298a3667aaeSNaresh Kumar Inna { 1299a3667aaeSNaresh Kumar Inna const struct fw_hdr *fw_hdr = (const struct fw_hdr *)fw_data; 1300a3667aaeSNaresh Kumar Inna int reset, ret; 1301a3667aaeSNaresh Kumar Inna 1302a3667aaeSNaresh Kumar Inna ret = csio_hw_fw_halt(hw, mbox, force); 1303a3667aaeSNaresh Kumar Inna if (ret != 0 && !force) 1304a3667aaeSNaresh Kumar Inna return ret; 1305a3667aaeSNaresh Kumar Inna 1306a3667aaeSNaresh Kumar Inna ret = csio_hw_fw_dload(hw, (uint8_t *) fw_data, size); 1307a3667aaeSNaresh Kumar Inna if (ret != 0) 1308a3667aaeSNaresh Kumar Inna return ret; 1309a3667aaeSNaresh Kumar Inna 1310a3667aaeSNaresh Kumar Inna /* 1311a3667aaeSNaresh Kumar Inna * Older versions of the firmware don't understand the new 1312a3667aaeSNaresh Kumar Inna * PCIE_FW.HALT flag and so won't know to perform a RESET when they 1313a3667aaeSNaresh Kumar Inna * restart. So for newly loaded older firmware we'll have to do the 1314a3667aaeSNaresh Kumar Inna * RESET for it so it starts up on a clean slate. We can tell if 1315a3667aaeSNaresh Kumar Inna * the newly loaded firmware will handle this right by checking 1316a3667aaeSNaresh Kumar Inna * its header flags to see if it advertises the capability. 1317a3667aaeSNaresh Kumar Inna */ 1318a3667aaeSNaresh Kumar Inna reset = ((ntohl(fw_hdr->flags) & FW_HDR_FLAGS_RESET_HALT) == 0); 1319a3667aaeSNaresh Kumar Inna return csio_hw_fw_restart(hw, mbox, reset); 1320a3667aaeSNaresh Kumar Inna } 1321a3667aaeSNaresh Kumar Inna 1322a3667aaeSNaresh Kumar Inna 1323a3667aaeSNaresh Kumar Inna /* 1324a3667aaeSNaresh Kumar Inna * csio_hw_fw_config_file - setup an adapter via a Configuration File 1325a3667aaeSNaresh Kumar Inna * @hw: the HW module 1326a3667aaeSNaresh Kumar Inna * @mbox: mailbox to use for the FW command 1327a3667aaeSNaresh Kumar Inna * @mtype: the memory type where the Configuration File is located 1328a3667aaeSNaresh Kumar Inna * @maddr: the memory address where the Configuration File is located 1329a3667aaeSNaresh Kumar Inna * @finiver: return value for CF [fini] version 1330a3667aaeSNaresh Kumar Inna * @finicsum: return value for CF [fini] checksum 1331a3667aaeSNaresh Kumar Inna * @cfcsum: return value for CF computed checksum 1332a3667aaeSNaresh Kumar Inna * 1333a3667aaeSNaresh Kumar Inna * Issue a command to get the firmware to process the Configuration 1334a3667aaeSNaresh Kumar Inna * File located at the specified mtype/maddress. If the Configuration 1335a3667aaeSNaresh Kumar Inna * File is processed successfully and return value pointers are 1336a3667aaeSNaresh Kumar Inna * provided, the Configuration File "[fini] section version and 1337a3667aaeSNaresh Kumar Inna * checksum values will be returned along with the computed checksum. 1338a3667aaeSNaresh Kumar Inna * It's up to the caller to decide how it wants to respond to the 1339a3667aaeSNaresh Kumar Inna * checksums not matching but it recommended that a prominant warning 1340a3667aaeSNaresh Kumar Inna * be emitted in order to help people rapidly identify changed or 1341a3667aaeSNaresh Kumar Inna * corrupted Configuration Files. 1342a3667aaeSNaresh Kumar Inna * 1343a3667aaeSNaresh Kumar Inna * Also note that it's possible to modify things like "niccaps", 1344a3667aaeSNaresh Kumar Inna * "toecaps",etc. between processing the Configuration File and telling 1345a3667aaeSNaresh Kumar Inna * the firmware to use the new configuration. Callers which want to 1346a3667aaeSNaresh Kumar Inna * do this will need to "hand-roll" their own CAPS_CONFIGS commands for 1347a3667aaeSNaresh Kumar Inna * Configuration Files if they want to do this. 1348a3667aaeSNaresh Kumar Inna */ 1349a3667aaeSNaresh Kumar Inna static int 1350a3667aaeSNaresh Kumar Inna csio_hw_fw_config_file(struct csio_hw *hw, 1351a3667aaeSNaresh Kumar Inna unsigned int mtype, unsigned int maddr, 1352a3667aaeSNaresh Kumar Inna uint32_t *finiver, uint32_t *finicsum, uint32_t *cfcsum) 1353a3667aaeSNaresh Kumar Inna { 1354a3667aaeSNaresh Kumar Inna struct csio_mb *mbp; 1355a3667aaeSNaresh Kumar Inna struct fw_caps_config_cmd *caps_cmd; 1356a3667aaeSNaresh Kumar Inna int rv = -EINVAL; 1357a3667aaeSNaresh Kumar Inna enum fw_retval ret; 1358a3667aaeSNaresh Kumar Inna 1359a3667aaeSNaresh Kumar Inna mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 1360a3667aaeSNaresh Kumar Inna if (!mbp) { 1361a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_nomem); 1362a3667aaeSNaresh Kumar Inna return -ENOMEM; 1363a3667aaeSNaresh Kumar Inna } 1364a3667aaeSNaresh Kumar Inna /* 1365a3667aaeSNaresh Kumar Inna * Tell the firmware to process the indicated Configuration File. 1366a3667aaeSNaresh Kumar Inna * If there are no errors and the caller has provided return value 1367a3667aaeSNaresh Kumar Inna * pointers for the [fini] section version, checksum and computed 1368a3667aaeSNaresh Kumar Inna * checksum, pass those back to the caller. 1369a3667aaeSNaresh Kumar Inna */ 1370a3667aaeSNaresh Kumar Inna caps_cmd = (struct fw_caps_config_cmd *)(mbp->mb); 1371a3667aaeSNaresh Kumar Inna CSIO_INIT_MBP(mbp, caps_cmd, CSIO_MB_DEFAULT_TMO, hw, NULL, 1); 1372a3667aaeSNaresh Kumar Inna caps_cmd->op_to_write = 1373a3667aaeSNaresh Kumar Inna htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 1374a3667aaeSNaresh Kumar Inna FW_CMD_REQUEST | 1375a3667aaeSNaresh Kumar Inna FW_CMD_READ); 1376a3667aaeSNaresh Kumar Inna caps_cmd->cfvalid_to_len16 = 1377a3667aaeSNaresh Kumar Inna htonl(FW_CAPS_CONFIG_CMD_CFVALID | 1378a3667aaeSNaresh Kumar Inna FW_CAPS_CONFIG_CMD_MEMTYPE_CF(mtype) | 1379a3667aaeSNaresh Kumar Inna FW_CAPS_CONFIG_CMD_MEMADDR64K_CF(maddr >> 16) | 1380a3667aaeSNaresh Kumar Inna FW_LEN16(*caps_cmd)); 1381a3667aaeSNaresh Kumar Inna 1382a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 1383a3667aaeSNaresh Kumar Inna csio_err(hw, "Issue of FW_CAPS_CONFIG_CMD failed!\n"); 1384a3667aaeSNaresh Kumar Inna goto out; 1385a3667aaeSNaresh Kumar Inna } 1386a3667aaeSNaresh Kumar Inna 1387a3667aaeSNaresh Kumar Inna ret = csio_mb_fw_retval(mbp); 1388a3667aaeSNaresh Kumar Inna if (ret != FW_SUCCESS) { 1389a3667aaeSNaresh Kumar Inna csio_dbg(hw, "FW_CAPS_CONFIG_CMD returned %d!\n", rv); 1390a3667aaeSNaresh Kumar Inna goto out; 1391a3667aaeSNaresh Kumar Inna } 1392a3667aaeSNaresh Kumar Inna 1393a3667aaeSNaresh Kumar Inna if (finiver) 1394a3667aaeSNaresh Kumar Inna *finiver = ntohl(caps_cmd->finiver); 1395a3667aaeSNaresh Kumar Inna if (finicsum) 1396a3667aaeSNaresh Kumar Inna *finicsum = ntohl(caps_cmd->finicsum); 1397a3667aaeSNaresh Kumar Inna if (cfcsum) 1398a3667aaeSNaresh Kumar Inna *cfcsum = ntohl(caps_cmd->cfcsum); 1399a3667aaeSNaresh Kumar Inna 1400a3667aaeSNaresh Kumar Inna /* Validate device capabilities */ 1401a3667aaeSNaresh Kumar Inna if (csio_hw_validate_caps(hw, mbp)) { 1402a3667aaeSNaresh Kumar Inna rv = -ENOENT; 1403a3667aaeSNaresh Kumar Inna goto out; 1404a3667aaeSNaresh Kumar Inna } 1405a3667aaeSNaresh Kumar Inna 1406a3667aaeSNaresh Kumar Inna /* 1407a3667aaeSNaresh Kumar Inna * And now tell the firmware to use the configuration we just loaded. 1408a3667aaeSNaresh Kumar Inna */ 1409a3667aaeSNaresh Kumar Inna caps_cmd->op_to_write = 1410a3667aaeSNaresh Kumar Inna htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 1411a3667aaeSNaresh Kumar Inna FW_CMD_REQUEST | 1412a3667aaeSNaresh Kumar Inna FW_CMD_WRITE); 1413a3667aaeSNaresh Kumar Inna caps_cmd->cfvalid_to_len16 = htonl(FW_LEN16(*caps_cmd)); 1414a3667aaeSNaresh Kumar Inna 1415a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 1416a3667aaeSNaresh Kumar Inna csio_err(hw, "Issue of FW_CAPS_CONFIG_CMD failed!\n"); 1417a3667aaeSNaresh Kumar Inna goto out; 1418a3667aaeSNaresh Kumar Inna } 1419a3667aaeSNaresh Kumar Inna 1420a3667aaeSNaresh Kumar Inna ret = csio_mb_fw_retval(mbp); 1421a3667aaeSNaresh Kumar Inna if (ret != FW_SUCCESS) { 1422a3667aaeSNaresh Kumar Inna csio_dbg(hw, "FW_CAPS_CONFIG_CMD returned %d!\n", rv); 1423a3667aaeSNaresh Kumar Inna goto out; 1424a3667aaeSNaresh Kumar Inna } 1425a3667aaeSNaresh Kumar Inna 1426a3667aaeSNaresh Kumar Inna rv = 0; 1427a3667aaeSNaresh Kumar Inna out: 1428a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1429a3667aaeSNaresh Kumar Inna return rv; 1430a3667aaeSNaresh Kumar Inna } 1431a3667aaeSNaresh Kumar Inna 1432a3667aaeSNaresh Kumar Inna /* 1433a3667aaeSNaresh Kumar Inna * csio_get_device_params - Get device parameters. 1434a3667aaeSNaresh Kumar Inna * @hw: HW module 1435a3667aaeSNaresh Kumar Inna * 1436a3667aaeSNaresh Kumar Inna */ 1437a3667aaeSNaresh Kumar Inna static int 1438a3667aaeSNaresh Kumar Inna csio_get_device_params(struct csio_hw *hw) 1439a3667aaeSNaresh Kumar Inna { 1440a3667aaeSNaresh Kumar Inna struct csio_wrm *wrm = csio_hw_to_wrm(hw); 1441a3667aaeSNaresh Kumar Inna struct csio_mb *mbp; 1442a3667aaeSNaresh Kumar Inna enum fw_retval retval; 1443a3667aaeSNaresh Kumar Inna u32 param[6]; 1444a3667aaeSNaresh Kumar Inna int i, j = 0; 1445a3667aaeSNaresh Kumar Inna 1446a3667aaeSNaresh Kumar Inna /* Initialize portids to -1 */ 1447a3667aaeSNaresh Kumar Inna for (i = 0; i < CSIO_MAX_PPORTS; i++) 1448a3667aaeSNaresh Kumar Inna hw->pport[i].portid = -1; 1449a3667aaeSNaresh Kumar Inna 1450a3667aaeSNaresh Kumar Inna mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 1451a3667aaeSNaresh Kumar Inna if (!mbp) { 1452a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_nomem); 1453a3667aaeSNaresh Kumar Inna return -ENOMEM; 1454a3667aaeSNaresh Kumar Inna } 1455a3667aaeSNaresh Kumar Inna 1456a3667aaeSNaresh Kumar Inna /* Get port vec information. */ 1457a3667aaeSNaresh Kumar Inna param[0] = FW_PARAM_DEV(PORTVEC); 1458a3667aaeSNaresh Kumar Inna 1459a3667aaeSNaresh Kumar Inna /* Get Core clock. */ 1460a3667aaeSNaresh Kumar Inna param[1] = FW_PARAM_DEV(CCLK); 1461a3667aaeSNaresh Kumar Inna 1462a3667aaeSNaresh Kumar Inna /* Get EQ id start and end. */ 1463a3667aaeSNaresh Kumar Inna param[2] = FW_PARAM_PFVF(EQ_START); 1464a3667aaeSNaresh Kumar Inna param[3] = FW_PARAM_PFVF(EQ_END); 1465a3667aaeSNaresh Kumar Inna 1466a3667aaeSNaresh Kumar Inna /* Get IQ id start and end. */ 1467a3667aaeSNaresh Kumar Inna param[4] = FW_PARAM_PFVF(IQFLINT_START); 1468a3667aaeSNaresh Kumar Inna param[5] = FW_PARAM_PFVF(IQFLINT_END); 1469a3667aaeSNaresh Kumar Inna 1470a3667aaeSNaresh Kumar Inna csio_mb_params(hw, mbp, CSIO_MB_DEFAULT_TMO, hw->pfn, 0, 1471a3667aaeSNaresh Kumar Inna ARRAY_SIZE(param), param, NULL, false, NULL); 1472a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 1473a3667aaeSNaresh Kumar Inna csio_err(hw, "Issue of FW_PARAMS_CMD(read) failed!\n"); 1474a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1475a3667aaeSNaresh Kumar Inna return -EINVAL; 1476a3667aaeSNaresh Kumar Inna } 1477a3667aaeSNaresh Kumar Inna 1478a3667aaeSNaresh Kumar Inna csio_mb_process_read_params_rsp(hw, mbp, &retval, 1479a3667aaeSNaresh Kumar Inna ARRAY_SIZE(param), param); 1480a3667aaeSNaresh Kumar Inna if (retval != FW_SUCCESS) { 1481a3667aaeSNaresh Kumar Inna csio_err(hw, "FW_PARAMS_CMD(read) failed with ret:0x%x!\n", 1482a3667aaeSNaresh Kumar Inna retval); 1483a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1484a3667aaeSNaresh Kumar Inna return -EINVAL; 1485a3667aaeSNaresh Kumar Inna } 1486a3667aaeSNaresh Kumar Inna 1487a3667aaeSNaresh Kumar Inna /* cache the information. */ 1488a3667aaeSNaresh Kumar Inna hw->port_vec = param[0]; 1489a3667aaeSNaresh Kumar Inna hw->vpd.cclk = param[1]; 1490a3667aaeSNaresh Kumar Inna wrm->fw_eq_start = param[2]; 1491a3667aaeSNaresh Kumar Inna wrm->fw_iq_start = param[4]; 1492a3667aaeSNaresh Kumar Inna 1493a3667aaeSNaresh Kumar Inna /* Using FW configured max iqs & eqs */ 1494a3667aaeSNaresh Kumar Inna if ((hw->flags & CSIO_HWF_USING_SOFT_PARAMS) || 1495a3667aaeSNaresh Kumar Inna !csio_is_hw_master(hw)) { 1496a3667aaeSNaresh Kumar Inna hw->cfg_niq = param[5] - param[4] + 1; 1497a3667aaeSNaresh Kumar Inna hw->cfg_neq = param[3] - param[2] + 1; 1498a3667aaeSNaresh Kumar Inna csio_dbg(hw, "Using fwconfig max niqs %d neqs %d\n", 1499a3667aaeSNaresh Kumar Inna hw->cfg_niq, hw->cfg_neq); 1500a3667aaeSNaresh Kumar Inna } 1501a3667aaeSNaresh Kumar Inna 1502a3667aaeSNaresh Kumar Inna hw->port_vec &= csio_port_mask; 1503a3667aaeSNaresh Kumar Inna 1504a3667aaeSNaresh Kumar Inna hw->num_pports = hweight32(hw->port_vec); 1505a3667aaeSNaresh Kumar Inna 1506a3667aaeSNaresh Kumar Inna csio_dbg(hw, "Port vector: 0x%x, #ports: %d\n", 1507a3667aaeSNaresh Kumar Inna hw->port_vec, hw->num_pports); 1508a3667aaeSNaresh Kumar Inna 1509a3667aaeSNaresh Kumar Inna for (i = 0; i < hw->num_pports; i++) { 1510a3667aaeSNaresh Kumar Inna while ((hw->port_vec & (1 << j)) == 0) 1511a3667aaeSNaresh Kumar Inna j++; 1512a3667aaeSNaresh Kumar Inna hw->pport[i].portid = j++; 1513a3667aaeSNaresh Kumar Inna csio_dbg(hw, "Found Port:%d\n", hw->pport[i].portid); 1514a3667aaeSNaresh Kumar Inna } 1515a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1516a3667aaeSNaresh Kumar Inna 1517a3667aaeSNaresh Kumar Inna return 0; 1518a3667aaeSNaresh Kumar Inna } 1519a3667aaeSNaresh Kumar Inna 1520a3667aaeSNaresh Kumar Inna 1521a3667aaeSNaresh Kumar Inna /* 1522a3667aaeSNaresh Kumar Inna * csio_config_device_caps - Get and set device capabilities. 1523a3667aaeSNaresh Kumar Inna * @hw: HW module 1524a3667aaeSNaresh Kumar Inna * 1525a3667aaeSNaresh Kumar Inna */ 1526a3667aaeSNaresh Kumar Inna static int 1527a3667aaeSNaresh Kumar Inna csio_config_device_caps(struct csio_hw *hw) 1528a3667aaeSNaresh Kumar Inna { 1529a3667aaeSNaresh Kumar Inna struct csio_mb *mbp; 1530a3667aaeSNaresh Kumar Inna enum fw_retval retval; 1531a3667aaeSNaresh Kumar Inna int rv = -EINVAL; 1532a3667aaeSNaresh Kumar Inna 1533a3667aaeSNaresh Kumar Inna mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 1534a3667aaeSNaresh Kumar Inna if (!mbp) { 1535a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_nomem); 1536a3667aaeSNaresh Kumar Inna return -ENOMEM; 1537a3667aaeSNaresh Kumar Inna } 1538a3667aaeSNaresh Kumar Inna 1539a3667aaeSNaresh Kumar Inna /* Get device capabilities */ 1540a3667aaeSNaresh Kumar Inna csio_mb_caps_config(hw, mbp, CSIO_MB_DEFAULT_TMO, 0, 0, 0, 0, NULL); 1541a3667aaeSNaresh Kumar Inna 1542a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 1543a3667aaeSNaresh Kumar Inna csio_err(hw, "Issue of FW_CAPS_CONFIG_CMD(r) failed!\n"); 1544a3667aaeSNaresh Kumar Inna goto out; 1545a3667aaeSNaresh Kumar Inna } 1546a3667aaeSNaresh Kumar Inna 1547a3667aaeSNaresh Kumar Inna retval = csio_mb_fw_retval(mbp); 1548a3667aaeSNaresh Kumar Inna if (retval != FW_SUCCESS) { 1549a3667aaeSNaresh Kumar Inna csio_err(hw, "FW_CAPS_CONFIG_CMD(r) returned %d!\n", retval); 1550a3667aaeSNaresh Kumar Inna goto out; 1551a3667aaeSNaresh Kumar Inna } 1552a3667aaeSNaresh Kumar Inna 1553a3667aaeSNaresh Kumar Inna /* Validate device capabilities */ 1554a3667aaeSNaresh Kumar Inna if (csio_hw_validate_caps(hw, mbp)) 1555a3667aaeSNaresh Kumar Inna goto out; 1556a3667aaeSNaresh Kumar Inna 1557a3667aaeSNaresh Kumar Inna /* Don't config device capabilities if already configured */ 1558a3667aaeSNaresh Kumar Inna if (hw->fw_state == CSIO_DEV_STATE_INIT) { 1559a3667aaeSNaresh Kumar Inna rv = 0; 1560a3667aaeSNaresh Kumar Inna goto out; 1561a3667aaeSNaresh Kumar Inna } 1562a3667aaeSNaresh Kumar Inna 1563a3667aaeSNaresh Kumar Inna /* Write back desired device capabilities */ 1564a3667aaeSNaresh Kumar Inna csio_mb_caps_config(hw, mbp, CSIO_MB_DEFAULT_TMO, true, true, 1565a3667aaeSNaresh Kumar Inna false, true, NULL); 1566a3667aaeSNaresh Kumar Inna 1567a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 1568a3667aaeSNaresh Kumar Inna csio_err(hw, "Issue of FW_CAPS_CONFIG_CMD(w) failed!\n"); 1569a3667aaeSNaresh Kumar Inna goto out; 1570a3667aaeSNaresh Kumar Inna } 1571a3667aaeSNaresh Kumar Inna 1572a3667aaeSNaresh Kumar Inna retval = csio_mb_fw_retval(mbp); 1573a3667aaeSNaresh Kumar Inna if (retval != FW_SUCCESS) { 1574a3667aaeSNaresh Kumar Inna csio_err(hw, "FW_CAPS_CONFIG_CMD(w) returned %d!\n", retval); 1575a3667aaeSNaresh Kumar Inna goto out; 1576a3667aaeSNaresh Kumar Inna } 1577a3667aaeSNaresh Kumar Inna 1578a3667aaeSNaresh Kumar Inna rv = 0; 1579a3667aaeSNaresh Kumar Inna out: 1580a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1581a3667aaeSNaresh Kumar Inna return rv; 1582a3667aaeSNaresh Kumar Inna } 1583a3667aaeSNaresh Kumar Inna 1584a3667aaeSNaresh Kumar Inna /* 1585a3667aaeSNaresh Kumar Inna * csio_enable_ports - Bring up all available ports. 1586a3667aaeSNaresh Kumar Inna * @hw: HW module. 1587a3667aaeSNaresh Kumar Inna * 1588a3667aaeSNaresh Kumar Inna */ 1589a3667aaeSNaresh Kumar Inna static int 1590a3667aaeSNaresh Kumar Inna csio_enable_ports(struct csio_hw *hw) 1591a3667aaeSNaresh Kumar Inna { 1592a3667aaeSNaresh Kumar Inna struct csio_mb *mbp; 1593a3667aaeSNaresh Kumar Inna enum fw_retval retval; 1594a3667aaeSNaresh Kumar Inna uint8_t portid; 1595a3667aaeSNaresh Kumar Inna int i; 1596a3667aaeSNaresh Kumar Inna 1597a3667aaeSNaresh Kumar Inna mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 1598a3667aaeSNaresh Kumar Inna if (!mbp) { 1599a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_nomem); 1600a3667aaeSNaresh Kumar Inna return -ENOMEM; 1601a3667aaeSNaresh Kumar Inna } 1602a3667aaeSNaresh Kumar Inna 1603a3667aaeSNaresh Kumar Inna for (i = 0; i < hw->num_pports; i++) { 1604a3667aaeSNaresh Kumar Inna portid = hw->pport[i].portid; 1605a3667aaeSNaresh Kumar Inna 1606a3667aaeSNaresh Kumar Inna /* Read PORT information */ 1607a3667aaeSNaresh Kumar Inna csio_mb_port(hw, mbp, CSIO_MB_DEFAULT_TMO, portid, 1608a3667aaeSNaresh Kumar Inna false, 0, 0, NULL); 1609a3667aaeSNaresh Kumar Inna 1610a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 1611a3667aaeSNaresh Kumar Inna csio_err(hw, "failed to issue FW_PORT_CMD(r) port:%d\n", 1612a3667aaeSNaresh Kumar Inna portid); 1613a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1614a3667aaeSNaresh Kumar Inna return -EINVAL; 1615a3667aaeSNaresh Kumar Inna } 1616a3667aaeSNaresh Kumar Inna 1617a3667aaeSNaresh Kumar Inna csio_mb_process_read_port_rsp(hw, mbp, &retval, 1618a3667aaeSNaresh Kumar Inna &hw->pport[i].pcap); 1619a3667aaeSNaresh Kumar Inna if (retval != FW_SUCCESS) { 1620a3667aaeSNaresh Kumar Inna csio_err(hw, "FW_PORT_CMD(r) port:%d failed: 0x%x\n", 1621a3667aaeSNaresh Kumar Inna portid, retval); 1622a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1623a3667aaeSNaresh Kumar Inna return -EINVAL; 1624a3667aaeSNaresh Kumar Inna } 1625a3667aaeSNaresh Kumar Inna 1626a3667aaeSNaresh Kumar Inna /* Write back PORT information */ 1627a3667aaeSNaresh Kumar Inna csio_mb_port(hw, mbp, CSIO_MB_DEFAULT_TMO, portid, true, 1628a3667aaeSNaresh Kumar Inna (PAUSE_RX | PAUSE_TX), hw->pport[i].pcap, NULL); 1629a3667aaeSNaresh Kumar Inna 1630a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 1631a3667aaeSNaresh Kumar Inna csio_err(hw, "failed to issue FW_PORT_CMD(w) port:%d\n", 1632a3667aaeSNaresh Kumar Inna portid); 1633a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1634a3667aaeSNaresh Kumar Inna return -EINVAL; 1635a3667aaeSNaresh Kumar Inna } 1636a3667aaeSNaresh Kumar Inna 1637a3667aaeSNaresh Kumar Inna retval = csio_mb_fw_retval(mbp); 1638a3667aaeSNaresh Kumar Inna if (retval != FW_SUCCESS) { 1639a3667aaeSNaresh Kumar Inna csio_err(hw, "FW_PORT_CMD(w) port:%d failed :0x%x\n", 1640a3667aaeSNaresh Kumar Inna portid, retval); 1641a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1642a3667aaeSNaresh Kumar Inna return -EINVAL; 1643a3667aaeSNaresh Kumar Inna } 1644a3667aaeSNaresh Kumar Inna 1645a3667aaeSNaresh Kumar Inna } /* For all ports */ 1646a3667aaeSNaresh Kumar Inna 1647a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1648a3667aaeSNaresh Kumar Inna 1649a3667aaeSNaresh Kumar Inna return 0; 1650a3667aaeSNaresh Kumar Inna } 1651a3667aaeSNaresh Kumar Inna 1652a3667aaeSNaresh Kumar Inna /* 1653a3667aaeSNaresh Kumar Inna * csio_get_fcoe_resinfo - Read fcoe fw resource info. 1654a3667aaeSNaresh Kumar Inna * @hw: HW module 1655a3667aaeSNaresh Kumar Inna * Issued with lock held. 1656a3667aaeSNaresh Kumar Inna */ 1657a3667aaeSNaresh Kumar Inna static int 1658a3667aaeSNaresh Kumar Inna csio_get_fcoe_resinfo(struct csio_hw *hw) 1659a3667aaeSNaresh Kumar Inna { 1660a3667aaeSNaresh Kumar Inna struct csio_fcoe_res_info *res_info = &hw->fres_info; 1661a3667aaeSNaresh Kumar Inna struct fw_fcoe_res_info_cmd *rsp; 1662a3667aaeSNaresh Kumar Inna struct csio_mb *mbp; 1663a3667aaeSNaresh Kumar Inna enum fw_retval retval; 1664a3667aaeSNaresh Kumar Inna 1665a3667aaeSNaresh Kumar Inna mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 1666a3667aaeSNaresh Kumar Inna if (!mbp) { 1667a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_nomem); 1668a3667aaeSNaresh Kumar Inna return -ENOMEM; 1669a3667aaeSNaresh Kumar Inna } 1670a3667aaeSNaresh Kumar Inna 1671a3667aaeSNaresh Kumar Inna /* Get FCoE FW resource information */ 1672a3667aaeSNaresh Kumar Inna csio_fcoe_read_res_info_init_mb(hw, mbp, CSIO_MB_DEFAULT_TMO, NULL); 1673a3667aaeSNaresh Kumar Inna 1674a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 1675a3667aaeSNaresh Kumar Inna csio_err(hw, "failed to issue FW_FCOE_RES_INFO_CMD\n"); 1676a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1677a3667aaeSNaresh Kumar Inna return -EINVAL; 1678a3667aaeSNaresh Kumar Inna } 1679a3667aaeSNaresh Kumar Inna 1680a3667aaeSNaresh Kumar Inna rsp = (struct fw_fcoe_res_info_cmd *)(mbp->mb); 1681a3667aaeSNaresh Kumar Inna retval = FW_CMD_RETVAL_GET(ntohl(rsp->retval_len16)); 1682a3667aaeSNaresh Kumar Inna if (retval != FW_SUCCESS) { 1683a3667aaeSNaresh Kumar Inna csio_err(hw, "FW_FCOE_RES_INFO_CMD failed with ret x%x\n", 1684a3667aaeSNaresh Kumar Inna retval); 1685a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1686a3667aaeSNaresh Kumar Inna return -EINVAL; 1687a3667aaeSNaresh Kumar Inna } 1688a3667aaeSNaresh Kumar Inna 1689a3667aaeSNaresh Kumar Inna res_info->e_d_tov = ntohs(rsp->e_d_tov); 1690a3667aaeSNaresh Kumar Inna res_info->r_a_tov_seq = ntohs(rsp->r_a_tov_seq); 1691a3667aaeSNaresh Kumar Inna res_info->r_a_tov_els = ntohs(rsp->r_a_tov_els); 1692a3667aaeSNaresh Kumar Inna res_info->r_r_tov = ntohs(rsp->r_r_tov); 1693a3667aaeSNaresh Kumar Inna res_info->max_xchgs = ntohl(rsp->max_xchgs); 1694a3667aaeSNaresh Kumar Inna res_info->max_ssns = ntohl(rsp->max_ssns); 1695a3667aaeSNaresh Kumar Inna res_info->used_xchgs = ntohl(rsp->used_xchgs); 1696a3667aaeSNaresh Kumar Inna res_info->used_ssns = ntohl(rsp->used_ssns); 1697a3667aaeSNaresh Kumar Inna res_info->max_fcfs = ntohl(rsp->max_fcfs); 1698a3667aaeSNaresh Kumar Inna res_info->max_vnps = ntohl(rsp->max_vnps); 1699a3667aaeSNaresh Kumar Inna res_info->used_fcfs = ntohl(rsp->used_fcfs); 1700a3667aaeSNaresh Kumar Inna res_info->used_vnps = ntohl(rsp->used_vnps); 1701a3667aaeSNaresh Kumar Inna 1702a3667aaeSNaresh Kumar Inna csio_dbg(hw, "max ssns:%d max xchgs:%d\n", res_info->max_ssns, 1703a3667aaeSNaresh Kumar Inna res_info->max_xchgs); 1704a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1705a3667aaeSNaresh Kumar Inna 1706a3667aaeSNaresh Kumar Inna return 0; 1707a3667aaeSNaresh Kumar Inna } 1708a3667aaeSNaresh Kumar Inna 1709a3667aaeSNaresh Kumar Inna static int 1710a3667aaeSNaresh Kumar Inna csio_hw_check_fwconfig(struct csio_hw *hw, u32 *param) 1711a3667aaeSNaresh Kumar Inna { 1712a3667aaeSNaresh Kumar Inna struct csio_mb *mbp; 1713a3667aaeSNaresh Kumar Inna enum fw_retval retval; 1714a3667aaeSNaresh Kumar Inna u32 _param[1]; 1715a3667aaeSNaresh Kumar Inna 1716a3667aaeSNaresh Kumar Inna mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 1717a3667aaeSNaresh Kumar Inna if (!mbp) { 1718a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_nomem); 1719a3667aaeSNaresh Kumar Inna return -ENOMEM; 1720a3667aaeSNaresh Kumar Inna } 1721a3667aaeSNaresh Kumar Inna 1722a3667aaeSNaresh Kumar Inna /* 1723a3667aaeSNaresh Kumar Inna * Find out whether we're dealing with a version of 1724a3667aaeSNaresh Kumar Inna * the firmware which has configuration file support. 1725a3667aaeSNaresh Kumar Inna */ 1726a3667aaeSNaresh Kumar Inna _param[0] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | 1727a3667aaeSNaresh Kumar Inna FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_CF)); 1728a3667aaeSNaresh Kumar Inna 1729a3667aaeSNaresh Kumar Inna csio_mb_params(hw, mbp, CSIO_MB_DEFAULT_TMO, hw->pfn, 0, 1730a3667aaeSNaresh Kumar Inna ARRAY_SIZE(_param), _param, NULL, false, NULL); 1731a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 1732a3667aaeSNaresh Kumar Inna csio_err(hw, "Issue of FW_PARAMS_CMD(read) failed!\n"); 1733a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1734a3667aaeSNaresh Kumar Inna return -EINVAL; 1735a3667aaeSNaresh Kumar Inna } 1736a3667aaeSNaresh Kumar Inna 1737a3667aaeSNaresh Kumar Inna csio_mb_process_read_params_rsp(hw, mbp, &retval, 1738a3667aaeSNaresh Kumar Inna ARRAY_SIZE(_param), _param); 1739a3667aaeSNaresh Kumar Inna if (retval != FW_SUCCESS) { 1740a3667aaeSNaresh Kumar Inna csio_err(hw, "FW_PARAMS_CMD(read) failed with ret:0x%x!\n", 1741a3667aaeSNaresh Kumar Inna retval); 1742a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1743a3667aaeSNaresh Kumar Inna return -EINVAL; 1744a3667aaeSNaresh Kumar Inna } 1745a3667aaeSNaresh Kumar Inna 1746a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1747a3667aaeSNaresh Kumar Inna *param = _param[0]; 1748a3667aaeSNaresh Kumar Inna 1749a3667aaeSNaresh Kumar Inna return 0; 1750a3667aaeSNaresh Kumar Inna } 1751a3667aaeSNaresh Kumar Inna 1752a3667aaeSNaresh Kumar Inna static int 1753a3667aaeSNaresh Kumar Inna csio_hw_flash_config(struct csio_hw *hw, u32 *fw_cfg_param, char *path) 1754a3667aaeSNaresh Kumar Inna { 1755a3667aaeSNaresh Kumar Inna int ret = 0; 1756a3667aaeSNaresh Kumar Inna const struct firmware *cf; 1757a3667aaeSNaresh Kumar Inna struct pci_dev *pci_dev = hw->pdev; 1758a3667aaeSNaresh Kumar Inna struct device *dev = &pci_dev->dev; 1759a3667aaeSNaresh Kumar Inna unsigned int mtype = 0, maddr = 0; 1760a3667aaeSNaresh Kumar Inna uint32_t *cfg_data; 1761a3667aaeSNaresh Kumar Inna int value_to_add = 0; 1762a3667aaeSNaresh Kumar Inna 17637cc16380SArvind Bhushan if (request_firmware(&cf, CSIO_CF_FNAME(hw), dev) < 0) { 17647cc16380SArvind Bhushan csio_err(hw, "could not find config file %s, err: %d\n", 17657cc16380SArvind Bhushan CSIO_CF_FNAME(hw), ret); 1766a3667aaeSNaresh Kumar Inna return -ENOENT; 1767a3667aaeSNaresh Kumar Inna } 1768a3667aaeSNaresh Kumar Inna 1769a3667aaeSNaresh Kumar Inna if (cf->size%4 != 0) 1770a3667aaeSNaresh Kumar Inna value_to_add = 4 - (cf->size % 4); 1771a3667aaeSNaresh Kumar Inna 1772a3667aaeSNaresh Kumar Inna cfg_data = kzalloc(cf->size+value_to_add, GFP_KERNEL); 177302db3db5SJesper Juhl if (cfg_data == NULL) { 177402db3db5SJesper Juhl ret = -ENOMEM; 177502db3db5SJesper Juhl goto leave; 177602db3db5SJesper Juhl } 1777a3667aaeSNaresh Kumar Inna 1778a3667aaeSNaresh Kumar Inna memcpy((void *)cfg_data, (const void *)cf->data, cf->size); 177902db3db5SJesper Juhl if (csio_hw_check_fwconfig(hw, fw_cfg_param) != 0) { 178002db3db5SJesper Juhl ret = -EINVAL; 178102db3db5SJesper Juhl goto leave; 178202db3db5SJesper Juhl } 1783a3667aaeSNaresh Kumar Inna 1784a3667aaeSNaresh Kumar Inna mtype = FW_PARAMS_PARAM_Y_GET(*fw_cfg_param); 1785a3667aaeSNaresh Kumar Inna maddr = FW_PARAMS_PARAM_Z_GET(*fw_cfg_param) << 16; 1786a3667aaeSNaresh Kumar Inna 1787a3667aaeSNaresh Kumar Inna ret = csio_memory_write(hw, mtype, maddr, 1788a3667aaeSNaresh Kumar Inna cf->size + value_to_add, cfg_data); 17897cc16380SArvind Bhushan 17907cc16380SArvind Bhushan if ((ret == 0) && (value_to_add != 0)) { 17917cc16380SArvind Bhushan union { 17927cc16380SArvind Bhushan u32 word; 17937cc16380SArvind Bhushan char buf[4]; 17947cc16380SArvind Bhushan } last; 17957cc16380SArvind Bhushan size_t size = cf->size & ~0x3; 17967cc16380SArvind Bhushan int i; 17977cc16380SArvind Bhushan 17987cc16380SArvind Bhushan last.word = cfg_data[size >> 2]; 17997cc16380SArvind Bhushan for (i = value_to_add; i < 4; i++) 18007cc16380SArvind Bhushan last.buf[i] = 0; 18017cc16380SArvind Bhushan ret = csio_memory_write(hw, mtype, maddr + size, 4, &last.word); 18027cc16380SArvind Bhushan } 1803a3667aaeSNaresh Kumar Inna if (ret == 0) { 18047cc16380SArvind Bhushan csio_info(hw, "config file upgraded to %s\n", 18057cc16380SArvind Bhushan CSIO_CF_FNAME(hw)); 18067cc16380SArvind Bhushan snprintf(path, 64, "%s%s", "/lib/firmware/", CSIO_CF_FNAME(hw)); 1807a3667aaeSNaresh Kumar Inna } 1808a3667aaeSNaresh Kumar Inna 180902db3db5SJesper Juhl leave: 1810a3667aaeSNaresh Kumar Inna kfree(cfg_data); 1811a3667aaeSNaresh Kumar Inna release_firmware(cf); 1812a3667aaeSNaresh Kumar Inna return ret; 1813a3667aaeSNaresh Kumar Inna } 1814a3667aaeSNaresh Kumar Inna 1815a3667aaeSNaresh Kumar Inna /* 1816a3667aaeSNaresh Kumar Inna * HW initialization: contact FW, obtain config, perform basic init. 1817a3667aaeSNaresh Kumar Inna * 1818a3667aaeSNaresh Kumar Inna * If the firmware we're dealing with has Configuration File support, then 1819a3667aaeSNaresh Kumar Inna * we use that to perform all configuration -- either using the configuration 1820a3667aaeSNaresh Kumar Inna * file stored in flash on the adapter or using a filesystem-local file 1821a3667aaeSNaresh Kumar Inna * if available. 1822a3667aaeSNaresh Kumar Inna * 1823a3667aaeSNaresh Kumar Inna * If we don't have configuration file support in the firmware, then we'll 1824a3667aaeSNaresh Kumar Inna * have to set things up the old fashioned way with hard-coded register 1825a3667aaeSNaresh Kumar Inna * writes and firmware commands ... 1826a3667aaeSNaresh Kumar Inna */ 1827a3667aaeSNaresh Kumar Inna 1828a3667aaeSNaresh Kumar Inna /* 1829a3667aaeSNaresh Kumar Inna * Attempt to initialize the HW via a Firmware Configuration File. 1830a3667aaeSNaresh Kumar Inna */ 1831a3667aaeSNaresh Kumar Inna static int 1832a3667aaeSNaresh Kumar Inna csio_hw_use_fwconfig(struct csio_hw *hw, int reset, u32 *fw_cfg_param) 1833a3667aaeSNaresh Kumar Inna { 1834a3667aaeSNaresh Kumar Inna unsigned int mtype, maddr; 1835a3667aaeSNaresh Kumar Inna int rv; 18367cc16380SArvind Bhushan uint32_t finiver = 0, finicsum = 0, cfcsum = 0; 1837a3667aaeSNaresh Kumar Inna int using_flash; 1838a3667aaeSNaresh Kumar Inna char path[64]; 1839a3667aaeSNaresh Kumar Inna 1840a3667aaeSNaresh Kumar Inna /* 1841a3667aaeSNaresh Kumar Inna * Reset device if necessary 1842a3667aaeSNaresh Kumar Inna */ 1843a3667aaeSNaresh Kumar Inna if (reset) { 1844a3667aaeSNaresh Kumar Inna rv = csio_do_reset(hw, true); 1845a3667aaeSNaresh Kumar Inna if (rv != 0) 1846a3667aaeSNaresh Kumar Inna goto bye; 1847a3667aaeSNaresh Kumar Inna } 1848a3667aaeSNaresh Kumar Inna 1849a3667aaeSNaresh Kumar Inna /* 1850a3667aaeSNaresh Kumar Inna * If we have a configuration file in host , 1851a3667aaeSNaresh Kumar Inna * then use that. Otherwise, use the configuration file stored 1852a3667aaeSNaresh Kumar Inna * in the HW flash ... 1853a3667aaeSNaresh Kumar Inna */ 1854a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 1855a3667aaeSNaresh Kumar Inna rv = csio_hw_flash_config(hw, fw_cfg_param, path); 1856a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 1857a3667aaeSNaresh Kumar Inna if (rv != 0) { 1858a3667aaeSNaresh Kumar Inna if (rv == -ENOENT) { 1859a3667aaeSNaresh Kumar Inna /* 1860a3667aaeSNaresh Kumar Inna * config file was not found. Use default 1861a3667aaeSNaresh Kumar Inna * config file from flash. 1862a3667aaeSNaresh Kumar Inna */ 1863a3667aaeSNaresh Kumar Inna mtype = FW_MEMTYPE_CF_FLASH; 18647cc16380SArvind Bhushan maddr = hw->chip_ops->chip_flash_cfg_addr(hw); 1865a3667aaeSNaresh Kumar Inna using_flash = 1; 1866a3667aaeSNaresh Kumar Inna } else { 1867a3667aaeSNaresh Kumar Inna /* 1868a3667aaeSNaresh Kumar Inna * we revert back to the hardwired config if 1869a3667aaeSNaresh Kumar Inna * flashing failed. 1870a3667aaeSNaresh Kumar Inna */ 1871a3667aaeSNaresh Kumar Inna goto bye; 1872a3667aaeSNaresh Kumar Inna } 1873a3667aaeSNaresh Kumar Inna } else { 1874a3667aaeSNaresh Kumar Inna mtype = FW_PARAMS_PARAM_Y_GET(*fw_cfg_param); 1875a3667aaeSNaresh Kumar Inna maddr = FW_PARAMS_PARAM_Z_GET(*fw_cfg_param) << 16; 1876a3667aaeSNaresh Kumar Inna using_flash = 0; 1877a3667aaeSNaresh Kumar Inna } 1878a3667aaeSNaresh Kumar Inna 1879a3667aaeSNaresh Kumar Inna hw->cfg_store = (uint8_t)mtype; 1880a3667aaeSNaresh Kumar Inna 1881a3667aaeSNaresh Kumar Inna /* 1882a3667aaeSNaresh Kumar Inna * Issue a Capability Configuration command to the firmware to get it 1883a3667aaeSNaresh Kumar Inna * to parse the Configuration File. 1884a3667aaeSNaresh Kumar Inna */ 1885a3667aaeSNaresh Kumar Inna rv = csio_hw_fw_config_file(hw, mtype, maddr, &finiver, 1886a3667aaeSNaresh Kumar Inna &finicsum, &cfcsum); 1887a3667aaeSNaresh Kumar Inna if (rv != 0) 1888a3667aaeSNaresh Kumar Inna goto bye; 1889a3667aaeSNaresh Kumar Inna 1890a3667aaeSNaresh Kumar Inna hw->cfg_finiver = finiver; 1891a3667aaeSNaresh Kumar Inna hw->cfg_finicsum = finicsum; 1892a3667aaeSNaresh Kumar Inna hw->cfg_cfcsum = cfcsum; 1893a3667aaeSNaresh Kumar Inna hw->cfg_csum_status = true; 1894a3667aaeSNaresh Kumar Inna 1895a3667aaeSNaresh Kumar Inna if (finicsum != cfcsum) { 1896a3667aaeSNaresh Kumar Inna csio_warn(hw, 1897a3667aaeSNaresh Kumar Inna "Config File checksum mismatch: csum=%#x, computed=%#x\n", 1898a3667aaeSNaresh Kumar Inna finicsum, cfcsum); 1899a3667aaeSNaresh Kumar Inna 1900a3667aaeSNaresh Kumar Inna hw->cfg_csum_status = false; 1901a3667aaeSNaresh Kumar Inna } 1902a3667aaeSNaresh Kumar Inna 1903a3667aaeSNaresh Kumar Inna /* 1904a3667aaeSNaresh Kumar Inna * Note that we're operating with parameters 1905a3667aaeSNaresh Kumar Inna * not supplied by the driver, rather than from hard-wired 1906a3667aaeSNaresh Kumar Inna * initialization constants buried in the driver. 1907a3667aaeSNaresh Kumar Inna */ 1908a3667aaeSNaresh Kumar Inna hw->flags |= CSIO_HWF_USING_SOFT_PARAMS; 1909a3667aaeSNaresh Kumar Inna 1910a3667aaeSNaresh Kumar Inna /* device parameters */ 1911a3667aaeSNaresh Kumar Inna rv = csio_get_device_params(hw); 1912a3667aaeSNaresh Kumar Inna if (rv != 0) 1913a3667aaeSNaresh Kumar Inna goto bye; 1914a3667aaeSNaresh Kumar Inna 1915a3667aaeSNaresh Kumar Inna /* Configure SGE */ 1916a3667aaeSNaresh Kumar Inna csio_wr_sge_init(hw); 1917a3667aaeSNaresh Kumar Inna 1918a3667aaeSNaresh Kumar Inna /* 1919a3667aaeSNaresh Kumar Inna * And finally tell the firmware to initialize itself using the 1920a3667aaeSNaresh Kumar Inna * parameters from the Configuration File. 1921a3667aaeSNaresh Kumar Inna */ 1922a3667aaeSNaresh Kumar Inna /* Post event to notify completion of configuration */ 1923a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_INIT); 1924a3667aaeSNaresh Kumar Inna 1925a3667aaeSNaresh Kumar Inna csio_info(hw, 1926a3667aaeSNaresh Kumar Inna "Firmware Configuration File %s, version %#x, computed checksum %#x\n", 1927a3667aaeSNaresh Kumar Inna (using_flash ? "in device FLASH" : path), finiver, cfcsum); 1928a3667aaeSNaresh Kumar Inna 1929a3667aaeSNaresh Kumar Inna return 0; 1930a3667aaeSNaresh Kumar Inna 1931a3667aaeSNaresh Kumar Inna /* 1932a3667aaeSNaresh Kumar Inna * Something bad happened. Return the error ... 1933a3667aaeSNaresh Kumar Inna */ 1934a3667aaeSNaresh Kumar Inna bye: 1935a3667aaeSNaresh Kumar Inna hw->flags &= ~CSIO_HWF_USING_SOFT_PARAMS; 1936a3667aaeSNaresh Kumar Inna csio_dbg(hw, "Configuration file error %d\n", rv); 1937a3667aaeSNaresh Kumar Inna return rv; 1938a3667aaeSNaresh Kumar Inna } 1939a3667aaeSNaresh Kumar Inna 1940a3667aaeSNaresh Kumar Inna /* 1941a3667aaeSNaresh Kumar Inna * Attempt to initialize the adapter via hard-coded, driver supplied 1942a3667aaeSNaresh Kumar Inna * parameters ... 1943a3667aaeSNaresh Kumar Inna */ 1944a3667aaeSNaresh Kumar Inna static int 1945a3667aaeSNaresh Kumar Inna csio_hw_no_fwconfig(struct csio_hw *hw, int reset) 1946a3667aaeSNaresh Kumar Inna { 1947a3667aaeSNaresh Kumar Inna int rv; 1948a3667aaeSNaresh Kumar Inna /* 1949a3667aaeSNaresh Kumar Inna * Reset device if necessary 1950a3667aaeSNaresh Kumar Inna */ 1951a3667aaeSNaresh Kumar Inna if (reset) { 1952a3667aaeSNaresh Kumar Inna rv = csio_do_reset(hw, true); 1953a3667aaeSNaresh Kumar Inna if (rv != 0) 1954a3667aaeSNaresh Kumar Inna goto out; 1955a3667aaeSNaresh Kumar Inna } 1956a3667aaeSNaresh Kumar Inna 1957a3667aaeSNaresh Kumar Inna /* Get and set device capabilities */ 1958a3667aaeSNaresh Kumar Inna rv = csio_config_device_caps(hw); 1959a3667aaeSNaresh Kumar Inna if (rv != 0) 1960a3667aaeSNaresh Kumar Inna goto out; 1961a3667aaeSNaresh Kumar Inna 1962a3667aaeSNaresh Kumar Inna /* device parameters */ 1963a3667aaeSNaresh Kumar Inna rv = csio_get_device_params(hw); 1964a3667aaeSNaresh Kumar Inna if (rv != 0) 1965a3667aaeSNaresh Kumar Inna goto out; 1966a3667aaeSNaresh Kumar Inna 1967a3667aaeSNaresh Kumar Inna /* Configure SGE */ 1968a3667aaeSNaresh Kumar Inna csio_wr_sge_init(hw); 1969a3667aaeSNaresh Kumar Inna 1970a3667aaeSNaresh Kumar Inna /* Post event to notify completion of configuration */ 1971a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_INIT); 1972a3667aaeSNaresh Kumar Inna 1973a3667aaeSNaresh Kumar Inna out: 1974a3667aaeSNaresh Kumar Inna return rv; 1975a3667aaeSNaresh Kumar Inna } 1976a3667aaeSNaresh Kumar Inna 1977a3667aaeSNaresh Kumar Inna /* 1978a3667aaeSNaresh Kumar Inna * Returns -EINVAL if attempts to flash the firmware failed 1979a3667aaeSNaresh Kumar Inna * else returns 0, 1980a3667aaeSNaresh Kumar Inna * if flashing was not attempted because the card had the 1981a3667aaeSNaresh Kumar Inna * latest firmware ECANCELED is returned 1982a3667aaeSNaresh Kumar Inna */ 1983a3667aaeSNaresh Kumar Inna static int 1984a3667aaeSNaresh Kumar Inna csio_hw_flash_fw(struct csio_hw *hw) 1985a3667aaeSNaresh Kumar Inna { 1986a3667aaeSNaresh Kumar Inna int ret = -ECANCELED; 1987a3667aaeSNaresh Kumar Inna const struct firmware *fw; 1988a3667aaeSNaresh Kumar Inna const struct fw_hdr *hdr; 1989a3667aaeSNaresh Kumar Inna u32 fw_ver; 1990a3667aaeSNaresh Kumar Inna struct pci_dev *pci_dev = hw->pdev; 1991a3667aaeSNaresh Kumar Inna struct device *dev = &pci_dev->dev ; 1992a3667aaeSNaresh Kumar Inna 19937cc16380SArvind Bhushan if (request_firmware(&fw, CSIO_FW_FNAME(hw), dev) < 0) { 19947cc16380SArvind Bhushan csio_err(hw, "could not find firmware image %s, err: %d\n", 19957cc16380SArvind Bhushan CSIO_FW_FNAME(hw), ret); 1996a3667aaeSNaresh Kumar Inna return -EINVAL; 1997a3667aaeSNaresh Kumar Inna } 1998a3667aaeSNaresh Kumar Inna 1999a3667aaeSNaresh Kumar Inna hdr = (const struct fw_hdr *)fw->data; 2000a3667aaeSNaresh Kumar Inna fw_ver = ntohl(hdr->fw_ver); 20017cc16380SArvind Bhushan if (FW_HDR_FW_VER_MAJOR_GET(fw_ver) != FW_VERSION_MAJOR(hw)) 2002a3667aaeSNaresh Kumar Inna return -EINVAL; /* wrong major version, won't do */ 2003a3667aaeSNaresh Kumar Inna 2004a3667aaeSNaresh Kumar Inna /* 2005a3667aaeSNaresh Kumar Inna * If the flash FW is unusable or we found something newer, load it. 2006a3667aaeSNaresh Kumar Inna */ 20077cc16380SArvind Bhushan if (FW_HDR_FW_VER_MAJOR_GET(hw->fwrev) != FW_VERSION_MAJOR(hw) || 2008a3667aaeSNaresh Kumar Inna fw_ver > hw->fwrev) { 2009a3667aaeSNaresh Kumar Inna ret = csio_hw_fw_upgrade(hw, hw->pfn, fw->data, fw->size, 2010a3667aaeSNaresh Kumar Inna /*force=*/false); 2011a3667aaeSNaresh Kumar Inna if (!ret) 20127cc16380SArvind Bhushan csio_info(hw, 20137cc16380SArvind Bhushan "firmware upgraded to version %pI4 from %s\n", 20147cc16380SArvind Bhushan &hdr->fw_ver, CSIO_FW_FNAME(hw)); 2015a3667aaeSNaresh Kumar Inna else 2016a3667aaeSNaresh Kumar Inna csio_err(hw, "firmware upgrade failed! err=%d\n", ret); 20177cc16380SArvind Bhushan } else 20187cc16380SArvind Bhushan ret = -EINVAL; 2019a3667aaeSNaresh Kumar Inna 2020a3667aaeSNaresh Kumar Inna release_firmware(fw); 2021a3667aaeSNaresh Kumar Inna 2022a3667aaeSNaresh Kumar Inna return ret; 2023a3667aaeSNaresh Kumar Inna } 2024a3667aaeSNaresh Kumar Inna 2025a3667aaeSNaresh Kumar Inna 2026a3667aaeSNaresh Kumar Inna /* 2027a3667aaeSNaresh Kumar Inna * csio_hw_configure - Configure HW 2028a3667aaeSNaresh Kumar Inna * @hw - HW module 2029a3667aaeSNaresh Kumar Inna * 2030a3667aaeSNaresh Kumar Inna */ 2031a3667aaeSNaresh Kumar Inna static void 2032a3667aaeSNaresh Kumar Inna csio_hw_configure(struct csio_hw *hw) 2033a3667aaeSNaresh Kumar Inna { 2034a3667aaeSNaresh Kumar Inna int reset = 1; 2035a3667aaeSNaresh Kumar Inna int rv; 2036a3667aaeSNaresh Kumar Inna u32 param[1]; 2037a3667aaeSNaresh Kumar Inna 2038a3667aaeSNaresh Kumar Inna rv = csio_hw_dev_ready(hw); 2039a3667aaeSNaresh Kumar Inna if (rv != 0) { 2040a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_fatal); 2041a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_FATAL); 2042a3667aaeSNaresh Kumar Inna goto out; 2043a3667aaeSNaresh Kumar Inna } 2044a3667aaeSNaresh Kumar Inna 2045a3667aaeSNaresh Kumar Inna /* HW version */ 2046a3667aaeSNaresh Kumar Inna hw->chip_ver = (char)csio_rd_reg32(hw, PL_REV); 2047a3667aaeSNaresh Kumar Inna 2048a3667aaeSNaresh Kumar Inna /* Needed for FW download */ 2049a3667aaeSNaresh Kumar Inna rv = csio_hw_get_flash_params(hw); 2050a3667aaeSNaresh Kumar Inna if (rv != 0) { 2051a3667aaeSNaresh Kumar Inna csio_err(hw, "Failed to get serial flash params rv:%d\n", rv); 2052a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_FATAL); 2053a3667aaeSNaresh Kumar Inna goto out; 2054a3667aaeSNaresh Kumar Inna } 2055a3667aaeSNaresh Kumar Inna 2056*ad4d35f8SYijing Wang /* Set PCIe completion timeout to 4 seconds */ 2057*ad4d35f8SYijing Wang if (pci_is_pcie(hw->pdev)) 2058*ad4d35f8SYijing Wang pcie_capability_clear_and_set_word(hw->pdev, PCI_EXP_DEVCTL2, 2059*ad4d35f8SYijing Wang PCI_EXP_DEVCTL2_COMP_TIMEOUT, 0xd); 2060a3667aaeSNaresh Kumar Inna 20617cc16380SArvind Bhushan hw->chip_ops->chip_set_mem_win(hw, MEMWIN_CSIOSTOR); 2062a3667aaeSNaresh Kumar Inna 2063a3667aaeSNaresh Kumar Inna rv = csio_hw_get_fw_version(hw, &hw->fwrev); 2064a3667aaeSNaresh Kumar Inna if (rv != 0) 2065a3667aaeSNaresh Kumar Inna goto out; 2066a3667aaeSNaresh Kumar Inna 2067a3667aaeSNaresh Kumar Inna csio_hw_print_fw_version(hw, "Firmware revision"); 2068a3667aaeSNaresh Kumar Inna 2069a3667aaeSNaresh Kumar Inna rv = csio_do_hello(hw, &hw->fw_state); 2070a3667aaeSNaresh Kumar Inna if (rv != 0) { 2071a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_fatal); 2072a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_FATAL); 2073a3667aaeSNaresh Kumar Inna goto out; 2074a3667aaeSNaresh Kumar Inna } 2075a3667aaeSNaresh Kumar Inna 2076a3667aaeSNaresh Kumar Inna /* Read vpd */ 2077a3667aaeSNaresh Kumar Inna rv = csio_hw_get_vpd_params(hw, &hw->vpd); 2078a3667aaeSNaresh Kumar Inna if (rv != 0) 2079a3667aaeSNaresh Kumar Inna goto out; 2080a3667aaeSNaresh Kumar Inna 2081a3667aaeSNaresh Kumar Inna if (csio_is_hw_master(hw) && hw->fw_state != CSIO_DEV_STATE_INIT) { 2082a3667aaeSNaresh Kumar Inna rv = csio_hw_check_fw_version(hw); 2083a3667aaeSNaresh Kumar Inna if (rv == -EINVAL) { 2084a3667aaeSNaresh Kumar Inna 2085a3667aaeSNaresh Kumar Inna /* Do firmware update */ 2086a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 2087a3667aaeSNaresh Kumar Inna rv = csio_hw_flash_fw(hw); 2088a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 2089a3667aaeSNaresh Kumar Inna 2090a3667aaeSNaresh Kumar Inna if (rv == 0) { 2091a3667aaeSNaresh Kumar Inna reset = 0; 2092a3667aaeSNaresh Kumar Inna /* 2093a3667aaeSNaresh Kumar Inna * Note that the chip was reset as part of the 2094a3667aaeSNaresh Kumar Inna * firmware upgrade so we don't reset it again 2095a3667aaeSNaresh Kumar Inna * below and grab the new firmware version. 2096a3667aaeSNaresh Kumar Inna */ 2097a3667aaeSNaresh Kumar Inna rv = csio_hw_check_fw_version(hw); 2098a3667aaeSNaresh Kumar Inna } 2099a3667aaeSNaresh Kumar Inna } 2100a3667aaeSNaresh Kumar Inna /* 2101a3667aaeSNaresh Kumar Inna * If the firmware doesn't support Configuration 2102a3667aaeSNaresh Kumar Inna * Files, use the old Driver-based, hard-wired 2103a3667aaeSNaresh Kumar Inna * initialization. Otherwise, try using the 2104a3667aaeSNaresh Kumar Inna * Configuration File support and fall back to the 2105a3667aaeSNaresh Kumar Inna * Driver-based initialization if there's no 2106a3667aaeSNaresh Kumar Inna * Configuration File found. 2107a3667aaeSNaresh Kumar Inna */ 2108a3667aaeSNaresh Kumar Inna if (csio_hw_check_fwconfig(hw, param) == 0) { 2109a3667aaeSNaresh Kumar Inna rv = csio_hw_use_fwconfig(hw, reset, param); 2110a3667aaeSNaresh Kumar Inna if (rv == -ENOENT) 2111a3667aaeSNaresh Kumar Inna goto out; 2112a3667aaeSNaresh Kumar Inna if (rv != 0) { 2113a3667aaeSNaresh Kumar Inna csio_info(hw, 2114a3667aaeSNaresh Kumar Inna "No Configuration File present " 2115a3667aaeSNaresh Kumar Inna "on adapter. Using hard-wired " 2116a3667aaeSNaresh Kumar Inna "configuration parameters.\n"); 2117a3667aaeSNaresh Kumar Inna rv = csio_hw_no_fwconfig(hw, reset); 2118a3667aaeSNaresh Kumar Inna } 2119a3667aaeSNaresh Kumar Inna } else { 2120a3667aaeSNaresh Kumar Inna rv = csio_hw_no_fwconfig(hw, reset); 2121a3667aaeSNaresh Kumar Inna } 2122a3667aaeSNaresh Kumar Inna 2123a3667aaeSNaresh Kumar Inna if (rv != 0) 2124a3667aaeSNaresh Kumar Inna goto out; 2125a3667aaeSNaresh Kumar Inna 2126a3667aaeSNaresh Kumar Inna } else { 2127a3667aaeSNaresh Kumar Inna if (hw->fw_state == CSIO_DEV_STATE_INIT) { 2128a3667aaeSNaresh Kumar Inna 21297cc16380SArvind Bhushan hw->flags |= CSIO_HWF_USING_SOFT_PARAMS; 21307cc16380SArvind Bhushan 2131a3667aaeSNaresh Kumar Inna /* device parameters */ 2132a3667aaeSNaresh Kumar Inna rv = csio_get_device_params(hw); 2133a3667aaeSNaresh Kumar Inna if (rv != 0) 2134a3667aaeSNaresh Kumar Inna goto out; 2135a3667aaeSNaresh Kumar Inna 2136a3667aaeSNaresh Kumar Inna /* Get device capabilities */ 2137a3667aaeSNaresh Kumar Inna rv = csio_config_device_caps(hw); 2138a3667aaeSNaresh Kumar Inna if (rv != 0) 2139a3667aaeSNaresh Kumar Inna goto out; 2140a3667aaeSNaresh Kumar Inna 2141a3667aaeSNaresh Kumar Inna /* Configure SGE */ 2142a3667aaeSNaresh Kumar Inna csio_wr_sge_init(hw); 2143a3667aaeSNaresh Kumar Inna 2144a3667aaeSNaresh Kumar Inna /* Post event to notify completion of configuration */ 2145a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_INIT); 2146a3667aaeSNaresh Kumar Inna goto out; 2147a3667aaeSNaresh Kumar Inna } 2148a3667aaeSNaresh Kumar Inna } /* if not master */ 2149a3667aaeSNaresh Kumar Inna 2150a3667aaeSNaresh Kumar Inna out: 2151a3667aaeSNaresh Kumar Inna return; 2152a3667aaeSNaresh Kumar Inna } 2153a3667aaeSNaresh Kumar Inna 2154a3667aaeSNaresh Kumar Inna /* 2155a3667aaeSNaresh Kumar Inna * csio_hw_initialize - Initialize HW 2156a3667aaeSNaresh Kumar Inna * @hw - HW module 2157a3667aaeSNaresh Kumar Inna * 2158a3667aaeSNaresh Kumar Inna */ 2159a3667aaeSNaresh Kumar Inna static void 2160a3667aaeSNaresh Kumar Inna csio_hw_initialize(struct csio_hw *hw) 2161a3667aaeSNaresh Kumar Inna { 2162a3667aaeSNaresh Kumar Inna struct csio_mb *mbp; 2163a3667aaeSNaresh Kumar Inna enum fw_retval retval; 2164a3667aaeSNaresh Kumar Inna int rv; 2165a3667aaeSNaresh Kumar Inna int i; 2166a3667aaeSNaresh Kumar Inna 2167a3667aaeSNaresh Kumar Inna if (csio_is_hw_master(hw) && hw->fw_state != CSIO_DEV_STATE_INIT) { 2168a3667aaeSNaresh Kumar Inna mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 2169a3667aaeSNaresh Kumar Inna if (!mbp) 2170a3667aaeSNaresh Kumar Inna goto out; 2171a3667aaeSNaresh Kumar Inna 2172a3667aaeSNaresh Kumar Inna csio_mb_initialize(hw, mbp, CSIO_MB_DEFAULT_TMO, NULL); 2173a3667aaeSNaresh Kumar Inna 2174a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 2175a3667aaeSNaresh Kumar Inna csio_err(hw, "Issue of FW_INITIALIZE_CMD failed!\n"); 2176a3667aaeSNaresh Kumar Inna goto free_and_out; 2177a3667aaeSNaresh Kumar Inna } 2178a3667aaeSNaresh Kumar Inna 2179a3667aaeSNaresh Kumar Inna retval = csio_mb_fw_retval(mbp); 2180a3667aaeSNaresh Kumar Inna if (retval != FW_SUCCESS) { 2181a3667aaeSNaresh Kumar Inna csio_err(hw, "FW_INITIALIZE_CMD returned 0x%x!\n", 2182a3667aaeSNaresh Kumar Inna retval); 2183a3667aaeSNaresh Kumar Inna goto free_and_out; 2184a3667aaeSNaresh Kumar Inna } 2185a3667aaeSNaresh Kumar Inna 2186a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 2187a3667aaeSNaresh Kumar Inna } 2188a3667aaeSNaresh Kumar Inna 2189a3667aaeSNaresh Kumar Inna rv = csio_get_fcoe_resinfo(hw); 2190a3667aaeSNaresh Kumar Inna if (rv != 0) { 2191a3667aaeSNaresh Kumar Inna csio_err(hw, "Failed to read fcoe resource info: %d\n", rv); 2192a3667aaeSNaresh Kumar Inna goto out; 2193a3667aaeSNaresh Kumar Inna } 2194a3667aaeSNaresh Kumar Inna 2195a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 2196a3667aaeSNaresh Kumar Inna rv = csio_config_queues(hw); 2197a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 2198a3667aaeSNaresh Kumar Inna 2199a3667aaeSNaresh Kumar Inna if (rv != 0) { 2200a3667aaeSNaresh Kumar Inna csio_err(hw, "Config of queues failed!: %d\n", rv); 2201a3667aaeSNaresh Kumar Inna goto out; 2202a3667aaeSNaresh Kumar Inna } 2203a3667aaeSNaresh Kumar Inna 2204a3667aaeSNaresh Kumar Inna for (i = 0; i < hw->num_pports; i++) 2205a3667aaeSNaresh Kumar Inna hw->pport[i].mod_type = FW_PORT_MOD_TYPE_NA; 2206a3667aaeSNaresh Kumar Inna 2207a3667aaeSNaresh Kumar Inna if (csio_is_hw_master(hw) && hw->fw_state != CSIO_DEV_STATE_INIT) { 2208a3667aaeSNaresh Kumar Inna rv = csio_enable_ports(hw); 2209a3667aaeSNaresh Kumar Inna if (rv != 0) { 2210a3667aaeSNaresh Kumar Inna csio_err(hw, "Failed to enable ports: %d\n", rv); 2211a3667aaeSNaresh Kumar Inna goto out; 2212a3667aaeSNaresh Kumar Inna } 2213a3667aaeSNaresh Kumar Inna } 2214a3667aaeSNaresh Kumar Inna 2215a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_INIT_DONE); 2216a3667aaeSNaresh Kumar Inna return; 2217a3667aaeSNaresh Kumar Inna 2218a3667aaeSNaresh Kumar Inna free_and_out: 2219a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 2220a3667aaeSNaresh Kumar Inna out: 2221a3667aaeSNaresh Kumar Inna return; 2222a3667aaeSNaresh Kumar Inna } 2223a3667aaeSNaresh Kumar Inna 2224a3667aaeSNaresh Kumar Inna #define PF_INTR_MASK (PFSW | PFCIM) 2225a3667aaeSNaresh Kumar Inna 2226a3667aaeSNaresh Kumar Inna /* 2227a3667aaeSNaresh Kumar Inna * csio_hw_intr_enable - Enable HW interrupts 2228a3667aaeSNaresh Kumar Inna * @hw: Pointer to HW module. 2229a3667aaeSNaresh Kumar Inna * 2230a3667aaeSNaresh Kumar Inna * Enable interrupts in HW registers. 2231a3667aaeSNaresh Kumar Inna */ 2232a3667aaeSNaresh Kumar Inna static void 2233a3667aaeSNaresh Kumar Inna csio_hw_intr_enable(struct csio_hw *hw) 2234a3667aaeSNaresh Kumar Inna { 2235a3667aaeSNaresh Kumar Inna uint16_t vec = (uint16_t)csio_get_mb_intr_idx(csio_hw_to_mbm(hw)); 2236a3667aaeSNaresh Kumar Inna uint32_t pf = SOURCEPF_GET(csio_rd_reg32(hw, PL_WHOAMI)); 2237a3667aaeSNaresh Kumar Inna uint32_t pl = csio_rd_reg32(hw, PL_INT_ENABLE); 2238a3667aaeSNaresh Kumar Inna 2239a3667aaeSNaresh Kumar Inna /* 2240a3667aaeSNaresh Kumar Inna * Set aivec for MSI/MSIX. PCIE_PF_CFG.INTXType is set up 2241a3667aaeSNaresh Kumar Inna * by FW, so do nothing for INTX. 2242a3667aaeSNaresh Kumar Inna */ 2243a3667aaeSNaresh Kumar Inna if (hw->intr_mode == CSIO_IM_MSIX) 2244a3667aaeSNaresh Kumar Inna csio_set_reg_field(hw, MYPF_REG(PCIE_PF_CFG), 2245a3667aaeSNaresh Kumar Inna AIVEC(AIVEC_MASK), vec); 2246a3667aaeSNaresh Kumar Inna else if (hw->intr_mode == CSIO_IM_MSI) 2247a3667aaeSNaresh Kumar Inna csio_set_reg_field(hw, MYPF_REG(PCIE_PF_CFG), 2248a3667aaeSNaresh Kumar Inna AIVEC(AIVEC_MASK), 0); 2249a3667aaeSNaresh Kumar Inna 2250a3667aaeSNaresh Kumar Inna csio_wr_reg32(hw, PF_INTR_MASK, MYPF_REG(PL_PF_INT_ENABLE)); 2251a3667aaeSNaresh Kumar Inna 2252a3667aaeSNaresh Kumar Inna /* Turn on MB interrupts - this will internally flush PIO as well */ 2253a3667aaeSNaresh Kumar Inna csio_mb_intr_enable(hw); 2254a3667aaeSNaresh Kumar Inna 2255a3667aaeSNaresh Kumar Inna /* These are common registers - only a master can modify them */ 2256a3667aaeSNaresh Kumar Inna if (csio_is_hw_master(hw)) { 2257a3667aaeSNaresh Kumar Inna /* 2258a3667aaeSNaresh Kumar Inna * Disable the Serial FLASH interrupt, if enabled! 2259a3667aaeSNaresh Kumar Inna */ 2260a3667aaeSNaresh Kumar Inna pl &= (~SF); 2261a3667aaeSNaresh Kumar Inna csio_wr_reg32(hw, pl, PL_INT_ENABLE); 2262a3667aaeSNaresh Kumar Inna 2263a3667aaeSNaresh Kumar Inna csio_wr_reg32(hw, ERR_CPL_EXCEED_IQE_SIZE | 2264a3667aaeSNaresh Kumar Inna EGRESS_SIZE_ERR | ERR_INVALID_CIDX_INC | 2265a3667aaeSNaresh Kumar Inna ERR_CPL_OPCODE_0 | ERR_DROPPED_DB | 2266a3667aaeSNaresh Kumar Inna ERR_DATA_CPL_ON_HIGH_QID1 | 2267a3667aaeSNaresh Kumar Inna ERR_DATA_CPL_ON_HIGH_QID0 | ERR_BAD_DB_PIDX3 | 2268a3667aaeSNaresh Kumar Inna ERR_BAD_DB_PIDX2 | ERR_BAD_DB_PIDX1 | 2269a3667aaeSNaresh Kumar Inna ERR_BAD_DB_PIDX0 | ERR_ING_CTXT_PRIO | 2270a3667aaeSNaresh Kumar Inna ERR_EGR_CTXT_PRIO | INGRESS_SIZE_ERR, 2271a3667aaeSNaresh Kumar Inna SGE_INT_ENABLE3); 2272a3667aaeSNaresh Kumar Inna csio_set_reg_field(hw, PL_INT_MAP0, 0, 1 << pf); 2273a3667aaeSNaresh Kumar Inna } 2274a3667aaeSNaresh Kumar Inna 2275a3667aaeSNaresh Kumar Inna hw->flags |= CSIO_HWF_HW_INTR_ENABLED; 2276a3667aaeSNaresh Kumar Inna 2277a3667aaeSNaresh Kumar Inna } 2278a3667aaeSNaresh Kumar Inna 2279a3667aaeSNaresh Kumar Inna /* 2280a3667aaeSNaresh Kumar Inna * csio_hw_intr_disable - Disable HW interrupts 2281a3667aaeSNaresh Kumar Inna * @hw: Pointer to HW module. 2282a3667aaeSNaresh Kumar Inna * 2283a3667aaeSNaresh Kumar Inna * Turn off Mailbox and PCI_PF_CFG interrupts. 2284a3667aaeSNaresh Kumar Inna */ 2285a3667aaeSNaresh Kumar Inna void 2286a3667aaeSNaresh Kumar Inna csio_hw_intr_disable(struct csio_hw *hw) 2287a3667aaeSNaresh Kumar Inna { 2288a3667aaeSNaresh Kumar Inna uint32_t pf = SOURCEPF_GET(csio_rd_reg32(hw, PL_WHOAMI)); 2289a3667aaeSNaresh Kumar Inna 2290a3667aaeSNaresh Kumar Inna if (!(hw->flags & CSIO_HWF_HW_INTR_ENABLED)) 2291a3667aaeSNaresh Kumar Inna return; 2292a3667aaeSNaresh Kumar Inna 2293a3667aaeSNaresh Kumar Inna hw->flags &= ~CSIO_HWF_HW_INTR_ENABLED; 2294a3667aaeSNaresh Kumar Inna 2295a3667aaeSNaresh Kumar Inna csio_wr_reg32(hw, 0, MYPF_REG(PL_PF_INT_ENABLE)); 2296a3667aaeSNaresh Kumar Inna if (csio_is_hw_master(hw)) 2297a3667aaeSNaresh Kumar Inna csio_set_reg_field(hw, PL_INT_MAP0, 1 << pf, 0); 2298a3667aaeSNaresh Kumar Inna 2299a3667aaeSNaresh Kumar Inna /* Turn off MB interrupts */ 2300a3667aaeSNaresh Kumar Inna csio_mb_intr_disable(hw); 2301a3667aaeSNaresh Kumar Inna 2302a3667aaeSNaresh Kumar Inna } 2303a3667aaeSNaresh Kumar Inna 23047cc16380SArvind Bhushan void 2305a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(struct csio_hw *hw) 2306a3667aaeSNaresh Kumar Inna { 2307a3667aaeSNaresh Kumar Inna csio_set_reg_field(hw, SGE_CONTROL, GLOBALENABLE, 0); 2308a3667aaeSNaresh Kumar Inna csio_hw_intr_disable(hw); 2309a3667aaeSNaresh Kumar Inna 2310a3667aaeSNaresh Kumar Inna /* Do not reset HW, we may need FW state for debugging */ 2311a3667aaeSNaresh Kumar Inna csio_fatal(hw, "HW Fatal error encountered!\n"); 2312a3667aaeSNaresh Kumar Inna } 2313a3667aaeSNaresh Kumar Inna 2314a3667aaeSNaresh Kumar Inna /*****************************************************************************/ 2315a3667aaeSNaresh Kumar Inna /* START: HW SM */ 2316a3667aaeSNaresh Kumar Inna /*****************************************************************************/ 2317a3667aaeSNaresh Kumar Inna /* 2318a3667aaeSNaresh Kumar Inna * csio_hws_uninit - Uninit state 2319a3667aaeSNaresh Kumar Inna * @hw - HW module 2320a3667aaeSNaresh Kumar Inna * @evt - Event 2321a3667aaeSNaresh Kumar Inna * 2322a3667aaeSNaresh Kumar Inna */ 2323a3667aaeSNaresh Kumar Inna static void 2324a3667aaeSNaresh Kumar Inna csio_hws_uninit(struct csio_hw *hw, enum csio_hw_ev evt) 2325a3667aaeSNaresh Kumar Inna { 2326a3667aaeSNaresh Kumar Inna hw->prev_evt = hw->cur_evt; 2327a3667aaeSNaresh Kumar Inna hw->cur_evt = evt; 2328a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_sm[evt]); 2329a3667aaeSNaresh Kumar Inna 2330a3667aaeSNaresh Kumar Inna switch (evt) { 2331a3667aaeSNaresh Kumar Inna case CSIO_HWE_CFG: 2332a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_configuring); 2333a3667aaeSNaresh Kumar Inna csio_hw_configure(hw); 2334a3667aaeSNaresh Kumar Inna break; 2335a3667aaeSNaresh Kumar Inna 2336a3667aaeSNaresh Kumar Inna default: 2337a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_unexp); 2338a3667aaeSNaresh Kumar Inna break; 2339a3667aaeSNaresh Kumar Inna } 2340a3667aaeSNaresh Kumar Inna } 2341a3667aaeSNaresh Kumar Inna 2342a3667aaeSNaresh Kumar Inna /* 2343a3667aaeSNaresh Kumar Inna * csio_hws_configuring - Configuring state 2344a3667aaeSNaresh Kumar Inna * @hw - HW module 2345a3667aaeSNaresh Kumar Inna * @evt - Event 2346a3667aaeSNaresh Kumar Inna * 2347a3667aaeSNaresh Kumar Inna */ 2348a3667aaeSNaresh Kumar Inna static void 2349a3667aaeSNaresh Kumar Inna csio_hws_configuring(struct csio_hw *hw, enum csio_hw_ev evt) 2350a3667aaeSNaresh Kumar Inna { 2351a3667aaeSNaresh Kumar Inna hw->prev_evt = hw->cur_evt; 2352a3667aaeSNaresh Kumar Inna hw->cur_evt = evt; 2353a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_sm[evt]); 2354a3667aaeSNaresh Kumar Inna 2355a3667aaeSNaresh Kumar Inna switch (evt) { 2356a3667aaeSNaresh Kumar Inna case CSIO_HWE_INIT: 2357a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_initializing); 2358a3667aaeSNaresh Kumar Inna csio_hw_initialize(hw); 2359a3667aaeSNaresh Kumar Inna break; 2360a3667aaeSNaresh Kumar Inna 2361a3667aaeSNaresh Kumar Inna case CSIO_HWE_INIT_DONE: 2362a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_ready); 2363a3667aaeSNaresh Kumar Inna /* Fan out event to all lnode SMs */ 2364a3667aaeSNaresh Kumar Inna csio_notify_lnodes(hw, CSIO_LN_NOTIFY_HWREADY); 2365a3667aaeSNaresh Kumar Inna break; 2366a3667aaeSNaresh Kumar Inna 2367a3667aaeSNaresh Kumar Inna case CSIO_HWE_FATAL: 2368a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_uninit); 2369a3667aaeSNaresh Kumar Inna break; 2370a3667aaeSNaresh Kumar Inna 2371a3667aaeSNaresh Kumar Inna case CSIO_HWE_PCI_REMOVE: 2372a3667aaeSNaresh Kumar Inna csio_do_bye(hw); 2373a3667aaeSNaresh Kumar Inna break; 2374a3667aaeSNaresh Kumar Inna default: 2375a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_unexp); 2376a3667aaeSNaresh Kumar Inna break; 2377a3667aaeSNaresh Kumar Inna } 2378a3667aaeSNaresh Kumar Inna } 2379a3667aaeSNaresh Kumar Inna 2380a3667aaeSNaresh Kumar Inna /* 2381a3667aaeSNaresh Kumar Inna * csio_hws_initializing - Initialiazing state 2382a3667aaeSNaresh Kumar Inna * @hw - HW module 2383a3667aaeSNaresh Kumar Inna * @evt - Event 2384a3667aaeSNaresh Kumar Inna * 2385a3667aaeSNaresh Kumar Inna */ 2386a3667aaeSNaresh Kumar Inna static void 2387a3667aaeSNaresh Kumar Inna csio_hws_initializing(struct csio_hw *hw, enum csio_hw_ev evt) 2388a3667aaeSNaresh Kumar Inna { 2389a3667aaeSNaresh Kumar Inna hw->prev_evt = hw->cur_evt; 2390a3667aaeSNaresh Kumar Inna hw->cur_evt = evt; 2391a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_sm[evt]); 2392a3667aaeSNaresh Kumar Inna 2393a3667aaeSNaresh Kumar Inna switch (evt) { 2394a3667aaeSNaresh Kumar Inna case CSIO_HWE_INIT_DONE: 2395a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_ready); 2396a3667aaeSNaresh Kumar Inna 2397a3667aaeSNaresh Kumar Inna /* Fan out event to all lnode SMs */ 2398a3667aaeSNaresh Kumar Inna csio_notify_lnodes(hw, CSIO_LN_NOTIFY_HWREADY); 2399a3667aaeSNaresh Kumar Inna 2400a3667aaeSNaresh Kumar Inna /* Enable interrupts */ 2401a3667aaeSNaresh Kumar Inna csio_hw_intr_enable(hw); 2402a3667aaeSNaresh Kumar Inna break; 2403a3667aaeSNaresh Kumar Inna 2404a3667aaeSNaresh Kumar Inna case CSIO_HWE_FATAL: 2405a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_uninit); 2406a3667aaeSNaresh Kumar Inna break; 2407a3667aaeSNaresh Kumar Inna 2408a3667aaeSNaresh Kumar Inna case CSIO_HWE_PCI_REMOVE: 2409a3667aaeSNaresh Kumar Inna csio_do_bye(hw); 2410a3667aaeSNaresh Kumar Inna break; 2411a3667aaeSNaresh Kumar Inna 2412a3667aaeSNaresh Kumar Inna default: 2413a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_unexp); 2414a3667aaeSNaresh Kumar Inna break; 2415a3667aaeSNaresh Kumar Inna } 2416a3667aaeSNaresh Kumar Inna } 2417a3667aaeSNaresh Kumar Inna 2418a3667aaeSNaresh Kumar Inna /* 2419a3667aaeSNaresh Kumar Inna * csio_hws_ready - Ready state 2420a3667aaeSNaresh Kumar Inna * @hw - HW module 2421a3667aaeSNaresh Kumar Inna * @evt - Event 2422a3667aaeSNaresh Kumar Inna * 2423a3667aaeSNaresh Kumar Inna */ 2424a3667aaeSNaresh Kumar Inna static void 2425a3667aaeSNaresh Kumar Inna csio_hws_ready(struct csio_hw *hw, enum csio_hw_ev evt) 2426a3667aaeSNaresh Kumar Inna { 2427a3667aaeSNaresh Kumar Inna /* Remember the event */ 2428a3667aaeSNaresh Kumar Inna hw->evtflag = evt; 2429a3667aaeSNaresh Kumar Inna 2430a3667aaeSNaresh Kumar Inna hw->prev_evt = hw->cur_evt; 2431a3667aaeSNaresh Kumar Inna hw->cur_evt = evt; 2432a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_sm[evt]); 2433a3667aaeSNaresh Kumar Inna 2434a3667aaeSNaresh Kumar Inna switch (evt) { 2435a3667aaeSNaresh Kumar Inna case CSIO_HWE_HBA_RESET: 2436a3667aaeSNaresh Kumar Inna case CSIO_HWE_FW_DLOAD: 2437a3667aaeSNaresh Kumar Inna case CSIO_HWE_SUSPEND: 2438a3667aaeSNaresh Kumar Inna case CSIO_HWE_PCI_REMOVE: 2439a3667aaeSNaresh Kumar Inna case CSIO_HWE_PCIERR_DETECTED: 2440a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_quiescing); 2441a3667aaeSNaresh Kumar Inna /* cleanup all outstanding cmds */ 2442a3667aaeSNaresh Kumar Inna if (evt == CSIO_HWE_HBA_RESET || 2443a3667aaeSNaresh Kumar Inna evt == CSIO_HWE_PCIERR_DETECTED) 2444a3667aaeSNaresh Kumar Inna csio_scsim_cleanup_io(csio_hw_to_scsim(hw), false); 2445a3667aaeSNaresh Kumar Inna else 2446a3667aaeSNaresh Kumar Inna csio_scsim_cleanup_io(csio_hw_to_scsim(hw), true); 2447a3667aaeSNaresh Kumar Inna 2448a3667aaeSNaresh Kumar Inna csio_hw_intr_disable(hw); 2449a3667aaeSNaresh Kumar Inna csio_hw_mbm_cleanup(hw); 2450a3667aaeSNaresh Kumar Inna csio_evtq_stop(hw); 2451a3667aaeSNaresh Kumar Inna csio_notify_lnodes(hw, CSIO_LN_NOTIFY_HWSTOP); 2452a3667aaeSNaresh Kumar Inna csio_evtq_flush(hw); 2453a3667aaeSNaresh Kumar Inna csio_mgmtm_cleanup(csio_hw_to_mgmtm(hw)); 2454a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_QUIESCED); 2455a3667aaeSNaresh Kumar Inna break; 2456a3667aaeSNaresh Kumar Inna 2457a3667aaeSNaresh Kumar Inna case CSIO_HWE_FATAL: 2458a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_uninit); 2459a3667aaeSNaresh Kumar Inna break; 2460a3667aaeSNaresh Kumar Inna 2461a3667aaeSNaresh Kumar Inna default: 2462a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_unexp); 2463a3667aaeSNaresh Kumar Inna break; 2464a3667aaeSNaresh Kumar Inna } 2465a3667aaeSNaresh Kumar Inna } 2466a3667aaeSNaresh Kumar Inna 2467a3667aaeSNaresh Kumar Inna /* 2468a3667aaeSNaresh Kumar Inna * csio_hws_quiescing - Quiescing state 2469a3667aaeSNaresh Kumar Inna * @hw - HW module 2470a3667aaeSNaresh Kumar Inna * @evt - Event 2471a3667aaeSNaresh Kumar Inna * 2472a3667aaeSNaresh Kumar Inna */ 2473a3667aaeSNaresh Kumar Inna static void 2474a3667aaeSNaresh Kumar Inna csio_hws_quiescing(struct csio_hw *hw, enum csio_hw_ev evt) 2475a3667aaeSNaresh Kumar Inna { 2476a3667aaeSNaresh Kumar Inna hw->prev_evt = hw->cur_evt; 2477a3667aaeSNaresh Kumar Inna hw->cur_evt = evt; 2478a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_sm[evt]); 2479a3667aaeSNaresh Kumar Inna 2480a3667aaeSNaresh Kumar Inna switch (evt) { 2481a3667aaeSNaresh Kumar Inna case CSIO_HWE_QUIESCED: 2482a3667aaeSNaresh Kumar Inna switch (hw->evtflag) { 2483a3667aaeSNaresh Kumar Inna case CSIO_HWE_FW_DLOAD: 2484a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_resetting); 2485a3667aaeSNaresh Kumar Inna /* Download firmware */ 2486a3667aaeSNaresh Kumar Inna /* Fall through */ 2487a3667aaeSNaresh Kumar Inna 2488a3667aaeSNaresh Kumar Inna case CSIO_HWE_HBA_RESET: 2489a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_resetting); 2490a3667aaeSNaresh Kumar Inna /* Start reset of the HBA */ 2491a3667aaeSNaresh Kumar Inna csio_notify_lnodes(hw, CSIO_LN_NOTIFY_HWRESET); 2492a3667aaeSNaresh Kumar Inna csio_wr_destroy_queues(hw, false); 2493a3667aaeSNaresh Kumar Inna csio_do_reset(hw, false); 2494a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_HBA_RESET_DONE); 2495a3667aaeSNaresh Kumar Inna break; 2496a3667aaeSNaresh Kumar Inna 2497a3667aaeSNaresh Kumar Inna case CSIO_HWE_PCI_REMOVE: 2498a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_removing); 2499a3667aaeSNaresh Kumar Inna csio_notify_lnodes(hw, CSIO_LN_NOTIFY_HWREMOVE); 2500a3667aaeSNaresh Kumar Inna csio_wr_destroy_queues(hw, true); 2501a3667aaeSNaresh Kumar Inna /* Now send the bye command */ 2502a3667aaeSNaresh Kumar Inna csio_do_bye(hw); 2503a3667aaeSNaresh Kumar Inna break; 2504a3667aaeSNaresh Kumar Inna 2505a3667aaeSNaresh Kumar Inna case CSIO_HWE_SUSPEND: 2506a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_quiesced); 2507a3667aaeSNaresh Kumar Inna break; 2508a3667aaeSNaresh Kumar Inna 2509a3667aaeSNaresh Kumar Inna case CSIO_HWE_PCIERR_DETECTED: 2510a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_pcierr); 2511a3667aaeSNaresh Kumar Inna csio_wr_destroy_queues(hw, false); 2512a3667aaeSNaresh Kumar Inna break; 2513a3667aaeSNaresh Kumar Inna 2514a3667aaeSNaresh Kumar Inna default: 2515a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_unexp); 2516a3667aaeSNaresh Kumar Inna break; 2517a3667aaeSNaresh Kumar Inna 2518a3667aaeSNaresh Kumar Inna } 2519a3667aaeSNaresh Kumar Inna break; 2520a3667aaeSNaresh Kumar Inna 2521a3667aaeSNaresh Kumar Inna default: 2522a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_unexp); 2523a3667aaeSNaresh Kumar Inna break; 2524a3667aaeSNaresh Kumar Inna } 2525a3667aaeSNaresh Kumar Inna } 2526a3667aaeSNaresh Kumar Inna 2527a3667aaeSNaresh Kumar Inna /* 2528a3667aaeSNaresh Kumar Inna * csio_hws_quiesced - Quiesced state 2529a3667aaeSNaresh Kumar Inna * @hw - HW module 2530a3667aaeSNaresh Kumar Inna * @evt - Event 2531a3667aaeSNaresh Kumar Inna * 2532a3667aaeSNaresh Kumar Inna */ 2533a3667aaeSNaresh Kumar Inna static void 2534a3667aaeSNaresh Kumar Inna csio_hws_quiesced(struct csio_hw *hw, enum csio_hw_ev evt) 2535a3667aaeSNaresh Kumar Inna { 2536a3667aaeSNaresh Kumar Inna hw->prev_evt = hw->cur_evt; 2537a3667aaeSNaresh Kumar Inna hw->cur_evt = evt; 2538a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_sm[evt]); 2539a3667aaeSNaresh Kumar Inna 2540a3667aaeSNaresh Kumar Inna switch (evt) { 2541a3667aaeSNaresh Kumar Inna case CSIO_HWE_RESUME: 2542a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_configuring); 2543a3667aaeSNaresh Kumar Inna csio_hw_configure(hw); 2544a3667aaeSNaresh Kumar Inna break; 2545a3667aaeSNaresh Kumar Inna 2546a3667aaeSNaresh Kumar Inna default: 2547a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_unexp); 2548a3667aaeSNaresh Kumar Inna break; 2549a3667aaeSNaresh Kumar Inna } 2550a3667aaeSNaresh Kumar Inna } 2551a3667aaeSNaresh Kumar Inna 2552a3667aaeSNaresh Kumar Inna /* 2553a3667aaeSNaresh Kumar Inna * csio_hws_resetting - HW Resetting state 2554a3667aaeSNaresh Kumar Inna * @hw - HW module 2555a3667aaeSNaresh Kumar Inna * @evt - Event 2556a3667aaeSNaresh Kumar Inna * 2557a3667aaeSNaresh Kumar Inna */ 2558a3667aaeSNaresh Kumar Inna static void 2559a3667aaeSNaresh Kumar Inna csio_hws_resetting(struct csio_hw *hw, enum csio_hw_ev evt) 2560a3667aaeSNaresh Kumar Inna { 2561a3667aaeSNaresh Kumar Inna hw->prev_evt = hw->cur_evt; 2562a3667aaeSNaresh Kumar Inna hw->cur_evt = evt; 2563a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_sm[evt]); 2564a3667aaeSNaresh Kumar Inna 2565a3667aaeSNaresh Kumar Inna switch (evt) { 2566a3667aaeSNaresh Kumar Inna case CSIO_HWE_HBA_RESET_DONE: 2567a3667aaeSNaresh Kumar Inna csio_evtq_start(hw); 2568a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_configuring); 2569a3667aaeSNaresh Kumar Inna csio_hw_configure(hw); 2570a3667aaeSNaresh Kumar Inna break; 2571a3667aaeSNaresh Kumar Inna 2572a3667aaeSNaresh Kumar Inna default: 2573a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_unexp); 2574a3667aaeSNaresh Kumar Inna break; 2575a3667aaeSNaresh Kumar Inna } 2576a3667aaeSNaresh Kumar Inna } 2577a3667aaeSNaresh Kumar Inna 2578a3667aaeSNaresh Kumar Inna /* 2579a3667aaeSNaresh Kumar Inna * csio_hws_removing - PCI Hotplug removing state 2580a3667aaeSNaresh Kumar Inna * @hw - HW module 2581a3667aaeSNaresh Kumar Inna * @evt - Event 2582a3667aaeSNaresh Kumar Inna * 2583a3667aaeSNaresh Kumar Inna */ 2584a3667aaeSNaresh Kumar Inna static void 2585a3667aaeSNaresh Kumar Inna csio_hws_removing(struct csio_hw *hw, enum csio_hw_ev evt) 2586a3667aaeSNaresh Kumar Inna { 2587a3667aaeSNaresh Kumar Inna hw->prev_evt = hw->cur_evt; 2588a3667aaeSNaresh Kumar Inna hw->cur_evt = evt; 2589a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_sm[evt]); 2590a3667aaeSNaresh Kumar Inna 2591a3667aaeSNaresh Kumar Inna switch (evt) { 2592a3667aaeSNaresh Kumar Inna case CSIO_HWE_HBA_RESET: 2593a3667aaeSNaresh Kumar Inna if (!csio_is_hw_master(hw)) 2594a3667aaeSNaresh Kumar Inna break; 2595a3667aaeSNaresh Kumar Inna /* 2596a3667aaeSNaresh Kumar Inna * The BYE should have alerady been issued, so we cant 2597a3667aaeSNaresh Kumar Inna * use the mailbox interface. Hence we use the PL_RST 2598a3667aaeSNaresh Kumar Inna * register directly. 2599a3667aaeSNaresh Kumar Inna */ 2600a3667aaeSNaresh Kumar Inna csio_err(hw, "Resetting HW and waiting 2 seconds...\n"); 2601a3667aaeSNaresh Kumar Inna csio_wr_reg32(hw, PIORSTMODE | PIORST, PL_RST); 2602a3667aaeSNaresh Kumar Inna mdelay(2000); 2603a3667aaeSNaresh Kumar Inna break; 2604a3667aaeSNaresh Kumar Inna 2605a3667aaeSNaresh Kumar Inna /* Should never receive any new events */ 2606a3667aaeSNaresh Kumar Inna default: 2607a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_unexp); 2608a3667aaeSNaresh Kumar Inna break; 2609a3667aaeSNaresh Kumar Inna 2610a3667aaeSNaresh Kumar Inna } 2611a3667aaeSNaresh Kumar Inna } 2612a3667aaeSNaresh Kumar Inna 2613a3667aaeSNaresh Kumar Inna /* 2614a3667aaeSNaresh Kumar Inna * csio_hws_pcierr - PCI Error state 2615a3667aaeSNaresh Kumar Inna * @hw - HW module 2616a3667aaeSNaresh Kumar Inna * @evt - Event 2617a3667aaeSNaresh Kumar Inna * 2618a3667aaeSNaresh Kumar Inna */ 2619a3667aaeSNaresh Kumar Inna static void 2620a3667aaeSNaresh Kumar Inna csio_hws_pcierr(struct csio_hw *hw, enum csio_hw_ev evt) 2621a3667aaeSNaresh Kumar Inna { 2622a3667aaeSNaresh Kumar Inna hw->prev_evt = hw->cur_evt; 2623a3667aaeSNaresh Kumar Inna hw->cur_evt = evt; 2624a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_sm[evt]); 2625a3667aaeSNaresh Kumar Inna 2626a3667aaeSNaresh Kumar Inna switch (evt) { 2627a3667aaeSNaresh Kumar Inna case CSIO_HWE_PCIERR_SLOT_RESET: 2628a3667aaeSNaresh Kumar Inna csio_evtq_start(hw); 2629a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_configuring); 2630a3667aaeSNaresh Kumar Inna csio_hw_configure(hw); 2631a3667aaeSNaresh Kumar Inna break; 2632a3667aaeSNaresh Kumar Inna 2633a3667aaeSNaresh Kumar Inna default: 2634a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_unexp); 2635a3667aaeSNaresh Kumar Inna break; 2636a3667aaeSNaresh Kumar Inna } 2637a3667aaeSNaresh Kumar Inna } 2638a3667aaeSNaresh Kumar Inna 2639a3667aaeSNaresh Kumar Inna /*****************************************************************************/ 2640a3667aaeSNaresh Kumar Inna /* END: HW SM */ 2641a3667aaeSNaresh Kumar Inna /*****************************************************************************/ 2642a3667aaeSNaresh Kumar Inna 2643a3667aaeSNaresh Kumar Inna /* 2644a3667aaeSNaresh Kumar Inna * csio_handle_intr_status - table driven interrupt handler 2645a3667aaeSNaresh Kumar Inna * @hw: HW instance 2646a3667aaeSNaresh Kumar Inna * @reg: the interrupt status register to process 2647a3667aaeSNaresh Kumar Inna * @acts: table of interrupt actions 2648a3667aaeSNaresh Kumar Inna * 2649a3667aaeSNaresh Kumar Inna * A table driven interrupt handler that applies a set of masks to an 2650a3667aaeSNaresh Kumar Inna * interrupt status word and performs the corresponding actions if the 2651a3667aaeSNaresh Kumar Inna * interrupts described by the mask have occured. The actions include 2652a3667aaeSNaresh Kumar Inna * optionally emitting a warning or alert message. The table is terminated 2653a3667aaeSNaresh Kumar Inna * by an entry specifying mask 0. Returns the number of fatal interrupt 2654a3667aaeSNaresh Kumar Inna * conditions. 2655a3667aaeSNaresh Kumar Inna */ 26567cc16380SArvind Bhushan int 2657a3667aaeSNaresh Kumar Inna csio_handle_intr_status(struct csio_hw *hw, unsigned int reg, 2658a3667aaeSNaresh Kumar Inna const struct intr_info *acts) 2659a3667aaeSNaresh Kumar Inna { 2660a3667aaeSNaresh Kumar Inna int fatal = 0; 2661a3667aaeSNaresh Kumar Inna unsigned int mask = 0; 2662a3667aaeSNaresh Kumar Inna unsigned int status = csio_rd_reg32(hw, reg); 2663a3667aaeSNaresh Kumar Inna 2664a3667aaeSNaresh Kumar Inna for ( ; acts->mask; ++acts) { 2665a3667aaeSNaresh Kumar Inna if (!(status & acts->mask)) 2666a3667aaeSNaresh Kumar Inna continue; 2667a3667aaeSNaresh Kumar Inna if (acts->fatal) { 2668a3667aaeSNaresh Kumar Inna fatal++; 2669a3667aaeSNaresh Kumar Inna csio_fatal(hw, "Fatal %s (0x%x)\n", 2670a3667aaeSNaresh Kumar Inna acts->msg, status & acts->mask); 2671a3667aaeSNaresh Kumar Inna } else if (acts->msg) 2672a3667aaeSNaresh Kumar Inna csio_info(hw, "%s (0x%x)\n", 2673a3667aaeSNaresh Kumar Inna acts->msg, status & acts->mask); 2674a3667aaeSNaresh Kumar Inna mask |= acts->mask; 2675a3667aaeSNaresh Kumar Inna } 2676a3667aaeSNaresh Kumar Inna status &= mask; 2677a3667aaeSNaresh Kumar Inna if (status) /* clear processed interrupts */ 2678a3667aaeSNaresh Kumar Inna csio_wr_reg32(hw, status, reg); 2679a3667aaeSNaresh Kumar Inna return fatal; 2680a3667aaeSNaresh Kumar Inna } 2681a3667aaeSNaresh Kumar Inna 2682a3667aaeSNaresh Kumar Inna /* 2683a3667aaeSNaresh Kumar Inna * TP interrupt handler. 2684a3667aaeSNaresh Kumar Inna */ 2685a3667aaeSNaresh Kumar Inna static void csio_tp_intr_handler(struct csio_hw *hw) 2686a3667aaeSNaresh Kumar Inna { 2687a3667aaeSNaresh Kumar Inna static struct intr_info tp_intr_info[] = { 2688a3667aaeSNaresh Kumar Inna { 0x3fffffff, "TP parity error", -1, 1 }, 2689a3667aaeSNaresh Kumar Inna { FLMTXFLSTEMPTY, "TP out of Tx pages", -1, 1 }, 2690a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 2691a3667aaeSNaresh Kumar Inna }; 2692a3667aaeSNaresh Kumar Inna 2693a3667aaeSNaresh Kumar Inna if (csio_handle_intr_status(hw, TP_INT_CAUSE, tp_intr_info)) 2694a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 2695a3667aaeSNaresh Kumar Inna } 2696a3667aaeSNaresh Kumar Inna 2697a3667aaeSNaresh Kumar Inna /* 2698a3667aaeSNaresh Kumar Inna * SGE interrupt handler. 2699a3667aaeSNaresh Kumar Inna */ 2700a3667aaeSNaresh Kumar Inna static void csio_sge_intr_handler(struct csio_hw *hw) 2701a3667aaeSNaresh Kumar Inna { 2702a3667aaeSNaresh Kumar Inna uint64_t v; 2703a3667aaeSNaresh Kumar Inna 2704a3667aaeSNaresh Kumar Inna static struct intr_info sge_intr_info[] = { 2705a3667aaeSNaresh Kumar Inna { ERR_CPL_EXCEED_IQE_SIZE, 2706a3667aaeSNaresh Kumar Inna "SGE received CPL exceeding IQE size", -1, 1 }, 2707a3667aaeSNaresh Kumar Inna { ERR_INVALID_CIDX_INC, 2708a3667aaeSNaresh Kumar Inna "SGE GTS CIDX increment too large", -1, 0 }, 2709a3667aaeSNaresh Kumar Inna { ERR_CPL_OPCODE_0, "SGE received 0-length CPL", -1, 0 }, 2710a3667aaeSNaresh Kumar Inna { ERR_DROPPED_DB, "SGE doorbell dropped", -1, 0 }, 2711a3667aaeSNaresh Kumar Inna { ERR_DATA_CPL_ON_HIGH_QID1 | ERR_DATA_CPL_ON_HIGH_QID0, 2712a3667aaeSNaresh Kumar Inna "SGE IQID > 1023 received CPL for FL", -1, 0 }, 2713a3667aaeSNaresh Kumar Inna { ERR_BAD_DB_PIDX3, "SGE DBP 3 pidx increment too large", -1, 2714a3667aaeSNaresh Kumar Inna 0 }, 2715a3667aaeSNaresh Kumar Inna { ERR_BAD_DB_PIDX2, "SGE DBP 2 pidx increment too large", -1, 2716a3667aaeSNaresh Kumar Inna 0 }, 2717a3667aaeSNaresh Kumar Inna { ERR_BAD_DB_PIDX1, "SGE DBP 1 pidx increment too large", -1, 2718a3667aaeSNaresh Kumar Inna 0 }, 2719a3667aaeSNaresh Kumar Inna { ERR_BAD_DB_PIDX0, "SGE DBP 0 pidx increment too large", -1, 2720a3667aaeSNaresh Kumar Inna 0 }, 2721a3667aaeSNaresh Kumar Inna { ERR_ING_CTXT_PRIO, 2722a3667aaeSNaresh Kumar Inna "SGE too many priority ingress contexts", -1, 0 }, 2723a3667aaeSNaresh Kumar Inna { ERR_EGR_CTXT_PRIO, 2724a3667aaeSNaresh Kumar Inna "SGE too many priority egress contexts", -1, 0 }, 2725a3667aaeSNaresh Kumar Inna { INGRESS_SIZE_ERR, "SGE illegal ingress QID", -1, 0 }, 2726a3667aaeSNaresh Kumar Inna { EGRESS_SIZE_ERR, "SGE illegal egress QID", -1, 0 }, 2727a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 2728a3667aaeSNaresh Kumar Inna }; 2729a3667aaeSNaresh Kumar Inna 2730a3667aaeSNaresh Kumar Inna v = (uint64_t)csio_rd_reg32(hw, SGE_INT_CAUSE1) | 2731a3667aaeSNaresh Kumar Inna ((uint64_t)csio_rd_reg32(hw, SGE_INT_CAUSE2) << 32); 2732a3667aaeSNaresh Kumar Inna if (v) { 2733a3667aaeSNaresh Kumar Inna csio_fatal(hw, "SGE parity error (%#llx)\n", 2734a3667aaeSNaresh Kumar Inna (unsigned long long)v); 2735a3667aaeSNaresh Kumar Inna csio_wr_reg32(hw, (uint32_t)(v & 0xFFFFFFFF), 2736a3667aaeSNaresh Kumar Inna SGE_INT_CAUSE1); 2737a3667aaeSNaresh Kumar Inna csio_wr_reg32(hw, (uint32_t)(v >> 32), SGE_INT_CAUSE2); 2738a3667aaeSNaresh Kumar Inna } 2739a3667aaeSNaresh Kumar Inna 2740a3667aaeSNaresh Kumar Inna v |= csio_handle_intr_status(hw, SGE_INT_CAUSE3, sge_intr_info); 2741a3667aaeSNaresh Kumar Inna 2742a3667aaeSNaresh Kumar Inna if (csio_handle_intr_status(hw, SGE_INT_CAUSE3, sge_intr_info) || 2743a3667aaeSNaresh Kumar Inna v != 0) 2744a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 2745a3667aaeSNaresh Kumar Inna } 2746a3667aaeSNaresh Kumar Inna 2747a3667aaeSNaresh Kumar Inna #define CIM_OBQ_INTR (OBQULP0PARERR | OBQULP1PARERR | OBQULP2PARERR |\ 2748a3667aaeSNaresh Kumar Inna OBQULP3PARERR | OBQSGEPARERR | OBQNCSIPARERR) 2749a3667aaeSNaresh Kumar Inna #define CIM_IBQ_INTR (IBQTP0PARERR | IBQTP1PARERR | IBQULPPARERR |\ 2750a3667aaeSNaresh Kumar Inna IBQSGEHIPARERR | IBQSGELOPARERR | IBQNCSIPARERR) 2751a3667aaeSNaresh Kumar Inna 2752a3667aaeSNaresh Kumar Inna /* 2753a3667aaeSNaresh Kumar Inna * CIM interrupt handler. 2754a3667aaeSNaresh Kumar Inna */ 2755a3667aaeSNaresh Kumar Inna static void csio_cim_intr_handler(struct csio_hw *hw) 2756a3667aaeSNaresh Kumar Inna { 2757a3667aaeSNaresh Kumar Inna static struct intr_info cim_intr_info[] = { 2758a3667aaeSNaresh Kumar Inna { PREFDROPINT, "CIM control register prefetch drop", -1, 1 }, 2759a3667aaeSNaresh Kumar Inna { CIM_OBQ_INTR, "CIM OBQ parity error", -1, 1 }, 2760a3667aaeSNaresh Kumar Inna { CIM_IBQ_INTR, "CIM IBQ parity error", -1, 1 }, 2761a3667aaeSNaresh Kumar Inna { MBUPPARERR, "CIM mailbox uP parity error", -1, 1 }, 2762a3667aaeSNaresh Kumar Inna { MBHOSTPARERR, "CIM mailbox host parity error", -1, 1 }, 2763a3667aaeSNaresh Kumar Inna { TIEQINPARERRINT, "CIM TIEQ outgoing parity error", -1, 1 }, 2764a3667aaeSNaresh Kumar Inna { TIEQOUTPARERRINT, "CIM TIEQ incoming parity error", -1, 1 }, 2765a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 2766a3667aaeSNaresh Kumar Inna }; 2767a3667aaeSNaresh Kumar Inna static struct intr_info cim_upintr_info[] = { 2768a3667aaeSNaresh Kumar Inna { RSVDSPACEINT, "CIM reserved space access", -1, 1 }, 2769a3667aaeSNaresh Kumar Inna { ILLTRANSINT, "CIM illegal transaction", -1, 1 }, 2770a3667aaeSNaresh Kumar Inna { ILLWRINT, "CIM illegal write", -1, 1 }, 2771a3667aaeSNaresh Kumar Inna { ILLRDINT, "CIM illegal read", -1, 1 }, 2772a3667aaeSNaresh Kumar Inna { ILLRDBEINT, "CIM illegal read BE", -1, 1 }, 2773a3667aaeSNaresh Kumar Inna { ILLWRBEINT, "CIM illegal write BE", -1, 1 }, 2774a3667aaeSNaresh Kumar Inna { SGLRDBOOTINT, "CIM single read from boot space", -1, 1 }, 2775a3667aaeSNaresh Kumar Inna { SGLWRBOOTINT, "CIM single write to boot space", -1, 1 }, 2776a3667aaeSNaresh Kumar Inna { BLKWRBOOTINT, "CIM block write to boot space", -1, 1 }, 2777a3667aaeSNaresh Kumar Inna { SGLRDFLASHINT, "CIM single read from flash space", -1, 1 }, 2778a3667aaeSNaresh Kumar Inna { SGLWRFLASHINT, "CIM single write to flash space", -1, 1 }, 2779a3667aaeSNaresh Kumar Inna { BLKWRFLASHINT, "CIM block write to flash space", -1, 1 }, 2780a3667aaeSNaresh Kumar Inna { SGLRDEEPROMINT, "CIM single EEPROM read", -1, 1 }, 2781a3667aaeSNaresh Kumar Inna { SGLWREEPROMINT, "CIM single EEPROM write", -1, 1 }, 2782a3667aaeSNaresh Kumar Inna { BLKRDEEPROMINT, "CIM block EEPROM read", -1, 1 }, 2783a3667aaeSNaresh Kumar Inna { BLKWREEPROMINT, "CIM block EEPROM write", -1, 1 }, 2784a3667aaeSNaresh Kumar Inna { SGLRDCTLINT , "CIM single read from CTL space", -1, 1 }, 2785a3667aaeSNaresh Kumar Inna { SGLWRCTLINT , "CIM single write to CTL space", -1, 1 }, 2786a3667aaeSNaresh Kumar Inna { BLKRDCTLINT , "CIM block read from CTL space", -1, 1 }, 2787a3667aaeSNaresh Kumar Inna { BLKWRCTLINT , "CIM block write to CTL space", -1, 1 }, 2788a3667aaeSNaresh Kumar Inna { SGLRDPLINT , "CIM single read from PL space", -1, 1 }, 2789a3667aaeSNaresh Kumar Inna { SGLWRPLINT , "CIM single write to PL space", -1, 1 }, 2790a3667aaeSNaresh Kumar Inna { BLKRDPLINT , "CIM block read from PL space", -1, 1 }, 2791a3667aaeSNaresh Kumar Inna { BLKWRPLINT , "CIM block write to PL space", -1, 1 }, 2792a3667aaeSNaresh Kumar Inna { REQOVRLOOKUPINT , "CIM request FIFO overwrite", -1, 1 }, 2793a3667aaeSNaresh Kumar Inna { RSPOVRLOOKUPINT , "CIM response FIFO overwrite", -1, 1 }, 2794a3667aaeSNaresh Kumar Inna { TIMEOUTINT , "CIM PIF timeout", -1, 1 }, 2795a3667aaeSNaresh Kumar Inna { TIMEOUTMAINT , "CIM PIF MA timeout", -1, 1 }, 2796a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 2797a3667aaeSNaresh Kumar Inna }; 2798a3667aaeSNaresh Kumar Inna 2799a3667aaeSNaresh Kumar Inna int fat; 2800a3667aaeSNaresh Kumar Inna 2801a3667aaeSNaresh Kumar Inna fat = csio_handle_intr_status(hw, CIM_HOST_INT_CAUSE, 2802a3667aaeSNaresh Kumar Inna cim_intr_info) + 2803a3667aaeSNaresh Kumar Inna csio_handle_intr_status(hw, CIM_HOST_UPACC_INT_CAUSE, 2804a3667aaeSNaresh Kumar Inna cim_upintr_info); 2805a3667aaeSNaresh Kumar Inna if (fat) 2806a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 2807a3667aaeSNaresh Kumar Inna } 2808a3667aaeSNaresh Kumar Inna 2809a3667aaeSNaresh Kumar Inna /* 2810a3667aaeSNaresh Kumar Inna * ULP RX interrupt handler. 2811a3667aaeSNaresh Kumar Inna */ 2812a3667aaeSNaresh Kumar Inna static void csio_ulprx_intr_handler(struct csio_hw *hw) 2813a3667aaeSNaresh Kumar Inna { 2814a3667aaeSNaresh Kumar Inna static struct intr_info ulprx_intr_info[] = { 2815a3667aaeSNaresh Kumar Inna { 0x1800000, "ULPRX context error", -1, 1 }, 2816a3667aaeSNaresh Kumar Inna { 0x7fffff, "ULPRX parity error", -1, 1 }, 2817a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 2818a3667aaeSNaresh Kumar Inna }; 2819a3667aaeSNaresh Kumar Inna 2820a3667aaeSNaresh Kumar Inna if (csio_handle_intr_status(hw, ULP_RX_INT_CAUSE, ulprx_intr_info)) 2821a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 2822a3667aaeSNaresh Kumar Inna } 2823a3667aaeSNaresh Kumar Inna 2824a3667aaeSNaresh Kumar Inna /* 2825a3667aaeSNaresh Kumar Inna * ULP TX interrupt handler. 2826a3667aaeSNaresh Kumar Inna */ 2827a3667aaeSNaresh Kumar Inna static void csio_ulptx_intr_handler(struct csio_hw *hw) 2828a3667aaeSNaresh Kumar Inna { 2829a3667aaeSNaresh Kumar Inna static struct intr_info ulptx_intr_info[] = { 2830a3667aaeSNaresh Kumar Inna { PBL_BOUND_ERR_CH3, "ULPTX channel 3 PBL out of bounds", -1, 2831a3667aaeSNaresh Kumar Inna 0 }, 2832a3667aaeSNaresh Kumar Inna { PBL_BOUND_ERR_CH2, "ULPTX channel 2 PBL out of bounds", -1, 2833a3667aaeSNaresh Kumar Inna 0 }, 2834a3667aaeSNaresh Kumar Inna { PBL_BOUND_ERR_CH1, "ULPTX channel 1 PBL out of bounds", -1, 2835a3667aaeSNaresh Kumar Inna 0 }, 2836a3667aaeSNaresh Kumar Inna { PBL_BOUND_ERR_CH0, "ULPTX channel 0 PBL out of bounds", -1, 2837a3667aaeSNaresh Kumar Inna 0 }, 2838a3667aaeSNaresh Kumar Inna { 0xfffffff, "ULPTX parity error", -1, 1 }, 2839a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 2840a3667aaeSNaresh Kumar Inna }; 2841a3667aaeSNaresh Kumar Inna 2842a3667aaeSNaresh Kumar Inna if (csio_handle_intr_status(hw, ULP_TX_INT_CAUSE, ulptx_intr_info)) 2843a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 2844a3667aaeSNaresh Kumar Inna } 2845a3667aaeSNaresh Kumar Inna 2846a3667aaeSNaresh Kumar Inna /* 2847a3667aaeSNaresh Kumar Inna * PM TX interrupt handler. 2848a3667aaeSNaresh Kumar Inna */ 2849a3667aaeSNaresh Kumar Inna static void csio_pmtx_intr_handler(struct csio_hw *hw) 2850a3667aaeSNaresh Kumar Inna { 2851a3667aaeSNaresh Kumar Inna static struct intr_info pmtx_intr_info[] = { 2852a3667aaeSNaresh Kumar Inna { PCMD_LEN_OVFL0, "PMTX channel 0 pcmd too large", -1, 1 }, 2853a3667aaeSNaresh Kumar Inna { PCMD_LEN_OVFL1, "PMTX channel 1 pcmd too large", -1, 1 }, 2854a3667aaeSNaresh Kumar Inna { PCMD_LEN_OVFL2, "PMTX channel 2 pcmd too large", -1, 1 }, 2855a3667aaeSNaresh Kumar Inna { ZERO_C_CMD_ERROR, "PMTX 0-length pcmd", -1, 1 }, 2856a3667aaeSNaresh Kumar Inna { 0xffffff0, "PMTX framing error", -1, 1 }, 2857a3667aaeSNaresh Kumar Inna { OESPI_PAR_ERROR, "PMTX oespi parity error", -1, 1 }, 2858a3667aaeSNaresh Kumar Inna { DB_OPTIONS_PAR_ERROR, "PMTX db_options parity error", -1, 2859a3667aaeSNaresh Kumar Inna 1 }, 2860a3667aaeSNaresh Kumar Inna { ICSPI_PAR_ERROR, "PMTX icspi parity error", -1, 1 }, 2861a3667aaeSNaresh Kumar Inna { C_PCMD_PAR_ERROR, "PMTX c_pcmd parity error", -1, 1}, 2862a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 2863a3667aaeSNaresh Kumar Inna }; 2864a3667aaeSNaresh Kumar Inna 2865a3667aaeSNaresh Kumar Inna if (csio_handle_intr_status(hw, PM_TX_INT_CAUSE, pmtx_intr_info)) 2866a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 2867a3667aaeSNaresh Kumar Inna } 2868a3667aaeSNaresh Kumar Inna 2869a3667aaeSNaresh Kumar Inna /* 2870a3667aaeSNaresh Kumar Inna * PM RX interrupt handler. 2871a3667aaeSNaresh Kumar Inna */ 2872a3667aaeSNaresh Kumar Inna static void csio_pmrx_intr_handler(struct csio_hw *hw) 2873a3667aaeSNaresh Kumar Inna { 2874a3667aaeSNaresh Kumar Inna static struct intr_info pmrx_intr_info[] = { 2875a3667aaeSNaresh Kumar Inna { ZERO_E_CMD_ERROR, "PMRX 0-length pcmd", -1, 1 }, 2876a3667aaeSNaresh Kumar Inna { 0x3ffff0, "PMRX framing error", -1, 1 }, 2877a3667aaeSNaresh Kumar Inna { OCSPI_PAR_ERROR, "PMRX ocspi parity error", -1, 1 }, 2878a3667aaeSNaresh Kumar Inna { DB_OPTIONS_PAR_ERROR, "PMRX db_options parity error", -1, 2879a3667aaeSNaresh Kumar Inna 1 }, 2880a3667aaeSNaresh Kumar Inna { IESPI_PAR_ERROR, "PMRX iespi parity error", -1, 1 }, 2881a3667aaeSNaresh Kumar Inna { E_PCMD_PAR_ERROR, "PMRX e_pcmd parity error", -1, 1}, 2882a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 2883a3667aaeSNaresh Kumar Inna }; 2884a3667aaeSNaresh Kumar Inna 2885a3667aaeSNaresh Kumar Inna if (csio_handle_intr_status(hw, PM_RX_INT_CAUSE, pmrx_intr_info)) 2886a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 2887a3667aaeSNaresh Kumar Inna } 2888a3667aaeSNaresh Kumar Inna 2889a3667aaeSNaresh Kumar Inna /* 2890a3667aaeSNaresh Kumar Inna * CPL switch interrupt handler. 2891a3667aaeSNaresh Kumar Inna */ 2892a3667aaeSNaresh Kumar Inna static void csio_cplsw_intr_handler(struct csio_hw *hw) 2893a3667aaeSNaresh Kumar Inna { 2894a3667aaeSNaresh Kumar Inna static struct intr_info cplsw_intr_info[] = { 2895a3667aaeSNaresh Kumar Inna { CIM_OP_MAP_PERR, "CPLSW CIM op_map parity error", -1, 1 }, 2896a3667aaeSNaresh Kumar Inna { CIM_OVFL_ERROR, "CPLSW CIM overflow", -1, 1 }, 2897a3667aaeSNaresh Kumar Inna { TP_FRAMING_ERROR, "CPLSW TP framing error", -1, 1 }, 2898a3667aaeSNaresh Kumar Inna { SGE_FRAMING_ERROR, "CPLSW SGE framing error", -1, 1 }, 2899a3667aaeSNaresh Kumar Inna { CIM_FRAMING_ERROR, "CPLSW CIM framing error", -1, 1 }, 2900a3667aaeSNaresh Kumar Inna { ZERO_SWITCH_ERROR, "CPLSW no-switch error", -1, 1 }, 2901a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 2902a3667aaeSNaresh Kumar Inna }; 2903a3667aaeSNaresh Kumar Inna 2904a3667aaeSNaresh Kumar Inna if (csio_handle_intr_status(hw, CPL_INTR_CAUSE, cplsw_intr_info)) 2905a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 2906a3667aaeSNaresh Kumar Inna } 2907a3667aaeSNaresh Kumar Inna 2908a3667aaeSNaresh Kumar Inna /* 2909a3667aaeSNaresh Kumar Inna * LE interrupt handler. 2910a3667aaeSNaresh Kumar Inna */ 2911a3667aaeSNaresh Kumar Inna static void csio_le_intr_handler(struct csio_hw *hw) 2912a3667aaeSNaresh Kumar Inna { 2913a3667aaeSNaresh Kumar Inna static struct intr_info le_intr_info[] = { 2914a3667aaeSNaresh Kumar Inna { LIPMISS, "LE LIP miss", -1, 0 }, 2915a3667aaeSNaresh Kumar Inna { LIP0, "LE 0 LIP error", -1, 0 }, 2916a3667aaeSNaresh Kumar Inna { PARITYERR, "LE parity error", -1, 1 }, 2917a3667aaeSNaresh Kumar Inna { UNKNOWNCMD, "LE unknown command", -1, 1 }, 2918a3667aaeSNaresh Kumar Inna { REQQPARERR, "LE request queue parity error", -1, 1 }, 2919a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 2920a3667aaeSNaresh Kumar Inna }; 2921a3667aaeSNaresh Kumar Inna 2922a3667aaeSNaresh Kumar Inna if (csio_handle_intr_status(hw, LE_DB_INT_CAUSE, le_intr_info)) 2923a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 2924a3667aaeSNaresh Kumar Inna } 2925a3667aaeSNaresh Kumar Inna 2926a3667aaeSNaresh Kumar Inna /* 2927a3667aaeSNaresh Kumar Inna * MPS interrupt handler. 2928a3667aaeSNaresh Kumar Inna */ 2929a3667aaeSNaresh Kumar Inna static void csio_mps_intr_handler(struct csio_hw *hw) 2930a3667aaeSNaresh Kumar Inna { 2931a3667aaeSNaresh Kumar Inna static struct intr_info mps_rx_intr_info[] = { 2932a3667aaeSNaresh Kumar Inna { 0xffffff, "MPS Rx parity error", -1, 1 }, 2933a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 2934a3667aaeSNaresh Kumar Inna }; 2935a3667aaeSNaresh Kumar Inna static struct intr_info mps_tx_intr_info[] = { 2936a3667aaeSNaresh Kumar Inna { TPFIFO, "MPS Tx TP FIFO parity error", -1, 1 }, 2937a3667aaeSNaresh Kumar Inna { NCSIFIFO, "MPS Tx NC-SI FIFO parity error", -1, 1 }, 2938a3667aaeSNaresh Kumar Inna { TXDATAFIFO, "MPS Tx data FIFO parity error", -1, 1 }, 2939a3667aaeSNaresh Kumar Inna { TXDESCFIFO, "MPS Tx desc FIFO parity error", -1, 1 }, 2940a3667aaeSNaresh Kumar Inna { BUBBLE, "MPS Tx underflow", -1, 1 }, 2941a3667aaeSNaresh Kumar Inna { SECNTERR, "MPS Tx SOP/EOP error", -1, 1 }, 2942a3667aaeSNaresh Kumar Inna { FRMERR, "MPS Tx framing error", -1, 1 }, 2943a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 2944a3667aaeSNaresh Kumar Inna }; 2945a3667aaeSNaresh Kumar Inna static struct intr_info mps_trc_intr_info[] = { 2946a3667aaeSNaresh Kumar Inna { FILTMEM, "MPS TRC filter parity error", -1, 1 }, 2947a3667aaeSNaresh Kumar Inna { PKTFIFO, "MPS TRC packet FIFO parity error", -1, 1 }, 2948a3667aaeSNaresh Kumar Inna { MISCPERR, "MPS TRC misc parity error", -1, 1 }, 2949a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 2950a3667aaeSNaresh Kumar Inna }; 2951a3667aaeSNaresh Kumar Inna static struct intr_info mps_stat_sram_intr_info[] = { 2952a3667aaeSNaresh Kumar Inna { 0x1fffff, "MPS statistics SRAM parity error", -1, 1 }, 2953a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 2954a3667aaeSNaresh Kumar Inna }; 2955a3667aaeSNaresh Kumar Inna static struct intr_info mps_stat_tx_intr_info[] = { 2956a3667aaeSNaresh Kumar Inna { 0xfffff, "MPS statistics Tx FIFO parity error", -1, 1 }, 2957a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 2958a3667aaeSNaresh Kumar Inna }; 2959a3667aaeSNaresh Kumar Inna static struct intr_info mps_stat_rx_intr_info[] = { 2960a3667aaeSNaresh Kumar Inna { 0xffffff, "MPS statistics Rx FIFO parity error", -1, 1 }, 2961a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 2962a3667aaeSNaresh Kumar Inna }; 2963a3667aaeSNaresh Kumar Inna static struct intr_info mps_cls_intr_info[] = { 2964a3667aaeSNaresh Kumar Inna { MATCHSRAM, "MPS match SRAM parity error", -1, 1 }, 2965a3667aaeSNaresh Kumar Inna { MATCHTCAM, "MPS match TCAM parity error", -1, 1 }, 2966a3667aaeSNaresh Kumar Inna { HASHSRAM, "MPS hash SRAM parity error", -1, 1 }, 2967a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 2968a3667aaeSNaresh Kumar Inna }; 2969a3667aaeSNaresh Kumar Inna 2970a3667aaeSNaresh Kumar Inna int fat; 2971a3667aaeSNaresh Kumar Inna 2972a3667aaeSNaresh Kumar Inna fat = csio_handle_intr_status(hw, MPS_RX_PERR_INT_CAUSE, 2973a3667aaeSNaresh Kumar Inna mps_rx_intr_info) + 2974a3667aaeSNaresh Kumar Inna csio_handle_intr_status(hw, MPS_TX_INT_CAUSE, 2975a3667aaeSNaresh Kumar Inna mps_tx_intr_info) + 2976a3667aaeSNaresh Kumar Inna csio_handle_intr_status(hw, MPS_TRC_INT_CAUSE, 2977a3667aaeSNaresh Kumar Inna mps_trc_intr_info) + 2978a3667aaeSNaresh Kumar Inna csio_handle_intr_status(hw, MPS_STAT_PERR_INT_CAUSE_SRAM, 2979a3667aaeSNaresh Kumar Inna mps_stat_sram_intr_info) + 2980a3667aaeSNaresh Kumar Inna csio_handle_intr_status(hw, MPS_STAT_PERR_INT_CAUSE_TX_FIFO, 2981a3667aaeSNaresh Kumar Inna mps_stat_tx_intr_info) + 2982a3667aaeSNaresh Kumar Inna csio_handle_intr_status(hw, MPS_STAT_PERR_INT_CAUSE_RX_FIFO, 2983a3667aaeSNaresh Kumar Inna mps_stat_rx_intr_info) + 2984a3667aaeSNaresh Kumar Inna csio_handle_intr_status(hw, MPS_CLS_INT_CAUSE, 2985a3667aaeSNaresh Kumar Inna mps_cls_intr_info); 2986a3667aaeSNaresh Kumar Inna 2987a3667aaeSNaresh Kumar Inna csio_wr_reg32(hw, 0, MPS_INT_CAUSE); 2988a3667aaeSNaresh Kumar Inna csio_rd_reg32(hw, MPS_INT_CAUSE); /* flush */ 2989a3667aaeSNaresh Kumar Inna if (fat) 2990a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 2991a3667aaeSNaresh Kumar Inna } 2992a3667aaeSNaresh Kumar Inna 2993a3667aaeSNaresh Kumar Inna #define MEM_INT_MASK (PERR_INT_CAUSE | ECC_CE_INT_CAUSE | ECC_UE_INT_CAUSE) 2994a3667aaeSNaresh Kumar Inna 2995a3667aaeSNaresh Kumar Inna /* 2996a3667aaeSNaresh Kumar Inna * EDC/MC interrupt handler. 2997a3667aaeSNaresh Kumar Inna */ 2998a3667aaeSNaresh Kumar Inna static void csio_mem_intr_handler(struct csio_hw *hw, int idx) 2999a3667aaeSNaresh Kumar Inna { 3000a3667aaeSNaresh Kumar Inna static const char name[3][5] = { "EDC0", "EDC1", "MC" }; 3001a3667aaeSNaresh Kumar Inna 3002a3667aaeSNaresh Kumar Inna unsigned int addr, cnt_addr, v; 3003a3667aaeSNaresh Kumar Inna 3004a3667aaeSNaresh Kumar Inna if (idx <= MEM_EDC1) { 3005a3667aaeSNaresh Kumar Inna addr = EDC_REG(EDC_INT_CAUSE, idx); 3006a3667aaeSNaresh Kumar Inna cnt_addr = EDC_REG(EDC_ECC_STATUS, idx); 3007a3667aaeSNaresh Kumar Inna } else { 3008a3667aaeSNaresh Kumar Inna addr = MC_INT_CAUSE; 3009a3667aaeSNaresh Kumar Inna cnt_addr = MC_ECC_STATUS; 3010a3667aaeSNaresh Kumar Inna } 3011a3667aaeSNaresh Kumar Inna 3012a3667aaeSNaresh Kumar Inna v = csio_rd_reg32(hw, addr) & MEM_INT_MASK; 3013a3667aaeSNaresh Kumar Inna if (v & PERR_INT_CAUSE) 3014a3667aaeSNaresh Kumar Inna csio_fatal(hw, "%s FIFO parity error\n", name[idx]); 3015a3667aaeSNaresh Kumar Inna if (v & ECC_CE_INT_CAUSE) { 3016a3667aaeSNaresh Kumar Inna uint32_t cnt = ECC_CECNT_GET(csio_rd_reg32(hw, cnt_addr)); 3017a3667aaeSNaresh Kumar Inna 3018a3667aaeSNaresh Kumar Inna csio_wr_reg32(hw, ECC_CECNT_MASK, cnt_addr); 3019a3667aaeSNaresh Kumar Inna csio_warn(hw, "%u %s correctable ECC data error%s\n", 3020a3667aaeSNaresh Kumar Inna cnt, name[idx], cnt > 1 ? "s" : ""); 3021a3667aaeSNaresh Kumar Inna } 3022a3667aaeSNaresh Kumar Inna if (v & ECC_UE_INT_CAUSE) 3023a3667aaeSNaresh Kumar Inna csio_fatal(hw, "%s uncorrectable ECC data error\n", name[idx]); 3024a3667aaeSNaresh Kumar Inna 3025a3667aaeSNaresh Kumar Inna csio_wr_reg32(hw, v, addr); 3026a3667aaeSNaresh Kumar Inna if (v & (PERR_INT_CAUSE | ECC_UE_INT_CAUSE)) 3027a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 3028a3667aaeSNaresh Kumar Inna } 3029a3667aaeSNaresh Kumar Inna 3030a3667aaeSNaresh Kumar Inna /* 3031a3667aaeSNaresh Kumar Inna * MA interrupt handler. 3032a3667aaeSNaresh Kumar Inna */ 3033a3667aaeSNaresh Kumar Inna static void csio_ma_intr_handler(struct csio_hw *hw) 3034a3667aaeSNaresh Kumar Inna { 3035a3667aaeSNaresh Kumar Inna uint32_t v, status = csio_rd_reg32(hw, MA_INT_CAUSE); 3036a3667aaeSNaresh Kumar Inna 3037a3667aaeSNaresh Kumar Inna if (status & MEM_PERR_INT_CAUSE) 3038a3667aaeSNaresh Kumar Inna csio_fatal(hw, "MA parity error, parity status %#x\n", 3039a3667aaeSNaresh Kumar Inna csio_rd_reg32(hw, MA_PARITY_ERROR_STATUS)); 3040a3667aaeSNaresh Kumar Inna if (status & MEM_WRAP_INT_CAUSE) { 3041a3667aaeSNaresh Kumar Inna v = csio_rd_reg32(hw, MA_INT_WRAP_STATUS); 3042a3667aaeSNaresh Kumar Inna csio_fatal(hw, 3043a3667aaeSNaresh Kumar Inna "MA address wrap-around error by client %u to address %#x\n", 3044a3667aaeSNaresh Kumar Inna MEM_WRAP_CLIENT_NUM_GET(v), MEM_WRAP_ADDRESS_GET(v) << 4); 3045a3667aaeSNaresh Kumar Inna } 3046a3667aaeSNaresh Kumar Inna csio_wr_reg32(hw, status, MA_INT_CAUSE); 3047a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 3048a3667aaeSNaresh Kumar Inna } 3049a3667aaeSNaresh Kumar Inna 3050a3667aaeSNaresh Kumar Inna /* 3051a3667aaeSNaresh Kumar Inna * SMB interrupt handler. 3052a3667aaeSNaresh Kumar Inna */ 3053a3667aaeSNaresh Kumar Inna static void csio_smb_intr_handler(struct csio_hw *hw) 3054a3667aaeSNaresh Kumar Inna { 3055a3667aaeSNaresh Kumar Inna static struct intr_info smb_intr_info[] = { 3056a3667aaeSNaresh Kumar Inna { MSTTXFIFOPARINT, "SMB master Tx FIFO parity error", -1, 1 }, 3057a3667aaeSNaresh Kumar Inna { MSTRXFIFOPARINT, "SMB master Rx FIFO parity error", -1, 1 }, 3058a3667aaeSNaresh Kumar Inna { SLVFIFOPARINT, "SMB slave FIFO parity error", -1, 1 }, 3059a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3060a3667aaeSNaresh Kumar Inna }; 3061a3667aaeSNaresh Kumar Inna 3062a3667aaeSNaresh Kumar Inna if (csio_handle_intr_status(hw, SMB_INT_CAUSE, smb_intr_info)) 3063a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 3064a3667aaeSNaresh Kumar Inna } 3065a3667aaeSNaresh Kumar Inna 3066a3667aaeSNaresh Kumar Inna /* 3067a3667aaeSNaresh Kumar Inna * NC-SI interrupt handler. 3068a3667aaeSNaresh Kumar Inna */ 3069a3667aaeSNaresh Kumar Inna static void csio_ncsi_intr_handler(struct csio_hw *hw) 3070a3667aaeSNaresh Kumar Inna { 3071a3667aaeSNaresh Kumar Inna static struct intr_info ncsi_intr_info[] = { 3072a3667aaeSNaresh Kumar Inna { CIM_DM_PRTY_ERR, "NC-SI CIM parity error", -1, 1 }, 3073a3667aaeSNaresh Kumar Inna { MPS_DM_PRTY_ERR, "NC-SI MPS parity error", -1, 1 }, 3074a3667aaeSNaresh Kumar Inna { TXFIFO_PRTY_ERR, "NC-SI Tx FIFO parity error", -1, 1 }, 3075a3667aaeSNaresh Kumar Inna { RXFIFO_PRTY_ERR, "NC-SI Rx FIFO parity error", -1, 1 }, 3076a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3077a3667aaeSNaresh Kumar Inna }; 3078a3667aaeSNaresh Kumar Inna 3079a3667aaeSNaresh Kumar Inna if (csio_handle_intr_status(hw, NCSI_INT_CAUSE, ncsi_intr_info)) 3080a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 3081a3667aaeSNaresh Kumar Inna } 3082a3667aaeSNaresh Kumar Inna 3083a3667aaeSNaresh Kumar Inna /* 3084a3667aaeSNaresh Kumar Inna * XGMAC interrupt handler. 3085a3667aaeSNaresh Kumar Inna */ 3086a3667aaeSNaresh Kumar Inna static void csio_xgmac_intr_handler(struct csio_hw *hw, int port) 3087a3667aaeSNaresh Kumar Inna { 30887cc16380SArvind Bhushan uint32_t v = csio_rd_reg32(hw, CSIO_MAC_INT_CAUSE_REG(hw, port)); 3089a3667aaeSNaresh Kumar Inna 3090a3667aaeSNaresh Kumar Inna v &= TXFIFO_PRTY_ERR | RXFIFO_PRTY_ERR; 3091a3667aaeSNaresh Kumar Inna if (!v) 3092a3667aaeSNaresh Kumar Inna return; 3093a3667aaeSNaresh Kumar Inna 3094a3667aaeSNaresh Kumar Inna if (v & TXFIFO_PRTY_ERR) 3095a3667aaeSNaresh Kumar Inna csio_fatal(hw, "XGMAC %d Tx FIFO parity error\n", port); 3096a3667aaeSNaresh Kumar Inna if (v & RXFIFO_PRTY_ERR) 3097a3667aaeSNaresh Kumar Inna csio_fatal(hw, "XGMAC %d Rx FIFO parity error\n", port); 30987cc16380SArvind Bhushan csio_wr_reg32(hw, v, CSIO_MAC_INT_CAUSE_REG(hw, port)); 3099a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 3100a3667aaeSNaresh Kumar Inna } 3101a3667aaeSNaresh Kumar Inna 3102a3667aaeSNaresh Kumar Inna /* 3103a3667aaeSNaresh Kumar Inna * PL interrupt handler. 3104a3667aaeSNaresh Kumar Inna */ 3105a3667aaeSNaresh Kumar Inna static void csio_pl_intr_handler(struct csio_hw *hw) 3106a3667aaeSNaresh Kumar Inna { 3107a3667aaeSNaresh Kumar Inna static struct intr_info pl_intr_info[] = { 3108a3667aaeSNaresh Kumar Inna { FATALPERR, "T4 fatal parity error", -1, 1 }, 3109a3667aaeSNaresh Kumar Inna { PERRVFID, "PL VFID_MAP parity error", -1, 1 }, 3110a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3111a3667aaeSNaresh Kumar Inna }; 3112a3667aaeSNaresh Kumar Inna 3113a3667aaeSNaresh Kumar Inna if (csio_handle_intr_status(hw, PL_PL_INT_CAUSE, pl_intr_info)) 3114a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 3115a3667aaeSNaresh Kumar Inna } 3116a3667aaeSNaresh Kumar Inna 3117a3667aaeSNaresh Kumar Inna /* 3118a3667aaeSNaresh Kumar Inna * csio_hw_slow_intr_handler - control path interrupt handler 3119a3667aaeSNaresh Kumar Inna * @hw: HW module 3120a3667aaeSNaresh Kumar Inna * 3121a3667aaeSNaresh Kumar Inna * Interrupt handler for non-data global interrupt events, e.g., errors. 3122a3667aaeSNaresh Kumar Inna * The designation 'slow' is because it involves register reads, while 3123a3667aaeSNaresh Kumar Inna * data interrupts typically don't involve any MMIOs. 3124a3667aaeSNaresh Kumar Inna */ 3125a3667aaeSNaresh Kumar Inna int 3126a3667aaeSNaresh Kumar Inna csio_hw_slow_intr_handler(struct csio_hw *hw) 3127a3667aaeSNaresh Kumar Inna { 3128a3667aaeSNaresh Kumar Inna uint32_t cause = csio_rd_reg32(hw, PL_INT_CAUSE); 3129a3667aaeSNaresh Kumar Inna 3130a3667aaeSNaresh Kumar Inna if (!(cause & CSIO_GLBL_INTR_MASK)) { 3131a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_plint_unexp); 3132a3667aaeSNaresh Kumar Inna return 0; 3133a3667aaeSNaresh Kumar Inna } 3134a3667aaeSNaresh Kumar Inna 3135a3667aaeSNaresh Kumar Inna csio_dbg(hw, "Slow interrupt! cause: 0x%x\n", cause); 3136a3667aaeSNaresh Kumar Inna 3137a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_plint_cnt); 3138a3667aaeSNaresh Kumar Inna 3139a3667aaeSNaresh Kumar Inna if (cause & CIM) 3140a3667aaeSNaresh Kumar Inna csio_cim_intr_handler(hw); 3141a3667aaeSNaresh Kumar Inna 3142a3667aaeSNaresh Kumar Inna if (cause & MPS) 3143a3667aaeSNaresh Kumar Inna csio_mps_intr_handler(hw); 3144a3667aaeSNaresh Kumar Inna 3145a3667aaeSNaresh Kumar Inna if (cause & NCSI) 3146a3667aaeSNaresh Kumar Inna csio_ncsi_intr_handler(hw); 3147a3667aaeSNaresh Kumar Inna 3148a3667aaeSNaresh Kumar Inna if (cause & PL) 3149a3667aaeSNaresh Kumar Inna csio_pl_intr_handler(hw); 3150a3667aaeSNaresh Kumar Inna 3151a3667aaeSNaresh Kumar Inna if (cause & SMB) 3152a3667aaeSNaresh Kumar Inna csio_smb_intr_handler(hw); 3153a3667aaeSNaresh Kumar Inna 3154a3667aaeSNaresh Kumar Inna if (cause & XGMAC0) 3155a3667aaeSNaresh Kumar Inna csio_xgmac_intr_handler(hw, 0); 3156a3667aaeSNaresh Kumar Inna 3157a3667aaeSNaresh Kumar Inna if (cause & XGMAC1) 3158a3667aaeSNaresh Kumar Inna csio_xgmac_intr_handler(hw, 1); 3159a3667aaeSNaresh Kumar Inna 3160a3667aaeSNaresh Kumar Inna if (cause & XGMAC_KR0) 3161a3667aaeSNaresh Kumar Inna csio_xgmac_intr_handler(hw, 2); 3162a3667aaeSNaresh Kumar Inna 3163a3667aaeSNaresh Kumar Inna if (cause & XGMAC_KR1) 3164a3667aaeSNaresh Kumar Inna csio_xgmac_intr_handler(hw, 3); 3165a3667aaeSNaresh Kumar Inna 3166a3667aaeSNaresh Kumar Inna if (cause & PCIE) 31677cc16380SArvind Bhushan hw->chip_ops->chip_pcie_intr_handler(hw); 3168a3667aaeSNaresh Kumar Inna 3169a3667aaeSNaresh Kumar Inna if (cause & MC) 3170a3667aaeSNaresh Kumar Inna csio_mem_intr_handler(hw, MEM_MC); 3171a3667aaeSNaresh Kumar Inna 3172a3667aaeSNaresh Kumar Inna if (cause & EDC0) 3173a3667aaeSNaresh Kumar Inna csio_mem_intr_handler(hw, MEM_EDC0); 3174a3667aaeSNaresh Kumar Inna 3175a3667aaeSNaresh Kumar Inna if (cause & EDC1) 3176a3667aaeSNaresh Kumar Inna csio_mem_intr_handler(hw, MEM_EDC1); 3177a3667aaeSNaresh Kumar Inna 3178a3667aaeSNaresh Kumar Inna if (cause & LE) 3179a3667aaeSNaresh Kumar Inna csio_le_intr_handler(hw); 3180a3667aaeSNaresh Kumar Inna 3181a3667aaeSNaresh Kumar Inna if (cause & TP) 3182a3667aaeSNaresh Kumar Inna csio_tp_intr_handler(hw); 3183a3667aaeSNaresh Kumar Inna 3184a3667aaeSNaresh Kumar Inna if (cause & MA) 3185a3667aaeSNaresh Kumar Inna csio_ma_intr_handler(hw); 3186a3667aaeSNaresh Kumar Inna 3187a3667aaeSNaresh Kumar Inna if (cause & PM_TX) 3188a3667aaeSNaresh Kumar Inna csio_pmtx_intr_handler(hw); 3189a3667aaeSNaresh Kumar Inna 3190a3667aaeSNaresh Kumar Inna if (cause & PM_RX) 3191a3667aaeSNaresh Kumar Inna csio_pmrx_intr_handler(hw); 3192a3667aaeSNaresh Kumar Inna 3193a3667aaeSNaresh Kumar Inna if (cause & ULP_RX) 3194a3667aaeSNaresh Kumar Inna csio_ulprx_intr_handler(hw); 3195a3667aaeSNaresh Kumar Inna 3196a3667aaeSNaresh Kumar Inna if (cause & CPL_SWITCH) 3197a3667aaeSNaresh Kumar Inna csio_cplsw_intr_handler(hw); 3198a3667aaeSNaresh Kumar Inna 3199a3667aaeSNaresh Kumar Inna if (cause & SGE) 3200a3667aaeSNaresh Kumar Inna csio_sge_intr_handler(hw); 3201a3667aaeSNaresh Kumar Inna 3202a3667aaeSNaresh Kumar Inna if (cause & ULP_TX) 3203a3667aaeSNaresh Kumar Inna csio_ulptx_intr_handler(hw); 3204a3667aaeSNaresh Kumar Inna 3205a3667aaeSNaresh Kumar Inna /* Clear the interrupts just processed for which we are the master. */ 3206a3667aaeSNaresh Kumar Inna csio_wr_reg32(hw, cause & CSIO_GLBL_INTR_MASK, PL_INT_CAUSE); 3207a3667aaeSNaresh Kumar Inna csio_rd_reg32(hw, PL_INT_CAUSE); /* flush */ 3208a3667aaeSNaresh Kumar Inna 3209a3667aaeSNaresh Kumar Inna return 1; 3210a3667aaeSNaresh Kumar Inna } 3211a3667aaeSNaresh Kumar Inna 3212a3667aaeSNaresh Kumar Inna /***************************************************************************** 3213a3667aaeSNaresh Kumar Inna * HW <--> mailbox interfacing routines. 3214a3667aaeSNaresh Kumar Inna ****************************************************************************/ 3215a3667aaeSNaresh Kumar Inna /* 3216a3667aaeSNaresh Kumar Inna * csio_mberr_worker - Worker thread (dpc) for mailbox/error completions 3217a3667aaeSNaresh Kumar Inna * 3218a3667aaeSNaresh Kumar Inna * @data: Private data pointer. 3219a3667aaeSNaresh Kumar Inna * 3220a3667aaeSNaresh Kumar Inna * Called from worker thread context. 3221a3667aaeSNaresh Kumar Inna */ 3222a3667aaeSNaresh Kumar Inna static void 3223a3667aaeSNaresh Kumar Inna csio_mberr_worker(void *data) 3224a3667aaeSNaresh Kumar Inna { 3225a3667aaeSNaresh Kumar Inna struct csio_hw *hw = (struct csio_hw *)data; 3226a3667aaeSNaresh Kumar Inna struct csio_mbm *mbm = &hw->mbm; 3227a3667aaeSNaresh Kumar Inna LIST_HEAD(cbfn_q); 3228a3667aaeSNaresh Kumar Inna struct csio_mb *mbp_next; 3229a3667aaeSNaresh Kumar Inna int rv; 3230a3667aaeSNaresh Kumar Inna 3231a3667aaeSNaresh Kumar Inna del_timer_sync(&mbm->timer); 3232a3667aaeSNaresh Kumar Inna 3233a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 3234a3667aaeSNaresh Kumar Inna if (list_empty(&mbm->cbfn_q)) { 3235a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 3236a3667aaeSNaresh Kumar Inna return; 3237a3667aaeSNaresh Kumar Inna } 3238a3667aaeSNaresh Kumar Inna 3239a3667aaeSNaresh Kumar Inna list_splice_tail_init(&mbm->cbfn_q, &cbfn_q); 3240a3667aaeSNaresh Kumar Inna mbm->stats.n_cbfnq = 0; 3241a3667aaeSNaresh Kumar Inna 3242a3667aaeSNaresh Kumar Inna /* Try to start waiting mailboxes */ 3243a3667aaeSNaresh Kumar Inna if (!list_empty(&mbm->req_q)) { 3244a3667aaeSNaresh Kumar Inna mbp_next = list_first_entry(&mbm->req_q, struct csio_mb, list); 3245a3667aaeSNaresh Kumar Inna list_del_init(&mbp_next->list); 3246a3667aaeSNaresh Kumar Inna 3247a3667aaeSNaresh Kumar Inna rv = csio_mb_issue(hw, mbp_next); 3248a3667aaeSNaresh Kumar Inna if (rv != 0) 3249a3667aaeSNaresh Kumar Inna list_add_tail(&mbp_next->list, &mbm->req_q); 3250a3667aaeSNaresh Kumar Inna else 3251a3667aaeSNaresh Kumar Inna CSIO_DEC_STATS(mbm, n_activeq); 3252a3667aaeSNaresh Kumar Inna } 3253a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 3254a3667aaeSNaresh Kumar Inna 3255a3667aaeSNaresh Kumar Inna /* Now callback completions */ 3256a3667aaeSNaresh Kumar Inna csio_mb_completions(hw, &cbfn_q); 3257a3667aaeSNaresh Kumar Inna } 3258a3667aaeSNaresh Kumar Inna 3259a3667aaeSNaresh Kumar Inna /* 3260a3667aaeSNaresh Kumar Inna * csio_hw_mb_timer - Top-level Mailbox timeout handler. 3261a3667aaeSNaresh Kumar Inna * 3262a3667aaeSNaresh Kumar Inna * @data: private data pointer 3263a3667aaeSNaresh Kumar Inna * 3264a3667aaeSNaresh Kumar Inna **/ 3265a3667aaeSNaresh Kumar Inna static void 3266a3667aaeSNaresh Kumar Inna csio_hw_mb_timer(uintptr_t data) 3267a3667aaeSNaresh Kumar Inna { 3268a3667aaeSNaresh Kumar Inna struct csio_hw *hw = (struct csio_hw *)data; 3269a3667aaeSNaresh Kumar Inna struct csio_mb *mbp = NULL; 3270a3667aaeSNaresh Kumar Inna 3271a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 3272a3667aaeSNaresh Kumar Inna mbp = csio_mb_tmo_handler(hw); 3273a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 3274a3667aaeSNaresh Kumar Inna 3275a3667aaeSNaresh Kumar Inna /* Call back the function for the timed-out Mailbox */ 3276a3667aaeSNaresh Kumar Inna if (mbp) 3277a3667aaeSNaresh Kumar Inna mbp->mb_cbfn(hw, mbp); 3278a3667aaeSNaresh Kumar Inna 3279a3667aaeSNaresh Kumar Inna } 3280a3667aaeSNaresh Kumar Inna 3281a3667aaeSNaresh Kumar Inna /* 3282a3667aaeSNaresh Kumar Inna * csio_hw_mbm_cleanup - Cleanup Mailbox module. 3283a3667aaeSNaresh Kumar Inna * @hw: HW module 3284a3667aaeSNaresh Kumar Inna * 3285a3667aaeSNaresh Kumar Inna * Called with lock held, should exit with lock held. 3286a3667aaeSNaresh Kumar Inna * Cancels outstanding mailboxes (waiting, in-flight) and gathers them 3287a3667aaeSNaresh Kumar Inna * into a local queue. Drops lock and calls the completions. Holds 3288a3667aaeSNaresh Kumar Inna * lock and returns. 3289a3667aaeSNaresh Kumar Inna */ 3290a3667aaeSNaresh Kumar Inna static void 3291a3667aaeSNaresh Kumar Inna csio_hw_mbm_cleanup(struct csio_hw *hw) 3292a3667aaeSNaresh Kumar Inna { 3293a3667aaeSNaresh Kumar Inna LIST_HEAD(cbfn_q); 3294a3667aaeSNaresh Kumar Inna 3295a3667aaeSNaresh Kumar Inna csio_mb_cancel_all(hw, &cbfn_q); 3296a3667aaeSNaresh Kumar Inna 3297a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 3298a3667aaeSNaresh Kumar Inna csio_mb_completions(hw, &cbfn_q); 3299a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 3300a3667aaeSNaresh Kumar Inna } 3301a3667aaeSNaresh Kumar Inna 3302a3667aaeSNaresh Kumar Inna /***************************************************************************** 3303a3667aaeSNaresh Kumar Inna * Event handling 3304a3667aaeSNaresh Kumar Inna ****************************************************************************/ 3305a3667aaeSNaresh Kumar Inna int 3306a3667aaeSNaresh Kumar Inna csio_enqueue_evt(struct csio_hw *hw, enum csio_evt type, void *evt_msg, 3307a3667aaeSNaresh Kumar Inna uint16_t len) 3308a3667aaeSNaresh Kumar Inna { 3309a3667aaeSNaresh Kumar Inna struct csio_evt_msg *evt_entry = NULL; 3310a3667aaeSNaresh Kumar Inna 3311a3667aaeSNaresh Kumar Inna if (type >= CSIO_EVT_MAX) 3312a3667aaeSNaresh Kumar Inna return -EINVAL; 3313a3667aaeSNaresh Kumar Inna 3314a3667aaeSNaresh Kumar Inna if (len > CSIO_EVT_MSG_SIZE) 3315a3667aaeSNaresh Kumar Inna return -EINVAL; 3316a3667aaeSNaresh Kumar Inna 3317a3667aaeSNaresh Kumar Inna if (hw->flags & CSIO_HWF_FWEVT_STOP) 3318a3667aaeSNaresh Kumar Inna return -EINVAL; 3319a3667aaeSNaresh Kumar Inna 3320a3667aaeSNaresh Kumar Inna if (list_empty(&hw->evt_free_q)) { 3321a3667aaeSNaresh Kumar Inna csio_err(hw, "Failed to alloc evt entry, msg type %d len %d\n", 3322a3667aaeSNaresh Kumar Inna type, len); 3323a3667aaeSNaresh Kumar Inna return -ENOMEM; 3324a3667aaeSNaresh Kumar Inna } 3325a3667aaeSNaresh Kumar Inna 3326a3667aaeSNaresh Kumar Inna evt_entry = list_first_entry(&hw->evt_free_q, 3327a3667aaeSNaresh Kumar Inna struct csio_evt_msg, list); 3328a3667aaeSNaresh Kumar Inna list_del_init(&evt_entry->list); 3329a3667aaeSNaresh Kumar Inna 3330a3667aaeSNaresh Kumar Inna /* copy event msg and queue the event */ 3331a3667aaeSNaresh Kumar Inna evt_entry->type = type; 3332a3667aaeSNaresh Kumar Inna memcpy((void *)evt_entry->data, evt_msg, len); 3333a3667aaeSNaresh Kumar Inna list_add_tail(&evt_entry->list, &hw->evt_active_q); 3334a3667aaeSNaresh Kumar Inna 3335a3667aaeSNaresh Kumar Inna CSIO_DEC_STATS(hw, n_evt_freeq); 3336a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_activeq); 3337a3667aaeSNaresh Kumar Inna 3338a3667aaeSNaresh Kumar Inna return 0; 3339a3667aaeSNaresh Kumar Inna } 3340a3667aaeSNaresh Kumar Inna 3341a3667aaeSNaresh Kumar Inna static int 3342a3667aaeSNaresh Kumar Inna csio_enqueue_evt_lock(struct csio_hw *hw, enum csio_evt type, void *evt_msg, 3343a3667aaeSNaresh Kumar Inna uint16_t len, bool msg_sg) 3344a3667aaeSNaresh Kumar Inna { 3345a3667aaeSNaresh Kumar Inna struct csio_evt_msg *evt_entry = NULL; 3346a3667aaeSNaresh Kumar Inna struct csio_fl_dma_buf *fl_sg; 3347a3667aaeSNaresh Kumar Inna uint32_t off = 0; 3348a3667aaeSNaresh Kumar Inna unsigned long flags; 3349a3667aaeSNaresh Kumar Inna int n, ret = 0; 3350a3667aaeSNaresh Kumar Inna 3351a3667aaeSNaresh Kumar Inna if (type >= CSIO_EVT_MAX) 3352a3667aaeSNaresh Kumar Inna return -EINVAL; 3353a3667aaeSNaresh Kumar Inna 3354a3667aaeSNaresh Kumar Inna if (len > CSIO_EVT_MSG_SIZE) 3355a3667aaeSNaresh Kumar Inna return -EINVAL; 3356a3667aaeSNaresh Kumar Inna 3357a3667aaeSNaresh Kumar Inna spin_lock_irqsave(&hw->lock, flags); 3358a3667aaeSNaresh Kumar Inna if (hw->flags & CSIO_HWF_FWEVT_STOP) { 3359a3667aaeSNaresh Kumar Inna ret = -EINVAL; 3360a3667aaeSNaresh Kumar Inna goto out; 3361a3667aaeSNaresh Kumar Inna } 3362a3667aaeSNaresh Kumar Inna 3363a3667aaeSNaresh Kumar Inna if (list_empty(&hw->evt_free_q)) { 3364a3667aaeSNaresh Kumar Inna csio_err(hw, "Failed to alloc evt entry, msg type %d len %d\n", 3365a3667aaeSNaresh Kumar Inna type, len); 3366a3667aaeSNaresh Kumar Inna ret = -ENOMEM; 3367a3667aaeSNaresh Kumar Inna goto out; 3368a3667aaeSNaresh Kumar Inna } 3369a3667aaeSNaresh Kumar Inna 3370a3667aaeSNaresh Kumar Inna evt_entry = list_first_entry(&hw->evt_free_q, 3371a3667aaeSNaresh Kumar Inna struct csio_evt_msg, list); 3372a3667aaeSNaresh Kumar Inna list_del_init(&evt_entry->list); 3373a3667aaeSNaresh Kumar Inna 3374a3667aaeSNaresh Kumar Inna /* copy event msg and queue the event */ 3375a3667aaeSNaresh Kumar Inna evt_entry->type = type; 3376a3667aaeSNaresh Kumar Inna 3377a3667aaeSNaresh Kumar Inna /* If Payload in SG list*/ 3378a3667aaeSNaresh Kumar Inna if (msg_sg) { 3379a3667aaeSNaresh Kumar Inna fl_sg = (struct csio_fl_dma_buf *) evt_msg; 3380a3667aaeSNaresh Kumar Inna for (n = 0; (n < CSIO_MAX_FLBUF_PER_IQWR && off < len); n++) { 3381a3667aaeSNaresh Kumar Inna memcpy((void *)((uintptr_t)evt_entry->data + off), 3382a3667aaeSNaresh Kumar Inna fl_sg->flbufs[n].vaddr, 3383a3667aaeSNaresh Kumar Inna fl_sg->flbufs[n].len); 3384a3667aaeSNaresh Kumar Inna off += fl_sg->flbufs[n].len; 3385a3667aaeSNaresh Kumar Inna } 3386a3667aaeSNaresh Kumar Inna } else 3387a3667aaeSNaresh Kumar Inna memcpy((void *)evt_entry->data, evt_msg, len); 3388a3667aaeSNaresh Kumar Inna 3389a3667aaeSNaresh Kumar Inna list_add_tail(&evt_entry->list, &hw->evt_active_q); 3390a3667aaeSNaresh Kumar Inna CSIO_DEC_STATS(hw, n_evt_freeq); 3391a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_activeq); 3392a3667aaeSNaresh Kumar Inna out: 3393a3667aaeSNaresh Kumar Inna spin_unlock_irqrestore(&hw->lock, flags); 3394a3667aaeSNaresh Kumar Inna return ret; 3395a3667aaeSNaresh Kumar Inna } 3396a3667aaeSNaresh Kumar Inna 3397a3667aaeSNaresh Kumar Inna static void 3398a3667aaeSNaresh Kumar Inna csio_free_evt(struct csio_hw *hw, struct csio_evt_msg *evt_entry) 3399a3667aaeSNaresh Kumar Inna { 3400a3667aaeSNaresh Kumar Inna if (evt_entry) { 3401a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 3402a3667aaeSNaresh Kumar Inna list_del_init(&evt_entry->list); 3403a3667aaeSNaresh Kumar Inna list_add_tail(&evt_entry->list, &hw->evt_free_q); 3404a3667aaeSNaresh Kumar Inna CSIO_DEC_STATS(hw, n_evt_activeq); 3405a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_freeq); 3406a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 3407a3667aaeSNaresh Kumar Inna } 3408a3667aaeSNaresh Kumar Inna } 3409a3667aaeSNaresh Kumar Inna 3410a3667aaeSNaresh Kumar Inna void 3411a3667aaeSNaresh Kumar Inna csio_evtq_flush(struct csio_hw *hw) 3412a3667aaeSNaresh Kumar Inna { 3413a3667aaeSNaresh Kumar Inna uint32_t count; 3414a3667aaeSNaresh Kumar Inna count = 30; 3415a3667aaeSNaresh Kumar Inna while (hw->flags & CSIO_HWF_FWEVT_PENDING && count--) { 3416a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 3417a3667aaeSNaresh Kumar Inna msleep(2000); 3418a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 3419a3667aaeSNaresh Kumar Inna } 3420a3667aaeSNaresh Kumar Inna 3421a3667aaeSNaresh Kumar Inna CSIO_DB_ASSERT(!(hw->flags & CSIO_HWF_FWEVT_PENDING)); 3422a3667aaeSNaresh Kumar Inna } 3423a3667aaeSNaresh Kumar Inna 3424a3667aaeSNaresh Kumar Inna static void 3425a3667aaeSNaresh Kumar Inna csio_evtq_stop(struct csio_hw *hw) 3426a3667aaeSNaresh Kumar Inna { 3427a3667aaeSNaresh Kumar Inna hw->flags |= CSIO_HWF_FWEVT_STOP; 3428a3667aaeSNaresh Kumar Inna } 3429a3667aaeSNaresh Kumar Inna 3430a3667aaeSNaresh Kumar Inna static void 3431a3667aaeSNaresh Kumar Inna csio_evtq_start(struct csio_hw *hw) 3432a3667aaeSNaresh Kumar Inna { 3433a3667aaeSNaresh Kumar Inna hw->flags &= ~CSIO_HWF_FWEVT_STOP; 3434a3667aaeSNaresh Kumar Inna } 3435a3667aaeSNaresh Kumar Inna 3436a3667aaeSNaresh Kumar Inna static void 3437a3667aaeSNaresh Kumar Inna csio_evtq_cleanup(struct csio_hw *hw) 3438a3667aaeSNaresh Kumar Inna { 3439a3667aaeSNaresh Kumar Inna struct list_head *evt_entry, *next_entry; 3440a3667aaeSNaresh Kumar Inna 3441a3667aaeSNaresh Kumar Inna /* Release outstanding events from activeq to freeq*/ 3442a3667aaeSNaresh Kumar Inna if (!list_empty(&hw->evt_active_q)) 3443a3667aaeSNaresh Kumar Inna list_splice_tail_init(&hw->evt_active_q, &hw->evt_free_q); 3444a3667aaeSNaresh Kumar Inna 3445a3667aaeSNaresh Kumar Inna hw->stats.n_evt_activeq = 0; 3446a3667aaeSNaresh Kumar Inna hw->flags &= ~CSIO_HWF_FWEVT_PENDING; 3447a3667aaeSNaresh Kumar Inna 3448a3667aaeSNaresh Kumar Inna /* Freeup event entry */ 3449a3667aaeSNaresh Kumar Inna list_for_each_safe(evt_entry, next_entry, &hw->evt_free_q) { 3450a3667aaeSNaresh Kumar Inna kfree(evt_entry); 3451a3667aaeSNaresh Kumar Inna CSIO_DEC_STATS(hw, n_evt_freeq); 3452a3667aaeSNaresh Kumar Inna } 3453a3667aaeSNaresh Kumar Inna 3454a3667aaeSNaresh Kumar Inna hw->stats.n_evt_freeq = 0; 3455a3667aaeSNaresh Kumar Inna } 3456a3667aaeSNaresh Kumar Inna 3457a3667aaeSNaresh Kumar Inna 3458a3667aaeSNaresh Kumar Inna static void 3459a3667aaeSNaresh Kumar Inna csio_process_fwevtq_entry(struct csio_hw *hw, void *wr, uint32_t len, 3460a3667aaeSNaresh Kumar Inna struct csio_fl_dma_buf *flb, void *priv) 3461a3667aaeSNaresh Kumar Inna { 3462a3667aaeSNaresh Kumar Inna __u8 op; 3463a3667aaeSNaresh Kumar Inna void *msg = NULL; 3464a3667aaeSNaresh Kumar Inna uint32_t msg_len = 0; 3465a3667aaeSNaresh Kumar Inna bool msg_sg = 0; 3466a3667aaeSNaresh Kumar Inna 3467a3667aaeSNaresh Kumar Inna op = ((struct rss_header *) wr)->opcode; 3468a3667aaeSNaresh Kumar Inna if (op == CPL_FW6_PLD) { 3469a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_cpl_fw6_pld); 3470a3667aaeSNaresh Kumar Inna if (!flb || !flb->totlen) { 3471a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_cpl_unexp); 3472a3667aaeSNaresh Kumar Inna return; 3473a3667aaeSNaresh Kumar Inna } 3474a3667aaeSNaresh Kumar Inna 3475a3667aaeSNaresh Kumar Inna msg = (void *) flb; 3476a3667aaeSNaresh Kumar Inna msg_len = flb->totlen; 3477a3667aaeSNaresh Kumar Inna msg_sg = 1; 3478a3667aaeSNaresh Kumar Inna } else if (op == CPL_FW6_MSG || op == CPL_FW4_MSG) { 3479a3667aaeSNaresh Kumar Inna 3480a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_cpl_fw6_msg); 3481a3667aaeSNaresh Kumar Inna /* skip RSS header */ 3482a3667aaeSNaresh Kumar Inna msg = (void *)((uintptr_t)wr + sizeof(__be64)); 3483a3667aaeSNaresh Kumar Inna msg_len = (op == CPL_FW6_MSG) ? sizeof(struct cpl_fw6_msg) : 3484a3667aaeSNaresh Kumar Inna sizeof(struct cpl_fw4_msg); 3485a3667aaeSNaresh Kumar Inna } else { 3486a3667aaeSNaresh Kumar Inna csio_warn(hw, "unexpected CPL %#x on FW event queue\n", op); 3487a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_cpl_unexp); 3488a3667aaeSNaresh Kumar Inna return; 3489a3667aaeSNaresh Kumar Inna } 3490a3667aaeSNaresh Kumar Inna 3491a3667aaeSNaresh Kumar Inna /* 3492a3667aaeSNaresh Kumar Inna * Enqueue event to EventQ. Events processing happens 3493a3667aaeSNaresh Kumar Inna * in Event worker thread context 3494a3667aaeSNaresh Kumar Inna */ 3495a3667aaeSNaresh Kumar Inna if (csio_enqueue_evt_lock(hw, CSIO_EVT_FW, msg, 3496a3667aaeSNaresh Kumar Inna (uint16_t)msg_len, msg_sg)) 3497a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_drop); 3498a3667aaeSNaresh Kumar Inna } 3499a3667aaeSNaresh Kumar Inna 3500a3667aaeSNaresh Kumar Inna void 3501a3667aaeSNaresh Kumar Inna csio_evtq_worker(struct work_struct *work) 3502a3667aaeSNaresh Kumar Inna { 3503a3667aaeSNaresh Kumar Inna struct csio_hw *hw = container_of(work, struct csio_hw, evtq_work); 3504a3667aaeSNaresh Kumar Inna struct list_head *evt_entry, *next_entry; 3505a3667aaeSNaresh Kumar Inna LIST_HEAD(evt_q); 3506a3667aaeSNaresh Kumar Inna struct csio_evt_msg *evt_msg; 3507a3667aaeSNaresh Kumar Inna struct cpl_fw6_msg *msg; 3508a3667aaeSNaresh Kumar Inna struct csio_rnode *rn; 3509a3667aaeSNaresh Kumar Inna int rv = 0; 3510a3667aaeSNaresh Kumar Inna uint8_t evtq_stop = 0; 3511a3667aaeSNaresh Kumar Inna 3512a3667aaeSNaresh Kumar Inna csio_dbg(hw, "event worker thread active evts#%d\n", 3513a3667aaeSNaresh Kumar Inna hw->stats.n_evt_activeq); 3514a3667aaeSNaresh Kumar Inna 3515a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 3516a3667aaeSNaresh Kumar Inna while (!list_empty(&hw->evt_active_q)) { 3517a3667aaeSNaresh Kumar Inna list_splice_tail_init(&hw->evt_active_q, &evt_q); 3518a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 3519a3667aaeSNaresh Kumar Inna 3520a3667aaeSNaresh Kumar Inna list_for_each_safe(evt_entry, next_entry, &evt_q) { 3521a3667aaeSNaresh Kumar Inna evt_msg = (struct csio_evt_msg *) evt_entry; 3522a3667aaeSNaresh Kumar Inna 3523a3667aaeSNaresh Kumar Inna /* Drop events if queue is STOPPED */ 3524a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 3525a3667aaeSNaresh Kumar Inna if (hw->flags & CSIO_HWF_FWEVT_STOP) 3526a3667aaeSNaresh Kumar Inna evtq_stop = 1; 3527a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 3528a3667aaeSNaresh Kumar Inna if (evtq_stop) { 3529a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_drop); 3530a3667aaeSNaresh Kumar Inna goto free_evt; 3531a3667aaeSNaresh Kumar Inna } 3532a3667aaeSNaresh Kumar Inna 3533a3667aaeSNaresh Kumar Inna switch (evt_msg->type) { 3534a3667aaeSNaresh Kumar Inna case CSIO_EVT_FW: 3535a3667aaeSNaresh Kumar Inna msg = (struct cpl_fw6_msg *)(evt_msg->data); 3536a3667aaeSNaresh Kumar Inna 3537a3667aaeSNaresh Kumar Inna if ((msg->opcode == CPL_FW6_MSG || 3538a3667aaeSNaresh Kumar Inna msg->opcode == CPL_FW4_MSG) && 3539a3667aaeSNaresh Kumar Inna !msg->type) { 3540a3667aaeSNaresh Kumar Inna rv = csio_mb_fwevt_handler(hw, 3541a3667aaeSNaresh Kumar Inna msg->data); 3542a3667aaeSNaresh Kumar Inna if (!rv) 3543a3667aaeSNaresh Kumar Inna break; 3544a3667aaeSNaresh Kumar Inna /* Handle any remaining fw events */ 3545a3667aaeSNaresh Kumar Inna csio_fcoe_fwevt_handler(hw, 3546a3667aaeSNaresh Kumar Inna msg->opcode, msg->data); 3547a3667aaeSNaresh Kumar Inna } else if (msg->opcode == CPL_FW6_PLD) { 3548a3667aaeSNaresh Kumar Inna 3549a3667aaeSNaresh Kumar Inna csio_fcoe_fwevt_handler(hw, 3550a3667aaeSNaresh Kumar Inna msg->opcode, msg->data); 3551a3667aaeSNaresh Kumar Inna } else { 3552a3667aaeSNaresh Kumar Inna csio_warn(hw, 3553a3667aaeSNaresh Kumar Inna "Unhandled FW msg op %x type %x\n", 3554a3667aaeSNaresh Kumar Inna msg->opcode, msg->type); 3555a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_drop); 3556a3667aaeSNaresh Kumar Inna } 3557a3667aaeSNaresh Kumar Inna break; 3558a3667aaeSNaresh Kumar Inna 3559a3667aaeSNaresh Kumar Inna case CSIO_EVT_MBX: 3560a3667aaeSNaresh Kumar Inna csio_mberr_worker(hw); 3561a3667aaeSNaresh Kumar Inna break; 3562a3667aaeSNaresh Kumar Inna 3563a3667aaeSNaresh Kumar Inna case CSIO_EVT_DEV_LOSS: 3564a3667aaeSNaresh Kumar Inna memcpy(&rn, evt_msg->data, sizeof(rn)); 3565a3667aaeSNaresh Kumar Inna csio_rnode_devloss_handler(rn); 3566a3667aaeSNaresh Kumar Inna break; 3567a3667aaeSNaresh Kumar Inna 3568a3667aaeSNaresh Kumar Inna default: 3569a3667aaeSNaresh Kumar Inna csio_warn(hw, "Unhandled event %x on evtq\n", 3570a3667aaeSNaresh Kumar Inna evt_msg->type); 3571a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_unexp); 3572a3667aaeSNaresh Kumar Inna break; 3573a3667aaeSNaresh Kumar Inna } 3574a3667aaeSNaresh Kumar Inna free_evt: 3575a3667aaeSNaresh Kumar Inna csio_free_evt(hw, evt_msg); 3576a3667aaeSNaresh Kumar Inna } 3577a3667aaeSNaresh Kumar Inna 3578a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 3579a3667aaeSNaresh Kumar Inna } 3580a3667aaeSNaresh Kumar Inna hw->flags &= ~CSIO_HWF_FWEVT_PENDING; 3581a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 3582a3667aaeSNaresh Kumar Inna } 3583a3667aaeSNaresh Kumar Inna 3584a3667aaeSNaresh Kumar Inna int 3585a3667aaeSNaresh Kumar Inna csio_fwevtq_handler(struct csio_hw *hw) 3586a3667aaeSNaresh Kumar Inna { 3587a3667aaeSNaresh Kumar Inna int rv; 3588a3667aaeSNaresh Kumar Inna 3589a3667aaeSNaresh Kumar Inna if (csio_q_iqid(hw, hw->fwevt_iq_idx) == CSIO_MAX_QID) { 3590a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_int_stray); 3591a3667aaeSNaresh Kumar Inna return -EINVAL; 3592a3667aaeSNaresh Kumar Inna } 3593a3667aaeSNaresh Kumar Inna 3594a3667aaeSNaresh Kumar Inna rv = csio_wr_process_iq_idx(hw, hw->fwevt_iq_idx, 3595a3667aaeSNaresh Kumar Inna csio_process_fwevtq_entry, NULL); 3596a3667aaeSNaresh Kumar Inna return rv; 3597a3667aaeSNaresh Kumar Inna } 3598a3667aaeSNaresh Kumar Inna 3599a3667aaeSNaresh Kumar Inna /**************************************************************************** 3600a3667aaeSNaresh Kumar Inna * Entry points 3601a3667aaeSNaresh Kumar Inna ****************************************************************************/ 3602a3667aaeSNaresh Kumar Inna 3603a3667aaeSNaresh Kumar Inna /* Management module */ 3604a3667aaeSNaresh Kumar Inna /* 3605a3667aaeSNaresh Kumar Inna * csio_mgmt_req_lookup - Lookup the given IO req exist in Active Q. 3606a3667aaeSNaresh Kumar Inna * mgmt - mgmt module 3607a3667aaeSNaresh Kumar Inna * @io_req - io request 3608a3667aaeSNaresh Kumar Inna * 3609a3667aaeSNaresh Kumar Inna * Return - 0:if given IO Req exists in active Q. 3610a3667aaeSNaresh Kumar Inna * -EINVAL :if lookup fails. 3611a3667aaeSNaresh Kumar Inna */ 3612a3667aaeSNaresh Kumar Inna int 3613a3667aaeSNaresh Kumar Inna csio_mgmt_req_lookup(struct csio_mgmtm *mgmtm, struct csio_ioreq *io_req) 3614a3667aaeSNaresh Kumar Inna { 3615a3667aaeSNaresh Kumar Inna struct list_head *tmp; 3616a3667aaeSNaresh Kumar Inna 3617a3667aaeSNaresh Kumar Inna /* Lookup ioreq in the ACTIVEQ */ 3618a3667aaeSNaresh Kumar Inna list_for_each(tmp, &mgmtm->active_q) { 3619a3667aaeSNaresh Kumar Inna if (io_req == (struct csio_ioreq *)tmp) 3620a3667aaeSNaresh Kumar Inna return 0; 3621a3667aaeSNaresh Kumar Inna } 3622a3667aaeSNaresh Kumar Inna return -EINVAL; 3623a3667aaeSNaresh Kumar Inna } 3624a3667aaeSNaresh Kumar Inna 3625a3667aaeSNaresh Kumar Inna #define ECM_MIN_TMO 1000 /* Minimum timeout value for req */ 3626a3667aaeSNaresh Kumar Inna 3627a3667aaeSNaresh Kumar Inna /* 3628a3667aaeSNaresh Kumar Inna * csio_mgmts_tmo_handler - MGMT IO Timeout handler. 3629a3667aaeSNaresh Kumar Inna * @data - Event data. 3630a3667aaeSNaresh Kumar Inna * 3631a3667aaeSNaresh Kumar Inna * Return - none. 3632a3667aaeSNaresh Kumar Inna */ 3633a3667aaeSNaresh Kumar Inna static void 3634a3667aaeSNaresh Kumar Inna csio_mgmt_tmo_handler(uintptr_t data) 3635a3667aaeSNaresh Kumar Inna { 3636a3667aaeSNaresh Kumar Inna struct csio_mgmtm *mgmtm = (struct csio_mgmtm *) data; 3637a3667aaeSNaresh Kumar Inna struct list_head *tmp; 3638a3667aaeSNaresh Kumar Inna struct csio_ioreq *io_req; 3639a3667aaeSNaresh Kumar Inna 3640a3667aaeSNaresh Kumar Inna csio_dbg(mgmtm->hw, "Mgmt timer invoked!\n"); 3641a3667aaeSNaresh Kumar Inna 3642a3667aaeSNaresh Kumar Inna spin_lock_irq(&mgmtm->hw->lock); 3643a3667aaeSNaresh Kumar Inna 3644a3667aaeSNaresh Kumar Inna list_for_each(tmp, &mgmtm->active_q) { 3645a3667aaeSNaresh Kumar Inna io_req = (struct csio_ioreq *) tmp; 3646a3667aaeSNaresh Kumar Inna io_req->tmo -= min_t(uint32_t, io_req->tmo, ECM_MIN_TMO); 3647a3667aaeSNaresh Kumar Inna 3648a3667aaeSNaresh Kumar Inna if (!io_req->tmo) { 3649a3667aaeSNaresh Kumar Inna /* Dequeue the request from retry Q. */ 3650a3667aaeSNaresh Kumar Inna tmp = csio_list_prev(tmp); 3651a3667aaeSNaresh Kumar Inna list_del_init(&io_req->sm.sm_list); 3652a3667aaeSNaresh Kumar Inna if (io_req->io_cbfn) { 3653a3667aaeSNaresh Kumar Inna /* io_req will be freed by completion handler */ 3654a3667aaeSNaresh Kumar Inna io_req->wr_status = -ETIMEDOUT; 3655a3667aaeSNaresh Kumar Inna io_req->io_cbfn(mgmtm->hw, io_req); 3656a3667aaeSNaresh Kumar Inna } else { 3657a3667aaeSNaresh Kumar Inna CSIO_DB_ASSERT(0); 3658a3667aaeSNaresh Kumar Inna } 3659a3667aaeSNaresh Kumar Inna } 3660a3667aaeSNaresh Kumar Inna } 3661a3667aaeSNaresh Kumar Inna 3662a3667aaeSNaresh Kumar Inna /* If retry queue is not empty, re-arm timer */ 3663a3667aaeSNaresh Kumar Inna if (!list_empty(&mgmtm->active_q)) 3664a3667aaeSNaresh Kumar Inna mod_timer(&mgmtm->mgmt_timer, 3665a3667aaeSNaresh Kumar Inna jiffies + msecs_to_jiffies(ECM_MIN_TMO)); 3666a3667aaeSNaresh Kumar Inna spin_unlock_irq(&mgmtm->hw->lock); 3667a3667aaeSNaresh Kumar Inna } 3668a3667aaeSNaresh Kumar Inna 3669a3667aaeSNaresh Kumar Inna static void 3670a3667aaeSNaresh Kumar Inna csio_mgmtm_cleanup(struct csio_mgmtm *mgmtm) 3671a3667aaeSNaresh Kumar Inna { 3672a3667aaeSNaresh Kumar Inna struct csio_hw *hw = mgmtm->hw; 3673a3667aaeSNaresh Kumar Inna struct csio_ioreq *io_req; 3674a3667aaeSNaresh Kumar Inna struct list_head *tmp; 3675a3667aaeSNaresh Kumar Inna uint32_t count; 3676a3667aaeSNaresh Kumar Inna 3677a3667aaeSNaresh Kumar Inna count = 30; 3678a3667aaeSNaresh Kumar Inna /* Wait for all outstanding req to complete gracefully */ 3679a3667aaeSNaresh Kumar Inna while ((!list_empty(&mgmtm->active_q)) && count--) { 3680a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 3681a3667aaeSNaresh Kumar Inna msleep(2000); 3682a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 3683a3667aaeSNaresh Kumar Inna } 3684a3667aaeSNaresh Kumar Inna 3685a3667aaeSNaresh Kumar Inna /* release outstanding req from ACTIVEQ */ 3686a3667aaeSNaresh Kumar Inna list_for_each(tmp, &mgmtm->active_q) { 3687a3667aaeSNaresh Kumar Inna io_req = (struct csio_ioreq *) tmp; 3688a3667aaeSNaresh Kumar Inna tmp = csio_list_prev(tmp); 3689a3667aaeSNaresh Kumar Inna list_del_init(&io_req->sm.sm_list); 3690a3667aaeSNaresh Kumar Inna mgmtm->stats.n_active--; 3691a3667aaeSNaresh Kumar Inna if (io_req->io_cbfn) { 3692a3667aaeSNaresh Kumar Inna /* io_req will be freed by completion handler */ 3693a3667aaeSNaresh Kumar Inna io_req->wr_status = -ETIMEDOUT; 3694a3667aaeSNaresh Kumar Inna io_req->io_cbfn(mgmtm->hw, io_req); 3695a3667aaeSNaresh Kumar Inna } 3696a3667aaeSNaresh Kumar Inna } 3697a3667aaeSNaresh Kumar Inna } 3698a3667aaeSNaresh Kumar Inna 3699a3667aaeSNaresh Kumar Inna /* 3700a3667aaeSNaresh Kumar Inna * csio_mgmt_init - Mgmt module init entry point 3701a3667aaeSNaresh Kumar Inna * @mgmtsm - mgmt module 3702a3667aaeSNaresh Kumar Inna * @hw - HW module 3703a3667aaeSNaresh Kumar Inna * 3704a3667aaeSNaresh Kumar Inna * Initialize mgmt timer, resource wait queue, active queue, 3705a3667aaeSNaresh Kumar Inna * completion q. Allocate Egress and Ingress 3706a3667aaeSNaresh Kumar Inna * WR queues and save off the queue index returned by the WR 3707a3667aaeSNaresh Kumar Inna * module for future use. Allocate and save off mgmt reqs in the 3708a3667aaeSNaresh Kumar Inna * mgmt_req_freelist for future use. Make sure their SM is initialized 3709a3667aaeSNaresh Kumar Inna * to uninit state. 3710a3667aaeSNaresh Kumar Inna * Returns: 0 - on success 3711a3667aaeSNaresh Kumar Inna * -ENOMEM - on error. 3712a3667aaeSNaresh Kumar Inna */ 3713a3667aaeSNaresh Kumar Inna static int 3714a3667aaeSNaresh Kumar Inna csio_mgmtm_init(struct csio_mgmtm *mgmtm, struct csio_hw *hw) 3715a3667aaeSNaresh Kumar Inna { 3716a3667aaeSNaresh Kumar Inna struct timer_list *timer = &mgmtm->mgmt_timer; 3717a3667aaeSNaresh Kumar Inna 3718a3667aaeSNaresh Kumar Inna init_timer(timer); 3719a3667aaeSNaresh Kumar Inna timer->function = csio_mgmt_tmo_handler; 3720a3667aaeSNaresh Kumar Inna timer->data = (unsigned long)mgmtm; 3721a3667aaeSNaresh Kumar Inna 3722a3667aaeSNaresh Kumar Inna INIT_LIST_HEAD(&mgmtm->active_q); 3723a3667aaeSNaresh Kumar Inna INIT_LIST_HEAD(&mgmtm->cbfn_q); 3724a3667aaeSNaresh Kumar Inna 3725a3667aaeSNaresh Kumar Inna mgmtm->hw = hw; 3726a3667aaeSNaresh Kumar Inna /*mgmtm->iq_idx = hw->fwevt_iq_idx;*/ 3727a3667aaeSNaresh Kumar Inna 3728a3667aaeSNaresh Kumar Inna return 0; 3729a3667aaeSNaresh Kumar Inna } 3730a3667aaeSNaresh Kumar Inna 3731a3667aaeSNaresh Kumar Inna /* 3732a3667aaeSNaresh Kumar Inna * csio_mgmtm_exit - MGMT module exit entry point 3733a3667aaeSNaresh Kumar Inna * @mgmtsm - mgmt module 3734a3667aaeSNaresh Kumar Inna * 3735a3667aaeSNaresh Kumar Inna * This function called during MGMT module uninit. 3736a3667aaeSNaresh Kumar Inna * Stop timers, free ioreqs allocated. 3737a3667aaeSNaresh Kumar Inna * Returns: None 3738a3667aaeSNaresh Kumar Inna * 3739a3667aaeSNaresh Kumar Inna */ 3740a3667aaeSNaresh Kumar Inna static void 3741a3667aaeSNaresh Kumar Inna csio_mgmtm_exit(struct csio_mgmtm *mgmtm) 3742a3667aaeSNaresh Kumar Inna { 3743a3667aaeSNaresh Kumar Inna del_timer_sync(&mgmtm->mgmt_timer); 3744a3667aaeSNaresh Kumar Inna } 3745a3667aaeSNaresh Kumar Inna 3746a3667aaeSNaresh Kumar Inna 3747a3667aaeSNaresh Kumar Inna /** 3748a3667aaeSNaresh Kumar Inna * csio_hw_start - Kicks off the HW State machine 3749a3667aaeSNaresh Kumar Inna * @hw: Pointer to HW module. 3750a3667aaeSNaresh Kumar Inna * 3751a3667aaeSNaresh Kumar Inna * It is assumed that the initialization is a synchronous operation. 3752a3667aaeSNaresh Kumar Inna * So when we return afer posting the event, the HW SM should be in 3753a3667aaeSNaresh Kumar Inna * the ready state, if there were no errors during init. 3754a3667aaeSNaresh Kumar Inna */ 3755a3667aaeSNaresh Kumar Inna int 3756a3667aaeSNaresh Kumar Inna csio_hw_start(struct csio_hw *hw) 3757a3667aaeSNaresh Kumar Inna { 3758a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 3759a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_CFG); 3760a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 3761a3667aaeSNaresh Kumar Inna 3762a3667aaeSNaresh Kumar Inna if (csio_is_hw_ready(hw)) 3763a3667aaeSNaresh Kumar Inna return 0; 3764a3667aaeSNaresh Kumar Inna else 3765a3667aaeSNaresh Kumar Inna return -EINVAL; 3766a3667aaeSNaresh Kumar Inna } 3767a3667aaeSNaresh Kumar Inna 3768a3667aaeSNaresh Kumar Inna int 3769a3667aaeSNaresh Kumar Inna csio_hw_stop(struct csio_hw *hw) 3770a3667aaeSNaresh Kumar Inna { 3771a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_PCI_REMOVE); 3772a3667aaeSNaresh Kumar Inna 3773a3667aaeSNaresh Kumar Inna if (csio_is_hw_removing(hw)) 3774a3667aaeSNaresh Kumar Inna return 0; 3775a3667aaeSNaresh Kumar Inna else 3776a3667aaeSNaresh Kumar Inna return -EINVAL; 3777a3667aaeSNaresh Kumar Inna } 3778a3667aaeSNaresh Kumar Inna 3779a3667aaeSNaresh Kumar Inna /* Max reset retries */ 3780a3667aaeSNaresh Kumar Inna #define CSIO_MAX_RESET_RETRIES 3 3781a3667aaeSNaresh Kumar Inna 3782a3667aaeSNaresh Kumar Inna /** 3783a3667aaeSNaresh Kumar Inna * csio_hw_reset - Reset the hardware 3784a3667aaeSNaresh Kumar Inna * @hw: HW module. 3785a3667aaeSNaresh Kumar Inna * 3786a3667aaeSNaresh Kumar Inna * Caller should hold lock across this function. 3787a3667aaeSNaresh Kumar Inna */ 3788a3667aaeSNaresh Kumar Inna int 3789a3667aaeSNaresh Kumar Inna csio_hw_reset(struct csio_hw *hw) 3790a3667aaeSNaresh Kumar Inna { 3791a3667aaeSNaresh Kumar Inna if (!csio_is_hw_master(hw)) 3792a3667aaeSNaresh Kumar Inna return -EPERM; 3793a3667aaeSNaresh Kumar Inna 3794a3667aaeSNaresh Kumar Inna if (hw->rst_retries >= CSIO_MAX_RESET_RETRIES) { 3795a3667aaeSNaresh Kumar Inna csio_dbg(hw, "Max hw reset attempts reached.."); 3796a3667aaeSNaresh Kumar Inna return -EINVAL; 3797a3667aaeSNaresh Kumar Inna } 3798a3667aaeSNaresh Kumar Inna 3799a3667aaeSNaresh Kumar Inna hw->rst_retries++; 3800a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_HBA_RESET); 3801a3667aaeSNaresh Kumar Inna 3802a3667aaeSNaresh Kumar Inna if (csio_is_hw_ready(hw)) { 3803a3667aaeSNaresh Kumar Inna hw->rst_retries = 0; 3804a3667aaeSNaresh Kumar Inna hw->stats.n_reset_start = jiffies_to_msecs(jiffies); 3805a3667aaeSNaresh Kumar Inna return 0; 3806a3667aaeSNaresh Kumar Inna } else 3807a3667aaeSNaresh Kumar Inna return -EINVAL; 3808a3667aaeSNaresh Kumar Inna } 3809a3667aaeSNaresh Kumar Inna 3810a3667aaeSNaresh Kumar Inna /* 3811a3667aaeSNaresh Kumar Inna * csio_hw_get_device_id - Caches the Adapter's vendor & device id. 3812a3667aaeSNaresh Kumar Inna * @hw: HW module. 3813a3667aaeSNaresh Kumar Inna */ 3814a3667aaeSNaresh Kumar Inna static void 3815a3667aaeSNaresh Kumar Inna csio_hw_get_device_id(struct csio_hw *hw) 3816a3667aaeSNaresh Kumar Inna { 3817a3667aaeSNaresh Kumar Inna /* Is the adapter device id cached already ?*/ 3818a3667aaeSNaresh Kumar Inna if (csio_is_dev_id_cached(hw)) 3819a3667aaeSNaresh Kumar Inna return; 3820a3667aaeSNaresh Kumar Inna 3821a3667aaeSNaresh Kumar Inna /* Get the PCI vendor & device id */ 3822a3667aaeSNaresh Kumar Inna pci_read_config_word(hw->pdev, PCI_VENDOR_ID, 3823a3667aaeSNaresh Kumar Inna &hw->params.pci.vendor_id); 3824a3667aaeSNaresh Kumar Inna pci_read_config_word(hw->pdev, PCI_DEVICE_ID, 3825a3667aaeSNaresh Kumar Inna &hw->params.pci.device_id); 3826a3667aaeSNaresh Kumar Inna 3827a3667aaeSNaresh Kumar Inna csio_dev_id_cached(hw); 38287cc16380SArvind Bhushan hw->chip_id = (hw->params.pci.device_id & CSIO_HW_CHIP_MASK); 3829a3667aaeSNaresh Kumar Inna 3830a3667aaeSNaresh Kumar Inna } /* csio_hw_get_device_id */ 3831a3667aaeSNaresh Kumar Inna 3832a3667aaeSNaresh Kumar Inna /* 3833a3667aaeSNaresh Kumar Inna * csio_hw_set_description - Set the model, description of the hw. 3834a3667aaeSNaresh Kumar Inna * @hw: HW module. 3835a3667aaeSNaresh Kumar Inna * @ven_id: PCI Vendor ID 3836a3667aaeSNaresh Kumar Inna * @dev_id: PCI Device ID 3837a3667aaeSNaresh Kumar Inna */ 3838a3667aaeSNaresh Kumar Inna static void 3839a3667aaeSNaresh Kumar Inna csio_hw_set_description(struct csio_hw *hw, uint16_t ven_id, uint16_t dev_id) 3840a3667aaeSNaresh Kumar Inna { 3841a3667aaeSNaresh Kumar Inna uint32_t adap_type, prot_type; 3842a3667aaeSNaresh Kumar Inna 3843a3667aaeSNaresh Kumar Inna if (ven_id == CSIO_VENDOR_ID) { 3844a3667aaeSNaresh Kumar Inna prot_type = (dev_id & CSIO_ASIC_DEVID_PROTO_MASK); 3845a3667aaeSNaresh Kumar Inna adap_type = (dev_id & CSIO_ASIC_DEVID_TYPE_MASK); 3846a3667aaeSNaresh Kumar Inna 38477cc16380SArvind Bhushan if (prot_type == CSIO_T4_FCOE_ASIC) { 3848a3667aaeSNaresh Kumar Inna memcpy(hw->hw_ver, 38497cc16380SArvind Bhushan csio_t4_fcoe_adapters[adap_type].model_no, 16); 3850a3667aaeSNaresh Kumar Inna memcpy(hw->model_desc, 38517cc16380SArvind Bhushan csio_t4_fcoe_adapters[adap_type].description, 38527cc16380SArvind Bhushan 32); 38537cc16380SArvind Bhushan } else if (prot_type == CSIO_T5_FCOE_ASIC) { 38547cc16380SArvind Bhushan memcpy(hw->hw_ver, 38557cc16380SArvind Bhushan csio_t5_fcoe_adapters[adap_type].model_no, 16); 38567cc16380SArvind Bhushan memcpy(hw->model_desc, 38577cc16380SArvind Bhushan csio_t5_fcoe_adapters[adap_type].description, 38587cc16380SArvind Bhushan 32); 3859a3667aaeSNaresh Kumar Inna } else { 3860a3667aaeSNaresh Kumar Inna char tempName[32] = "Chelsio FCoE Controller"; 3861a3667aaeSNaresh Kumar Inna memcpy(hw->model_desc, tempName, 32); 3862a3667aaeSNaresh Kumar Inna } 3863a3667aaeSNaresh Kumar Inna } 3864a3667aaeSNaresh Kumar Inna } /* csio_hw_set_description */ 3865a3667aaeSNaresh Kumar Inna 3866a3667aaeSNaresh Kumar Inna /** 3867a3667aaeSNaresh Kumar Inna * csio_hw_init - Initialize HW module. 3868a3667aaeSNaresh Kumar Inna * @hw: Pointer to HW module. 3869a3667aaeSNaresh Kumar Inna * 3870a3667aaeSNaresh Kumar Inna * Initialize the members of the HW module. 3871a3667aaeSNaresh Kumar Inna */ 3872a3667aaeSNaresh Kumar Inna int 3873a3667aaeSNaresh Kumar Inna csio_hw_init(struct csio_hw *hw) 3874a3667aaeSNaresh Kumar Inna { 3875a3667aaeSNaresh Kumar Inna int rv = -EINVAL; 3876a3667aaeSNaresh Kumar Inna uint32_t i; 3877a3667aaeSNaresh Kumar Inna uint16_t ven_id, dev_id; 3878a3667aaeSNaresh Kumar Inna struct csio_evt_msg *evt_entry; 3879a3667aaeSNaresh Kumar Inna 3880a3667aaeSNaresh Kumar Inna INIT_LIST_HEAD(&hw->sm.sm_list); 3881a3667aaeSNaresh Kumar Inna csio_init_state(&hw->sm, csio_hws_uninit); 3882a3667aaeSNaresh Kumar Inna spin_lock_init(&hw->lock); 3883a3667aaeSNaresh Kumar Inna INIT_LIST_HEAD(&hw->sln_head); 3884a3667aaeSNaresh Kumar Inna 3885a3667aaeSNaresh Kumar Inna /* Get the PCI vendor & device id */ 3886a3667aaeSNaresh Kumar Inna csio_hw_get_device_id(hw); 3887a3667aaeSNaresh Kumar Inna 3888a3667aaeSNaresh Kumar Inna strcpy(hw->name, CSIO_HW_NAME); 3889a3667aaeSNaresh Kumar Inna 38907cc16380SArvind Bhushan /* Initialize the HW chip ops with T4/T5 specific ops */ 38917cc16380SArvind Bhushan hw->chip_ops = csio_is_t4(hw->chip_id) ? &t4_ops : &t5_ops; 38927cc16380SArvind Bhushan 3893a3667aaeSNaresh Kumar Inna /* Set the model & its description */ 3894a3667aaeSNaresh Kumar Inna 3895a3667aaeSNaresh Kumar Inna ven_id = hw->params.pci.vendor_id; 3896a3667aaeSNaresh Kumar Inna dev_id = hw->params.pci.device_id; 3897a3667aaeSNaresh Kumar Inna 3898a3667aaeSNaresh Kumar Inna csio_hw_set_description(hw, ven_id, dev_id); 3899a3667aaeSNaresh Kumar Inna 3900a3667aaeSNaresh Kumar Inna /* Initialize default log level */ 3901a3667aaeSNaresh Kumar Inna hw->params.log_level = (uint32_t) csio_dbg_level; 3902a3667aaeSNaresh Kumar Inna 3903a3667aaeSNaresh Kumar Inna csio_set_fwevt_intr_idx(hw, -1); 3904a3667aaeSNaresh Kumar Inna csio_set_nondata_intr_idx(hw, -1); 3905a3667aaeSNaresh Kumar Inna 3906a3667aaeSNaresh Kumar Inna /* Init all the modules: Mailbox, WorkRequest and Transport */ 3907a3667aaeSNaresh Kumar Inna if (csio_mbm_init(csio_hw_to_mbm(hw), hw, csio_hw_mb_timer)) 3908a3667aaeSNaresh Kumar Inna goto err; 3909a3667aaeSNaresh Kumar Inna 3910a3667aaeSNaresh Kumar Inna rv = csio_wrm_init(csio_hw_to_wrm(hw), hw); 3911a3667aaeSNaresh Kumar Inna if (rv) 3912a3667aaeSNaresh Kumar Inna goto err_mbm_exit; 3913a3667aaeSNaresh Kumar Inna 3914a3667aaeSNaresh Kumar Inna rv = csio_scsim_init(csio_hw_to_scsim(hw), hw); 3915a3667aaeSNaresh Kumar Inna if (rv) 3916a3667aaeSNaresh Kumar Inna goto err_wrm_exit; 3917a3667aaeSNaresh Kumar Inna 3918a3667aaeSNaresh Kumar Inna rv = csio_mgmtm_init(csio_hw_to_mgmtm(hw), hw); 3919a3667aaeSNaresh Kumar Inna if (rv) 3920a3667aaeSNaresh Kumar Inna goto err_scsim_exit; 3921a3667aaeSNaresh Kumar Inna /* Pre-allocate evtq and initialize them */ 3922a3667aaeSNaresh Kumar Inna INIT_LIST_HEAD(&hw->evt_active_q); 3923a3667aaeSNaresh Kumar Inna INIT_LIST_HEAD(&hw->evt_free_q); 3924a3667aaeSNaresh Kumar Inna for (i = 0; i < csio_evtq_sz; i++) { 3925a3667aaeSNaresh Kumar Inna 3926a3667aaeSNaresh Kumar Inna evt_entry = kzalloc(sizeof(struct csio_evt_msg), GFP_KERNEL); 3927a3667aaeSNaresh Kumar Inna if (!evt_entry) { 3928a3667aaeSNaresh Kumar Inna csio_err(hw, "Failed to initialize eventq"); 3929a3667aaeSNaresh Kumar Inna goto err_evtq_cleanup; 3930a3667aaeSNaresh Kumar Inna } 3931a3667aaeSNaresh Kumar Inna 3932a3667aaeSNaresh Kumar Inna list_add_tail(&evt_entry->list, &hw->evt_free_q); 3933a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_freeq); 3934a3667aaeSNaresh Kumar Inna } 3935a3667aaeSNaresh Kumar Inna 3936a3667aaeSNaresh Kumar Inna hw->dev_num = dev_num; 3937a3667aaeSNaresh Kumar Inna dev_num++; 3938a3667aaeSNaresh Kumar Inna 3939a3667aaeSNaresh Kumar Inna return 0; 3940a3667aaeSNaresh Kumar Inna 3941a3667aaeSNaresh Kumar Inna err_evtq_cleanup: 3942a3667aaeSNaresh Kumar Inna csio_evtq_cleanup(hw); 3943a3667aaeSNaresh Kumar Inna csio_mgmtm_exit(csio_hw_to_mgmtm(hw)); 3944a3667aaeSNaresh Kumar Inna err_scsim_exit: 3945a3667aaeSNaresh Kumar Inna csio_scsim_exit(csio_hw_to_scsim(hw)); 3946a3667aaeSNaresh Kumar Inna err_wrm_exit: 3947a3667aaeSNaresh Kumar Inna csio_wrm_exit(csio_hw_to_wrm(hw), hw); 3948a3667aaeSNaresh Kumar Inna err_mbm_exit: 3949a3667aaeSNaresh Kumar Inna csio_mbm_exit(csio_hw_to_mbm(hw)); 3950a3667aaeSNaresh Kumar Inna err: 3951a3667aaeSNaresh Kumar Inna return rv; 3952a3667aaeSNaresh Kumar Inna } 3953a3667aaeSNaresh Kumar Inna 3954a3667aaeSNaresh Kumar Inna /** 3955a3667aaeSNaresh Kumar Inna * csio_hw_exit - Un-initialize HW module. 3956a3667aaeSNaresh Kumar Inna * @hw: Pointer to HW module. 3957a3667aaeSNaresh Kumar Inna * 3958a3667aaeSNaresh Kumar Inna */ 3959a3667aaeSNaresh Kumar Inna void 3960a3667aaeSNaresh Kumar Inna csio_hw_exit(struct csio_hw *hw) 3961a3667aaeSNaresh Kumar Inna { 3962a3667aaeSNaresh Kumar Inna csio_evtq_cleanup(hw); 3963a3667aaeSNaresh Kumar Inna csio_mgmtm_exit(csio_hw_to_mgmtm(hw)); 3964a3667aaeSNaresh Kumar Inna csio_scsim_exit(csio_hw_to_scsim(hw)); 3965a3667aaeSNaresh Kumar Inna csio_wrm_exit(csio_hw_to_wrm(hw), hw); 3966a3667aaeSNaresh Kumar Inna csio_mbm_exit(csio_hw_to_mbm(hw)); 3967a3667aaeSNaresh Kumar Inna } 3968