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_dbg_level = 0xFEFF; 51a3667aaeSNaresh Kumar Inna unsigned int csio_port_mask = 0xf; 52a3667aaeSNaresh Kumar Inna 53a3667aaeSNaresh Kumar Inna /* Default FW event queue entries. */ 54a3667aaeSNaresh Kumar Inna static uint32_t csio_evtq_sz = CSIO_EVTQ_SIZE; 55a3667aaeSNaresh Kumar Inna 56a3667aaeSNaresh Kumar Inna /* Default MSI param level */ 57a3667aaeSNaresh Kumar Inna int csio_msi = 2; 58a3667aaeSNaresh Kumar Inna 59a3667aaeSNaresh Kumar Inna /* FCoE function instances */ 60a3667aaeSNaresh Kumar Inna static int dev_num; 61a3667aaeSNaresh Kumar Inna 62a3667aaeSNaresh Kumar Inna /* FCoE Adapter types & its description */ 637cc16380SArvind Bhushan static const struct csio_adap_desc csio_t4_fcoe_adapters[] = { 64a3667aaeSNaresh Kumar Inna {"T440-Dbg 10G", "Chelsio T440-Dbg 10G [FCoE]"}, 65a3667aaeSNaresh Kumar Inna {"T420-CR 10G", "Chelsio T420-CR 10G [FCoE]"}, 66a3667aaeSNaresh Kumar Inna {"T422-CR 10G/1G", "Chelsio T422-CR 10G/1G [FCoE]"}, 67a3667aaeSNaresh Kumar Inna {"T440-CR 10G", "Chelsio T440-CR 10G [FCoE]"}, 68a3667aaeSNaresh Kumar Inna {"T420-BCH 10G", "Chelsio T420-BCH 10G [FCoE]"}, 69a3667aaeSNaresh Kumar Inna {"T440-BCH 10G", "Chelsio T440-BCH 10G [FCoE]"}, 70a3667aaeSNaresh Kumar Inna {"T440-CH 10G", "Chelsio T440-CH 10G [FCoE]"}, 71a3667aaeSNaresh Kumar Inna {"T420-SO 10G", "Chelsio T420-SO 10G [FCoE]"}, 72a3667aaeSNaresh Kumar Inna {"T420-CX4 10G", "Chelsio T420-CX4 10G [FCoE]"}, 73a3667aaeSNaresh Kumar Inna {"T420-BT 10G", "Chelsio T420-BT 10G [FCoE]"}, 74a3667aaeSNaresh Kumar Inna {"T404-BT 1G", "Chelsio T404-BT 1G [FCoE]"}, 75a3667aaeSNaresh Kumar Inna {"B420-SR 10G", "Chelsio B420-SR 10G [FCoE]"}, 76a3667aaeSNaresh Kumar Inna {"B404-BT 1G", "Chelsio B404-BT 1G [FCoE]"}, 77a3667aaeSNaresh Kumar Inna {"T480-CR 10G", "Chelsio T480-CR 10G [FCoE]"}, 78a3667aaeSNaresh Kumar Inna {"T440-LP-CR 10G", "Chelsio T440-LP-CR 10G [FCoE]"}, 797cc16380SArvind Bhushan {"AMSTERDAM 10G", "Chelsio AMSTERDAM 10G [FCoE]"}, 807cc16380SArvind Bhushan {"HUAWEI T480 10G", "Chelsio HUAWEI T480 10G [FCoE]"}, 817cc16380SArvind Bhushan {"HUAWEI T440 10G", "Chelsio HUAWEI T440 10G [FCoE]"}, 827cc16380SArvind Bhushan {"HUAWEI STG 10G", "Chelsio HUAWEI STG 10G [FCoE]"}, 837cc16380SArvind Bhushan {"ACROMAG XAUI 10G", "Chelsio ACROMAG XAUI 10G [FCoE]"}, 847cc16380SArvind Bhushan {"ACROMAG SFP+ 10G", "Chelsio ACROMAG SFP+ 10G [FCoE]"}, 857cc16380SArvind Bhushan {"QUANTA SFP+ 10G", "Chelsio QUANTA SFP+ 10G [FCoE]"}, 867cc16380SArvind Bhushan {"HUAWEI 10Gbase-T", "Chelsio HUAWEI 10Gbase-T [FCoE]"}, 877cc16380SArvind Bhushan {"HUAWEI T4TOE 10G", "Chelsio HUAWEI T4TOE 10G [FCoE]"} 887cc16380SArvind Bhushan }; 897cc16380SArvind Bhushan 907cc16380SArvind Bhushan static const struct csio_adap_desc csio_t5_fcoe_adapters[] = { 917cc16380SArvind Bhushan {"T580-Dbg 10G", "Chelsio T580-Dbg 10G [FCoE]"}, 927cc16380SArvind Bhushan {"T520-CR 10G", "Chelsio T520-CR 10G [FCoE]"}, 937cc16380SArvind Bhushan {"T522-CR 10G/1G", "Chelsio T452-CR 10G/1G [FCoE]"}, 947cc16380SArvind Bhushan {"T540-CR 10G", "Chelsio T540-CR 10G [FCoE]"}, 957cc16380SArvind Bhushan {"T520-BCH 10G", "Chelsio T520-BCH 10G [FCoE]"}, 967cc16380SArvind Bhushan {"T540-BCH 10G", "Chelsio T540-BCH 10G [FCoE]"}, 977cc16380SArvind Bhushan {"T540-CH 10G", "Chelsio T540-CH 10G [FCoE]"}, 987cc16380SArvind Bhushan {"T520-SO 10G", "Chelsio T520-SO 10G [FCoE]"}, 997cc16380SArvind Bhushan {"T520-CX4 10G", "Chelsio T520-CX4 10G [FCoE]"}, 1007cc16380SArvind Bhushan {"T520-BT 10G", "Chelsio T520-BT 10G [FCoE]"}, 1017cc16380SArvind Bhushan {"T504-BT 1G", "Chelsio T504-BT 1G [FCoE]"}, 1027cc16380SArvind Bhushan {"B520-SR 10G", "Chelsio B520-SR 10G [FCoE]"}, 1037cc16380SArvind Bhushan {"B504-BT 1G", "Chelsio B504-BT 1G [FCoE]"}, 1047cc16380SArvind Bhushan {"T580-CR 10G", "Chelsio T580-CR 10G [FCoE]"}, 1057cc16380SArvind Bhushan {"T540-LP-CR 10G", "Chelsio T540-LP-CR 10G [FCoE]"}, 1067cc16380SArvind Bhushan {"AMSTERDAM 10G", "Chelsio AMSTERDAM 10G [FCoE]"}, 1077cc16380SArvind Bhushan {"T580-LP-CR 40G", "Chelsio T580-LP-CR 40G [FCoE]"}, 1087cc16380SArvind Bhushan {"T520-LL-CR 10G", "Chelsio T520-LL-CR 10G [FCoE]"}, 1097cc16380SArvind Bhushan {"T560-CR 40G", "Chelsio T560-CR 40G [FCoE]"}, 1107cc16380SArvind Bhushan {"T580-CR 40G", "Chelsio T580-CR 40G [FCoE]"} 111a3667aaeSNaresh Kumar Inna }; 112a3667aaeSNaresh Kumar Inna 113a3667aaeSNaresh Kumar Inna static void csio_mgmtm_cleanup(struct csio_mgmtm *); 114a3667aaeSNaresh Kumar Inna static void csio_hw_mbm_cleanup(struct csio_hw *); 115a3667aaeSNaresh Kumar Inna 116a3667aaeSNaresh Kumar Inna /* State machine forward declarations */ 117a3667aaeSNaresh Kumar Inna static void csio_hws_uninit(struct csio_hw *, enum csio_hw_ev); 118a3667aaeSNaresh Kumar Inna static void csio_hws_configuring(struct csio_hw *, enum csio_hw_ev); 119a3667aaeSNaresh Kumar Inna static void csio_hws_initializing(struct csio_hw *, enum csio_hw_ev); 120a3667aaeSNaresh Kumar Inna static void csio_hws_ready(struct csio_hw *, enum csio_hw_ev); 121a3667aaeSNaresh Kumar Inna static void csio_hws_quiescing(struct csio_hw *, enum csio_hw_ev); 122a3667aaeSNaresh Kumar Inna static void csio_hws_quiesced(struct csio_hw *, enum csio_hw_ev); 123a3667aaeSNaresh Kumar Inna static void csio_hws_resetting(struct csio_hw *, enum csio_hw_ev); 124a3667aaeSNaresh Kumar Inna static void csio_hws_removing(struct csio_hw *, enum csio_hw_ev); 125a3667aaeSNaresh Kumar Inna static void csio_hws_pcierr(struct csio_hw *, enum csio_hw_ev); 126a3667aaeSNaresh Kumar Inna 127a3667aaeSNaresh Kumar Inna static void csio_hw_initialize(struct csio_hw *hw); 128a3667aaeSNaresh Kumar Inna static void csio_evtq_stop(struct csio_hw *hw); 129a3667aaeSNaresh Kumar Inna static void csio_evtq_start(struct csio_hw *hw); 130a3667aaeSNaresh Kumar Inna 131a3667aaeSNaresh Kumar Inna int csio_is_hw_ready(struct csio_hw *hw) 132a3667aaeSNaresh Kumar Inna { 133a3667aaeSNaresh Kumar Inna return csio_match_state(hw, csio_hws_ready); 134a3667aaeSNaresh Kumar Inna } 135a3667aaeSNaresh Kumar Inna 136a3667aaeSNaresh Kumar Inna int csio_is_hw_removing(struct csio_hw *hw) 137a3667aaeSNaresh Kumar Inna { 138a3667aaeSNaresh Kumar Inna return csio_match_state(hw, csio_hws_removing); 139a3667aaeSNaresh Kumar Inna } 140a3667aaeSNaresh Kumar Inna 141a3667aaeSNaresh Kumar Inna 142a3667aaeSNaresh Kumar Inna /* 143a3667aaeSNaresh Kumar Inna * csio_hw_wait_op_done_val - wait until an operation is completed 144a3667aaeSNaresh Kumar Inna * @hw: the HW module 145a3667aaeSNaresh Kumar Inna * @reg: the register to check for completion 146a3667aaeSNaresh Kumar Inna * @mask: a single-bit field within @reg that indicates completion 147a3667aaeSNaresh Kumar Inna * @polarity: the value of the field when the operation is completed 148a3667aaeSNaresh Kumar Inna * @attempts: number of check iterations 149a3667aaeSNaresh Kumar Inna * @delay: delay in usecs between iterations 150a3667aaeSNaresh Kumar Inna * @valp: where to store the value of the register at completion time 151a3667aaeSNaresh Kumar Inna * 152a3667aaeSNaresh Kumar Inna * Wait until an operation is completed by checking a bit in a register 153a3667aaeSNaresh Kumar Inna * up to @attempts times. If @valp is not NULL the value of the register 154a3667aaeSNaresh Kumar Inna * at the time it indicated completion is stored there. Returns 0 if the 155a3667aaeSNaresh Kumar Inna * operation completes and -EAGAIN otherwise. 156a3667aaeSNaresh Kumar Inna */ 1577cc16380SArvind Bhushan int 158a3667aaeSNaresh Kumar Inna csio_hw_wait_op_done_val(struct csio_hw *hw, int reg, uint32_t mask, 159a3667aaeSNaresh Kumar Inna int polarity, int attempts, int delay, uint32_t *valp) 160a3667aaeSNaresh Kumar Inna { 161a3667aaeSNaresh Kumar Inna uint32_t val; 162a3667aaeSNaresh Kumar Inna while (1) { 163a3667aaeSNaresh Kumar Inna val = csio_rd_reg32(hw, reg); 164a3667aaeSNaresh Kumar Inna 165a3667aaeSNaresh Kumar Inna if (!!(val & mask) == polarity) { 166a3667aaeSNaresh Kumar Inna if (valp) 167a3667aaeSNaresh Kumar Inna *valp = val; 168a3667aaeSNaresh Kumar Inna return 0; 169a3667aaeSNaresh Kumar Inna } 170a3667aaeSNaresh Kumar Inna 171a3667aaeSNaresh Kumar Inna if (--attempts == 0) 172a3667aaeSNaresh Kumar Inna return -EAGAIN; 173a3667aaeSNaresh Kumar Inna if (delay) 174a3667aaeSNaresh Kumar Inna udelay(delay); 175a3667aaeSNaresh Kumar Inna } 176a3667aaeSNaresh Kumar Inna } 177a3667aaeSNaresh Kumar Inna 1787cc16380SArvind Bhushan /* 1797cc16380SArvind Bhushan * csio_hw_tp_wr_bits_indirect - set/clear bits in an indirect TP register 1807cc16380SArvind Bhushan * @hw: the adapter 1817cc16380SArvind Bhushan * @addr: the indirect TP register address 1827cc16380SArvind Bhushan * @mask: specifies the field within the register to modify 1837cc16380SArvind Bhushan * @val: new value for the field 1847cc16380SArvind Bhushan * 1857cc16380SArvind Bhushan * Sets a field of an indirect TP register to the given value. 1867cc16380SArvind Bhushan */ 1877cc16380SArvind Bhushan void 1887cc16380SArvind Bhushan csio_hw_tp_wr_bits_indirect(struct csio_hw *hw, unsigned int addr, 1897cc16380SArvind Bhushan unsigned int mask, unsigned int val) 1907cc16380SArvind Bhushan { 191837e4a42SHariprasad Shenai csio_wr_reg32(hw, addr, TP_PIO_ADDR_A); 192837e4a42SHariprasad Shenai val |= csio_rd_reg32(hw, TP_PIO_DATA_A) & ~mask; 193837e4a42SHariprasad Shenai csio_wr_reg32(hw, val, TP_PIO_DATA_A); 1947cc16380SArvind Bhushan } 1957cc16380SArvind Bhushan 196a3667aaeSNaresh Kumar Inna void 197a3667aaeSNaresh Kumar Inna csio_set_reg_field(struct csio_hw *hw, uint32_t reg, uint32_t mask, 198a3667aaeSNaresh Kumar Inna uint32_t value) 199a3667aaeSNaresh Kumar Inna { 200a3667aaeSNaresh Kumar Inna uint32_t val = csio_rd_reg32(hw, reg) & ~mask; 201a3667aaeSNaresh Kumar Inna 202a3667aaeSNaresh Kumar Inna csio_wr_reg32(hw, val | value, reg); 203a3667aaeSNaresh Kumar Inna /* Flush */ 204a3667aaeSNaresh Kumar Inna csio_rd_reg32(hw, reg); 205a3667aaeSNaresh Kumar Inna 206a3667aaeSNaresh Kumar Inna } 207a3667aaeSNaresh Kumar Inna 208a3667aaeSNaresh Kumar Inna static int 2095036f0a0SNaresh Kumar Inna csio_memory_write(struct csio_hw *hw, int mtype, u32 addr, u32 len, u32 *buf) 210a3667aaeSNaresh Kumar Inna { 2117cc16380SArvind Bhushan return hw->chip_ops->chip_memory_rw(hw, MEMWIN_CSIOSTOR, mtype, 2127cc16380SArvind Bhushan addr, len, buf, 0); 213a3667aaeSNaresh Kumar Inna } 214a3667aaeSNaresh Kumar Inna 215a3667aaeSNaresh Kumar Inna /* 216a3667aaeSNaresh Kumar Inna * EEPROM reads take a few tens of us while writes can take a bit over 5 ms. 217a3667aaeSNaresh Kumar Inna */ 218a3667aaeSNaresh Kumar Inna #define EEPROM_MAX_RD_POLL 40 219a3667aaeSNaresh Kumar Inna #define EEPROM_MAX_WR_POLL 6 220a3667aaeSNaresh Kumar Inna #define EEPROM_STAT_ADDR 0x7bfc 221a3667aaeSNaresh Kumar Inna #define VPD_BASE 0x400 222a3667aaeSNaresh Kumar Inna #define VPD_BASE_OLD 0 2237cc16380SArvind Bhushan #define VPD_LEN 1024 224a3667aaeSNaresh Kumar Inna #define VPD_INFO_FLD_HDR_SIZE 3 225a3667aaeSNaresh Kumar Inna 226a3667aaeSNaresh Kumar Inna /* 227a3667aaeSNaresh Kumar Inna * csio_hw_seeprom_read - read a serial EEPROM location 228a3667aaeSNaresh Kumar Inna * @hw: hw to read 229a3667aaeSNaresh Kumar Inna * @addr: EEPROM virtual address 230a3667aaeSNaresh Kumar Inna * @data: where to store the read data 231a3667aaeSNaresh Kumar Inna * 232a3667aaeSNaresh Kumar Inna * Read a 32-bit word from a location in serial EEPROM using the card's PCI 233a3667aaeSNaresh Kumar Inna * VPD capability. Note that this function must be called with a virtual 234a3667aaeSNaresh Kumar Inna * address. 235a3667aaeSNaresh Kumar Inna */ 236a3667aaeSNaresh Kumar Inna static int 237a3667aaeSNaresh Kumar Inna csio_hw_seeprom_read(struct csio_hw *hw, uint32_t addr, uint32_t *data) 238a3667aaeSNaresh Kumar Inna { 239a3667aaeSNaresh Kumar Inna uint16_t val = 0; 240a3667aaeSNaresh Kumar Inna int attempts = EEPROM_MAX_RD_POLL; 241a3667aaeSNaresh Kumar Inna uint32_t base = hw->params.pci.vpd_cap_addr; 242a3667aaeSNaresh Kumar Inna 243a3667aaeSNaresh Kumar Inna if (addr >= EEPROMVSIZE || (addr & 3)) 244a3667aaeSNaresh Kumar Inna return -EINVAL; 245a3667aaeSNaresh Kumar Inna 246a3667aaeSNaresh Kumar Inna pci_write_config_word(hw->pdev, base + PCI_VPD_ADDR, (uint16_t)addr); 247a3667aaeSNaresh Kumar Inna 248a3667aaeSNaresh Kumar Inna do { 249a3667aaeSNaresh Kumar Inna udelay(10); 250a3667aaeSNaresh Kumar Inna pci_read_config_word(hw->pdev, base + PCI_VPD_ADDR, &val); 251a3667aaeSNaresh Kumar Inna } while (!(val & PCI_VPD_ADDR_F) && --attempts); 252a3667aaeSNaresh Kumar Inna 253a3667aaeSNaresh Kumar Inna if (!(val & PCI_VPD_ADDR_F)) { 254a3667aaeSNaresh Kumar Inna csio_err(hw, "reading EEPROM address 0x%x failed\n", addr); 255a3667aaeSNaresh Kumar Inna return -EINVAL; 256a3667aaeSNaresh Kumar Inna } 257a3667aaeSNaresh Kumar Inna 258a3667aaeSNaresh Kumar Inna pci_read_config_dword(hw->pdev, base + PCI_VPD_DATA, data); 259*78890ed7SPraveen Madhavan *data = le32_to_cpu(*(__le32 *)data); 2605036f0a0SNaresh Kumar Inna 261a3667aaeSNaresh Kumar Inna return 0; 262a3667aaeSNaresh Kumar Inna } 263a3667aaeSNaresh Kumar Inna 264a3667aaeSNaresh Kumar Inna /* 265a3667aaeSNaresh Kumar Inna * Partial EEPROM Vital Product Data structure. Includes only the ID and 266a3667aaeSNaresh Kumar Inna * VPD-R sections. 267a3667aaeSNaresh Kumar Inna */ 268a3667aaeSNaresh Kumar Inna struct t4_vpd_hdr { 269a3667aaeSNaresh Kumar Inna u8 id_tag; 270a3667aaeSNaresh Kumar Inna u8 id_len[2]; 271a3667aaeSNaresh Kumar Inna u8 id_data[ID_LEN]; 272a3667aaeSNaresh Kumar Inna u8 vpdr_tag; 273a3667aaeSNaresh Kumar Inna u8 vpdr_len[2]; 274a3667aaeSNaresh Kumar Inna }; 275a3667aaeSNaresh Kumar Inna 276a3667aaeSNaresh Kumar Inna /* 277a3667aaeSNaresh Kumar Inna * csio_hw_get_vpd_keyword_val - Locates an information field keyword in 278a3667aaeSNaresh Kumar Inna * the VPD 279a3667aaeSNaresh Kumar Inna * @v: Pointer to buffered vpd data structure 280a3667aaeSNaresh Kumar Inna * @kw: The keyword to search for 281a3667aaeSNaresh Kumar Inna * 282a3667aaeSNaresh Kumar Inna * Returns the value of the information field keyword or 283a3667aaeSNaresh Kumar Inna * -EINVAL otherwise. 284a3667aaeSNaresh Kumar Inna */ 285a3667aaeSNaresh Kumar Inna static int 286a3667aaeSNaresh Kumar Inna csio_hw_get_vpd_keyword_val(const struct t4_vpd_hdr *v, const char *kw) 287a3667aaeSNaresh Kumar Inna { 288a3667aaeSNaresh Kumar Inna int32_t i; 289a3667aaeSNaresh Kumar Inna int32_t offset , len; 290a3667aaeSNaresh Kumar Inna const uint8_t *buf = &v->id_tag; 291a3667aaeSNaresh Kumar Inna const uint8_t *vpdr_len = &v->vpdr_tag; 292a3667aaeSNaresh Kumar Inna offset = sizeof(struct t4_vpd_hdr); 293a3667aaeSNaresh Kumar Inna len = (uint16_t)vpdr_len[1] + ((uint16_t)vpdr_len[2] << 8); 294a3667aaeSNaresh Kumar Inna 295a3667aaeSNaresh Kumar Inna if (len + sizeof(struct t4_vpd_hdr) > VPD_LEN) 296a3667aaeSNaresh Kumar Inna return -EINVAL; 297a3667aaeSNaresh Kumar Inna 298a3667aaeSNaresh Kumar Inna for (i = offset; (i + VPD_INFO_FLD_HDR_SIZE) <= (offset + len);) { 299a3667aaeSNaresh Kumar Inna if (memcmp(buf + i , kw, 2) == 0) { 300a3667aaeSNaresh Kumar Inna i += VPD_INFO_FLD_HDR_SIZE; 301a3667aaeSNaresh Kumar Inna return i; 302a3667aaeSNaresh Kumar Inna } 303a3667aaeSNaresh Kumar Inna 304a3667aaeSNaresh Kumar Inna i += VPD_INFO_FLD_HDR_SIZE + buf[i+2]; 305a3667aaeSNaresh Kumar Inna } 306a3667aaeSNaresh Kumar Inna 307a3667aaeSNaresh Kumar Inna return -EINVAL; 308a3667aaeSNaresh Kumar Inna } 309a3667aaeSNaresh Kumar Inna 310a3667aaeSNaresh Kumar Inna static int 311a3667aaeSNaresh Kumar Inna csio_pci_capability(struct pci_dev *pdev, int cap, int *pos) 312a3667aaeSNaresh Kumar Inna { 313a3667aaeSNaresh Kumar Inna *pos = pci_find_capability(pdev, cap); 314a3667aaeSNaresh Kumar Inna if (*pos) 315a3667aaeSNaresh Kumar Inna return 0; 316a3667aaeSNaresh Kumar Inna 317a3667aaeSNaresh Kumar Inna return -1; 318a3667aaeSNaresh Kumar Inna } 319a3667aaeSNaresh Kumar Inna 320a3667aaeSNaresh Kumar Inna /* 321a3667aaeSNaresh Kumar Inna * csio_hw_get_vpd_params - read VPD parameters from VPD EEPROM 322a3667aaeSNaresh Kumar Inna * @hw: HW module 323a3667aaeSNaresh Kumar Inna * @p: where to store the parameters 324a3667aaeSNaresh Kumar Inna * 325a3667aaeSNaresh Kumar Inna * Reads card parameters stored in VPD EEPROM. 326a3667aaeSNaresh Kumar Inna */ 327a3667aaeSNaresh Kumar Inna static int 328a3667aaeSNaresh Kumar Inna csio_hw_get_vpd_params(struct csio_hw *hw, struct csio_vpd *p) 329a3667aaeSNaresh Kumar Inna { 330a3667aaeSNaresh Kumar Inna int i, ret, ec, sn, addr; 331a3667aaeSNaresh Kumar Inna uint8_t *vpd, csum; 332a3667aaeSNaresh Kumar Inna const struct t4_vpd_hdr *v; 333a3667aaeSNaresh Kumar Inna /* To get around compilation warning from strstrip */ 334a3667aaeSNaresh Kumar Inna char *s; 335a3667aaeSNaresh Kumar Inna 336a3667aaeSNaresh Kumar Inna if (csio_is_valid_vpd(hw)) 337a3667aaeSNaresh Kumar Inna return 0; 338a3667aaeSNaresh Kumar Inna 339a3667aaeSNaresh Kumar Inna ret = csio_pci_capability(hw->pdev, PCI_CAP_ID_VPD, 340a3667aaeSNaresh Kumar Inna &hw->params.pci.vpd_cap_addr); 341a3667aaeSNaresh Kumar Inna if (ret) 342a3667aaeSNaresh Kumar Inna return -EINVAL; 343a3667aaeSNaresh Kumar Inna 344a3667aaeSNaresh Kumar Inna vpd = kzalloc(VPD_LEN, GFP_ATOMIC); 345a3667aaeSNaresh Kumar Inna if (vpd == NULL) 346a3667aaeSNaresh Kumar Inna return -ENOMEM; 347a3667aaeSNaresh Kumar Inna 348a3667aaeSNaresh Kumar Inna /* 349a3667aaeSNaresh Kumar Inna * Card information normally starts at VPD_BASE but early cards had 350a3667aaeSNaresh Kumar Inna * it at 0. 351a3667aaeSNaresh Kumar Inna */ 352a3667aaeSNaresh Kumar Inna ret = csio_hw_seeprom_read(hw, VPD_BASE, (uint32_t *)(vpd)); 353a3667aaeSNaresh Kumar Inna addr = *vpd == 0x82 ? VPD_BASE : VPD_BASE_OLD; 354a3667aaeSNaresh Kumar Inna 355a3667aaeSNaresh Kumar Inna for (i = 0; i < VPD_LEN; i += 4) { 356a3667aaeSNaresh Kumar Inna ret = csio_hw_seeprom_read(hw, addr + i, (uint32_t *)(vpd + i)); 357a3667aaeSNaresh Kumar Inna if (ret) { 358a3667aaeSNaresh Kumar Inna kfree(vpd); 359a3667aaeSNaresh Kumar Inna return ret; 360a3667aaeSNaresh Kumar Inna } 361a3667aaeSNaresh Kumar Inna } 362a3667aaeSNaresh Kumar Inna 363a3667aaeSNaresh Kumar Inna /* Reset the VPD flag! */ 364a3667aaeSNaresh Kumar Inna hw->flags &= (~CSIO_HWF_VPD_VALID); 365a3667aaeSNaresh Kumar Inna 366a3667aaeSNaresh Kumar Inna v = (const struct t4_vpd_hdr *)vpd; 367a3667aaeSNaresh Kumar Inna 368a3667aaeSNaresh Kumar Inna #define FIND_VPD_KW(var, name) do { \ 369a3667aaeSNaresh Kumar Inna var = csio_hw_get_vpd_keyword_val(v, name); \ 370a3667aaeSNaresh Kumar Inna if (var < 0) { \ 371a3667aaeSNaresh Kumar Inna csio_err(hw, "missing VPD keyword " name "\n"); \ 372a3667aaeSNaresh Kumar Inna kfree(vpd); \ 373a3667aaeSNaresh Kumar Inna return -EINVAL; \ 374a3667aaeSNaresh Kumar Inna } \ 375a3667aaeSNaresh Kumar Inna } while (0) 376a3667aaeSNaresh Kumar Inna 377a3667aaeSNaresh Kumar Inna FIND_VPD_KW(i, "RV"); 378a3667aaeSNaresh Kumar Inna for (csum = 0; i >= 0; i--) 379a3667aaeSNaresh Kumar Inna csum += vpd[i]; 380a3667aaeSNaresh Kumar Inna 381a3667aaeSNaresh Kumar Inna if (csum) { 382a3667aaeSNaresh Kumar Inna csio_err(hw, "corrupted VPD EEPROM, actual csum %u\n", csum); 383a3667aaeSNaresh Kumar Inna kfree(vpd); 384a3667aaeSNaresh Kumar Inna return -EINVAL; 385a3667aaeSNaresh Kumar Inna } 386a3667aaeSNaresh Kumar Inna FIND_VPD_KW(ec, "EC"); 387a3667aaeSNaresh Kumar Inna FIND_VPD_KW(sn, "SN"); 388a3667aaeSNaresh Kumar Inna #undef FIND_VPD_KW 389a3667aaeSNaresh Kumar Inna 390a3667aaeSNaresh Kumar Inna memcpy(p->id, v->id_data, ID_LEN); 391a3667aaeSNaresh Kumar Inna s = strstrip(p->id); 392a3667aaeSNaresh Kumar Inna memcpy(p->ec, vpd + ec, EC_LEN); 393a3667aaeSNaresh Kumar Inna s = strstrip(p->ec); 394a3667aaeSNaresh Kumar Inna i = vpd[sn - VPD_INFO_FLD_HDR_SIZE + 2]; 395a3667aaeSNaresh Kumar Inna memcpy(p->sn, vpd + sn, min(i, SERNUM_LEN)); 396a3667aaeSNaresh Kumar Inna s = strstrip(p->sn); 397a3667aaeSNaresh Kumar Inna 398a3667aaeSNaresh Kumar Inna csio_valid_vpd_copied(hw); 399a3667aaeSNaresh Kumar Inna 400a3667aaeSNaresh Kumar Inna kfree(vpd); 401a3667aaeSNaresh Kumar Inna return 0; 402a3667aaeSNaresh Kumar Inna } 403a3667aaeSNaresh Kumar Inna 404a3667aaeSNaresh Kumar Inna /* 405a3667aaeSNaresh Kumar Inna * csio_hw_sf1_read - read data from the serial flash 406a3667aaeSNaresh Kumar Inna * @hw: the HW module 407a3667aaeSNaresh Kumar Inna * @byte_cnt: number of bytes to read 408a3667aaeSNaresh Kumar Inna * @cont: whether another operation will be chained 409a3667aaeSNaresh Kumar Inna * @lock: whether to lock SF for PL access only 410a3667aaeSNaresh Kumar Inna * @valp: where to store the read data 411a3667aaeSNaresh Kumar Inna * 412a3667aaeSNaresh Kumar Inna * Reads up to 4 bytes of data from the serial flash. The location of 413a3667aaeSNaresh Kumar Inna * the read needs to be specified prior to calling this by issuing the 414a3667aaeSNaresh Kumar Inna * appropriate commands to the serial flash. 415a3667aaeSNaresh Kumar Inna */ 416a3667aaeSNaresh Kumar Inna static int 417a3667aaeSNaresh Kumar Inna csio_hw_sf1_read(struct csio_hw *hw, uint32_t byte_cnt, int32_t cont, 418a3667aaeSNaresh Kumar Inna int32_t lock, uint32_t *valp) 419a3667aaeSNaresh Kumar Inna { 420a3667aaeSNaresh Kumar Inna int ret; 421a3667aaeSNaresh Kumar Inna 422a3667aaeSNaresh Kumar Inna if (!byte_cnt || byte_cnt > 4) 423a3667aaeSNaresh Kumar Inna return -EINVAL; 4240d804338SHariprasad Shenai if (csio_rd_reg32(hw, SF_OP_A) & SF_BUSY_F) 425a3667aaeSNaresh Kumar Inna return -EBUSY; 426a3667aaeSNaresh Kumar Inna 4270d804338SHariprasad Shenai csio_wr_reg32(hw, SF_LOCK_V(lock) | SF_CONT_V(cont) | 4280d804338SHariprasad Shenai BYTECNT_V(byte_cnt - 1), SF_OP_A); 4290d804338SHariprasad Shenai ret = csio_hw_wait_op_done_val(hw, SF_OP_A, SF_BUSY_F, 0, SF_ATTEMPTS, 430a3667aaeSNaresh Kumar Inna 10, NULL); 431a3667aaeSNaresh Kumar Inna if (!ret) 4320d804338SHariprasad Shenai *valp = csio_rd_reg32(hw, SF_DATA_A); 433a3667aaeSNaresh Kumar Inna return ret; 434a3667aaeSNaresh Kumar Inna } 435a3667aaeSNaresh Kumar Inna 436a3667aaeSNaresh Kumar Inna /* 437a3667aaeSNaresh Kumar Inna * csio_hw_sf1_write - write data to the serial flash 438a3667aaeSNaresh Kumar Inna * @hw: the HW module 439a3667aaeSNaresh Kumar Inna * @byte_cnt: number of bytes to write 440a3667aaeSNaresh Kumar Inna * @cont: whether another operation will be chained 441a3667aaeSNaresh Kumar Inna * @lock: whether to lock SF for PL access only 442a3667aaeSNaresh Kumar Inna * @val: value to write 443a3667aaeSNaresh Kumar Inna * 444a3667aaeSNaresh Kumar Inna * Writes up to 4 bytes of data to the serial flash. The location of 445a3667aaeSNaresh Kumar Inna * the write needs to be specified prior to calling this by issuing the 446a3667aaeSNaresh Kumar Inna * appropriate commands to the serial flash. 447a3667aaeSNaresh Kumar Inna */ 448a3667aaeSNaresh Kumar Inna static int 449a3667aaeSNaresh Kumar Inna csio_hw_sf1_write(struct csio_hw *hw, uint32_t byte_cnt, uint32_t cont, 450a3667aaeSNaresh Kumar Inna int32_t lock, uint32_t val) 451a3667aaeSNaresh Kumar Inna { 452a3667aaeSNaresh Kumar Inna if (!byte_cnt || byte_cnt > 4) 453a3667aaeSNaresh Kumar Inna return -EINVAL; 4540d804338SHariprasad Shenai if (csio_rd_reg32(hw, SF_OP_A) & SF_BUSY_F) 455a3667aaeSNaresh Kumar Inna return -EBUSY; 456a3667aaeSNaresh Kumar Inna 4570d804338SHariprasad Shenai csio_wr_reg32(hw, val, SF_DATA_A); 4580d804338SHariprasad Shenai csio_wr_reg32(hw, SF_CONT_V(cont) | BYTECNT_V(byte_cnt - 1) | 4590d804338SHariprasad Shenai OP_V(1) | SF_LOCK_V(lock), SF_OP_A); 460a3667aaeSNaresh Kumar Inna 4610d804338SHariprasad Shenai return csio_hw_wait_op_done_val(hw, SF_OP_A, SF_BUSY_F, 0, SF_ATTEMPTS, 462a3667aaeSNaresh Kumar Inna 10, NULL); 463a3667aaeSNaresh Kumar Inna } 464a3667aaeSNaresh Kumar Inna 465a3667aaeSNaresh Kumar Inna /* 466a3667aaeSNaresh Kumar Inna * csio_hw_flash_wait_op - wait for a flash operation to complete 467a3667aaeSNaresh Kumar Inna * @hw: the HW module 468a3667aaeSNaresh Kumar Inna * @attempts: max number of polls of the status register 469a3667aaeSNaresh Kumar Inna * @delay: delay between polls in ms 470a3667aaeSNaresh Kumar Inna * 471a3667aaeSNaresh Kumar Inna * Wait for a flash operation to complete by polling the status register. 472a3667aaeSNaresh Kumar Inna */ 473a3667aaeSNaresh Kumar Inna static int 474a3667aaeSNaresh Kumar Inna csio_hw_flash_wait_op(struct csio_hw *hw, int32_t attempts, int32_t delay) 475a3667aaeSNaresh Kumar Inna { 476a3667aaeSNaresh Kumar Inna int ret; 477a3667aaeSNaresh Kumar Inna uint32_t status; 478a3667aaeSNaresh Kumar Inna 479a3667aaeSNaresh Kumar Inna while (1) { 480a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_write(hw, 1, 1, 1, SF_RD_STATUS); 481a3667aaeSNaresh Kumar Inna if (ret != 0) 482a3667aaeSNaresh Kumar Inna return ret; 483a3667aaeSNaresh Kumar Inna 484a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_read(hw, 1, 0, 1, &status); 485a3667aaeSNaresh Kumar Inna if (ret != 0) 486a3667aaeSNaresh Kumar Inna return ret; 487a3667aaeSNaresh Kumar Inna 488a3667aaeSNaresh Kumar Inna if (!(status & 1)) 489a3667aaeSNaresh Kumar Inna return 0; 490a3667aaeSNaresh Kumar Inna if (--attempts == 0) 491a3667aaeSNaresh Kumar Inna return -EAGAIN; 492a3667aaeSNaresh Kumar Inna if (delay) 493a3667aaeSNaresh Kumar Inna msleep(delay); 494a3667aaeSNaresh Kumar Inna } 495a3667aaeSNaresh Kumar Inna } 496a3667aaeSNaresh Kumar Inna 497a3667aaeSNaresh Kumar Inna /* 498a3667aaeSNaresh Kumar Inna * csio_hw_read_flash - read words from serial flash 499a3667aaeSNaresh Kumar Inna * @hw: the HW module 500a3667aaeSNaresh Kumar Inna * @addr: the start address for the read 501a3667aaeSNaresh Kumar Inna * @nwords: how many 32-bit words to read 502a3667aaeSNaresh Kumar Inna * @data: where to store the read data 503a3667aaeSNaresh Kumar Inna * @byte_oriented: whether to store data as bytes or as words 504a3667aaeSNaresh Kumar Inna * 505a3667aaeSNaresh Kumar Inna * Read the specified number of 32-bit words from the serial flash. 506a3667aaeSNaresh Kumar Inna * If @byte_oriented is set the read data is stored as a byte array 507a3667aaeSNaresh Kumar Inna * (i.e., big-endian), otherwise as 32-bit words in the platform's 508a3667aaeSNaresh Kumar Inna * natural endianess. 509a3667aaeSNaresh Kumar Inna */ 510a3667aaeSNaresh Kumar Inna static int 511a3667aaeSNaresh Kumar Inna csio_hw_read_flash(struct csio_hw *hw, uint32_t addr, uint32_t nwords, 512a3667aaeSNaresh Kumar Inna uint32_t *data, int32_t byte_oriented) 513a3667aaeSNaresh Kumar Inna { 514a3667aaeSNaresh Kumar Inna int ret; 515a3667aaeSNaresh Kumar Inna 516a3667aaeSNaresh Kumar Inna if (addr + nwords * sizeof(uint32_t) > hw->params.sf_size || (addr & 3)) 517a3667aaeSNaresh Kumar Inna return -EINVAL; 518a3667aaeSNaresh Kumar Inna 519a3667aaeSNaresh Kumar Inna addr = swab32(addr) | SF_RD_DATA_FAST; 520a3667aaeSNaresh Kumar Inna 521a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_write(hw, 4, 1, 0, addr); 522a3667aaeSNaresh Kumar Inna if (ret != 0) 523a3667aaeSNaresh Kumar Inna return ret; 524a3667aaeSNaresh Kumar Inna 525a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_read(hw, 1, 1, 0, data); 526a3667aaeSNaresh Kumar Inna if (ret != 0) 527a3667aaeSNaresh Kumar Inna return ret; 528a3667aaeSNaresh Kumar Inna 529a3667aaeSNaresh Kumar Inna for ( ; nwords; nwords--, data++) { 530a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_read(hw, 4, nwords > 1, nwords == 1, data); 531a3667aaeSNaresh Kumar Inna if (nwords == 1) 5320d804338SHariprasad Shenai csio_wr_reg32(hw, 0, SF_OP_A); /* unlock SF */ 533a3667aaeSNaresh Kumar Inna if (ret) 534a3667aaeSNaresh Kumar Inna return ret; 535a3667aaeSNaresh Kumar Inna if (byte_oriented) 536*78890ed7SPraveen Madhavan *data = (__force __u32) htonl(*data); 537a3667aaeSNaresh Kumar Inna } 538a3667aaeSNaresh Kumar Inna return 0; 539a3667aaeSNaresh Kumar Inna } 540a3667aaeSNaresh Kumar Inna 541a3667aaeSNaresh Kumar Inna /* 542a3667aaeSNaresh Kumar Inna * csio_hw_write_flash - write up to a page of data to the serial flash 543a3667aaeSNaresh Kumar Inna * @hw: the hw 544a3667aaeSNaresh Kumar Inna * @addr: the start address to write 545a3667aaeSNaresh Kumar Inna * @n: length of data to write in bytes 546a3667aaeSNaresh Kumar Inna * @data: the data to write 547a3667aaeSNaresh Kumar Inna * 548a3667aaeSNaresh Kumar Inna * Writes up to a page of data (256 bytes) to the serial flash starting 549a3667aaeSNaresh Kumar Inna * at the given address. All the data must be written to the same page. 550a3667aaeSNaresh Kumar Inna */ 551a3667aaeSNaresh Kumar Inna static int 552a3667aaeSNaresh Kumar Inna csio_hw_write_flash(struct csio_hw *hw, uint32_t addr, 553a3667aaeSNaresh Kumar Inna uint32_t n, const uint8_t *data) 554a3667aaeSNaresh Kumar Inna { 555a3667aaeSNaresh Kumar Inna int ret = -EINVAL; 556a3667aaeSNaresh Kumar Inna uint32_t buf[64]; 557a3667aaeSNaresh Kumar Inna uint32_t i, c, left, val, offset = addr & 0xff; 558a3667aaeSNaresh Kumar Inna 559a3667aaeSNaresh Kumar Inna if (addr >= hw->params.sf_size || offset + n > SF_PAGE_SIZE) 560a3667aaeSNaresh Kumar Inna return -EINVAL; 561a3667aaeSNaresh Kumar Inna 562a3667aaeSNaresh Kumar Inna val = swab32(addr) | SF_PROG_PAGE; 563a3667aaeSNaresh Kumar Inna 564a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_write(hw, 1, 0, 1, SF_WR_ENABLE); 565a3667aaeSNaresh Kumar Inna if (ret != 0) 566a3667aaeSNaresh Kumar Inna goto unlock; 567a3667aaeSNaresh Kumar Inna 568a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_write(hw, 4, 1, 1, val); 569a3667aaeSNaresh Kumar Inna if (ret != 0) 570a3667aaeSNaresh Kumar Inna goto unlock; 571a3667aaeSNaresh Kumar Inna 572a3667aaeSNaresh Kumar Inna for (left = n; left; left -= c) { 573a3667aaeSNaresh Kumar Inna c = min(left, 4U); 574a3667aaeSNaresh Kumar Inna for (val = 0, i = 0; i < c; ++i) 575a3667aaeSNaresh Kumar Inna val = (val << 8) + *data++; 576a3667aaeSNaresh Kumar Inna 577a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_write(hw, c, c != left, 1, val); 578a3667aaeSNaresh Kumar Inna if (ret) 579a3667aaeSNaresh Kumar Inna goto unlock; 580a3667aaeSNaresh Kumar Inna } 581a3667aaeSNaresh Kumar Inna ret = csio_hw_flash_wait_op(hw, 8, 1); 582a3667aaeSNaresh Kumar Inna if (ret) 583a3667aaeSNaresh Kumar Inna goto unlock; 584a3667aaeSNaresh Kumar Inna 5850d804338SHariprasad Shenai csio_wr_reg32(hw, 0, SF_OP_A); /* unlock SF */ 586a3667aaeSNaresh Kumar Inna 587a3667aaeSNaresh Kumar Inna /* Read the page to verify the write succeeded */ 588a3667aaeSNaresh Kumar Inna ret = csio_hw_read_flash(hw, addr & ~0xff, ARRAY_SIZE(buf), buf, 1); 589a3667aaeSNaresh Kumar Inna if (ret) 590a3667aaeSNaresh Kumar Inna return ret; 591a3667aaeSNaresh Kumar Inna 592a3667aaeSNaresh Kumar Inna if (memcmp(data - n, (uint8_t *)buf + offset, n)) { 593a3667aaeSNaresh Kumar Inna csio_err(hw, 594a3667aaeSNaresh Kumar Inna "failed to correctly write the flash page at %#x\n", 595a3667aaeSNaresh Kumar Inna addr); 596a3667aaeSNaresh Kumar Inna return -EINVAL; 597a3667aaeSNaresh Kumar Inna } 598a3667aaeSNaresh Kumar Inna 599a3667aaeSNaresh Kumar Inna return 0; 600a3667aaeSNaresh Kumar Inna 601a3667aaeSNaresh Kumar Inna unlock: 6020d804338SHariprasad Shenai csio_wr_reg32(hw, 0, SF_OP_A); /* unlock SF */ 603a3667aaeSNaresh Kumar Inna return ret; 604a3667aaeSNaresh Kumar Inna } 605a3667aaeSNaresh Kumar Inna 606a3667aaeSNaresh Kumar Inna /* 607a3667aaeSNaresh Kumar Inna * csio_hw_flash_erase_sectors - erase a range of flash sectors 608a3667aaeSNaresh Kumar Inna * @hw: the HW module 609a3667aaeSNaresh Kumar Inna * @start: the first sector to erase 610a3667aaeSNaresh Kumar Inna * @end: the last sector to erase 611a3667aaeSNaresh Kumar Inna * 612a3667aaeSNaresh Kumar Inna * Erases the sectors in the given inclusive range. 613a3667aaeSNaresh Kumar Inna */ 614a3667aaeSNaresh Kumar Inna static int 615a3667aaeSNaresh Kumar Inna csio_hw_flash_erase_sectors(struct csio_hw *hw, int32_t start, int32_t end) 616a3667aaeSNaresh Kumar Inna { 617a3667aaeSNaresh Kumar Inna int ret = 0; 618a3667aaeSNaresh Kumar Inna 619a3667aaeSNaresh Kumar Inna while (start <= end) { 620a3667aaeSNaresh Kumar Inna 621a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_write(hw, 1, 0, 1, SF_WR_ENABLE); 622a3667aaeSNaresh Kumar Inna if (ret != 0) 623a3667aaeSNaresh Kumar Inna goto out; 624a3667aaeSNaresh Kumar Inna 625a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_write(hw, 4, 0, 1, 626a3667aaeSNaresh Kumar Inna SF_ERASE_SECTOR | (start << 8)); 627a3667aaeSNaresh Kumar Inna if (ret != 0) 628a3667aaeSNaresh Kumar Inna goto out; 629a3667aaeSNaresh Kumar Inna 630a3667aaeSNaresh Kumar Inna ret = csio_hw_flash_wait_op(hw, 14, 500); 631a3667aaeSNaresh Kumar Inna if (ret != 0) 632a3667aaeSNaresh Kumar Inna goto out; 633a3667aaeSNaresh Kumar Inna 634a3667aaeSNaresh Kumar Inna start++; 635a3667aaeSNaresh Kumar Inna } 636a3667aaeSNaresh Kumar Inna out: 637a3667aaeSNaresh Kumar Inna if (ret) 638a3667aaeSNaresh Kumar Inna csio_err(hw, "erase of flash sector %d failed, error %d\n", 639a3667aaeSNaresh Kumar Inna start, ret); 6400d804338SHariprasad Shenai csio_wr_reg32(hw, 0, SF_OP_A); /* unlock SF */ 641a3667aaeSNaresh Kumar Inna return 0; 642a3667aaeSNaresh Kumar Inna } 643a3667aaeSNaresh Kumar Inna 644a3667aaeSNaresh Kumar Inna static void 645a3667aaeSNaresh Kumar Inna csio_hw_print_fw_version(struct csio_hw *hw, char *str) 646a3667aaeSNaresh Kumar Inna { 647a3667aaeSNaresh Kumar Inna csio_info(hw, "%s: %u.%u.%u.%u\n", str, 648b2e1a3f0SHariprasad Shenai FW_HDR_FW_VER_MAJOR_G(hw->fwrev), 649b2e1a3f0SHariprasad Shenai FW_HDR_FW_VER_MINOR_G(hw->fwrev), 650b2e1a3f0SHariprasad Shenai FW_HDR_FW_VER_MICRO_G(hw->fwrev), 651b2e1a3f0SHariprasad Shenai FW_HDR_FW_VER_BUILD_G(hw->fwrev)); 652a3667aaeSNaresh Kumar Inna } 653a3667aaeSNaresh Kumar Inna 654a3667aaeSNaresh Kumar Inna /* 655a3667aaeSNaresh Kumar Inna * csio_hw_get_fw_version - read the firmware version 656a3667aaeSNaresh Kumar Inna * @hw: HW module 657a3667aaeSNaresh Kumar Inna * @vers: where to place the version 658a3667aaeSNaresh Kumar Inna * 659a3667aaeSNaresh Kumar Inna * Reads the FW version from flash. 660a3667aaeSNaresh Kumar Inna */ 661a3667aaeSNaresh Kumar Inna static int 662a3667aaeSNaresh Kumar Inna csio_hw_get_fw_version(struct csio_hw *hw, uint32_t *vers) 663a3667aaeSNaresh Kumar Inna { 664a3667aaeSNaresh Kumar Inna return csio_hw_read_flash(hw, FW_IMG_START + 665a3667aaeSNaresh Kumar Inna offsetof(struct fw_hdr, fw_ver), 1, 666a3667aaeSNaresh Kumar Inna vers, 0); 667a3667aaeSNaresh Kumar Inna } 668a3667aaeSNaresh Kumar Inna 669a3667aaeSNaresh Kumar Inna /* 670a3667aaeSNaresh Kumar Inna * csio_hw_get_tp_version - read the TP microcode version 671a3667aaeSNaresh Kumar Inna * @hw: HW module 672a3667aaeSNaresh Kumar Inna * @vers: where to place the version 673a3667aaeSNaresh Kumar Inna * 674a3667aaeSNaresh Kumar Inna * Reads the TP microcode version from flash. 675a3667aaeSNaresh Kumar Inna */ 676a3667aaeSNaresh Kumar Inna static int 677a3667aaeSNaresh Kumar Inna csio_hw_get_tp_version(struct csio_hw *hw, u32 *vers) 678a3667aaeSNaresh Kumar Inna { 679a3667aaeSNaresh Kumar Inna return csio_hw_read_flash(hw, FLASH_FW_START + 680a3667aaeSNaresh Kumar Inna offsetof(struct fw_hdr, tp_microcode_ver), 1, 681a3667aaeSNaresh Kumar Inna vers, 0); 682a3667aaeSNaresh Kumar Inna } 683a3667aaeSNaresh Kumar Inna 684a3667aaeSNaresh Kumar Inna /* 685a3667aaeSNaresh Kumar Inna * csio_hw_fw_dload - download firmware. 686a3667aaeSNaresh Kumar Inna * @hw: HW module 687a3667aaeSNaresh Kumar Inna * @fw_data: firmware image to write. 688a3667aaeSNaresh Kumar Inna * @size: image size 689a3667aaeSNaresh Kumar Inna * 690a3667aaeSNaresh Kumar Inna * Write the supplied firmware image to the card's serial flash. 691a3667aaeSNaresh Kumar Inna */ 692a3667aaeSNaresh Kumar Inna static int 693a3667aaeSNaresh Kumar Inna csio_hw_fw_dload(struct csio_hw *hw, uint8_t *fw_data, uint32_t size) 694a3667aaeSNaresh Kumar Inna { 695a3667aaeSNaresh Kumar Inna uint32_t csum; 696a3667aaeSNaresh Kumar Inna int32_t addr; 697a3667aaeSNaresh Kumar Inna int ret; 698a3667aaeSNaresh Kumar Inna uint32_t i; 699a3667aaeSNaresh Kumar Inna uint8_t first_page[SF_PAGE_SIZE]; 7005036f0a0SNaresh Kumar Inna const __be32 *p = (const __be32 *)fw_data; 701a3667aaeSNaresh Kumar Inna struct fw_hdr *hdr = (struct fw_hdr *)fw_data; 702a3667aaeSNaresh Kumar Inna uint32_t sf_sec_size; 703a3667aaeSNaresh Kumar Inna 704a3667aaeSNaresh Kumar Inna if ((!hw->params.sf_size) || (!hw->params.sf_nsec)) { 705a3667aaeSNaresh Kumar Inna csio_err(hw, "Serial Flash data invalid\n"); 706a3667aaeSNaresh Kumar Inna return -EINVAL; 707a3667aaeSNaresh Kumar Inna } 708a3667aaeSNaresh Kumar Inna 709a3667aaeSNaresh Kumar Inna if (!size) { 710a3667aaeSNaresh Kumar Inna csio_err(hw, "FW image has no data\n"); 711a3667aaeSNaresh Kumar Inna return -EINVAL; 712a3667aaeSNaresh Kumar Inna } 713a3667aaeSNaresh Kumar Inna 714a3667aaeSNaresh Kumar Inna if (size & 511) { 715a3667aaeSNaresh Kumar Inna csio_err(hw, "FW image size not multiple of 512 bytes\n"); 716a3667aaeSNaresh Kumar Inna return -EINVAL; 717a3667aaeSNaresh Kumar Inna } 718a3667aaeSNaresh Kumar Inna 719a3667aaeSNaresh Kumar Inna if (ntohs(hdr->len512) * 512 != size) { 720a3667aaeSNaresh Kumar Inna csio_err(hw, "FW image size differs from size in FW header\n"); 721a3667aaeSNaresh Kumar Inna return -EINVAL; 722a3667aaeSNaresh Kumar Inna } 723a3667aaeSNaresh Kumar Inna 724a3667aaeSNaresh Kumar Inna if (size > FW_MAX_SIZE) { 725a3667aaeSNaresh Kumar Inna csio_err(hw, "FW image too large, max is %u bytes\n", 726a3667aaeSNaresh Kumar Inna FW_MAX_SIZE); 727a3667aaeSNaresh Kumar Inna return -EINVAL; 728a3667aaeSNaresh Kumar Inna } 729a3667aaeSNaresh Kumar Inna 730a3667aaeSNaresh Kumar Inna for (csum = 0, i = 0; i < size / sizeof(csum); i++) 731a3667aaeSNaresh Kumar Inna csum += ntohl(p[i]); 732a3667aaeSNaresh Kumar Inna 733a3667aaeSNaresh Kumar Inna if (csum != 0xffffffff) { 734a3667aaeSNaresh Kumar Inna csio_err(hw, "corrupted firmware image, checksum %#x\n", csum); 735a3667aaeSNaresh Kumar Inna return -EINVAL; 736a3667aaeSNaresh Kumar Inna } 737a3667aaeSNaresh Kumar Inna 738a3667aaeSNaresh Kumar Inna sf_sec_size = hw->params.sf_size / hw->params.sf_nsec; 739a3667aaeSNaresh Kumar Inna i = DIV_ROUND_UP(size, sf_sec_size); /* # of sectors spanned */ 740a3667aaeSNaresh Kumar Inna 741a3667aaeSNaresh Kumar Inna csio_dbg(hw, "Erasing sectors... start:%d end:%d\n", 742a3667aaeSNaresh Kumar Inna FW_START_SEC, FW_START_SEC + i - 1); 743a3667aaeSNaresh Kumar Inna 744a3667aaeSNaresh Kumar Inna ret = csio_hw_flash_erase_sectors(hw, FW_START_SEC, 745a3667aaeSNaresh Kumar Inna FW_START_SEC + i - 1); 746a3667aaeSNaresh Kumar Inna if (ret) { 747a3667aaeSNaresh Kumar Inna csio_err(hw, "Flash Erase failed\n"); 748a3667aaeSNaresh Kumar Inna goto out; 749a3667aaeSNaresh Kumar Inna } 750a3667aaeSNaresh Kumar Inna 751a3667aaeSNaresh Kumar Inna /* 752a3667aaeSNaresh Kumar Inna * We write the correct version at the end so the driver can see a bad 753a3667aaeSNaresh Kumar Inna * version if the FW write fails. Start by writing a copy of the 754a3667aaeSNaresh Kumar Inna * first page with a bad version. 755a3667aaeSNaresh Kumar Inna */ 756a3667aaeSNaresh Kumar Inna memcpy(first_page, fw_data, SF_PAGE_SIZE); 757a3667aaeSNaresh Kumar Inna ((struct fw_hdr *)first_page)->fw_ver = htonl(0xffffffff); 758a3667aaeSNaresh Kumar Inna ret = csio_hw_write_flash(hw, FW_IMG_START, SF_PAGE_SIZE, first_page); 759a3667aaeSNaresh Kumar Inna if (ret) 760a3667aaeSNaresh Kumar Inna goto out; 761a3667aaeSNaresh Kumar Inna 762a3667aaeSNaresh Kumar Inna csio_dbg(hw, "Writing Flash .. start:%d end:%d\n", 763a3667aaeSNaresh Kumar Inna FW_IMG_START, FW_IMG_START + size); 764a3667aaeSNaresh Kumar Inna 765a3667aaeSNaresh Kumar Inna addr = FW_IMG_START; 766a3667aaeSNaresh Kumar Inna for (size -= SF_PAGE_SIZE; size; size -= SF_PAGE_SIZE) { 767a3667aaeSNaresh Kumar Inna addr += SF_PAGE_SIZE; 768a3667aaeSNaresh Kumar Inna fw_data += SF_PAGE_SIZE; 769a3667aaeSNaresh Kumar Inna ret = csio_hw_write_flash(hw, addr, SF_PAGE_SIZE, fw_data); 770a3667aaeSNaresh Kumar Inna if (ret) 771a3667aaeSNaresh Kumar Inna goto out; 772a3667aaeSNaresh Kumar Inna } 773a3667aaeSNaresh Kumar Inna 774a3667aaeSNaresh Kumar Inna ret = csio_hw_write_flash(hw, 775a3667aaeSNaresh Kumar Inna FW_IMG_START + 776a3667aaeSNaresh Kumar Inna offsetof(struct fw_hdr, fw_ver), 777a3667aaeSNaresh Kumar Inna sizeof(hdr->fw_ver), 778a3667aaeSNaresh Kumar Inna (const uint8_t *)&hdr->fw_ver); 779a3667aaeSNaresh Kumar Inna 780a3667aaeSNaresh Kumar Inna out: 781a3667aaeSNaresh Kumar Inna if (ret) 782a3667aaeSNaresh Kumar Inna csio_err(hw, "firmware download failed, error %d\n", ret); 783a3667aaeSNaresh Kumar Inna return ret; 784a3667aaeSNaresh Kumar Inna } 785a3667aaeSNaresh Kumar Inna 786a3667aaeSNaresh Kumar Inna static int 787a3667aaeSNaresh Kumar Inna csio_hw_get_flash_params(struct csio_hw *hw) 788a3667aaeSNaresh Kumar Inna { 789a3667aaeSNaresh Kumar Inna int ret; 790a3667aaeSNaresh Kumar Inna uint32_t info = 0; 791a3667aaeSNaresh Kumar Inna 792a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_write(hw, 1, 1, 0, SF_RD_ID); 793a3667aaeSNaresh Kumar Inna if (!ret) 794a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_read(hw, 3, 0, 1, &info); 7950d804338SHariprasad Shenai csio_wr_reg32(hw, 0, SF_OP_A); /* unlock SF */ 796a3667aaeSNaresh Kumar Inna if (ret != 0) 797a3667aaeSNaresh Kumar Inna return ret; 798a3667aaeSNaresh Kumar Inna 799a3667aaeSNaresh Kumar Inna if ((info & 0xff) != 0x20) /* not a Numonix flash */ 800a3667aaeSNaresh Kumar Inna return -EINVAL; 801a3667aaeSNaresh Kumar Inna info >>= 16; /* log2 of size */ 802a3667aaeSNaresh Kumar Inna if (info >= 0x14 && info < 0x18) 803a3667aaeSNaresh Kumar Inna hw->params.sf_nsec = 1 << (info - 16); 804a3667aaeSNaresh Kumar Inna else if (info == 0x18) 805a3667aaeSNaresh Kumar Inna hw->params.sf_nsec = 64; 806a3667aaeSNaresh Kumar Inna else 807a3667aaeSNaresh Kumar Inna return -EINVAL; 808a3667aaeSNaresh Kumar Inna hw->params.sf_size = 1 << info; 809a3667aaeSNaresh Kumar Inna 810a3667aaeSNaresh Kumar Inna return 0; 811a3667aaeSNaresh Kumar Inna } 812a3667aaeSNaresh Kumar Inna 813a3667aaeSNaresh Kumar Inna /*****************************************************************************/ 814a3667aaeSNaresh Kumar Inna /* HW State machine assists */ 815a3667aaeSNaresh Kumar Inna /*****************************************************************************/ 816a3667aaeSNaresh Kumar Inna 817a3667aaeSNaresh Kumar Inna static int 818a3667aaeSNaresh Kumar Inna csio_hw_dev_ready(struct csio_hw *hw) 819a3667aaeSNaresh Kumar Inna { 820a3667aaeSNaresh Kumar Inna uint32_t reg; 821a3667aaeSNaresh Kumar Inna int cnt = 6; 822a3667aaeSNaresh Kumar Inna 8230d804338SHariprasad Shenai while (((reg = csio_rd_reg32(hw, PL_WHOAMI_A)) == 0xFFFFFFFF) && 824a3667aaeSNaresh Kumar Inna (--cnt != 0)) 825a3667aaeSNaresh Kumar Inna mdelay(100); 826a3667aaeSNaresh Kumar Inna 8270d804338SHariprasad Shenai if ((cnt == 0) && (((int32_t)(SOURCEPF_G(reg)) < 0) || 8280d804338SHariprasad Shenai (SOURCEPF_G(reg) >= CSIO_MAX_PFN))) { 829a3667aaeSNaresh Kumar Inna csio_err(hw, "PL_WHOAMI returned 0x%x, cnt:%d\n", reg, cnt); 830a3667aaeSNaresh Kumar Inna return -EIO; 831a3667aaeSNaresh Kumar Inna } 832a3667aaeSNaresh Kumar Inna 8330d804338SHariprasad Shenai hw->pfn = SOURCEPF_G(reg); 834a3667aaeSNaresh Kumar Inna 835a3667aaeSNaresh Kumar Inna return 0; 836a3667aaeSNaresh Kumar Inna } 837a3667aaeSNaresh Kumar Inna 838a3667aaeSNaresh Kumar Inna /* 839a3667aaeSNaresh Kumar Inna * csio_do_hello - Perform the HELLO FW Mailbox command and process response. 840a3667aaeSNaresh Kumar Inna * @hw: HW module 841a3667aaeSNaresh Kumar Inna * @state: Device state 842a3667aaeSNaresh Kumar Inna * 843a3667aaeSNaresh Kumar Inna * FW_HELLO_CMD has to be polled for completion. 844a3667aaeSNaresh Kumar Inna */ 845a3667aaeSNaresh Kumar Inna static int 846a3667aaeSNaresh Kumar Inna csio_do_hello(struct csio_hw *hw, enum csio_dev_state *state) 847a3667aaeSNaresh Kumar Inna { 848a3667aaeSNaresh Kumar Inna struct csio_mb *mbp; 849a3667aaeSNaresh Kumar Inna int rv = 0; 850a3667aaeSNaresh Kumar Inna enum fw_retval retval; 851a3667aaeSNaresh Kumar Inna uint8_t mpfn; 852a3667aaeSNaresh Kumar Inna char state_str[16]; 853a3667aaeSNaresh Kumar Inna int retries = FW_CMD_HELLO_RETRIES; 854a3667aaeSNaresh Kumar Inna 855a3667aaeSNaresh Kumar Inna memset(state_str, 0, sizeof(state_str)); 856a3667aaeSNaresh Kumar Inna 857a3667aaeSNaresh Kumar Inna mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 858a3667aaeSNaresh Kumar Inna if (!mbp) { 859a3667aaeSNaresh Kumar Inna rv = -ENOMEM; 860a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_nomem); 861a3667aaeSNaresh Kumar Inna goto out; 862a3667aaeSNaresh Kumar Inna } 863a3667aaeSNaresh Kumar Inna 864a3667aaeSNaresh Kumar Inna retry: 865a3667aaeSNaresh Kumar Inna csio_mb_hello(hw, mbp, CSIO_MB_DEFAULT_TMO, hw->pfn, 866666224d4SHariprasad Shenai hw->pfn, CSIO_MASTER_MAY, NULL); 867a3667aaeSNaresh Kumar Inna 868a3667aaeSNaresh Kumar Inna rv = csio_mb_issue(hw, mbp); 869a3667aaeSNaresh Kumar Inna if (rv) { 870a3667aaeSNaresh Kumar Inna csio_err(hw, "failed to issue HELLO cmd. ret:%d.\n", rv); 871a3667aaeSNaresh Kumar Inna goto out_free_mb; 872a3667aaeSNaresh Kumar Inna } 873a3667aaeSNaresh Kumar Inna 874a3667aaeSNaresh Kumar Inna csio_mb_process_hello_rsp(hw, mbp, &retval, state, &mpfn); 875a3667aaeSNaresh Kumar Inna if (retval != FW_SUCCESS) { 876a3667aaeSNaresh Kumar Inna csio_err(hw, "HELLO cmd failed with ret: %d\n", retval); 877a3667aaeSNaresh Kumar Inna rv = -EINVAL; 878a3667aaeSNaresh Kumar Inna goto out_free_mb; 879a3667aaeSNaresh Kumar Inna } 880a3667aaeSNaresh Kumar Inna 881a3667aaeSNaresh Kumar Inna /* Firmware has designated us to be master */ 882a3667aaeSNaresh Kumar Inna if (hw->pfn == mpfn) { 883a3667aaeSNaresh Kumar Inna hw->flags |= CSIO_HWF_MASTER; 884a3667aaeSNaresh Kumar Inna } else if (*state == CSIO_DEV_STATE_UNINIT) { 885a3667aaeSNaresh Kumar Inna /* 886a3667aaeSNaresh Kumar Inna * If we're not the Master PF then we need to wait around for 887a3667aaeSNaresh Kumar Inna * the Master PF Driver to finish setting up the adapter. 888a3667aaeSNaresh Kumar Inna * 889a3667aaeSNaresh Kumar Inna * Note that we also do this wait if we're a non-Master-capable 890a3667aaeSNaresh Kumar Inna * PF and there is no current Master PF; a Master PF may show up 891a3667aaeSNaresh Kumar Inna * momentarily and we wouldn't want to fail pointlessly. (This 892a3667aaeSNaresh Kumar Inna * can happen when an OS loads lots of different drivers rapidly 893a3667aaeSNaresh Kumar Inna * at the same time). In this case, the Master PF returned by 894a3667aaeSNaresh Kumar Inna * the firmware will be PCIE_FW_MASTER_MASK so the test below 895a3667aaeSNaresh Kumar Inna * will work ... 896a3667aaeSNaresh Kumar Inna */ 897a3667aaeSNaresh Kumar Inna 898a3667aaeSNaresh Kumar Inna int waiting = FW_CMD_HELLO_TIMEOUT; 899a3667aaeSNaresh Kumar Inna 900a3667aaeSNaresh Kumar Inna /* 901a3667aaeSNaresh Kumar Inna * Wait for the firmware to either indicate an error or 902a3667aaeSNaresh Kumar Inna * initialized state. If we see either of these we bail out 903a3667aaeSNaresh Kumar Inna * and report the issue to the caller. If we exhaust the 904a3667aaeSNaresh Kumar Inna * "hello timeout" and we haven't exhausted our retries, try 905a3667aaeSNaresh Kumar Inna * again. Otherwise bail with a timeout error. 906a3667aaeSNaresh Kumar Inna */ 907a3667aaeSNaresh Kumar Inna for (;;) { 908a3667aaeSNaresh Kumar Inna uint32_t pcie_fw; 909a3667aaeSNaresh Kumar Inna 9107cc16380SArvind Bhushan spin_unlock_irq(&hw->lock); 911a3667aaeSNaresh Kumar Inna msleep(50); 9127cc16380SArvind Bhushan spin_lock_irq(&hw->lock); 913a3667aaeSNaresh Kumar Inna waiting -= 50; 914a3667aaeSNaresh Kumar Inna 915a3667aaeSNaresh Kumar Inna /* 916a3667aaeSNaresh Kumar Inna * If neither Error nor Initialialized are indicated 917a3667aaeSNaresh Kumar Inna * by the firmware keep waiting till we exaust our 918a3667aaeSNaresh Kumar Inna * timeout ... and then retry if we haven't exhausted 919a3667aaeSNaresh Kumar Inna * our retries ... 920a3667aaeSNaresh Kumar Inna */ 921f061de42SHariprasad Shenai pcie_fw = csio_rd_reg32(hw, PCIE_FW_A); 922f061de42SHariprasad Shenai if (!(pcie_fw & (PCIE_FW_ERR_F|PCIE_FW_INIT_F))) { 923a3667aaeSNaresh Kumar Inna if (waiting <= 0) { 924a3667aaeSNaresh Kumar Inna if (retries-- > 0) 925a3667aaeSNaresh Kumar Inna goto retry; 926a3667aaeSNaresh Kumar Inna 927a3667aaeSNaresh Kumar Inna rv = -ETIMEDOUT; 928a3667aaeSNaresh Kumar Inna break; 929a3667aaeSNaresh Kumar Inna } 930a3667aaeSNaresh Kumar Inna continue; 931a3667aaeSNaresh Kumar Inna } 932a3667aaeSNaresh Kumar Inna 933a3667aaeSNaresh Kumar Inna /* 934a3667aaeSNaresh Kumar Inna * We either have an Error or Initialized condition 935a3667aaeSNaresh Kumar Inna * report errors preferentially. 936a3667aaeSNaresh Kumar Inna */ 937a3667aaeSNaresh Kumar Inna if (state) { 938f061de42SHariprasad Shenai if (pcie_fw & PCIE_FW_ERR_F) { 939a3667aaeSNaresh Kumar Inna *state = CSIO_DEV_STATE_ERR; 940a3667aaeSNaresh Kumar Inna rv = -ETIMEDOUT; 941f061de42SHariprasad Shenai } else if (pcie_fw & PCIE_FW_INIT_F) 942a3667aaeSNaresh Kumar Inna *state = CSIO_DEV_STATE_INIT; 943a3667aaeSNaresh Kumar Inna } 944a3667aaeSNaresh Kumar Inna 945a3667aaeSNaresh Kumar Inna /* 946a3667aaeSNaresh Kumar Inna * If we arrived before a Master PF was selected and 947a3667aaeSNaresh Kumar Inna * there's not a valid Master PF, grab its identity 948a3667aaeSNaresh Kumar Inna * for our caller. 949a3667aaeSNaresh Kumar Inna */ 950f061de42SHariprasad Shenai if (mpfn == PCIE_FW_MASTER_M && 951f061de42SHariprasad Shenai (pcie_fw & PCIE_FW_MASTER_VLD_F)) 952f061de42SHariprasad Shenai mpfn = PCIE_FW_MASTER_G(pcie_fw); 953a3667aaeSNaresh Kumar Inna break; 954a3667aaeSNaresh Kumar Inna } 955a3667aaeSNaresh Kumar Inna hw->flags &= ~CSIO_HWF_MASTER; 956a3667aaeSNaresh Kumar Inna } 957a3667aaeSNaresh Kumar Inna 958a3667aaeSNaresh Kumar Inna switch (*state) { 959a3667aaeSNaresh Kumar Inna case CSIO_DEV_STATE_UNINIT: 960a3667aaeSNaresh Kumar Inna strcpy(state_str, "Initializing"); 961a3667aaeSNaresh Kumar Inna break; 962a3667aaeSNaresh Kumar Inna case CSIO_DEV_STATE_INIT: 963a3667aaeSNaresh Kumar Inna strcpy(state_str, "Initialized"); 964a3667aaeSNaresh Kumar Inna break; 965a3667aaeSNaresh Kumar Inna case CSIO_DEV_STATE_ERR: 966a3667aaeSNaresh Kumar Inna strcpy(state_str, "Error"); 967a3667aaeSNaresh Kumar Inna break; 968a3667aaeSNaresh Kumar Inna default: 969a3667aaeSNaresh Kumar Inna strcpy(state_str, "Unknown"); 970a3667aaeSNaresh Kumar Inna break; 971a3667aaeSNaresh Kumar Inna } 972a3667aaeSNaresh Kumar Inna 973a3667aaeSNaresh Kumar Inna if (hw->pfn == mpfn) 974a3667aaeSNaresh Kumar Inna csio_info(hw, "PF: %d, Coming up as MASTER, HW state: %s\n", 975a3667aaeSNaresh Kumar Inna hw->pfn, state_str); 976a3667aaeSNaresh Kumar Inna else 977a3667aaeSNaresh Kumar Inna csio_info(hw, 978a3667aaeSNaresh Kumar Inna "PF: %d, Coming up as SLAVE, Master PF: %d, HW state: %s\n", 979a3667aaeSNaresh Kumar Inna hw->pfn, mpfn, state_str); 980a3667aaeSNaresh Kumar Inna 981a3667aaeSNaresh Kumar Inna out_free_mb: 982a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 983a3667aaeSNaresh Kumar Inna out: 984a3667aaeSNaresh Kumar Inna return rv; 985a3667aaeSNaresh Kumar Inna } 986a3667aaeSNaresh Kumar Inna 987a3667aaeSNaresh Kumar Inna /* 988a3667aaeSNaresh Kumar Inna * csio_do_bye - Perform the BYE FW Mailbox command and process response. 989a3667aaeSNaresh Kumar Inna * @hw: HW module 990a3667aaeSNaresh Kumar Inna * 991a3667aaeSNaresh Kumar Inna */ 992a3667aaeSNaresh Kumar Inna static int 993a3667aaeSNaresh Kumar Inna csio_do_bye(struct csio_hw *hw) 994a3667aaeSNaresh Kumar Inna { 995a3667aaeSNaresh Kumar Inna struct csio_mb *mbp; 996a3667aaeSNaresh Kumar Inna enum fw_retval retval; 997a3667aaeSNaresh Kumar Inna 998a3667aaeSNaresh Kumar Inna mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 999a3667aaeSNaresh Kumar Inna if (!mbp) { 1000a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_nomem); 1001a3667aaeSNaresh Kumar Inna return -ENOMEM; 1002a3667aaeSNaresh Kumar Inna } 1003a3667aaeSNaresh Kumar Inna 1004a3667aaeSNaresh Kumar Inna csio_mb_bye(hw, mbp, CSIO_MB_DEFAULT_TMO, NULL); 1005a3667aaeSNaresh Kumar Inna 1006a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 1007a3667aaeSNaresh Kumar Inna csio_err(hw, "Issue of BYE command failed\n"); 1008a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1009a3667aaeSNaresh Kumar Inna return -EINVAL; 1010a3667aaeSNaresh Kumar Inna } 1011a3667aaeSNaresh Kumar Inna 1012a3667aaeSNaresh Kumar Inna retval = csio_mb_fw_retval(mbp); 1013a3667aaeSNaresh Kumar Inna if (retval != FW_SUCCESS) { 1014a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1015a3667aaeSNaresh Kumar Inna return -EINVAL; 1016a3667aaeSNaresh Kumar Inna } 1017a3667aaeSNaresh Kumar Inna 1018a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1019a3667aaeSNaresh Kumar Inna 1020a3667aaeSNaresh Kumar Inna return 0; 1021a3667aaeSNaresh Kumar Inna } 1022a3667aaeSNaresh Kumar Inna 1023a3667aaeSNaresh Kumar Inna /* 1024a3667aaeSNaresh Kumar Inna * csio_do_reset- Perform the device reset. 1025a3667aaeSNaresh Kumar Inna * @hw: HW module 1026a3667aaeSNaresh Kumar Inna * @fw_rst: FW reset 1027a3667aaeSNaresh Kumar Inna * 1028a3667aaeSNaresh Kumar Inna * If fw_rst is set, issues FW reset mbox cmd otherwise 1029a3667aaeSNaresh Kumar Inna * does PIO reset. 1030a3667aaeSNaresh Kumar Inna * Performs reset of the function. 1031a3667aaeSNaresh Kumar Inna */ 1032a3667aaeSNaresh Kumar Inna static int 1033a3667aaeSNaresh Kumar Inna csio_do_reset(struct csio_hw *hw, bool fw_rst) 1034a3667aaeSNaresh Kumar Inna { 1035a3667aaeSNaresh Kumar Inna struct csio_mb *mbp; 1036a3667aaeSNaresh Kumar Inna enum fw_retval retval; 1037a3667aaeSNaresh Kumar Inna 1038a3667aaeSNaresh Kumar Inna if (!fw_rst) { 1039a3667aaeSNaresh Kumar Inna /* PIO reset */ 10400d804338SHariprasad Shenai csio_wr_reg32(hw, PIORSTMODE_F | PIORST_F, PL_RST_A); 1041a3667aaeSNaresh Kumar Inna mdelay(2000); 1042a3667aaeSNaresh Kumar Inna return 0; 1043a3667aaeSNaresh Kumar Inna } 1044a3667aaeSNaresh Kumar Inna 1045a3667aaeSNaresh Kumar Inna mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 1046a3667aaeSNaresh Kumar Inna if (!mbp) { 1047a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_nomem); 1048a3667aaeSNaresh Kumar Inna return -ENOMEM; 1049a3667aaeSNaresh Kumar Inna } 1050a3667aaeSNaresh Kumar Inna 1051a3667aaeSNaresh Kumar Inna csio_mb_reset(hw, mbp, CSIO_MB_DEFAULT_TMO, 10520d804338SHariprasad Shenai PIORSTMODE_F | PIORST_F, 0, NULL); 1053a3667aaeSNaresh Kumar Inna 1054a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 1055a3667aaeSNaresh Kumar Inna csio_err(hw, "Issue of RESET command failed.n"); 1056a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1057a3667aaeSNaresh Kumar Inna return -EINVAL; 1058a3667aaeSNaresh Kumar Inna } 1059a3667aaeSNaresh Kumar Inna 1060a3667aaeSNaresh Kumar Inna retval = csio_mb_fw_retval(mbp); 1061a3667aaeSNaresh Kumar Inna if (retval != FW_SUCCESS) { 1062a3667aaeSNaresh Kumar Inna csio_err(hw, "RESET cmd failed with ret:0x%x.\n", retval); 1063a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1064a3667aaeSNaresh Kumar Inna return -EINVAL; 1065a3667aaeSNaresh Kumar Inna } 1066a3667aaeSNaresh Kumar Inna 1067a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1068a3667aaeSNaresh Kumar Inna 1069a3667aaeSNaresh Kumar Inna return 0; 1070a3667aaeSNaresh Kumar Inna } 1071a3667aaeSNaresh Kumar Inna 1072a3667aaeSNaresh Kumar Inna static int 1073a3667aaeSNaresh Kumar Inna csio_hw_validate_caps(struct csio_hw *hw, struct csio_mb *mbp) 1074a3667aaeSNaresh Kumar Inna { 1075a3667aaeSNaresh Kumar Inna struct fw_caps_config_cmd *rsp = (struct fw_caps_config_cmd *)mbp->mb; 1076a3667aaeSNaresh Kumar Inna uint16_t caps; 1077a3667aaeSNaresh Kumar Inna 1078a3667aaeSNaresh Kumar Inna caps = ntohs(rsp->fcoecaps); 1079a3667aaeSNaresh Kumar Inna 1080a3667aaeSNaresh Kumar Inna if (!(caps & FW_CAPS_CONFIG_FCOE_INITIATOR)) { 1081a3667aaeSNaresh Kumar Inna csio_err(hw, "No FCoE Initiator capability in the firmware.\n"); 1082a3667aaeSNaresh Kumar Inna return -EINVAL; 1083a3667aaeSNaresh Kumar Inna } 1084a3667aaeSNaresh Kumar Inna 1085a3667aaeSNaresh Kumar Inna if (!(caps & FW_CAPS_CONFIG_FCOE_CTRL_OFLD)) { 1086a3667aaeSNaresh Kumar Inna csio_err(hw, "No FCoE Control Offload capability\n"); 1087a3667aaeSNaresh Kumar Inna return -EINVAL; 1088a3667aaeSNaresh Kumar Inna } 1089a3667aaeSNaresh Kumar Inna 1090a3667aaeSNaresh Kumar Inna return 0; 1091a3667aaeSNaresh Kumar Inna } 1092a3667aaeSNaresh Kumar Inna 1093a3667aaeSNaresh Kumar Inna /* 1094a3667aaeSNaresh Kumar Inna * csio_hw_fw_halt - issue a reset/halt to FW and put uP into RESET 1095a3667aaeSNaresh Kumar Inna * @hw: the HW module 1096a3667aaeSNaresh Kumar Inna * @mbox: mailbox to use for the FW RESET command (if desired) 1097a3667aaeSNaresh Kumar Inna * @force: force uP into RESET even if FW RESET command fails 1098a3667aaeSNaresh Kumar Inna * 1099a3667aaeSNaresh Kumar Inna * Issues a RESET command to firmware (if desired) with a HALT indication 1100a3667aaeSNaresh Kumar Inna * and then puts the microprocessor into RESET state. The RESET command 1101a3667aaeSNaresh Kumar Inna * will only be issued if a legitimate mailbox is provided (mbox <= 1102a3667aaeSNaresh Kumar Inna * PCIE_FW_MASTER_MASK). 1103a3667aaeSNaresh Kumar Inna * 1104a3667aaeSNaresh Kumar Inna * This is generally used in order for the host to safely manipulate the 1105a3667aaeSNaresh Kumar Inna * adapter without fear of conflicting with whatever the firmware might 1106a3667aaeSNaresh Kumar Inna * be doing. The only way out of this state is to RESTART the firmware 1107a3667aaeSNaresh Kumar Inna * ... 1108a3667aaeSNaresh Kumar Inna */ 1109a3667aaeSNaresh Kumar Inna static int 1110a3667aaeSNaresh Kumar Inna csio_hw_fw_halt(struct csio_hw *hw, uint32_t mbox, int32_t force) 1111a3667aaeSNaresh Kumar Inna { 1112a3667aaeSNaresh Kumar Inna enum fw_retval retval = 0; 1113a3667aaeSNaresh Kumar Inna 1114a3667aaeSNaresh Kumar Inna /* 1115a3667aaeSNaresh Kumar Inna * If a legitimate mailbox is provided, issue a RESET command 1116a3667aaeSNaresh Kumar Inna * with a HALT indication. 1117a3667aaeSNaresh Kumar Inna */ 1118f061de42SHariprasad Shenai if (mbox <= PCIE_FW_MASTER_M) { 1119a3667aaeSNaresh Kumar Inna struct csio_mb *mbp; 1120a3667aaeSNaresh Kumar Inna 1121a3667aaeSNaresh Kumar Inna mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 1122a3667aaeSNaresh Kumar Inna if (!mbp) { 1123a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_nomem); 1124a3667aaeSNaresh Kumar Inna return -ENOMEM; 1125a3667aaeSNaresh Kumar Inna } 1126a3667aaeSNaresh Kumar Inna 1127a3667aaeSNaresh Kumar Inna csio_mb_reset(hw, mbp, CSIO_MB_DEFAULT_TMO, 11280d804338SHariprasad Shenai PIORSTMODE_F | PIORST_F, FW_RESET_CMD_HALT_F, 1129a3667aaeSNaresh Kumar Inna NULL); 1130a3667aaeSNaresh Kumar Inna 1131a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 1132a3667aaeSNaresh Kumar Inna csio_err(hw, "Issue of RESET command failed!\n"); 1133a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1134a3667aaeSNaresh Kumar Inna return -EINVAL; 1135a3667aaeSNaresh Kumar Inna } 1136a3667aaeSNaresh Kumar Inna 1137a3667aaeSNaresh Kumar Inna retval = csio_mb_fw_retval(mbp); 1138a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1139a3667aaeSNaresh Kumar Inna } 1140a3667aaeSNaresh Kumar Inna 1141a3667aaeSNaresh Kumar Inna /* 1142a3667aaeSNaresh Kumar Inna * Normally we won't complete the operation if the firmware RESET 1143a3667aaeSNaresh Kumar Inna * command fails but if our caller insists we'll go ahead and put the 1144a3667aaeSNaresh Kumar Inna * uP into RESET. This can be useful if the firmware is hung or even 1145a3667aaeSNaresh Kumar Inna * missing ... We'll have to take the risk of putting the uP into 1146a3667aaeSNaresh Kumar Inna * RESET without the cooperation of firmware in that case. 1147a3667aaeSNaresh Kumar Inna * 1148a3667aaeSNaresh Kumar Inna * We also force the firmware's HALT flag to be on in case we bypassed 1149a3667aaeSNaresh Kumar Inna * the firmware RESET command above or we're dealing with old firmware 1150a3667aaeSNaresh Kumar Inna * which doesn't have the HALT capability. This will serve as a flag 1151a3667aaeSNaresh Kumar Inna * for the incoming firmware to know that it's coming out of a HALT 1152a3667aaeSNaresh Kumar Inna * rather than a RESET ... if it's new enough to understand that ... 1153a3667aaeSNaresh Kumar Inna */ 1154a3667aaeSNaresh Kumar Inna if (retval == 0 || force) { 115589c3a86cSHariprasad Shenai csio_set_reg_field(hw, CIM_BOOT_CFG_A, UPCRST_F, UPCRST_F); 1156f061de42SHariprasad Shenai csio_set_reg_field(hw, PCIE_FW_A, PCIE_FW_HALT_F, 1157f061de42SHariprasad Shenai PCIE_FW_HALT_F); 1158a3667aaeSNaresh Kumar Inna } 1159a3667aaeSNaresh Kumar Inna 1160a3667aaeSNaresh Kumar Inna /* 1161a3667aaeSNaresh Kumar Inna * And we always return the result of the firmware RESET command 1162a3667aaeSNaresh Kumar Inna * even when we force the uP into RESET ... 1163a3667aaeSNaresh Kumar Inna */ 1164a3667aaeSNaresh Kumar Inna return retval ? -EINVAL : 0; 1165a3667aaeSNaresh Kumar Inna } 1166a3667aaeSNaresh Kumar Inna 1167a3667aaeSNaresh Kumar Inna /* 1168a3667aaeSNaresh Kumar Inna * csio_hw_fw_restart - restart the firmware by taking the uP out of RESET 1169a3667aaeSNaresh Kumar Inna * @hw: the HW module 1170a3667aaeSNaresh Kumar Inna * @reset: if we want to do a RESET to restart things 1171a3667aaeSNaresh Kumar Inna * 1172a3667aaeSNaresh Kumar Inna * Restart firmware previously halted by csio_hw_fw_halt(). On successful 1173a3667aaeSNaresh Kumar Inna * return the previous PF Master remains as the new PF Master and there 1174a3667aaeSNaresh Kumar Inna * is no need to issue a new HELLO command, etc. 1175a3667aaeSNaresh Kumar Inna * 1176a3667aaeSNaresh Kumar Inna * We do this in two ways: 1177a3667aaeSNaresh Kumar Inna * 1178a3667aaeSNaresh Kumar Inna * 1. If we're dealing with newer firmware we'll simply want to take 1179a3667aaeSNaresh Kumar Inna * the chip's microprocessor out of RESET. This will cause the 1180a3667aaeSNaresh Kumar Inna * firmware to start up from its start vector. And then we'll loop 1181a3667aaeSNaresh Kumar Inna * until the firmware indicates it's started again (PCIE_FW.HALT 1182a3667aaeSNaresh Kumar Inna * reset to 0) or we timeout. 1183a3667aaeSNaresh Kumar Inna * 1184a3667aaeSNaresh Kumar Inna * 2. If we're dealing with older firmware then we'll need to RESET 1185a3667aaeSNaresh Kumar Inna * the chip since older firmware won't recognize the PCIE_FW.HALT 1186a3667aaeSNaresh Kumar Inna * flag and automatically RESET itself on startup. 1187a3667aaeSNaresh Kumar Inna */ 1188a3667aaeSNaresh Kumar Inna static int 1189a3667aaeSNaresh Kumar Inna csio_hw_fw_restart(struct csio_hw *hw, uint32_t mbox, int32_t reset) 1190a3667aaeSNaresh Kumar Inna { 1191a3667aaeSNaresh Kumar Inna if (reset) { 1192a3667aaeSNaresh Kumar Inna /* 1193a3667aaeSNaresh Kumar Inna * Since we're directing the RESET instead of the firmware 1194a3667aaeSNaresh Kumar Inna * doing it automatically, we need to clear the PCIE_FW.HALT 1195a3667aaeSNaresh Kumar Inna * bit. 1196a3667aaeSNaresh Kumar Inna */ 1197f061de42SHariprasad Shenai csio_set_reg_field(hw, PCIE_FW_A, PCIE_FW_HALT_F, 0); 1198a3667aaeSNaresh Kumar Inna 1199a3667aaeSNaresh Kumar Inna /* 1200a3667aaeSNaresh Kumar Inna * If we've been given a valid mailbox, first try to get the 1201a3667aaeSNaresh Kumar Inna * firmware to do the RESET. If that works, great and we can 1202a3667aaeSNaresh Kumar Inna * return success. Otherwise, if we haven't been given a 1203a3667aaeSNaresh Kumar Inna * valid mailbox or the RESET command failed, fall back to 1204a3667aaeSNaresh Kumar Inna * hitting the chip with a hammer. 1205a3667aaeSNaresh Kumar Inna */ 1206f061de42SHariprasad Shenai if (mbox <= PCIE_FW_MASTER_M) { 120789c3a86cSHariprasad Shenai csio_set_reg_field(hw, CIM_BOOT_CFG_A, UPCRST_F, 0); 1208a3667aaeSNaresh Kumar Inna msleep(100); 1209a3667aaeSNaresh Kumar Inna if (csio_do_reset(hw, true) == 0) 1210a3667aaeSNaresh Kumar Inna return 0; 1211a3667aaeSNaresh Kumar Inna } 1212a3667aaeSNaresh Kumar Inna 12130d804338SHariprasad Shenai csio_wr_reg32(hw, PIORSTMODE_F | PIORST_F, PL_RST_A); 1214a3667aaeSNaresh Kumar Inna msleep(2000); 1215a3667aaeSNaresh Kumar Inna } else { 1216a3667aaeSNaresh Kumar Inna int ms; 1217a3667aaeSNaresh Kumar Inna 121889c3a86cSHariprasad Shenai csio_set_reg_field(hw, CIM_BOOT_CFG_A, UPCRST_F, 0); 1219a3667aaeSNaresh Kumar Inna for (ms = 0; ms < FW_CMD_MAX_TIMEOUT; ) { 1220f061de42SHariprasad Shenai if (!(csio_rd_reg32(hw, PCIE_FW_A) & PCIE_FW_HALT_F)) 1221a3667aaeSNaresh Kumar Inna return 0; 1222a3667aaeSNaresh Kumar Inna msleep(100); 1223a3667aaeSNaresh Kumar Inna ms += 100; 1224a3667aaeSNaresh Kumar Inna } 1225a3667aaeSNaresh Kumar Inna return -ETIMEDOUT; 1226a3667aaeSNaresh Kumar Inna } 1227a3667aaeSNaresh Kumar Inna return 0; 1228a3667aaeSNaresh Kumar Inna } 1229a3667aaeSNaresh Kumar Inna 1230a3667aaeSNaresh Kumar Inna /* 1231a3667aaeSNaresh Kumar Inna * csio_hw_fw_upgrade - perform all of the steps necessary to upgrade FW 1232a3667aaeSNaresh Kumar Inna * @hw: the HW module 1233a3667aaeSNaresh Kumar Inna * @mbox: mailbox to use for the FW RESET command (if desired) 1234a3667aaeSNaresh Kumar Inna * @fw_data: the firmware image to write 1235a3667aaeSNaresh Kumar Inna * @size: image size 1236a3667aaeSNaresh Kumar Inna * @force: force upgrade even if firmware doesn't cooperate 1237a3667aaeSNaresh Kumar Inna * 1238a3667aaeSNaresh Kumar Inna * Perform all of the steps necessary for upgrading an adapter's 1239a3667aaeSNaresh Kumar Inna * firmware image. Normally this requires the cooperation of the 1240a3667aaeSNaresh Kumar Inna * existing firmware in order to halt all existing activities 1241a3667aaeSNaresh Kumar Inna * but if an invalid mailbox token is passed in we skip that step 1242a3667aaeSNaresh Kumar Inna * (though we'll still put the adapter microprocessor into RESET in 1243a3667aaeSNaresh Kumar Inna * that case). 1244a3667aaeSNaresh Kumar Inna * 1245a3667aaeSNaresh Kumar Inna * On successful return the new firmware will have been loaded and 1246a3667aaeSNaresh Kumar Inna * the adapter will have been fully RESET losing all previous setup 1247a3667aaeSNaresh Kumar Inna * state. On unsuccessful return the adapter may be completely hosed ... 1248a3667aaeSNaresh Kumar Inna * positive errno indicates that the adapter is ~probably~ intact, a 1249a3667aaeSNaresh Kumar Inna * negative errno indicates that things are looking bad ... 1250a3667aaeSNaresh Kumar Inna */ 1251a3667aaeSNaresh Kumar Inna static int 1252a3667aaeSNaresh Kumar Inna csio_hw_fw_upgrade(struct csio_hw *hw, uint32_t mbox, 1253a3667aaeSNaresh Kumar Inna const u8 *fw_data, uint32_t size, int32_t force) 1254a3667aaeSNaresh Kumar Inna { 1255a3667aaeSNaresh Kumar Inna const struct fw_hdr *fw_hdr = (const struct fw_hdr *)fw_data; 1256a3667aaeSNaresh Kumar Inna int reset, ret; 1257a3667aaeSNaresh Kumar Inna 1258a3667aaeSNaresh Kumar Inna ret = csio_hw_fw_halt(hw, mbox, force); 1259a3667aaeSNaresh Kumar Inna if (ret != 0 && !force) 1260a3667aaeSNaresh Kumar Inna return ret; 1261a3667aaeSNaresh Kumar Inna 1262a3667aaeSNaresh Kumar Inna ret = csio_hw_fw_dload(hw, (uint8_t *) fw_data, size); 1263a3667aaeSNaresh Kumar Inna if (ret != 0) 1264a3667aaeSNaresh Kumar Inna return ret; 1265a3667aaeSNaresh Kumar Inna 1266a3667aaeSNaresh Kumar Inna /* 1267a3667aaeSNaresh Kumar Inna * Older versions of the firmware don't understand the new 1268a3667aaeSNaresh Kumar Inna * PCIE_FW.HALT flag and so won't know to perform a RESET when they 1269a3667aaeSNaresh Kumar Inna * restart. So for newly loaded older firmware we'll have to do the 1270a3667aaeSNaresh Kumar Inna * RESET for it so it starts up on a clean slate. We can tell if 1271a3667aaeSNaresh Kumar Inna * the newly loaded firmware will handle this right by checking 1272a3667aaeSNaresh Kumar Inna * its header flags to see if it advertises the capability. 1273a3667aaeSNaresh Kumar Inna */ 1274a3667aaeSNaresh Kumar Inna reset = ((ntohl(fw_hdr->flags) & FW_HDR_FLAGS_RESET_HALT) == 0); 1275a3667aaeSNaresh Kumar Inna return csio_hw_fw_restart(hw, mbox, reset); 1276a3667aaeSNaresh Kumar Inna } 1277a3667aaeSNaresh Kumar Inna 1278a3667aaeSNaresh Kumar Inna 1279a3667aaeSNaresh Kumar Inna /* 1280a3667aaeSNaresh Kumar Inna * csio_hw_fw_config_file - setup an adapter via a Configuration File 1281a3667aaeSNaresh Kumar Inna * @hw: the HW module 1282a3667aaeSNaresh Kumar Inna * @mbox: mailbox to use for the FW command 1283a3667aaeSNaresh Kumar Inna * @mtype: the memory type where the Configuration File is located 1284a3667aaeSNaresh Kumar Inna * @maddr: the memory address where the Configuration File is located 1285a3667aaeSNaresh Kumar Inna * @finiver: return value for CF [fini] version 1286a3667aaeSNaresh Kumar Inna * @finicsum: return value for CF [fini] checksum 1287a3667aaeSNaresh Kumar Inna * @cfcsum: return value for CF computed checksum 1288a3667aaeSNaresh Kumar Inna * 1289a3667aaeSNaresh Kumar Inna * Issue a command to get the firmware to process the Configuration 1290a3667aaeSNaresh Kumar Inna * File located at the specified mtype/maddress. If the Configuration 1291a3667aaeSNaresh Kumar Inna * File is processed successfully and return value pointers are 1292a3667aaeSNaresh Kumar Inna * provided, the Configuration File "[fini] section version and 1293a3667aaeSNaresh Kumar Inna * checksum values will be returned along with the computed checksum. 1294a3667aaeSNaresh Kumar Inna * It's up to the caller to decide how it wants to respond to the 1295a3667aaeSNaresh Kumar Inna * checksums not matching but it recommended that a prominant warning 1296a3667aaeSNaresh Kumar Inna * be emitted in order to help people rapidly identify changed or 1297a3667aaeSNaresh Kumar Inna * corrupted Configuration Files. 1298a3667aaeSNaresh Kumar Inna * 1299a3667aaeSNaresh Kumar Inna * Also note that it's possible to modify things like "niccaps", 1300a3667aaeSNaresh Kumar Inna * "toecaps",etc. between processing the Configuration File and telling 1301a3667aaeSNaresh Kumar Inna * the firmware to use the new configuration. Callers which want to 1302a3667aaeSNaresh Kumar Inna * do this will need to "hand-roll" their own CAPS_CONFIGS commands for 1303a3667aaeSNaresh Kumar Inna * Configuration Files if they want to do this. 1304a3667aaeSNaresh Kumar Inna */ 1305a3667aaeSNaresh Kumar Inna static int 1306a3667aaeSNaresh Kumar Inna csio_hw_fw_config_file(struct csio_hw *hw, 1307a3667aaeSNaresh Kumar Inna unsigned int mtype, unsigned int maddr, 1308a3667aaeSNaresh Kumar Inna uint32_t *finiver, uint32_t *finicsum, uint32_t *cfcsum) 1309a3667aaeSNaresh Kumar Inna { 1310a3667aaeSNaresh Kumar Inna struct csio_mb *mbp; 1311a3667aaeSNaresh Kumar Inna struct fw_caps_config_cmd *caps_cmd; 1312a3667aaeSNaresh Kumar Inna int rv = -EINVAL; 1313a3667aaeSNaresh Kumar Inna enum fw_retval ret; 1314a3667aaeSNaresh Kumar Inna 1315a3667aaeSNaresh Kumar Inna mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 1316a3667aaeSNaresh Kumar Inna if (!mbp) { 1317a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_nomem); 1318a3667aaeSNaresh Kumar Inna return -ENOMEM; 1319a3667aaeSNaresh Kumar Inna } 1320a3667aaeSNaresh Kumar Inna /* 1321a3667aaeSNaresh Kumar Inna * Tell the firmware to process the indicated Configuration File. 1322a3667aaeSNaresh Kumar Inna * If there are no errors and the caller has provided return value 1323a3667aaeSNaresh Kumar Inna * pointers for the [fini] section version, checksum and computed 1324a3667aaeSNaresh Kumar Inna * checksum, pass those back to the caller. 1325a3667aaeSNaresh Kumar Inna */ 1326a3667aaeSNaresh Kumar Inna caps_cmd = (struct fw_caps_config_cmd *)(mbp->mb); 1327a3667aaeSNaresh Kumar Inna CSIO_INIT_MBP(mbp, caps_cmd, CSIO_MB_DEFAULT_TMO, hw, NULL, 1); 1328a3667aaeSNaresh Kumar Inna caps_cmd->op_to_write = 1329e2ac9628SHariprasad Shenai htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) | 1330e2ac9628SHariprasad Shenai FW_CMD_REQUEST_F | 1331e2ac9628SHariprasad Shenai FW_CMD_READ_F); 1332a3667aaeSNaresh Kumar Inna caps_cmd->cfvalid_to_len16 = 13335167865aSHariprasad Shenai htonl(FW_CAPS_CONFIG_CMD_CFVALID_F | 13345167865aSHariprasad Shenai FW_CAPS_CONFIG_CMD_MEMTYPE_CF_V(mtype) | 13355167865aSHariprasad Shenai FW_CAPS_CONFIG_CMD_MEMADDR64K_CF_V(maddr >> 16) | 1336a3667aaeSNaresh Kumar Inna FW_LEN16(*caps_cmd)); 1337a3667aaeSNaresh Kumar Inna 1338a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 1339a3667aaeSNaresh Kumar Inna csio_err(hw, "Issue of FW_CAPS_CONFIG_CMD failed!\n"); 1340a3667aaeSNaresh Kumar Inna goto out; 1341a3667aaeSNaresh Kumar Inna } 1342a3667aaeSNaresh Kumar Inna 1343a3667aaeSNaresh Kumar Inna ret = csio_mb_fw_retval(mbp); 1344a3667aaeSNaresh Kumar Inna if (ret != FW_SUCCESS) { 1345a3667aaeSNaresh Kumar Inna csio_dbg(hw, "FW_CAPS_CONFIG_CMD returned %d!\n", rv); 1346a3667aaeSNaresh Kumar Inna goto out; 1347a3667aaeSNaresh Kumar Inna } 1348a3667aaeSNaresh Kumar Inna 1349a3667aaeSNaresh Kumar Inna if (finiver) 1350a3667aaeSNaresh Kumar Inna *finiver = ntohl(caps_cmd->finiver); 1351a3667aaeSNaresh Kumar Inna if (finicsum) 1352a3667aaeSNaresh Kumar Inna *finicsum = ntohl(caps_cmd->finicsum); 1353a3667aaeSNaresh Kumar Inna if (cfcsum) 1354a3667aaeSNaresh Kumar Inna *cfcsum = ntohl(caps_cmd->cfcsum); 1355a3667aaeSNaresh Kumar Inna 1356a3667aaeSNaresh Kumar Inna /* Validate device capabilities */ 1357a3667aaeSNaresh Kumar Inna if (csio_hw_validate_caps(hw, mbp)) { 1358a3667aaeSNaresh Kumar Inna rv = -ENOENT; 1359a3667aaeSNaresh Kumar Inna goto out; 1360a3667aaeSNaresh Kumar Inna } 1361a3667aaeSNaresh Kumar Inna 1362a3667aaeSNaresh Kumar Inna /* 1363a3667aaeSNaresh Kumar Inna * And now tell the firmware to use the configuration we just loaded. 1364a3667aaeSNaresh Kumar Inna */ 1365a3667aaeSNaresh Kumar Inna caps_cmd->op_to_write = 1366e2ac9628SHariprasad Shenai htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) | 1367e2ac9628SHariprasad Shenai FW_CMD_REQUEST_F | 1368e2ac9628SHariprasad Shenai FW_CMD_WRITE_F); 1369a3667aaeSNaresh Kumar Inna caps_cmd->cfvalid_to_len16 = htonl(FW_LEN16(*caps_cmd)); 1370a3667aaeSNaresh Kumar Inna 1371a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 1372a3667aaeSNaresh Kumar Inna csio_err(hw, "Issue of FW_CAPS_CONFIG_CMD failed!\n"); 1373a3667aaeSNaresh Kumar Inna goto out; 1374a3667aaeSNaresh Kumar Inna } 1375a3667aaeSNaresh Kumar Inna 1376a3667aaeSNaresh Kumar Inna ret = csio_mb_fw_retval(mbp); 1377a3667aaeSNaresh Kumar Inna if (ret != FW_SUCCESS) { 1378a3667aaeSNaresh Kumar Inna csio_dbg(hw, "FW_CAPS_CONFIG_CMD returned %d!\n", rv); 1379a3667aaeSNaresh Kumar Inna goto out; 1380a3667aaeSNaresh Kumar Inna } 1381a3667aaeSNaresh Kumar Inna 1382a3667aaeSNaresh Kumar Inna rv = 0; 1383a3667aaeSNaresh Kumar Inna out: 1384a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1385a3667aaeSNaresh Kumar Inna return rv; 1386a3667aaeSNaresh Kumar Inna } 1387a3667aaeSNaresh Kumar Inna 1388a3667aaeSNaresh Kumar Inna /* 1389a3667aaeSNaresh Kumar Inna * csio_get_device_params - Get device parameters. 1390a3667aaeSNaresh Kumar Inna * @hw: HW module 1391a3667aaeSNaresh Kumar Inna * 1392a3667aaeSNaresh Kumar Inna */ 1393a3667aaeSNaresh Kumar Inna static int 1394a3667aaeSNaresh Kumar Inna csio_get_device_params(struct csio_hw *hw) 1395a3667aaeSNaresh Kumar Inna { 1396a3667aaeSNaresh Kumar Inna struct csio_wrm *wrm = csio_hw_to_wrm(hw); 1397a3667aaeSNaresh Kumar Inna struct csio_mb *mbp; 1398a3667aaeSNaresh Kumar Inna enum fw_retval retval; 1399a3667aaeSNaresh Kumar Inna u32 param[6]; 1400a3667aaeSNaresh Kumar Inna int i, j = 0; 1401a3667aaeSNaresh Kumar Inna 1402a3667aaeSNaresh Kumar Inna /* Initialize portids to -1 */ 1403a3667aaeSNaresh Kumar Inna for (i = 0; i < CSIO_MAX_PPORTS; i++) 1404a3667aaeSNaresh Kumar Inna hw->pport[i].portid = -1; 1405a3667aaeSNaresh Kumar Inna 1406a3667aaeSNaresh Kumar Inna mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 1407a3667aaeSNaresh Kumar Inna if (!mbp) { 1408a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_nomem); 1409a3667aaeSNaresh Kumar Inna return -ENOMEM; 1410a3667aaeSNaresh Kumar Inna } 1411a3667aaeSNaresh Kumar Inna 1412a3667aaeSNaresh Kumar Inna /* Get port vec information. */ 1413a3667aaeSNaresh Kumar Inna param[0] = FW_PARAM_DEV(PORTVEC); 1414a3667aaeSNaresh Kumar Inna 1415a3667aaeSNaresh Kumar Inna /* Get Core clock. */ 1416a3667aaeSNaresh Kumar Inna param[1] = FW_PARAM_DEV(CCLK); 1417a3667aaeSNaresh Kumar Inna 1418a3667aaeSNaresh Kumar Inna /* Get EQ id start and end. */ 1419a3667aaeSNaresh Kumar Inna param[2] = FW_PARAM_PFVF(EQ_START); 1420a3667aaeSNaresh Kumar Inna param[3] = FW_PARAM_PFVF(EQ_END); 1421a3667aaeSNaresh Kumar Inna 1422a3667aaeSNaresh Kumar Inna /* Get IQ id start and end. */ 1423a3667aaeSNaresh Kumar Inna param[4] = FW_PARAM_PFVF(IQFLINT_START); 1424a3667aaeSNaresh Kumar Inna param[5] = FW_PARAM_PFVF(IQFLINT_END); 1425a3667aaeSNaresh Kumar Inna 1426a3667aaeSNaresh Kumar Inna csio_mb_params(hw, mbp, CSIO_MB_DEFAULT_TMO, hw->pfn, 0, 1427a3667aaeSNaresh Kumar Inna ARRAY_SIZE(param), param, NULL, false, NULL); 1428a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 1429a3667aaeSNaresh Kumar Inna csio_err(hw, "Issue of FW_PARAMS_CMD(read) failed!\n"); 1430a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1431a3667aaeSNaresh Kumar Inna return -EINVAL; 1432a3667aaeSNaresh Kumar Inna } 1433a3667aaeSNaresh Kumar Inna 1434a3667aaeSNaresh Kumar Inna csio_mb_process_read_params_rsp(hw, mbp, &retval, 1435a3667aaeSNaresh Kumar Inna ARRAY_SIZE(param), param); 1436a3667aaeSNaresh Kumar Inna if (retval != FW_SUCCESS) { 1437a3667aaeSNaresh Kumar Inna csio_err(hw, "FW_PARAMS_CMD(read) failed with ret:0x%x!\n", 1438a3667aaeSNaresh Kumar Inna retval); 1439a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1440a3667aaeSNaresh Kumar Inna return -EINVAL; 1441a3667aaeSNaresh Kumar Inna } 1442a3667aaeSNaresh Kumar Inna 1443a3667aaeSNaresh Kumar Inna /* cache the information. */ 1444a3667aaeSNaresh Kumar Inna hw->port_vec = param[0]; 1445a3667aaeSNaresh Kumar Inna hw->vpd.cclk = param[1]; 1446a3667aaeSNaresh Kumar Inna wrm->fw_eq_start = param[2]; 1447a3667aaeSNaresh Kumar Inna wrm->fw_iq_start = param[4]; 1448a3667aaeSNaresh Kumar Inna 1449a3667aaeSNaresh Kumar Inna /* Using FW configured max iqs & eqs */ 1450a3667aaeSNaresh Kumar Inna if ((hw->flags & CSIO_HWF_USING_SOFT_PARAMS) || 1451a3667aaeSNaresh Kumar Inna !csio_is_hw_master(hw)) { 1452a3667aaeSNaresh Kumar Inna hw->cfg_niq = param[5] - param[4] + 1; 1453a3667aaeSNaresh Kumar Inna hw->cfg_neq = param[3] - param[2] + 1; 1454a3667aaeSNaresh Kumar Inna csio_dbg(hw, "Using fwconfig max niqs %d neqs %d\n", 1455a3667aaeSNaresh Kumar Inna hw->cfg_niq, hw->cfg_neq); 1456a3667aaeSNaresh Kumar Inna } 1457a3667aaeSNaresh Kumar Inna 1458a3667aaeSNaresh Kumar Inna hw->port_vec &= csio_port_mask; 1459a3667aaeSNaresh Kumar Inna 1460a3667aaeSNaresh Kumar Inna hw->num_pports = hweight32(hw->port_vec); 1461a3667aaeSNaresh Kumar Inna 1462a3667aaeSNaresh Kumar Inna csio_dbg(hw, "Port vector: 0x%x, #ports: %d\n", 1463a3667aaeSNaresh Kumar Inna hw->port_vec, hw->num_pports); 1464a3667aaeSNaresh Kumar Inna 1465a3667aaeSNaresh Kumar Inna for (i = 0; i < hw->num_pports; i++) { 1466a3667aaeSNaresh Kumar Inna while ((hw->port_vec & (1 << j)) == 0) 1467a3667aaeSNaresh Kumar Inna j++; 1468a3667aaeSNaresh Kumar Inna hw->pport[i].portid = j++; 1469a3667aaeSNaresh Kumar Inna csio_dbg(hw, "Found Port:%d\n", hw->pport[i].portid); 1470a3667aaeSNaresh Kumar Inna } 1471a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1472a3667aaeSNaresh Kumar Inna 1473a3667aaeSNaresh Kumar Inna return 0; 1474a3667aaeSNaresh Kumar Inna } 1475a3667aaeSNaresh Kumar Inna 1476a3667aaeSNaresh Kumar Inna 1477a3667aaeSNaresh Kumar Inna /* 1478a3667aaeSNaresh Kumar Inna * csio_config_device_caps - Get and set device capabilities. 1479a3667aaeSNaresh Kumar Inna * @hw: HW module 1480a3667aaeSNaresh Kumar Inna * 1481a3667aaeSNaresh Kumar Inna */ 1482a3667aaeSNaresh Kumar Inna static int 1483a3667aaeSNaresh Kumar Inna csio_config_device_caps(struct csio_hw *hw) 1484a3667aaeSNaresh Kumar Inna { 1485a3667aaeSNaresh Kumar Inna struct csio_mb *mbp; 1486a3667aaeSNaresh Kumar Inna enum fw_retval retval; 1487a3667aaeSNaresh Kumar Inna int rv = -EINVAL; 1488a3667aaeSNaresh Kumar Inna 1489a3667aaeSNaresh Kumar Inna mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 1490a3667aaeSNaresh Kumar Inna if (!mbp) { 1491a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_nomem); 1492a3667aaeSNaresh Kumar Inna return -ENOMEM; 1493a3667aaeSNaresh Kumar Inna } 1494a3667aaeSNaresh Kumar Inna 1495a3667aaeSNaresh Kumar Inna /* Get device capabilities */ 1496a3667aaeSNaresh Kumar Inna csio_mb_caps_config(hw, mbp, CSIO_MB_DEFAULT_TMO, 0, 0, 0, 0, NULL); 1497a3667aaeSNaresh Kumar Inna 1498a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 1499a3667aaeSNaresh Kumar Inna csio_err(hw, "Issue of FW_CAPS_CONFIG_CMD(r) failed!\n"); 1500a3667aaeSNaresh Kumar Inna goto out; 1501a3667aaeSNaresh Kumar Inna } 1502a3667aaeSNaresh Kumar Inna 1503a3667aaeSNaresh Kumar Inna retval = csio_mb_fw_retval(mbp); 1504a3667aaeSNaresh Kumar Inna if (retval != FW_SUCCESS) { 1505a3667aaeSNaresh Kumar Inna csio_err(hw, "FW_CAPS_CONFIG_CMD(r) returned %d!\n", retval); 1506a3667aaeSNaresh Kumar Inna goto out; 1507a3667aaeSNaresh Kumar Inna } 1508a3667aaeSNaresh Kumar Inna 1509a3667aaeSNaresh Kumar Inna /* Validate device capabilities */ 1510a3667aaeSNaresh Kumar Inna if (csio_hw_validate_caps(hw, mbp)) 1511a3667aaeSNaresh Kumar Inna goto out; 1512a3667aaeSNaresh Kumar Inna 1513a3667aaeSNaresh Kumar Inna /* Don't config device capabilities if already configured */ 1514a3667aaeSNaresh Kumar Inna if (hw->fw_state == CSIO_DEV_STATE_INIT) { 1515a3667aaeSNaresh Kumar Inna rv = 0; 1516a3667aaeSNaresh Kumar Inna goto out; 1517a3667aaeSNaresh Kumar Inna } 1518a3667aaeSNaresh Kumar Inna 1519a3667aaeSNaresh Kumar Inna /* Write back desired device capabilities */ 1520a3667aaeSNaresh Kumar Inna csio_mb_caps_config(hw, mbp, CSIO_MB_DEFAULT_TMO, true, true, 1521a3667aaeSNaresh Kumar Inna false, true, NULL); 1522a3667aaeSNaresh Kumar Inna 1523a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 1524a3667aaeSNaresh Kumar Inna csio_err(hw, "Issue of FW_CAPS_CONFIG_CMD(w) failed!\n"); 1525a3667aaeSNaresh Kumar Inna goto out; 1526a3667aaeSNaresh Kumar Inna } 1527a3667aaeSNaresh Kumar Inna 1528a3667aaeSNaresh Kumar Inna retval = csio_mb_fw_retval(mbp); 1529a3667aaeSNaresh Kumar Inna if (retval != FW_SUCCESS) { 1530a3667aaeSNaresh Kumar Inna csio_err(hw, "FW_CAPS_CONFIG_CMD(w) returned %d!\n", retval); 1531a3667aaeSNaresh Kumar Inna goto out; 1532a3667aaeSNaresh Kumar Inna } 1533a3667aaeSNaresh Kumar Inna 1534a3667aaeSNaresh Kumar Inna rv = 0; 1535a3667aaeSNaresh Kumar Inna out: 1536a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1537a3667aaeSNaresh Kumar Inna return rv; 1538a3667aaeSNaresh Kumar Inna } 1539a3667aaeSNaresh Kumar Inna 1540a3667aaeSNaresh Kumar Inna /* 1541a3667aaeSNaresh Kumar Inna * csio_enable_ports - Bring up all available ports. 1542a3667aaeSNaresh Kumar Inna * @hw: HW module. 1543a3667aaeSNaresh Kumar Inna * 1544a3667aaeSNaresh Kumar Inna */ 1545a3667aaeSNaresh Kumar Inna static int 1546a3667aaeSNaresh Kumar Inna csio_enable_ports(struct csio_hw *hw) 1547a3667aaeSNaresh Kumar Inna { 1548a3667aaeSNaresh Kumar Inna struct csio_mb *mbp; 1549a3667aaeSNaresh Kumar Inna enum fw_retval retval; 1550a3667aaeSNaresh Kumar Inna uint8_t portid; 1551a3667aaeSNaresh Kumar Inna int i; 1552a3667aaeSNaresh Kumar Inna 1553a3667aaeSNaresh Kumar Inna mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 1554a3667aaeSNaresh Kumar Inna if (!mbp) { 1555a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_nomem); 1556a3667aaeSNaresh Kumar Inna return -ENOMEM; 1557a3667aaeSNaresh Kumar Inna } 1558a3667aaeSNaresh Kumar Inna 1559a3667aaeSNaresh Kumar Inna for (i = 0; i < hw->num_pports; i++) { 1560a3667aaeSNaresh Kumar Inna portid = hw->pport[i].portid; 1561a3667aaeSNaresh Kumar Inna 1562a3667aaeSNaresh Kumar Inna /* Read PORT information */ 1563a3667aaeSNaresh Kumar Inna csio_mb_port(hw, mbp, CSIO_MB_DEFAULT_TMO, portid, 1564a3667aaeSNaresh Kumar Inna false, 0, 0, NULL); 1565a3667aaeSNaresh Kumar Inna 1566a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 1567a3667aaeSNaresh Kumar Inna csio_err(hw, "failed to issue FW_PORT_CMD(r) port:%d\n", 1568a3667aaeSNaresh Kumar Inna portid); 1569a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1570a3667aaeSNaresh Kumar Inna return -EINVAL; 1571a3667aaeSNaresh Kumar Inna } 1572a3667aaeSNaresh Kumar Inna 1573a3667aaeSNaresh Kumar Inna csio_mb_process_read_port_rsp(hw, mbp, &retval, 1574a3667aaeSNaresh Kumar Inna &hw->pport[i].pcap); 1575a3667aaeSNaresh Kumar Inna if (retval != FW_SUCCESS) { 1576a3667aaeSNaresh Kumar Inna csio_err(hw, "FW_PORT_CMD(r) port:%d failed: 0x%x\n", 1577a3667aaeSNaresh Kumar Inna portid, retval); 1578a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1579a3667aaeSNaresh Kumar Inna return -EINVAL; 1580a3667aaeSNaresh Kumar Inna } 1581a3667aaeSNaresh Kumar Inna 1582a3667aaeSNaresh Kumar Inna /* Write back PORT information */ 1583a3667aaeSNaresh Kumar Inna csio_mb_port(hw, mbp, CSIO_MB_DEFAULT_TMO, portid, true, 1584a3667aaeSNaresh Kumar Inna (PAUSE_RX | PAUSE_TX), hw->pport[i].pcap, NULL); 1585a3667aaeSNaresh Kumar Inna 1586a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 1587a3667aaeSNaresh Kumar Inna csio_err(hw, "failed to issue FW_PORT_CMD(w) port:%d\n", 1588a3667aaeSNaresh Kumar Inna portid); 1589a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1590a3667aaeSNaresh Kumar Inna return -EINVAL; 1591a3667aaeSNaresh Kumar Inna } 1592a3667aaeSNaresh Kumar Inna 1593a3667aaeSNaresh Kumar Inna retval = csio_mb_fw_retval(mbp); 1594a3667aaeSNaresh Kumar Inna if (retval != FW_SUCCESS) { 1595a3667aaeSNaresh Kumar Inna csio_err(hw, "FW_PORT_CMD(w) port:%d failed :0x%x\n", 1596a3667aaeSNaresh Kumar Inna portid, retval); 1597a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1598a3667aaeSNaresh Kumar Inna return -EINVAL; 1599a3667aaeSNaresh Kumar Inna } 1600a3667aaeSNaresh Kumar Inna 1601a3667aaeSNaresh Kumar Inna } /* For all ports */ 1602a3667aaeSNaresh Kumar Inna 1603a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1604a3667aaeSNaresh Kumar Inna 1605a3667aaeSNaresh Kumar Inna return 0; 1606a3667aaeSNaresh Kumar Inna } 1607a3667aaeSNaresh Kumar Inna 1608a3667aaeSNaresh Kumar Inna /* 1609a3667aaeSNaresh Kumar Inna * csio_get_fcoe_resinfo - Read fcoe fw resource info. 1610a3667aaeSNaresh Kumar Inna * @hw: HW module 1611a3667aaeSNaresh Kumar Inna * Issued with lock held. 1612a3667aaeSNaresh Kumar Inna */ 1613a3667aaeSNaresh Kumar Inna static int 1614a3667aaeSNaresh Kumar Inna csio_get_fcoe_resinfo(struct csio_hw *hw) 1615a3667aaeSNaresh Kumar Inna { 1616a3667aaeSNaresh Kumar Inna struct csio_fcoe_res_info *res_info = &hw->fres_info; 1617a3667aaeSNaresh Kumar Inna struct fw_fcoe_res_info_cmd *rsp; 1618a3667aaeSNaresh Kumar Inna struct csio_mb *mbp; 1619a3667aaeSNaresh Kumar Inna enum fw_retval retval; 1620a3667aaeSNaresh Kumar Inna 1621a3667aaeSNaresh Kumar Inna mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 1622a3667aaeSNaresh Kumar Inna if (!mbp) { 1623a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_nomem); 1624a3667aaeSNaresh Kumar Inna return -ENOMEM; 1625a3667aaeSNaresh Kumar Inna } 1626a3667aaeSNaresh Kumar Inna 1627a3667aaeSNaresh Kumar Inna /* Get FCoE FW resource information */ 1628a3667aaeSNaresh Kumar Inna csio_fcoe_read_res_info_init_mb(hw, mbp, CSIO_MB_DEFAULT_TMO, NULL); 1629a3667aaeSNaresh Kumar Inna 1630a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 1631a3667aaeSNaresh Kumar Inna csio_err(hw, "failed to issue FW_FCOE_RES_INFO_CMD\n"); 1632a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1633a3667aaeSNaresh Kumar Inna return -EINVAL; 1634a3667aaeSNaresh Kumar Inna } 1635a3667aaeSNaresh Kumar Inna 1636a3667aaeSNaresh Kumar Inna rsp = (struct fw_fcoe_res_info_cmd *)(mbp->mb); 1637e2ac9628SHariprasad Shenai retval = FW_CMD_RETVAL_G(ntohl(rsp->retval_len16)); 1638a3667aaeSNaresh Kumar Inna if (retval != FW_SUCCESS) { 1639a3667aaeSNaresh Kumar Inna csio_err(hw, "FW_FCOE_RES_INFO_CMD failed with ret x%x\n", 1640a3667aaeSNaresh Kumar Inna retval); 1641a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1642a3667aaeSNaresh Kumar Inna return -EINVAL; 1643a3667aaeSNaresh Kumar Inna } 1644a3667aaeSNaresh Kumar Inna 1645a3667aaeSNaresh Kumar Inna res_info->e_d_tov = ntohs(rsp->e_d_tov); 1646a3667aaeSNaresh Kumar Inna res_info->r_a_tov_seq = ntohs(rsp->r_a_tov_seq); 1647a3667aaeSNaresh Kumar Inna res_info->r_a_tov_els = ntohs(rsp->r_a_tov_els); 1648a3667aaeSNaresh Kumar Inna res_info->r_r_tov = ntohs(rsp->r_r_tov); 1649a3667aaeSNaresh Kumar Inna res_info->max_xchgs = ntohl(rsp->max_xchgs); 1650a3667aaeSNaresh Kumar Inna res_info->max_ssns = ntohl(rsp->max_ssns); 1651a3667aaeSNaresh Kumar Inna res_info->used_xchgs = ntohl(rsp->used_xchgs); 1652a3667aaeSNaresh Kumar Inna res_info->used_ssns = ntohl(rsp->used_ssns); 1653a3667aaeSNaresh Kumar Inna res_info->max_fcfs = ntohl(rsp->max_fcfs); 1654a3667aaeSNaresh Kumar Inna res_info->max_vnps = ntohl(rsp->max_vnps); 1655a3667aaeSNaresh Kumar Inna res_info->used_fcfs = ntohl(rsp->used_fcfs); 1656a3667aaeSNaresh Kumar Inna res_info->used_vnps = ntohl(rsp->used_vnps); 1657a3667aaeSNaresh Kumar Inna 1658a3667aaeSNaresh Kumar Inna csio_dbg(hw, "max ssns:%d max xchgs:%d\n", res_info->max_ssns, 1659a3667aaeSNaresh Kumar Inna res_info->max_xchgs); 1660a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1661a3667aaeSNaresh Kumar Inna 1662a3667aaeSNaresh Kumar Inna return 0; 1663a3667aaeSNaresh Kumar Inna } 1664a3667aaeSNaresh Kumar Inna 1665a3667aaeSNaresh Kumar Inna static int 1666a3667aaeSNaresh Kumar Inna csio_hw_check_fwconfig(struct csio_hw *hw, u32 *param) 1667a3667aaeSNaresh Kumar Inna { 1668a3667aaeSNaresh Kumar Inna struct csio_mb *mbp; 1669a3667aaeSNaresh Kumar Inna enum fw_retval retval; 1670a3667aaeSNaresh Kumar Inna u32 _param[1]; 1671a3667aaeSNaresh Kumar Inna 1672a3667aaeSNaresh Kumar Inna mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 1673a3667aaeSNaresh Kumar Inna if (!mbp) { 1674a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_nomem); 1675a3667aaeSNaresh Kumar Inna return -ENOMEM; 1676a3667aaeSNaresh Kumar Inna } 1677a3667aaeSNaresh Kumar Inna 1678a3667aaeSNaresh Kumar Inna /* 1679a3667aaeSNaresh Kumar Inna * Find out whether we're dealing with a version of 1680a3667aaeSNaresh Kumar Inna * the firmware which has configuration file support. 1681a3667aaeSNaresh Kumar Inna */ 16825167865aSHariprasad Shenai _param[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | 16835167865aSHariprasad Shenai FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_CF)); 1684a3667aaeSNaresh Kumar Inna 1685a3667aaeSNaresh Kumar Inna csio_mb_params(hw, mbp, CSIO_MB_DEFAULT_TMO, hw->pfn, 0, 1686a3667aaeSNaresh Kumar Inna ARRAY_SIZE(_param), _param, NULL, false, NULL); 1687a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 1688a3667aaeSNaresh Kumar Inna csio_err(hw, "Issue of FW_PARAMS_CMD(read) failed!\n"); 1689a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1690a3667aaeSNaresh Kumar Inna return -EINVAL; 1691a3667aaeSNaresh Kumar Inna } 1692a3667aaeSNaresh Kumar Inna 1693a3667aaeSNaresh Kumar Inna csio_mb_process_read_params_rsp(hw, mbp, &retval, 1694a3667aaeSNaresh Kumar Inna ARRAY_SIZE(_param), _param); 1695a3667aaeSNaresh Kumar Inna if (retval != FW_SUCCESS) { 1696a3667aaeSNaresh Kumar Inna csio_err(hw, "FW_PARAMS_CMD(read) failed with ret:0x%x!\n", 1697a3667aaeSNaresh Kumar Inna retval); 1698a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1699a3667aaeSNaresh Kumar Inna return -EINVAL; 1700a3667aaeSNaresh Kumar Inna } 1701a3667aaeSNaresh Kumar Inna 1702a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1703a3667aaeSNaresh Kumar Inna *param = _param[0]; 1704a3667aaeSNaresh Kumar Inna 1705a3667aaeSNaresh Kumar Inna return 0; 1706a3667aaeSNaresh Kumar Inna } 1707a3667aaeSNaresh Kumar Inna 1708a3667aaeSNaresh Kumar Inna static int 1709a3667aaeSNaresh Kumar Inna csio_hw_flash_config(struct csio_hw *hw, u32 *fw_cfg_param, char *path) 1710a3667aaeSNaresh Kumar Inna { 1711a3667aaeSNaresh Kumar Inna int ret = 0; 1712a3667aaeSNaresh Kumar Inna const struct firmware *cf; 1713a3667aaeSNaresh Kumar Inna struct pci_dev *pci_dev = hw->pdev; 1714a3667aaeSNaresh Kumar Inna struct device *dev = &pci_dev->dev; 1715a3667aaeSNaresh Kumar Inna unsigned int mtype = 0, maddr = 0; 1716a3667aaeSNaresh Kumar Inna uint32_t *cfg_data; 1717a3667aaeSNaresh Kumar Inna int value_to_add = 0; 1718a3667aaeSNaresh Kumar Inna 17197cc16380SArvind Bhushan if (request_firmware(&cf, CSIO_CF_FNAME(hw), dev) < 0) { 17207cc16380SArvind Bhushan csio_err(hw, "could not find config file %s, err: %d\n", 17217cc16380SArvind Bhushan CSIO_CF_FNAME(hw), ret); 1722a3667aaeSNaresh Kumar Inna return -ENOENT; 1723a3667aaeSNaresh Kumar Inna } 1724a3667aaeSNaresh Kumar Inna 1725a3667aaeSNaresh Kumar Inna if (cf->size%4 != 0) 1726a3667aaeSNaresh Kumar Inna value_to_add = 4 - (cf->size % 4); 1727a3667aaeSNaresh Kumar Inna 1728a3667aaeSNaresh Kumar Inna cfg_data = kzalloc(cf->size+value_to_add, GFP_KERNEL); 172902db3db5SJesper Juhl if (cfg_data == NULL) { 173002db3db5SJesper Juhl ret = -ENOMEM; 173102db3db5SJesper Juhl goto leave; 173202db3db5SJesper Juhl } 1733a3667aaeSNaresh Kumar Inna 1734a3667aaeSNaresh Kumar Inna memcpy((void *)cfg_data, (const void *)cf->data, cf->size); 173502db3db5SJesper Juhl if (csio_hw_check_fwconfig(hw, fw_cfg_param) != 0) { 173602db3db5SJesper Juhl ret = -EINVAL; 173702db3db5SJesper Juhl goto leave; 173802db3db5SJesper Juhl } 1739a3667aaeSNaresh Kumar Inna 17405167865aSHariprasad Shenai mtype = FW_PARAMS_PARAM_Y_G(*fw_cfg_param); 17415167865aSHariprasad Shenai maddr = FW_PARAMS_PARAM_Z_G(*fw_cfg_param) << 16; 1742a3667aaeSNaresh Kumar Inna 1743a3667aaeSNaresh Kumar Inna ret = csio_memory_write(hw, mtype, maddr, 1744a3667aaeSNaresh Kumar Inna cf->size + value_to_add, cfg_data); 17457cc16380SArvind Bhushan 17467cc16380SArvind Bhushan if ((ret == 0) && (value_to_add != 0)) { 17477cc16380SArvind Bhushan union { 17487cc16380SArvind Bhushan u32 word; 17497cc16380SArvind Bhushan char buf[4]; 17507cc16380SArvind Bhushan } last; 17517cc16380SArvind Bhushan size_t size = cf->size & ~0x3; 17527cc16380SArvind Bhushan int i; 17537cc16380SArvind Bhushan 17547cc16380SArvind Bhushan last.word = cfg_data[size >> 2]; 17557cc16380SArvind Bhushan for (i = value_to_add; i < 4; i++) 17567cc16380SArvind Bhushan last.buf[i] = 0; 17577cc16380SArvind Bhushan ret = csio_memory_write(hw, mtype, maddr + size, 4, &last.word); 17587cc16380SArvind Bhushan } 1759a3667aaeSNaresh Kumar Inna if (ret == 0) { 17607cc16380SArvind Bhushan csio_info(hw, "config file upgraded to %s\n", 17617cc16380SArvind Bhushan CSIO_CF_FNAME(hw)); 17627cc16380SArvind Bhushan snprintf(path, 64, "%s%s", "/lib/firmware/", CSIO_CF_FNAME(hw)); 1763a3667aaeSNaresh Kumar Inna } 1764a3667aaeSNaresh Kumar Inna 176502db3db5SJesper Juhl leave: 1766a3667aaeSNaresh Kumar Inna kfree(cfg_data); 1767a3667aaeSNaresh Kumar Inna release_firmware(cf); 1768a3667aaeSNaresh Kumar Inna return ret; 1769a3667aaeSNaresh Kumar Inna } 1770a3667aaeSNaresh Kumar Inna 1771a3667aaeSNaresh Kumar Inna /* 1772a3667aaeSNaresh Kumar Inna * HW initialization: contact FW, obtain config, perform basic init. 1773a3667aaeSNaresh Kumar Inna * 1774a3667aaeSNaresh Kumar Inna * If the firmware we're dealing with has Configuration File support, then 1775a3667aaeSNaresh Kumar Inna * we use that to perform all configuration -- either using the configuration 1776a3667aaeSNaresh Kumar Inna * file stored in flash on the adapter or using a filesystem-local file 1777a3667aaeSNaresh Kumar Inna * if available. 1778a3667aaeSNaresh Kumar Inna * 1779a3667aaeSNaresh Kumar Inna * If we don't have configuration file support in the firmware, then we'll 1780a3667aaeSNaresh Kumar Inna * have to set things up the old fashioned way with hard-coded register 1781a3667aaeSNaresh Kumar Inna * writes and firmware commands ... 1782a3667aaeSNaresh Kumar Inna */ 1783a3667aaeSNaresh Kumar Inna 1784a3667aaeSNaresh Kumar Inna /* 1785a3667aaeSNaresh Kumar Inna * Attempt to initialize the HW via a Firmware Configuration File. 1786a3667aaeSNaresh Kumar Inna */ 1787a3667aaeSNaresh Kumar Inna static int 1788a3667aaeSNaresh Kumar Inna csio_hw_use_fwconfig(struct csio_hw *hw, int reset, u32 *fw_cfg_param) 1789a3667aaeSNaresh Kumar Inna { 1790a3667aaeSNaresh Kumar Inna unsigned int mtype, maddr; 1791a3667aaeSNaresh Kumar Inna int rv; 17927cc16380SArvind Bhushan uint32_t finiver = 0, finicsum = 0, cfcsum = 0; 1793a3667aaeSNaresh Kumar Inna int using_flash; 1794a3667aaeSNaresh Kumar Inna char path[64]; 1795a3667aaeSNaresh Kumar Inna 1796a3667aaeSNaresh Kumar Inna /* 1797a3667aaeSNaresh Kumar Inna * Reset device if necessary 1798a3667aaeSNaresh Kumar Inna */ 1799a3667aaeSNaresh Kumar Inna if (reset) { 1800a3667aaeSNaresh Kumar Inna rv = csio_do_reset(hw, true); 1801a3667aaeSNaresh Kumar Inna if (rv != 0) 1802a3667aaeSNaresh Kumar Inna goto bye; 1803a3667aaeSNaresh Kumar Inna } 1804a3667aaeSNaresh Kumar Inna 1805a3667aaeSNaresh Kumar Inna /* 1806a3667aaeSNaresh Kumar Inna * If we have a configuration file in host , 1807a3667aaeSNaresh Kumar Inna * then use that. Otherwise, use the configuration file stored 1808a3667aaeSNaresh Kumar Inna * in the HW flash ... 1809a3667aaeSNaresh Kumar Inna */ 1810a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 1811a3667aaeSNaresh Kumar Inna rv = csio_hw_flash_config(hw, fw_cfg_param, path); 1812a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 1813a3667aaeSNaresh Kumar Inna if (rv != 0) { 1814a3667aaeSNaresh Kumar Inna if (rv == -ENOENT) { 1815a3667aaeSNaresh Kumar Inna /* 1816a3667aaeSNaresh Kumar Inna * config file was not found. Use default 1817a3667aaeSNaresh Kumar Inna * config file from flash. 1818a3667aaeSNaresh Kumar Inna */ 1819a3667aaeSNaresh Kumar Inna mtype = FW_MEMTYPE_CF_FLASH; 18207cc16380SArvind Bhushan maddr = hw->chip_ops->chip_flash_cfg_addr(hw); 1821a3667aaeSNaresh Kumar Inna using_flash = 1; 1822a3667aaeSNaresh Kumar Inna } else { 1823a3667aaeSNaresh Kumar Inna /* 1824a3667aaeSNaresh Kumar Inna * we revert back to the hardwired config if 1825a3667aaeSNaresh Kumar Inna * flashing failed. 1826a3667aaeSNaresh Kumar Inna */ 1827a3667aaeSNaresh Kumar Inna goto bye; 1828a3667aaeSNaresh Kumar Inna } 1829a3667aaeSNaresh Kumar Inna } else { 18305167865aSHariprasad Shenai mtype = FW_PARAMS_PARAM_Y_G(*fw_cfg_param); 18315167865aSHariprasad Shenai maddr = FW_PARAMS_PARAM_Z_G(*fw_cfg_param) << 16; 1832a3667aaeSNaresh Kumar Inna using_flash = 0; 1833a3667aaeSNaresh Kumar Inna } 1834a3667aaeSNaresh Kumar Inna 1835a3667aaeSNaresh Kumar Inna hw->cfg_store = (uint8_t)mtype; 1836a3667aaeSNaresh Kumar Inna 1837a3667aaeSNaresh Kumar Inna /* 1838a3667aaeSNaresh Kumar Inna * Issue a Capability Configuration command to the firmware to get it 1839a3667aaeSNaresh Kumar Inna * to parse the Configuration File. 1840a3667aaeSNaresh Kumar Inna */ 1841a3667aaeSNaresh Kumar Inna rv = csio_hw_fw_config_file(hw, mtype, maddr, &finiver, 1842a3667aaeSNaresh Kumar Inna &finicsum, &cfcsum); 1843a3667aaeSNaresh Kumar Inna if (rv != 0) 1844a3667aaeSNaresh Kumar Inna goto bye; 1845a3667aaeSNaresh Kumar Inna 1846a3667aaeSNaresh Kumar Inna hw->cfg_finiver = finiver; 1847a3667aaeSNaresh Kumar Inna hw->cfg_finicsum = finicsum; 1848a3667aaeSNaresh Kumar Inna hw->cfg_cfcsum = cfcsum; 1849a3667aaeSNaresh Kumar Inna hw->cfg_csum_status = true; 1850a3667aaeSNaresh Kumar Inna 1851a3667aaeSNaresh Kumar Inna if (finicsum != cfcsum) { 1852a3667aaeSNaresh Kumar Inna csio_warn(hw, 1853a3667aaeSNaresh Kumar Inna "Config File checksum mismatch: csum=%#x, computed=%#x\n", 1854a3667aaeSNaresh Kumar Inna finicsum, cfcsum); 1855a3667aaeSNaresh Kumar Inna 1856a3667aaeSNaresh Kumar Inna hw->cfg_csum_status = false; 1857a3667aaeSNaresh Kumar Inna } 1858a3667aaeSNaresh Kumar Inna 1859a3667aaeSNaresh Kumar Inna /* 1860a3667aaeSNaresh Kumar Inna * Note that we're operating with parameters 1861a3667aaeSNaresh Kumar Inna * not supplied by the driver, rather than from hard-wired 1862a3667aaeSNaresh Kumar Inna * initialization constants buried in the driver. 1863a3667aaeSNaresh Kumar Inna */ 1864a3667aaeSNaresh Kumar Inna hw->flags |= CSIO_HWF_USING_SOFT_PARAMS; 1865a3667aaeSNaresh Kumar Inna 1866a3667aaeSNaresh Kumar Inna /* device parameters */ 1867a3667aaeSNaresh Kumar Inna rv = csio_get_device_params(hw); 1868a3667aaeSNaresh Kumar Inna if (rv != 0) 1869a3667aaeSNaresh Kumar Inna goto bye; 1870a3667aaeSNaresh Kumar Inna 1871a3667aaeSNaresh Kumar Inna /* Configure SGE */ 1872a3667aaeSNaresh Kumar Inna csio_wr_sge_init(hw); 1873a3667aaeSNaresh Kumar Inna 1874a3667aaeSNaresh Kumar Inna /* 1875a3667aaeSNaresh Kumar Inna * And finally tell the firmware to initialize itself using the 1876a3667aaeSNaresh Kumar Inna * parameters from the Configuration File. 1877a3667aaeSNaresh Kumar Inna */ 1878a3667aaeSNaresh Kumar Inna /* Post event to notify completion of configuration */ 1879a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_INIT); 1880a3667aaeSNaresh Kumar Inna 1881a3667aaeSNaresh Kumar Inna csio_info(hw, 1882a3667aaeSNaresh Kumar Inna "Firmware Configuration File %s, version %#x, computed checksum %#x\n", 1883a3667aaeSNaresh Kumar Inna (using_flash ? "in device FLASH" : path), finiver, cfcsum); 1884a3667aaeSNaresh Kumar Inna 1885a3667aaeSNaresh Kumar Inna return 0; 1886a3667aaeSNaresh Kumar Inna 1887a3667aaeSNaresh Kumar Inna /* 1888a3667aaeSNaresh Kumar Inna * Something bad happened. Return the error ... 1889a3667aaeSNaresh Kumar Inna */ 1890a3667aaeSNaresh Kumar Inna bye: 1891a3667aaeSNaresh Kumar Inna hw->flags &= ~CSIO_HWF_USING_SOFT_PARAMS; 1892a3667aaeSNaresh Kumar Inna csio_dbg(hw, "Configuration file error %d\n", rv); 1893a3667aaeSNaresh Kumar Inna return rv; 1894a3667aaeSNaresh Kumar Inna } 1895a3667aaeSNaresh Kumar Inna 1896a3667aaeSNaresh Kumar Inna /* 1897a3667aaeSNaresh Kumar Inna * Attempt to initialize the adapter via hard-coded, driver supplied 1898a3667aaeSNaresh Kumar Inna * parameters ... 1899a3667aaeSNaresh Kumar Inna */ 1900a3667aaeSNaresh Kumar Inna static int 1901a3667aaeSNaresh Kumar Inna csio_hw_no_fwconfig(struct csio_hw *hw, int reset) 1902a3667aaeSNaresh Kumar Inna { 1903a3667aaeSNaresh Kumar Inna int rv; 1904a3667aaeSNaresh Kumar Inna /* 1905a3667aaeSNaresh Kumar Inna * Reset device if necessary 1906a3667aaeSNaresh Kumar Inna */ 1907a3667aaeSNaresh Kumar Inna if (reset) { 1908a3667aaeSNaresh Kumar Inna rv = csio_do_reset(hw, true); 1909a3667aaeSNaresh Kumar Inna if (rv != 0) 1910a3667aaeSNaresh Kumar Inna goto out; 1911a3667aaeSNaresh Kumar Inna } 1912a3667aaeSNaresh Kumar Inna 1913a3667aaeSNaresh Kumar Inna /* Get and set device capabilities */ 1914a3667aaeSNaresh Kumar Inna rv = csio_config_device_caps(hw); 1915a3667aaeSNaresh Kumar Inna if (rv != 0) 1916a3667aaeSNaresh Kumar Inna goto out; 1917a3667aaeSNaresh Kumar Inna 1918a3667aaeSNaresh Kumar Inna /* device parameters */ 1919a3667aaeSNaresh Kumar Inna rv = csio_get_device_params(hw); 1920a3667aaeSNaresh Kumar Inna if (rv != 0) 1921a3667aaeSNaresh Kumar Inna goto out; 1922a3667aaeSNaresh Kumar Inna 1923a3667aaeSNaresh Kumar Inna /* Configure SGE */ 1924a3667aaeSNaresh Kumar Inna csio_wr_sge_init(hw); 1925a3667aaeSNaresh Kumar Inna 1926a3667aaeSNaresh Kumar Inna /* Post event to notify completion of configuration */ 1927a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_INIT); 1928a3667aaeSNaresh Kumar Inna 1929a3667aaeSNaresh Kumar Inna out: 1930a3667aaeSNaresh Kumar Inna return rv; 1931a3667aaeSNaresh Kumar Inna } 1932a3667aaeSNaresh Kumar Inna 1933f40e74ffSPraveen Madhavan /* Is the given firmware API compatible with the one the driver was compiled 1934f40e74ffSPraveen Madhavan * with? 1935f40e74ffSPraveen Madhavan */ 1936f40e74ffSPraveen Madhavan static int fw_compatible(const struct fw_hdr *hdr1, const struct fw_hdr *hdr2) 1937f40e74ffSPraveen Madhavan { 1938f40e74ffSPraveen Madhavan 1939f40e74ffSPraveen Madhavan /* short circuit if it's the exact same firmware version */ 1940f40e74ffSPraveen Madhavan if (hdr1->chip == hdr2->chip && hdr1->fw_ver == hdr2->fw_ver) 1941f40e74ffSPraveen Madhavan return 1; 1942f40e74ffSPraveen Madhavan 1943f40e74ffSPraveen Madhavan #define SAME_INTF(x) (hdr1->intfver_##x == hdr2->intfver_##x) 1944f40e74ffSPraveen Madhavan if (hdr1->chip == hdr2->chip && SAME_INTF(nic) && SAME_INTF(vnic) && 1945f40e74ffSPraveen Madhavan SAME_INTF(ri) && SAME_INTF(iscsi) && SAME_INTF(fcoe)) 1946f40e74ffSPraveen Madhavan return 1; 1947f40e74ffSPraveen Madhavan #undef SAME_INTF 1948f40e74ffSPraveen Madhavan 1949f40e74ffSPraveen Madhavan return 0; 1950f40e74ffSPraveen Madhavan } 1951f40e74ffSPraveen Madhavan 1952f40e74ffSPraveen Madhavan /* The firmware in the filesystem is usable, but should it be installed? 1953f40e74ffSPraveen Madhavan * This routine explains itself in detail if it indicates the filesystem 1954f40e74ffSPraveen Madhavan * firmware should be installed. 1955f40e74ffSPraveen Madhavan */ 1956f40e74ffSPraveen Madhavan static int csio_should_install_fs_fw(struct csio_hw *hw, int card_fw_usable, 1957f40e74ffSPraveen Madhavan int k, int c) 1958f40e74ffSPraveen Madhavan { 1959f40e74ffSPraveen Madhavan const char *reason; 1960f40e74ffSPraveen Madhavan 1961f40e74ffSPraveen Madhavan if (!card_fw_usable) { 1962f40e74ffSPraveen Madhavan reason = "incompatible or unusable"; 1963f40e74ffSPraveen Madhavan goto install; 1964f40e74ffSPraveen Madhavan } 1965f40e74ffSPraveen Madhavan 1966f40e74ffSPraveen Madhavan if (k > c) { 1967f40e74ffSPraveen Madhavan reason = "older than the version supported with this driver"; 1968f40e74ffSPraveen Madhavan goto install; 1969f40e74ffSPraveen Madhavan } 1970f40e74ffSPraveen Madhavan 1971f40e74ffSPraveen Madhavan return 0; 1972f40e74ffSPraveen Madhavan 1973f40e74ffSPraveen Madhavan install: 1974f40e74ffSPraveen Madhavan csio_err(hw, "firmware on card (%u.%u.%u.%u) is %s, " 1975f40e74ffSPraveen Madhavan "installing firmware %u.%u.%u.%u on card.\n", 1976f40e74ffSPraveen Madhavan FW_HDR_FW_VER_MAJOR_G(c), FW_HDR_FW_VER_MINOR_G(c), 1977f40e74ffSPraveen Madhavan FW_HDR_FW_VER_MICRO_G(c), FW_HDR_FW_VER_BUILD_G(c), reason, 1978f40e74ffSPraveen Madhavan FW_HDR_FW_VER_MAJOR_G(k), FW_HDR_FW_VER_MINOR_G(k), 1979f40e74ffSPraveen Madhavan FW_HDR_FW_VER_MICRO_G(k), FW_HDR_FW_VER_BUILD_G(k)); 1980f40e74ffSPraveen Madhavan 1981f40e74ffSPraveen Madhavan return 1; 1982f40e74ffSPraveen Madhavan } 1983f40e74ffSPraveen Madhavan 1984f40e74ffSPraveen Madhavan static struct fw_info fw_info_array[] = { 1985f40e74ffSPraveen Madhavan { 1986f40e74ffSPraveen Madhavan .chip = CHELSIO_T5, 1987f40e74ffSPraveen Madhavan .fs_name = FW_CFG_NAME_T5, 1988f40e74ffSPraveen Madhavan .fw_mod_name = FW_FNAME_T5, 1989f40e74ffSPraveen Madhavan .fw_hdr = { 1990f40e74ffSPraveen Madhavan .chip = FW_HDR_CHIP_T5, 1991f40e74ffSPraveen Madhavan .fw_ver = __cpu_to_be32(FW_VERSION(T5)), 1992f40e74ffSPraveen Madhavan .intfver_nic = FW_INTFVER(T5, NIC), 1993f40e74ffSPraveen Madhavan .intfver_vnic = FW_INTFVER(T5, VNIC), 1994f40e74ffSPraveen Madhavan .intfver_ri = FW_INTFVER(T5, RI), 1995f40e74ffSPraveen Madhavan .intfver_iscsi = FW_INTFVER(T5, ISCSI), 1996f40e74ffSPraveen Madhavan .intfver_fcoe = FW_INTFVER(T5, FCOE), 1997f40e74ffSPraveen Madhavan }, 1998f40e74ffSPraveen Madhavan } 1999f40e74ffSPraveen Madhavan }; 2000f40e74ffSPraveen Madhavan 2001f40e74ffSPraveen Madhavan static struct fw_info *find_fw_info(int chip) 2002f40e74ffSPraveen Madhavan { 2003f40e74ffSPraveen Madhavan int i; 2004f40e74ffSPraveen Madhavan 2005f40e74ffSPraveen Madhavan for (i = 0; i < ARRAY_SIZE(fw_info_array); i++) { 2006f40e74ffSPraveen Madhavan if (fw_info_array[i].chip == chip) 2007f40e74ffSPraveen Madhavan return &fw_info_array[i]; 2008f40e74ffSPraveen Madhavan } 2009f40e74ffSPraveen Madhavan return NULL; 2010f40e74ffSPraveen Madhavan } 2011f40e74ffSPraveen Madhavan 2012*78890ed7SPraveen Madhavan static int csio_hw_prep_fw(struct csio_hw *hw, struct fw_info *fw_info, 2013f40e74ffSPraveen Madhavan const u8 *fw_data, unsigned int fw_size, 2014f40e74ffSPraveen Madhavan struct fw_hdr *card_fw, enum csio_dev_state state, 2015f40e74ffSPraveen Madhavan int *reset) 2016f40e74ffSPraveen Madhavan { 2017f40e74ffSPraveen Madhavan int ret, card_fw_usable, fs_fw_usable; 2018f40e74ffSPraveen Madhavan const struct fw_hdr *fs_fw; 2019f40e74ffSPraveen Madhavan const struct fw_hdr *drv_fw; 2020f40e74ffSPraveen Madhavan 2021f40e74ffSPraveen Madhavan drv_fw = &fw_info->fw_hdr; 2022f40e74ffSPraveen Madhavan 2023f40e74ffSPraveen Madhavan /* Read the header of the firmware on the card */ 2024f40e74ffSPraveen Madhavan ret = csio_hw_read_flash(hw, FLASH_FW_START, 2025f40e74ffSPraveen Madhavan sizeof(*card_fw) / sizeof(uint32_t), 2026f40e74ffSPraveen Madhavan (uint32_t *)card_fw, 1); 2027f40e74ffSPraveen Madhavan if (ret == 0) { 2028f40e74ffSPraveen Madhavan card_fw_usable = fw_compatible(drv_fw, (const void *)card_fw); 2029f40e74ffSPraveen Madhavan } else { 2030f40e74ffSPraveen Madhavan csio_err(hw, 2031f40e74ffSPraveen Madhavan "Unable to read card's firmware header: %d\n", ret); 2032f40e74ffSPraveen Madhavan card_fw_usable = 0; 2033f40e74ffSPraveen Madhavan } 2034f40e74ffSPraveen Madhavan 2035f40e74ffSPraveen Madhavan if (fw_data != NULL) { 2036f40e74ffSPraveen Madhavan fs_fw = (const void *)fw_data; 2037f40e74ffSPraveen Madhavan fs_fw_usable = fw_compatible(drv_fw, fs_fw); 2038f40e74ffSPraveen Madhavan } else { 2039f40e74ffSPraveen Madhavan fs_fw = NULL; 2040f40e74ffSPraveen Madhavan fs_fw_usable = 0; 2041f40e74ffSPraveen Madhavan } 2042f40e74ffSPraveen Madhavan 2043f40e74ffSPraveen Madhavan if (card_fw_usable && card_fw->fw_ver == drv_fw->fw_ver && 2044f40e74ffSPraveen Madhavan (!fs_fw_usable || fs_fw->fw_ver == drv_fw->fw_ver)) { 2045f40e74ffSPraveen Madhavan /* Common case: the firmware on the card is an exact match and 2046f40e74ffSPraveen Madhavan * the filesystem one is an exact match too, or the filesystem 2047f40e74ffSPraveen Madhavan * one is absent/incompatible. 2048f40e74ffSPraveen Madhavan */ 2049f40e74ffSPraveen Madhavan } else if (fs_fw_usable && state == CSIO_DEV_STATE_UNINIT && 2050f40e74ffSPraveen Madhavan csio_should_install_fs_fw(hw, card_fw_usable, 2051f40e74ffSPraveen Madhavan be32_to_cpu(fs_fw->fw_ver), 2052f40e74ffSPraveen Madhavan be32_to_cpu(card_fw->fw_ver))) { 2053f40e74ffSPraveen Madhavan ret = csio_hw_fw_upgrade(hw, hw->pfn, fw_data, 2054f40e74ffSPraveen Madhavan fw_size, 0); 2055f40e74ffSPraveen Madhavan if (ret != 0) { 2056f40e74ffSPraveen Madhavan csio_err(hw, 2057f40e74ffSPraveen Madhavan "failed to install firmware: %d\n", ret); 2058f40e74ffSPraveen Madhavan goto bye; 2059f40e74ffSPraveen Madhavan } 2060f40e74ffSPraveen Madhavan 2061f40e74ffSPraveen Madhavan /* Installed successfully, update the cached header too. */ 2062f40e74ffSPraveen Madhavan memcpy(card_fw, fs_fw, sizeof(*card_fw)); 2063f40e74ffSPraveen Madhavan card_fw_usable = 1; 2064f40e74ffSPraveen Madhavan *reset = 0; /* already reset as part of load_fw */ 2065f40e74ffSPraveen Madhavan } 2066f40e74ffSPraveen Madhavan 2067f40e74ffSPraveen Madhavan if (!card_fw_usable) { 2068f40e74ffSPraveen Madhavan uint32_t d, c, k; 2069f40e74ffSPraveen Madhavan 2070f40e74ffSPraveen Madhavan d = be32_to_cpu(drv_fw->fw_ver); 2071f40e74ffSPraveen Madhavan c = be32_to_cpu(card_fw->fw_ver); 2072f40e74ffSPraveen Madhavan k = fs_fw ? be32_to_cpu(fs_fw->fw_ver) : 0; 2073f40e74ffSPraveen Madhavan 2074f40e74ffSPraveen Madhavan csio_err(hw, "Cannot find a usable firmware: " 2075f40e74ffSPraveen Madhavan "chip state %d, " 2076f40e74ffSPraveen Madhavan "driver compiled with %d.%d.%d.%d, " 2077f40e74ffSPraveen Madhavan "card has %d.%d.%d.%d, filesystem has %d.%d.%d.%d\n", 2078f40e74ffSPraveen Madhavan state, 2079f40e74ffSPraveen Madhavan FW_HDR_FW_VER_MAJOR_G(d), FW_HDR_FW_VER_MINOR_G(d), 2080f40e74ffSPraveen Madhavan FW_HDR_FW_VER_MICRO_G(d), FW_HDR_FW_VER_BUILD_G(d), 2081f40e74ffSPraveen Madhavan FW_HDR_FW_VER_MAJOR_G(c), FW_HDR_FW_VER_MINOR_G(c), 2082f40e74ffSPraveen Madhavan FW_HDR_FW_VER_MICRO_G(c), FW_HDR_FW_VER_BUILD_G(c), 2083f40e74ffSPraveen Madhavan FW_HDR_FW_VER_MAJOR_G(k), FW_HDR_FW_VER_MINOR_G(k), 2084f40e74ffSPraveen Madhavan FW_HDR_FW_VER_MICRO_G(k), FW_HDR_FW_VER_BUILD_G(k)); 2085f40e74ffSPraveen Madhavan ret = EINVAL; 2086f40e74ffSPraveen Madhavan goto bye; 2087f40e74ffSPraveen Madhavan } 2088f40e74ffSPraveen Madhavan 2089f40e74ffSPraveen Madhavan /* We're using whatever's on the card and it's known to be good. */ 2090f40e74ffSPraveen Madhavan hw->fwrev = be32_to_cpu(card_fw->fw_ver); 2091f40e74ffSPraveen Madhavan hw->tp_vers = be32_to_cpu(card_fw->tp_microcode_ver); 2092f40e74ffSPraveen Madhavan 2093f40e74ffSPraveen Madhavan bye: 2094f40e74ffSPraveen Madhavan return ret; 2095f40e74ffSPraveen Madhavan } 2096f40e74ffSPraveen Madhavan 2097a3667aaeSNaresh Kumar Inna /* 2098a3667aaeSNaresh Kumar Inna * Returns -EINVAL if attempts to flash the firmware failed 2099a3667aaeSNaresh Kumar Inna * else returns 0, 2100a3667aaeSNaresh Kumar Inna * if flashing was not attempted because the card had the 2101a3667aaeSNaresh Kumar Inna * latest firmware ECANCELED is returned 2102a3667aaeSNaresh Kumar Inna */ 2103a3667aaeSNaresh Kumar Inna static int 2104f40e74ffSPraveen Madhavan csio_hw_flash_fw(struct csio_hw *hw, int *reset) 2105a3667aaeSNaresh Kumar Inna { 2106a3667aaeSNaresh Kumar Inna int ret = -ECANCELED; 2107a3667aaeSNaresh Kumar Inna const struct firmware *fw; 2108f40e74ffSPraveen Madhavan struct fw_info *fw_info; 2109f40e74ffSPraveen Madhavan struct fw_hdr *card_fw; 2110a3667aaeSNaresh Kumar Inna struct pci_dev *pci_dev = hw->pdev; 2111a3667aaeSNaresh Kumar Inna struct device *dev = &pci_dev->dev ; 2112f40e74ffSPraveen Madhavan const u8 *fw_data = NULL; 2113f40e74ffSPraveen Madhavan unsigned int fw_size = 0; 2114f40e74ffSPraveen Madhavan 2115f40e74ffSPraveen Madhavan /* This is the firmware whose headers the driver was compiled 2116f40e74ffSPraveen Madhavan * against 2117f40e74ffSPraveen Madhavan */ 2118f40e74ffSPraveen Madhavan fw_info = find_fw_info(CHELSIO_CHIP_VERSION(hw->chip_id)); 2119f40e74ffSPraveen Madhavan if (fw_info == NULL) { 2120f40e74ffSPraveen Madhavan csio_err(hw, 2121f40e74ffSPraveen Madhavan "unable to get firmware info for chip %d.\n", 2122f40e74ffSPraveen Madhavan CHELSIO_CHIP_VERSION(hw->chip_id)); 2123f40e74ffSPraveen Madhavan return -EINVAL; 2124f40e74ffSPraveen Madhavan } 2125a3667aaeSNaresh Kumar Inna 21267cc16380SArvind Bhushan if (request_firmware(&fw, CSIO_FW_FNAME(hw), dev) < 0) { 21277cc16380SArvind Bhushan csio_err(hw, "could not find firmware image %s, err: %d\n", 21287cc16380SArvind Bhushan CSIO_FW_FNAME(hw), ret); 2129a3667aaeSNaresh Kumar Inna return -EINVAL; 2130a3667aaeSNaresh Kumar Inna } 2131a3667aaeSNaresh Kumar Inna 2132f40e74ffSPraveen Madhavan /* allocate memory to read the header of the firmware on the 2133f40e74ffSPraveen Madhavan * card 2134a3667aaeSNaresh Kumar Inna */ 2135f40e74ffSPraveen Madhavan card_fw = kmalloc(sizeof(*card_fw), GFP_KERNEL); 2136a3667aaeSNaresh Kumar Inna 2137f40e74ffSPraveen Madhavan fw_data = fw->data; 2138f40e74ffSPraveen Madhavan fw_size = fw->size; 2139f40e74ffSPraveen Madhavan 2140f40e74ffSPraveen Madhavan /* upgrade FW logic */ 2141f40e74ffSPraveen Madhavan ret = csio_hw_prep_fw(hw, fw_info, fw_data, fw_size, card_fw, 2142f40e74ffSPraveen Madhavan hw->fw_state, reset); 2143f40e74ffSPraveen Madhavan 2144f40e74ffSPraveen Madhavan /* Cleaning up */ 2145f40e74ffSPraveen Madhavan if (fw != NULL) 2146a3667aaeSNaresh Kumar Inna release_firmware(fw); 2147f40e74ffSPraveen Madhavan kfree(card_fw); 2148a3667aaeSNaresh Kumar Inna return ret; 2149a3667aaeSNaresh Kumar Inna } 2150a3667aaeSNaresh Kumar Inna 2151a3667aaeSNaresh Kumar Inna /* 2152a3667aaeSNaresh Kumar Inna * csio_hw_configure - Configure HW 2153a3667aaeSNaresh Kumar Inna * @hw - HW module 2154a3667aaeSNaresh Kumar Inna * 2155a3667aaeSNaresh Kumar Inna */ 2156a3667aaeSNaresh Kumar Inna static void 2157a3667aaeSNaresh Kumar Inna csio_hw_configure(struct csio_hw *hw) 2158a3667aaeSNaresh Kumar Inna { 2159a3667aaeSNaresh Kumar Inna int reset = 1; 2160a3667aaeSNaresh Kumar Inna int rv; 2161a3667aaeSNaresh Kumar Inna u32 param[1]; 2162a3667aaeSNaresh Kumar Inna 2163a3667aaeSNaresh Kumar Inna rv = csio_hw_dev_ready(hw); 2164a3667aaeSNaresh Kumar Inna if (rv != 0) { 2165a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_fatal); 2166a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_FATAL); 2167a3667aaeSNaresh Kumar Inna goto out; 2168a3667aaeSNaresh Kumar Inna } 2169a3667aaeSNaresh Kumar Inna 2170a3667aaeSNaresh Kumar Inna /* HW version */ 21710d804338SHariprasad Shenai hw->chip_ver = (char)csio_rd_reg32(hw, PL_REV_A); 2172a3667aaeSNaresh Kumar Inna 2173a3667aaeSNaresh Kumar Inna /* Needed for FW download */ 2174a3667aaeSNaresh Kumar Inna rv = csio_hw_get_flash_params(hw); 2175a3667aaeSNaresh Kumar Inna if (rv != 0) { 2176a3667aaeSNaresh Kumar Inna csio_err(hw, "Failed to get serial flash params rv:%d\n", rv); 2177a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_FATAL); 2178a3667aaeSNaresh Kumar Inna goto out; 2179a3667aaeSNaresh Kumar Inna } 2180a3667aaeSNaresh Kumar Inna 2181ad4d35f8SYijing Wang /* Set PCIe completion timeout to 4 seconds */ 2182ad4d35f8SYijing Wang if (pci_is_pcie(hw->pdev)) 2183ad4d35f8SYijing Wang pcie_capability_clear_and_set_word(hw->pdev, PCI_EXP_DEVCTL2, 2184ad4d35f8SYijing Wang PCI_EXP_DEVCTL2_COMP_TIMEOUT, 0xd); 2185a3667aaeSNaresh Kumar Inna 21867cc16380SArvind Bhushan hw->chip_ops->chip_set_mem_win(hw, MEMWIN_CSIOSTOR); 2187a3667aaeSNaresh Kumar Inna 2188a3667aaeSNaresh Kumar Inna rv = csio_hw_get_fw_version(hw, &hw->fwrev); 2189a3667aaeSNaresh Kumar Inna if (rv != 0) 2190a3667aaeSNaresh Kumar Inna goto out; 2191a3667aaeSNaresh Kumar Inna 2192a3667aaeSNaresh Kumar Inna csio_hw_print_fw_version(hw, "Firmware revision"); 2193a3667aaeSNaresh Kumar Inna 2194a3667aaeSNaresh Kumar Inna rv = csio_do_hello(hw, &hw->fw_state); 2195a3667aaeSNaresh Kumar Inna if (rv != 0) { 2196a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_fatal); 2197a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_FATAL); 2198a3667aaeSNaresh Kumar Inna goto out; 2199a3667aaeSNaresh Kumar Inna } 2200a3667aaeSNaresh Kumar Inna 2201a3667aaeSNaresh Kumar Inna /* Read vpd */ 2202a3667aaeSNaresh Kumar Inna rv = csio_hw_get_vpd_params(hw, &hw->vpd); 2203a3667aaeSNaresh Kumar Inna if (rv != 0) 2204a3667aaeSNaresh Kumar Inna goto out; 2205a3667aaeSNaresh Kumar Inna 2206f40e74ffSPraveen Madhavan csio_hw_get_fw_version(hw, &hw->fwrev); 2207f40e74ffSPraveen Madhavan csio_hw_get_tp_version(hw, &hw->tp_vers); 2208a3667aaeSNaresh Kumar Inna if (csio_is_hw_master(hw) && hw->fw_state != CSIO_DEV_STATE_INIT) { 2209a3667aaeSNaresh Kumar Inna 2210a3667aaeSNaresh Kumar Inna /* Do firmware update */ 2211a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 2212f40e74ffSPraveen Madhavan rv = csio_hw_flash_fw(hw, &reset); 2213a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 2214a3667aaeSNaresh Kumar Inna 2215f40e74ffSPraveen Madhavan if (rv != 0) 2216f40e74ffSPraveen Madhavan goto out; 2217f40e74ffSPraveen Madhavan 2218a3667aaeSNaresh Kumar Inna /* 2219a3667aaeSNaresh Kumar Inna * If the firmware doesn't support Configuration 2220a3667aaeSNaresh Kumar Inna * Files, use the old Driver-based, hard-wired 2221a3667aaeSNaresh Kumar Inna * initialization. Otherwise, try using the 2222a3667aaeSNaresh Kumar Inna * Configuration File support and fall back to the 2223a3667aaeSNaresh Kumar Inna * Driver-based initialization if there's no 2224a3667aaeSNaresh Kumar Inna * Configuration File found. 2225a3667aaeSNaresh Kumar Inna */ 2226a3667aaeSNaresh Kumar Inna if (csio_hw_check_fwconfig(hw, param) == 0) { 2227a3667aaeSNaresh Kumar Inna rv = csio_hw_use_fwconfig(hw, reset, param); 2228a3667aaeSNaresh Kumar Inna if (rv == -ENOENT) 2229a3667aaeSNaresh Kumar Inna goto out; 2230a3667aaeSNaresh Kumar Inna if (rv != 0) { 2231a3667aaeSNaresh Kumar Inna csio_info(hw, 2232a3667aaeSNaresh Kumar Inna "No Configuration File present " 2233a3667aaeSNaresh Kumar Inna "on adapter. Using hard-wired " 2234a3667aaeSNaresh Kumar Inna "configuration parameters.\n"); 2235a3667aaeSNaresh Kumar Inna rv = csio_hw_no_fwconfig(hw, reset); 2236a3667aaeSNaresh Kumar Inna } 2237a3667aaeSNaresh Kumar Inna } else { 2238a3667aaeSNaresh Kumar Inna rv = csio_hw_no_fwconfig(hw, reset); 2239a3667aaeSNaresh Kumar Inna } 2240a3667aaeSNaresh Kumar Inna 2241a3667aaeSNaresh Kumar Inna if (rv != 0) 2242a3667aaeSNaresh Kumar Inna goto out; 2243a3667aaeSNaresh Kumar Inna 2244a3667aaeSNaresh Kumar Inna } else { 2245a3667aaeSNaresh Kumar Inna if (hw->fw_state == CSIO_DEV_STATE_INIT) { 2246a3667aaeSNaresh Kumar Inna 22477cc16380SArvind Bhushan hw->flags |= CSIO_HWF_USING_SOFT_PARAMS; 22487cc16380SArvind Bhushan 2249a3667aaeSNaresh Kumar Inna /* device parameters */ 2250a3667aaeSNaresh Kumar Inna rv = csio_get_device_params(hw); 2251a3667aaeSNaresh Kumar Inna if (rv != 0) 2252a3667aaeSNaresh Kumar Inna goto out; 2253a3667aaeSNaresh Kumar Inna 2254a3667aaeSNaresh Kumar Inna /* Get device capabilities */ 2255a3667aaeSNaresh Kumar Inna rv = csio_config_device_caps(hw); 2256a3667aaeSNaresh Kumar Inna if (rv != 0) 2257a3667aaeSNaresh Kumar Inna goto out; 2258a3667aaeSNaresh Kumar Inna 2259a3667aaeSNaresh Kumar Inna /* Configure SGE */ 2260a3667aaeSNaresh Kumar Inna csio_wr_sge_init(hw); 2261a3667aaeSNaresh Kumar Inna 2262a3667aaeSNaresh Kumar Inna /* Post event to notify completion of configuration */ 2263a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_INIT); 2264a3667aaeSNaresh Kumar Inna goto out; 2265a3667aaeSNaresh Kumar Inna } 2266a3667aaeSNaresh Kumar Inna } /* if not master */ 2267a3667aaeSNaresh Kumar Inna 2268a3667aaeSNaresh Kumar Inna out: 2269a3667aaeSNaresh Kumar Inna return; 2270a3667aaeSNaresh Kumar Inna } 2271a3667aaeSNaresh Kumar Inna 2272a3667aaeSNaresh Kumar Inna /* 2273a3667aaeSNaresh Kumar Inna * csio_hw_initialize - Initialize HW 2274a3667aaeSNaresh Kumar Inna * @hw - HW module 2275a3667aaeSNaresh Kumar Inna * 2276a3667aaeSNaresh Kumar Inna */ 2277a3667aaeSNaresh Kumar Inna static void 2278a3667aaeSNaresh Kumar Inna csio_hw_initialize(struct csio_hw *hw) 2279a3667aaeSNaresh Kumar Inna { 2280a3667aaeSNaresh Kumar Inna struct csio_mb *mbp; 2281a3667aaeSNaresh Kumar Inna enum fw_retval retval; 2282a3667aaeSNaresh Kumar Inna int rv; 2283a3667aaeSNaresh Kumar Inna int i; 2284a3667aaeSNaresh Kumar Inna 2285a3667aaeSNaresh Kumar Inna if (csio_is_hw_master(hw) && hw->fw_state != CSIO_DEV_STATE_INIT) { 2286a3667aaeSNaresh Kumar Inna mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 2287a3667aaeSNaresh Kumar Inna if (!mbp) 2288a3667aaeSNaresh Kumar Inna goto out; 2289a3667aaeSNaresh Kumar Inna 2290a3667aaeSNaresh Kumar Inna csio_mb_initialize(hw, mbp, CSIO_MB_DEFAULT_TMO, NULL); 2291a3667aaeSNaresh Kumar Inna 2292a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 2293a3667aaeSNaresh Kumar Inna csio_err(hw, "Issue of FW_INITIALIZE_CMD failed!\n"); 2294a3667aaeSNaresh Kumar Inna goto free_and_out; 2295a3667aaeSNaresh Kumar Inna } 2296a3667aaeSNaresh Kumar Inna 2297a3667aaeSNaresh Kumar Inna retval = csio_mb_fw_retval(mbp); 2298a3667aaeSNaresh Kumar Inna if (retval != FW_SUCCESS) { 2299a3667aaeSNaresh Kumar Inna csio_err(hw, "FW_INITIALIZE_CMD returned 0x%x!\n", 2300a3667aaeSNaresh Kumar Inna retval); 2301a3667aaeSNaresh Kumar Inna goto free_and_out; 2302a3667aaeSNaresh Kumar Inna } 2303a3667aaeSNaresh Kumar Inna 2304a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 2305a3667aaeSNaresh Kumar Inna } 2306a3667aaeSNaresh Kumar Inna 2307a3667aaeSNaresh Kumar Inna rv = csio_get_fcoe_resinfo(hw); 2308a3667aaeSNaresh Kumar Inna if (rv != 0) { 2309a3667aaeSNaresh Kumar Inna csio_err(hw, "Failed to read fcoe resource info: %d\n", rv); 2310a3667aaeSNaresh Kumar Inna goto out; 2311a3667aaeSNaresh Kumar Inna } 2312a3667aaeSNaresh Kumar Inna 2313a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 2314a3667aaeSNaresh Kumar Inna rv = csio_config_queues(hw); 2315a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 2316a3667aaeSNaresh Kumar Inna 2317a3667aaeSNaresh Kumar Inna if (rv != 0) { 2318a3667aaeSNaresh Kumar Inna csio_err(hw, "Config of queues failed!: %d\n", rv); 2319a3667aaeSNaresh Kumar Inna goto out; 2320a3667aaeSNaresh Kumar Inna } 2321a3667aaeSNaresh Kumar Inna 2322a3667aaeSNaresh Kumar Inna for (i = 0; i < hw->num_pports; i++) 2323a3667aaeSNaresh Kumar Inna hw->pport[i].mod_type = FW_PORT_MOD_TYPE_NA; 2324a3667aaeSNaresh Kumar Inna 2325a3667aaeSNaresh Kumar Inna if (csio_is_hw_master(hw) && hw->fw_state != CSIO_DEV_STATE_INIT) { 2326a3667aaeSNaresh Kumar Inna rv = csio_enable_ports(hw); 2327a3667aaeSNaresh Kumar Inna if (rv != 0) { 2328a3667aaeSNaresh Kumar Inna csio_err(hw, "Failed to enable ports: %d\n", rv); 2329a3667aaeSNaresh Kumar Inna goto out; 2330a3667aaeSNaresh Kumar Inna } 2331a3667aaeSNaresh Kumar Inna } 2332a3667aaeSNaresh Kumar Inna 2333a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_INIT_DONE); 2334a3667aaeSNaresh Kumar Inna return; 2335a3667aaeSNaresh Kumar Inna 2336a3667aaeSNaresh Kumar Inna free_and_out: 2337a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 2338a3667aaeSNaresh Kumar Inna out: 2339a3667aaeSNaresh Kumar Inna return; 2340a3667aaeSNaresh Kumar Inna } 2341a3667aaeSNaresh Kumar Inna 23420d804338SHariprasad Shenai #define PF_INTR_MASK (PFSW_F | PFCIM_F) 2343a3667aaeSNaresh Kumar Inna 2344a3667aaeSNaresh Kumar Inna /* 2345a3667aaeSNaresh Kumar Inna * csio_hw_intr_enable - Enable HW interrupts 2346a3667aaeSNaresh Kumar Inna * @hw: Pointer to HW module. 2347a3667aaeSNaresh Kumar Inna * 2348a3667aaeSNaresh Kumar Inna * Enable interrupts in HW registers. 2349a3667aaeSNaresh Kumar Inna */ 2350a3667aaeSNaresh Kumar Inna static void 2351a3667aaeSNaresh Kumar Inna csio_hw_intr_enable(struct csio_hw *hw) 2352a3667aaeSNaresh Kumar Inna { 2353a3667aaeSNaresh Kumar Inna uint16_t vec = (uint16_t)csio_get_mb_intr_idx(csio_hw_to_mbm(hw)); 23540d804338SHariprasad Shenai uint32_t pf = SOURCEPF_G(csio_rd_reg32(hw, PL_WHOAMI_A)); 23550d804338SHariprasad Shenai uint32_t pl = csio_rd_reg32(hw, PL_INT_ENABLE_A); 2356a3667aaeSNaresh Kumar Inna 2357a3667aaeSNaresh Kumar Inna /* 2358a3667aaeSNaresh Kumar Inna * Set aivec for MSI/MSIX. PCIE_PF_CFG.INTXType is set up 2359a3667aaeSNaresh Kumar Inna * by FW, so do nothing for INTX. 2360a3667aaeSNaresh Kumar Inna */ 2361a3667aaeSNaresh Kumar Inna if (hw->intr_mode == CSIO_IM_MSIX) 2362f061de42SHariprasad Shenai csio_set_reg_field(hw, MYPF_REG(PCIE_PF_CFG_A), 2363f061de42SHariprasad Shenai AIVEC_V(AIVEC_M), vec); 2364a3667aaeSNaresh Kumar Inna else if (hw->intr_mode == CSIO_IM_MSI) 2365f061de42SHariprasad Shenai csio_set_reg_field(hw, MYPF_REG(PCIE_PF_CFG_A), 2366f061de42SHariprasad Shenai AIVEC_V(AIVEC_M), 0); 2367a3667aaeSNaresh Kumar Inna 23680d804338SHariprasad Shenai csio_wr_reg32(hw, PF_INTR_MASK, MYPF_REG(PL_PF_INT_ENABLE_A)); 2369a3667aaeSNaresh Kumar Inna 2370a3667aaeSNaresh Kumar Inna /* Turn on MB interrupts - this will internally flush PIO as well */ 2371a3667aaeSNaresh Kumar Inna csio_mb_intr_enable(hw); 2372a3667aaeSNaresh Kumar Inna 2373a3667aaeSNaresh Kumar Inna /* These are common registers - only a master can modify them */ 2374a3667aaeSNaresh Kumar Inna if (csio_is_hw_master(hw)) { 2375a3667aaeSNaresh Kumar Inna /* 2376a3667aaeSNaresh Kumar Inna * Disable the Serial FLASH interrupt, if enabled! 2377a3667aaeSNaresh Kumar Inna */ 23780d804338SHariprasad Shenai pl &= (~SF_F); 23790d804338SHariprasad Shenai csio_wr_reg32(hw, pl, PL_INT_ENABLE_A); 2380a3667aaeSNaresh Kumar Inna 2381f612b815SHariprasad Shenai csio_wr_reg32(hw, ERR_CPL_EXCEED_IQE_SIZE_F | 2382f612b815SHariprasad Shenai EGRESS_SIZE_ERR_F | ERR_INVALID_CIDX_INC_F | 2383f612b815SHariprasad Shenai ERR_CPL_OPCODE_0_F | ERR_DROPPED_DB_F | 2384f612b815SHariprasad Shenai ERR_DATA_CPL_ON_HIGH_QID1_F | 2385f612b815SHariprasad Shenai ERR_DATA_CPL_ON_HIGH_QID0_F | ERR_BAD_DB_PIDX3_F | 2386f612b815SHariprasad Shenai ERR_BAD_DB_PIDX2_F | ERR_BAD_DB_PIDX1_F | 2387f612b815SHariprasad Shenai ERR_BAD_DB_PIDX0_F | ERR_ING_CTXT_PRIO_F | 2388f612b815SHariprasad Shenai ERR_EGR_CTXT_PRIO_F | INGRESS_SIZE_ERR_F, 2389f612b815SHariprasad Shenai SGE_INT_ENABLE3_A); 23900d804338SHariprasad Shenai csio_set_reg_field(hw, PL_INT_MAP0_A, 0, 1 << pf); 2391a3667aaeSNaresh Kumar Inna } 2392a3667aaeSNaresh Kumar Inna 2393a3667aaeSNaresh Kumar Inna hw->flags |= CSIO_HWF_HW_INTR_ENABLED; 2394a3667aaeSNaresh Kumar Inna 2395a3667aaeSNaresh Kumar Inna } 2396a3667aaeSNaresh Kumar Inna 2397a3667aaeSNaresh Kumar Inna /* 2398a3667aaeSNaresh Kumar Inna * csio_hw_intr_disable - Disable HW interrupts 2399a3667aaeSNaresh Kumar Inna * @hw: Pointer to HW module. 2400a3667aaeSNaresh Kumar Inna * 2401a3667aaeSNaresh Kumar Inna * Turn off Mailbox and PCI_PF_CFG interrupts. 2402a3667aaeSNaresh Kumar Inna */ 2403a3667aaeSNaresh Kumar Inna void 2404a3667aaeSNaresh Kumar Inna csio_hw_intr_disable(struct csio_hw *hw) 2405a3667aaeSNaresh Kumar Inna { 24060d804338SHariprasad Shenai uint32_t pf = SOURCEPF_G(csio_rd_reg32(hw, PL_WHOAMI_A)); 2407a3667aaeSNaresh Kumar Inna 2408a3667aaeSNaresh Kumar Inna if (!(hw->flags & CSIO_HWF_HW_INTR_ENABLED)) 2409a3667aaeSNaresh Kumar Inna return; 2410a3667aaeSNaresh Kumar Inna 2411a3667aaeSNaresh Kumar Inna hw->flags &= ~CSIO_HWF_HW_INTR_ENABLED; 2412a3667aaeSNaresh Kumar Inna 24130d804338SHariprasad Shenai csio_wr_reg32(hw, 0, MYPF_REG(PL_PF_INT_ENABLE_A)); 2414a3667aaeSNaresh Kumar Inna if (csio_is_hw_master(hw)) 24150d804338SHariprasad Shenai csio_set_reg_field(hw, PL_INT_MAP0_A, 1 << pf, 0); 2416a3667aaeSNaresh Kumar Inna 2417a3667aaeSNaresh Kumar Inna /* Turn off MB interrupts */ 2418a3667aaeSNaresh Kumar Inna csio_mb_intr_disable(hw); 2419a3667aaeSNaresh Kumar Inna 2420a3667aaeSNaresh Kumar Inna } 2421a3667aaeSNaresh Kumar Inna 24227cc16380SArvind Bhushan void 2423a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(struct csio_hw *hw) 2424a3667aaeSNaresh Kumar Inna { 2425f612b815SHariprasad Shenai csio_set_reg_field(hw, SGE_CONTROL_A, GLOBALENABLE_F, 0); 2426a3667aaeSNaresh Kumar Inna csio_hw_intr_disable(hw); 2427a3667aaeSNaresh Kumar Inna 2428a3667aaeSNaresh Kumar Inna /* Do not reset HW, we may need FW state for debugging */ 2429a3667aaeSNaresh Kumar Inna csio_fatal(hw, "HW Fatal error encountered!\n"); 2430a3667aaeSNaresh Kumar Inna } 2431a3667aaeSNaresh Kumar Inna 2432a3667aaeSNaresh Kumar Inna /*****************************************************************************/ 2433a3667aaeSNaresh Kumar Inna /* START: HW SM */ 2434a3667aaeSNaresh Kumar Inna /*****************************************************************************/ 2435a3667aaeSNaresh Kumar Inna /* 2436a3667aaeSNaresh Kumar Inna * csio_hws_uninit - Uninit state 2437a3667aaeSNaresh Kumar Inna * @hw - HW module 2438a3667aaeSNaresh Kumar Inna * @evt - Event 2439a3667aaeSNaresh Kumar Inna * 2440a3667aaeSNaresh Kumar Inna */ 2441a3667aaeSNaresh Kumar Inna static void 2442a3667aaeSNaresh Kumar Inna csio_hws_uninit(struct csio_hw *hw, enum csio_hw_ev evt) 2443a3667aaeSNaresh Kumar Inna { 2444a3667aaeSNaresh Kumar Inna hw->prev_evt = hw->cur_evt; 2445a3667aaeSNaresh Kumar Inna hw->cur_evt = evt; 2446a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_sm[evt]); 2447a3667aaeSNaresh Kumar Inna 2448a3667aaeSNaresh Kumar Inna switch (evt) { 2449a3667aaeSNaresh Kumar Inna case CSIO_HWE_CFG: 2450a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_configuring); 2451a3667aaeSNaresh Kumar Inna csio_hw_configure(hw); 2452a3667aaeSNaresh Kumar Inna break; 2453a3667aaeSNaresh Kumar Inna 2454a3667aaeSNaresh Kumar Inna default: 2455a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_unexp); 2456a3667aaeSNaresh Kumar Inna break; 2457a3667aaeSNaresh Kumar Inna } 2458a3667aaeSNaresh Kumar Inna } 2459a3667aaeSNaresh Kumar Inna 2460a3667aaeSNaresh Kumar Inna /* 2461a3667aaeSNaresh Kumar Inna * csio_hws_configuring - Configuring state 2462a3667aaeSNaresh Kumar Inna * @hw - HW module 2463a3667aaeSNaresh Kumar Inna * @evt - Event 2464a3667aaeSNaresh Kumar Inna * 2465a3667aaeSNaresh Kumar Inna */ 2466a3667aaeSNaresh Kumar Inna static void 2467a3667aaeSNaresh Kumar Inna csio_hws_configuring(struct csio_hw *hw, enum csio_hw_ev evt) 2468a3667aaeSNaresh Kumar Inna { 2469a3667aaeSNaresh Kumar Inna hw->prev_evt = hw->cur_evt; 2470a3667aaeSNaresh Kumar Inna hw->cur_evt = evt; 2471a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_sm[evt]); 2472a3667aaeSNaresh Kumar Inna 2473a3667aaeSNaresh Kumar Inna switch (evt) { 2474a3667aaeSNaresh Kumar Inna case CSIO_HWE_INIT: 2475a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_initializing); 2476a3667aaeSNaresh Kumar Inna csio_hw_initialize(hw); 2477a3667aaeSNaresh Kumar Inna break; 2478a3667aaeSNaresh Kumar Inna 2479a3667aaeSNaresh Kumar Inna case CSIO_HWE_INIT_DONE: 2480a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_ready); 2481a3667aaeSNaresh Kumar Inna /* Fan out event to all lnode SMs */ 2482a3667aaeSNaresh Kumar Inna csio_notify_lnodes(hw, CSIO_LN_NOTIFY_HWREADY); 2483a3667aaeSNaresh Kumar Inna break; 2484a3667aaeSNaresh Kumar Inna 2485a3667aaeSNaresh Kumar Inna case CSIO_HWE_FATAL: 2486a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_uninit); 2487a3667aaeSNaresh Kumar Inna break; 2488a3667aaeSNaresh Kumar Inna 2489a3667aaeSNaresh Kumar Inna case CSIO_HWE_PCI_REMOVE: 2490a3667aaeSNaresh Kumar Inna csio_do_bye(hw); 2491a3667aaeSNaresh Kumar Inna break; 2492a3667aaeSNaresh Kumar Inna default: 2493a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_unexp); 2494a3667aaeSNaresh Kumar Inna break; 2495a3667aaeSNaresh Kumar Inna } 2496a3667aaeSNaresh Kumar Inna } 2497a3667aaeSNaresh Kumar Inna 2498a3667aaeSNaresh Kumar Inna /* 2499a3667aaeSNaresh Kumar Inna * csio_hws_initializing - Initialiazing state 2500a3667aaeSNaresh Kumar Inna * @hw - HW module 2501a3667aaeSNaresh Kumar Inna * @evt - Event 2502a3667aaeSNaresh Kumar Inna * 2503a3667aaeSNaresh Kumar Inna */ 2504a3667aaeSNaresh Kumar Inna static void 2505a3667aaeSNaresh Kumar Inna csio_hws_initializing(struct csio_hw *hw, enum csio_hw_ev evt) 2506a3667aaeSNaresh Kumar Inna { 2507a3667aaeSNaresh Kumar Inna hw->prev_evt = hw->cur_evt; 2508a3667aaeSNaresh Kumar Inna hw->cur_evt = evt; 2509a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_sm[evt]); 2510a3667aaeSNaresh Kumar Inna 2511a3667aaeSNaresh Kumar Inna switch (evt) { 2512a3667aaeSNaresh Kumar Inna case CSIO_HWE_INIT_DONE: 2513a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_ready); 2514a3667aaeSNaresh Kumar Inna 2515a3667aaeSNaresh Kumar Inna /* Fan out event to all lnode SMs */ 2516a3667aaeSNaresh Kumar Inna csio_notify_lnodes(hw, CSIO_LN_NOTIFY_HWREADY); 2517a3667aaeSNaresh Kumar Inna 2518a3667aaeSNaresh Kumar Inna /* Enable interrupts */ 2519a3667aaeSNaresh Kumar Inna csio_hw_intr_enable(hw); 2520a3667aaeSNaresh Kumar Inna break; 2521a3667aaeSNaresh Kumar Inna 2522a3667aaeSNaresh Kumar Inna case CSIO_HWE_FATAL: 2523a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_uninit); 2524a3667aaeSNaresh Kumar Inna break; 2525a3667aaeSNaresh Kumar Inna 2526a3667aaeSNaresh Kumar Inna case CSIO_HWE_PCI_REMOVE: 2527a3667aaeSNaresh Kumar Inna csio_do_bye(hw); 2528a3667aaeSNaresh Kumar Inna break; 2529a3667aaeSNaresh Kumar Inna 2530a3667aaeSNaresh Kumar Inna default: 2531a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_unexp); 2532a3667aaeSNaresh Kumar Inna break; 2533a3667aaeSNaresh Kumar Inna } 2534a3667aaeSNaresh Kumar Inna } 2535a3667aaeSNaresh Kumar Inna 2536a3667aaeSNaresh Kumar Inna /* 2537a3667aaeSNaresh Kumar Inna * csio_hws_ready - Ready state 2538a3667aaeSNaresh Kumar Inna * @hw - HW module 2539a3667aaeSNaresh Kumar Inna * @evt - Event 2540a3667aaeSNaresh Kumar Inna * 2541a3667aaeSNaresh Kumar Inna */ 2542a3667aaeSNaresh Kumar Inna static void 2543a3667aaeSNaresh Kumar Inna csio_hws_ready(struct csio_hw *hw, enum csio_hw_ev evt) 2544a3667aaeSNaresh Kumar Inna { 2545a3667aaeSNaresh Kumar Inna /* Remember the event */ 2546a3667aaeSNaresh Kumar Inna hw->evtflag = evt; 2547a3667aaeSNaresh Kumar Inna 2548a3667aaeSNaresh Kumar Inna hw->prev_evt = hw->cur_evt; 2549a3667aaeSNaresh Kumar Inna hw->cur_evt = evt; 2550a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_sm[evt]); 2551a3667aaeSNaresh Kumar Inna 2552a3667aaeSNaresh Kumar Inna switch (evt) { 2553a3667aaeSNaresh Kumar Inna case CSIO_HWE_HBA_RESET: 2554a3667aaeSNaresh Kumar Inna case CSIO_HWE_FW_DLOAD: 2555a3667aaeSNaresh Kumar Inna case CSIO_HWE_SUSPEND: 2556a3667aaeSNaresh Kumar Inna case CSIO_HWE_PCI_REMOVE: 2557a3667aaeSNaresh Kumar Inna case CSIO_HWE_PCIERR_DETECTED: 2558a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_quiescing); 2559a3667aaeSNaresh Kumar Inna /* cleanup all outstanding cmds */ 2560a3667aaeSNaresh Kumar Inna if (evt == CSIO_HWE_HBA_RESET || 2561a3667aaeSNaresh Kumar Inna evt == CSIO_HWE_PCIERR_DETECTED) 2562a3667aaeSNaresh Kumar Inna csio_scsim_cleanup_io(csio_hw_to_scsim(hw), false); 2563a3667aaeSNaresh Kumar Inna else 2564a3667aaeSNaresh Kumar Inna csio_scsim_cleanup_io(csio_hw_to_scsim(hw), true); 2565a3667aaeSNaresh Kumar Inna 2566a3667aaeSNaresh Kumar Inna csio_hw_intr_disable(hw); 2567a3667aaeSNaresh Kumar Inna csio_hw_mbm_cleanup(hw); 2568a3667aaeSNaresh Kumar Inna csio_evtq_stop(hw); 2569a3667aaeSNaresh Kumar Inna csio_notify_lnodes(hw, CSIO_LN_NOTIFY_HWSTOP); 2570a3667aaeSNaresh Kumar Inna csio_evtq_flush(hw); 2571a3667aaeSNaresh Kumar Inna csio_mgmtm_cleanup(csio_hw_to_mgmtm(hw)); 2572a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_QUIESCED); 2573a3667aaeSNaresh Kumar Inna break; 2574a3667aaeSNaresh Kumar Inna 2575a3667aaeSNaresh Kumar Inna case CSIO_HWE_FATAL: 2576a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_uninit); 2577a3667aaeSNaresh Kumar Inna break; 2578a3667aaeSNaresh Kumar Inna 2579a3667aaeSNaresh Kumar Inna default: 2580a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_unexp); 2581a3667aaeSNaresh Kumar Inna break; 2582a3667aaeSNaresh Kumar Inna } 2583a3667aaeSNaresh Kumar Inna } 2584a3667aaeSNaresh Kumar Inna 2585a3667aaeSNaresh Kumar Inna /* 2586a3667aaeSNaresh Kumar Inna * csio_hws_quiescing - Quiescing state 2587a3667aaeSNaresh Kumar Inna * @hw - HW module 2588a3667aaeSNaresh Kumar Inna * @evt - Event 2589a3667aaeSNaresh Kumar Inna * 2590a3667aaeSNaresh Kumar Inna */ 2591a3667aaeSNaresh Kumar Inna static void 2592a3667aaeSNaresh Kumar Inna csio_hws_quiescing(struct csio_hw *hw, enum csio_hw_ev evt) 2593a3667aaeSNaresh Kumar Inna { 2594a3667aaeSNaresh Kumar Inna hw->prev_evt = hw->cur_evt; 2595a3667aaeSNaresh Kumar Inna hw->cur_evt = evt; 2596a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_sm[evt]); 2597a3667aaeSNaresh Kumar Inna 2598a3667aaeSNaresh Kumar Inna switch (evt) { 2599a3667aaeSNaresh Kumar Inna case CSIO_HWE_QUIESCED: 2600a3667aaeSNaresh Kumar Inna switch (hw->evtflag) { 2601a3667aaeSNaresh Kumar Inna case CSIO_HWE_FW_DLOAD: 2602a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_resetting); 2603a3667aaeSNaresh Kumar Inna /* Download firmware */ 2604a3667aaeSNaresh Kumar Inna /* Fall through */ 2605a3667aaeSNaresh Kumar Inna 2606a3667aaeSNaresh Kumar Inna case CSIO_HWE_HBA_RESET: 2607a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_resetting); 2608a3667aaeSNaresh Kumar Inna /* Start reset of the HBA */ 2609a3667aaeSNaresh Kumar Inna csio_notify_lnodes(hw, CSIO_LN_NOTIFY_HWRESET); 2610a3667aaeSNaresh Kumar Inna csio_wr_destroy_queues(hw, false); 2611a3667aaeSNaresh Kumar Inna csio_do_reset(hw, false); 2612a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_HBA_RESET_DONE); 2613a3667aaeSNaresh Kumar Inna break; 2614a3667aaeSNaresh Kumar Inna 2615a3667aaeSNaresh Kumar Inna case CSIO_HWE_PCI_REMOVE: 2616a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_removing); 2617a3667aaeSNaresh Kumar Inna csio_notify_lnodes(hw, CSIO_LN_NOTIFY_HWREMOVE); 2618a3667aaeSNaresh Kumar Inna csio_wr_destroy_queues(hw, true); 2619a3667aaeSNaresh Kumar Inna /* Now send the bye command */ 2620a3667aaeSNaresh Kumar Inna csio_do_bye(hw); 2621a3667aaeSNaresh Kumar Inna break; 2622a3667aaeSNaresh Kumar Inna 2623a3667aaeSNaresh Kumar Inna case CSIO_HWE_SUSPEND: 2624a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_quiesced); 2625a3667aaeSNaresh Kumar Inna break; 2626a3667aaeSNaresh Kumar Inna 2627a3667aaeSNaresh Kumar Inna case CSIO_HWE_PCIERR_DETECTED: 2628a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_pcierr); 2629a3667aaeSNaresh Kumar Inna csio_wr_destroy_queues(hw, false); 2630a3667aaeSNaresh Kumar Inna break; 2631a3667aaeSNaresh Kumar Inna 2632a3667aaeSNaresh Kumar Inna default: 2633a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_unexp); 2634a3667aaeSNaresh Kumar Inna break; 2635a3667aaeSNaresh Kumar Inna 2636a3667aaeSNaresh Kumar Inna } 2637a3667aaeSNaresh Kumar Inna break; 2638a3667aaeSNaresh Kumar Inna 2639a3667aaeSNaresh Kumar Inna default: 2640a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_unexp); 2641a3667aaeSNaresh Kumar Inna break; 2642a3667aaeSNaresh Kumar Inna } 2643a3667aaeSNaresh Kumar Inna } 2644a3667aaeSNaresh Kumar Inna 2645a3667aaeSNaresh Kumar Inna /* 2646a3667aaeSNaresh Kumar Inna * csio_hws_quiesced - Quiesced state 2647a3667aaeSNaresh Kumar Inna * @hw - HW module 2648a3667aaeSNaresh Kumar Inna * @evt - Event 2649a3667aaeSNaresh Kumar Inna * 2650a3667aaeSNaresh Kumar Inna */ 2651a3667aaeSNaresh Kumar Inna static void 2652a3667aaeSNaresh Kumar Inna csio_hws_quiesced(struct csio_hw *hw, enum csio_hw_ev evt) 2653a3667aaeSNaresh Kumar Inna { 2654a3667aaeSNaresh Kumar Inna hw->prev_evt = hw->cur_evt; 2655a3667aaeSNaresh Kumar Inna hw->cur_evt = evt; 2656a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_sm[evt]); 2657a3667aaeSNaresh Kumar Inna 2658a3667aaeSNaresh Kumar Inna switch (evt) { 2659a3667aaeSNaresh Kumar Inna case CSIO_HWE_RESUME: 2660a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_configuring); 2661a3667aaeSNaresh Kumar Inna csio_hw_configure(hw); 2662a3667aaeSNaresh Kumar Inna break; 2663a3667aaeSNaresh Kumar Inna 2664a3667aaeSNaresh Kumar Inna default: 2665a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_unexp); 2666a3667aaeSNaresh Kumar Inna break; 2667a3667aaeSNaresh Kumar Inna } 2668a3667aaeSNaresh Kumar Inna } 2669a3667aaeSNaresh Kumar Inna 2670a3667aaeSNaresh Kumar Inna /* 2671a3667aaeSNaresh Kumar Inna * csio_hws_resetting - HW Resetting state 2672a3667aaeSNaresh Kumar Inna * @hw - HW module 2673a3667aaeSNaresh Kumar Inna * @evt - Event 2674a3667aaeSNaresh Kumar Inna * 2675a3667aaeSNaresh Kumar Inna */ 2676a3667aaeSNaresh Kumar Inna static void 2677a3667aaeSNaresh Kumar Inna csio_hws_resetting(struct csio_hw *hw, enum csio_hw_ev evt) 2678a3667aaeSNaresh Kumar Inna { 2679a3667aaeSNaresh Kumar Inna hw->prev_evt = hw->cur_evt; 2680a3667aaeSNaresh Kumar Inna hw->cur_evt = evt; 2681a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_sm[evt]); 2682a3667aaeSNaresh Kumar Inna 2683a3667aaeSNaresh Kumar Inna switch (evt) { 2684a3667aaeSNaresh Kumar Inna case CSIO_HWE_HBA_RESET_DONE: 2685a3667aaeSNaresh Kumar Inna csio_evtq_start(hw); 2686a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_configuring); 2687a3667aaeSNaresh Kumar Inna csio_hw_configure(hw); 2688a3667aaeSNaresh Kumar Inna break; 2689a3667aaeSNaresh Kumar Inna 2690a3667aaeSNaresh Kumar Inna default: 2691a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_unexp); 2692a3667aaeSNaresh Kumar Inna break; 2693a3667aaeSNaresh Kumar Inna } 2694a3667aaeSNaresh Kumar Inna } 2695a3667aaeSNaresh Kumar Inna 2696a3667aaeSNaresh Kumar Inna /* 2697a3667aaeSNaresh Kumar Inna * csio_hws_removing - PCI Hotplug removing state 2698a3667aaeSNaresh Kumar Inna * @hw - HW module 2699a3667aaeSNaresh Kumar Inna * @evt - Event 2700a3667aaeSNaresh Kumar Inna * 2701a3667aaeSNaresh Kumar Inna */ 2702a3667aaeSNaresh Kumar Inna static void 2703a3667aaeSNaresh Kumar Inna csio_hws_removing(struct csio_hw *hw, enum csio_hw_ev evt) 2704a3667aaeSNaresh Kumar Inna { 2705a3667aaeSNaresh Kumar Inna hw->prev_evt = hw->cur_evt; 2706a3667aaeSNaresh Kumar Inna hw->cur_evt = evt; 2707a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_sm[evt]); 2708a3667aaeSNaresh Kumar Inna 2709a3667aaeSNaresh Kumar Inna switch (evt) { 2710a3667aaeSNaresh Kumar Inna case CSIO_HWE_HBA_RESET: 2711a3667aaeSNaresh Kumar Inna if (!csio_is_hw_master(hw)) 2712a3667aaeSNaresh Kumar Inna break; 2713a3667aaeSNaresh Kumar Inna /* 2714a3667aaeSNaresh Kumar Inna * The BYE should have alerady been issued, so we cant 2715a3667aaeSNaresh Kumar Inna * use the mailbox interface. Hence we use the PL_RST 2716a3667aaeSNaresh Kumar Inna * register directly. 2717a3667aaeSNaresh Kumar Inna */ 2718a3667aaeSNaresh Kumar Inna csio_err(hw, "Resetting HW and waiting 2 seconds...\n"); 27190d804338SHariprasad Shenai csio_wr_reg32(hw, PIORSTMODE_F | PIORST_F, PL_RST_A); 2720a3667aaeSNaresh Kumar Inna mdelay(2000); 2721a3667aaeSNaresh Kumar Inna break; 2722a3667aaeSNaresh Kumar Inna 2723a3667aaeSNaresh Kumar Inna /* Should never receive any new events */ 2724a3667aaeSNaresh Kumar Inna default: 2725a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_unexp); 2726a3667aaeSNaresh Kumar Inna break; 2727a3667aaeSNaresh Kumar Inna 2728a3667aaeSNaresh Kumar Inna } 2729a3667aaeSNaresh Kumar Inna } 2730a3667aaeSNaresh Kumar Inna 2731a3667aaeSNaresh Kumar Inna /* 2732a3667aaeSNaresh Kumar Inna * csio_hws_pcierr - PCI Error state 2733a3667aaeSNaresh Kumar Inna * @hw - HW module 2734a3667aaeSNaresh Kumar Inna * @evt - Event 2735a3667aaeSNaresh Kumar Inna * 2736a3667aaeSNaresh Kumar Inna */ 2737a3667aaeSNaresh Kumar Inna static void 2738a3667aaeSNaresh Kumar Inna csio_hws_pcierr(struct csio_hw *hw, enum csio_hw_ev evt) 2739a3667aaeSNaresh Kumar Inna { 2740a3667aaeSNaresh Kumar Inna hw->prev_evt = hw->cur_evt; 2741a3667aaeSNaresh Kumar Inna hw->cur_evt = evt; 2742a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_sm[evt]); 2743a3667aaeSNaresh Kumar Inna 2744a3667aaeSNaresh Kumar Inna switch (evt) { 2745a3667aaeSNaresh Kumar Inna case CSIO_HWE_PCIERR_SLOT_RESET: 2746a3667aaeSNaresh Kumar Inna csio_evtq_start(hw); 2747a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_configuring); 2748a3667aaeSNaresh Kumar Inna csio_hw_configure(hw); 2749a3667aaeSNaresh Kumar Inna break; 2750a3667aaeSNaresh Kumar Inna 2751a3667aaeSNaresh Kumar Inna default: 2752a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_unexp); 2753a3667aaeSNaresh Kumar Inna break; 2754a3667aaeSNaresh Kumar Inna } 2755a3667aaeSNaresh Kumar Inna } 2756a3667aaeSNaresh Kumar Inna 2757a3667aaeSNaresh Kumar Inna /*****************************************************************************/ 2758a3667aaeSNaresh Kumar Inna /* END: HW SM */ 2759a3667aaeSNaresh Kumar Inna /*****************************************************************************/ 2760a3667aaeSNaresh Kumar Inna 2761a3667aaeSNaresh Kumar Inna /* 2762a3667aaeSNaresh Kumar Inna * csio_handle_intr_status - table driven interrupt handler 2763a3667aaeSNaresh Kumar Inna * @hw: HW instance 2764a3667aaeSNaresh Kumar Inna * @reg: the interrupt status register to process 2765a3667aaeSNaresh Kumar Inna * @acts: table of interrupt actions 2766a3667aaeSNaresh Kumar Inna * 2767a3667aaeSNaresh Kumar Inna * A table driven interrupt handler that applies a set of masks to an 2768a3667aaeSNaresh Kumar Inna * interrupt status word and performs the corresponding actions if the 2769a3667aaeSNaresh Kumar Inna * interrupts described by the mask have occured. The actions include 2770a3667aaeSNaresh Kumar Inna * optionally emitting a warning or alert message. The table is terminated 2771a3667aaeSNaresh Kumar Inna * by an entry specifying mask 0. Returns the number of fatal interrupt 2772a3667aaeSNaresh Kumar Inna * conditions. 2773a3667aaeSNaresh Kumar Inna */ 27747cc16380SArvind Bhushan int 2775a3667aaeSNaresh Kumar Inna csio_handle_intr_status(struct csio_hw *hw, unsigned int reg, 2776a3667aaeSNaresh Kumar Inna const struct intr_info *acts) 2777a3667aaeSNaresh Kumar Inna { 2778a3667aaeSNaresh Kumar Inna int fatal = 0; 2779a3667aaeSNaresh Kumar Inna unsigned int mask = 0; 2780a3667aaeSNaresh Kumar Inna unsigned int status = csio_rd_reg32(hw, reg); 2781a3667aaeSNaresh Kumar Inna 2782a3667aaeSNaresh Kumar Inna for ( ; acts->mask; ++acts) { 2783a3667aaeSNaresh Kumar Inna if (!(status & acts->mask)) 2784a3667aaeSNaresh Kumar Inna continue; 2785a3667aaeSNaresh Kumar Inna if (acts->fatal) { 2786a3667aaeSNaresh Kumar Inna fatal++; 2787a3667aaeSNaresh Kumar Inna csio_fatal(hw, "Fatal %s (0x%x)\n", 2788a3667aaeSNaresh Kumar Inna acts->msg, status & acts->mask); 2789a3667aaeSNaresh Kumar Inna } else if (acts->msg) 2790a3667aaeSNaresh Kumar Inna csio_info(hw, "%s (0x%x)\n", 2791a3667aaeSNaresh Kumar Inna acts->msg, status & acts->mask); 2792a3667aaeSNaresh Kumar Inna mask |= acts->mask; 2793a3667aaeSNaresh Kumar Inna } 2794a3667aaeSNaresh Kumar Inna status &= mask; 2795a3667aaeSNaresh Kumar Inna if (status) /* clear processed interrupts */ 2796a3667aaeSNaresh Kumar Inna csio_wr_reg32(hw, status, reg); 2797a3667aaeSNaresh Kumar Inna return fatal; 2798a3667aaeSNaresh Kumar Inna } 2799a3667aaeSNaresh Kumar Inna 2800a3667aaeSNaresh Kumar Inna /* 2801a3667aaeSNaresh Kumar Inna * TP interrupt handler. 2802a3667aaeSNaresh Kumar Inna */ 2803a3667aaeSNaresh Kumar Inna static void csio_tp_intr_handler(struct csio_hw *hw) 2804a3667aaeSNaresh Kumar Inna { 2805a3667aaeSNaresh Kumar Inna static struct intr_info tp_intr_info[] = { 2806a3667aaeSNaresh Kumar Inna { 0x3fffffff, "TP parity error", -1, 1 }, 2807837e4a42SHariprasad Shenai { FLMTXFLSTEMPTY_F, "TP out of Tx pages", -1, 1 }, 2808a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 2809a3667aaeSNaresh Kumar Inna }; 2810a3667aaeSNaresh Kumar Inna 2811837e4a42SHariprasad Shenai if (csio_handle_intr_status(hw, TP_INT_CAUSE_A, tp_intr_info)) 2812a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 2813a3667aaeSNaresh Kumar Inna } 2814a3667aaeSNaresh Kumar Inna 2815a3667aaeSNaresh Kumar Inna /* 2816a3667aaeSNaresh Kumar Inna * SGE interrupt handler. 2817a3667aaeSNaresh Kumar Inna */ 2818a3667aaeSNaresh Kumar Inna static void csio_sge_intr_handler(struct csio_hw *hw) 2819a3667aaeSNaresh Kumar Inna { 2820a3667aaeSNaresh Kumar Inna uint64_t v; 2821a3667aaeSNaresh Kumar Inna 2822a3667aaeSNaresh Kumar Inna static struct intr_info sge_intr_info[] = { 2823f612b815SHariprasad Shenai { ERR_CPL_EXCEED_IQE_SIZE_F, 2824a3667aaeSNaresh Kumar Inna "SGE received CPL exceeding IQE size", -1, 1 }, 2825f612b815SHariprasad Shenai { ERR_INVALID_CIDX_INC_F, 2826a3667aaeSNaresh Kumar Inna "SGE GTS CIDX increment too large", -1, 0 }, 2827f612b815SHariprasad Shenai { ERR_CPL_OPCODE_0_F, "SGE received 0-length CPL", -1, 0 }, 2828f612b815SHariprasad Shenai { ERR_DROPPED_DB_F, "SGE doorbell dropped", -1, 0 }, 2829f612b815SHariprasad Shenai { ERR_DATA_CPL_ON_HIGH_QID1_F | ERR_DATA_CPL_ON_HIGH_QID0_F, 2830a3667aaeSNaresh Kumar Inna "SGE IQID > 1023 received CPL for FL", -1, 0 }, 2831f612b815SHariprasad Shenai { ERR_BAD_DB_PIDX3_F, "SGE DBP 3 pidx increment too large", -1, 2832a3667aaeSNaresh Kumar Inna 0 }, 2833f612b815SHariprasad Shenai { ERR_BAD_DB_PIDX2_F, "SGE DBP 2 pidx increment too large", -1, 2834a3667aaeSNaresh Kumar Inna 0 }, 2835f612b815SHariprasad Shenai { ERR_BAD_DB_PIDX1_F, "SGE DBP 1 pidx increment too large", -1, 2836a3667aaeSNaresh Kumar Inna 0 }, 2837f612b815SHariprasad Shenai { ERR_BAD_DB_PIDX0_F, "SGE DBP 0 pidx increment too large", -1, 2838a3667aaeSNaresh Kumar Inna 0 }, 2839f612b815SHariprasad Shenai { ERR_ING_CTXT_PRIO_F, 2840a3667aaeSNaresh Kumar Inna "SGE too many priority ingress contexts", -1, 0 }, 2841f612b815SHariprasad Shenai { ERR_EGR_CTXT_PRIO_F, 2842a3667aaeSNaresh Kumar Inna "SGE too many priority egress contexts", -1, 0 }, 2843f612b815SHariprasad Shenai { INGRESS_SIZE_ERR_F, "SGE illegal ingress QID", -1, 0 }, 2844f612b815SHariprasad Shenai { EGRESS_SIZE_ERR_F, "SGE illegal egress QID", -1, 0 }, 2845a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 2846a3667aaeSNaresh Kumar Inna }; 2847a3667aaeSNaresh Kumar Inna 2848f612b815SHariprasad Shenai v = (uint64_t)csio_rd_reg32(hw, SGE_INT_CAUSE1_A) | 2849f612b815SHariprasad Shenai ((uint64_t)csio_rd_reg32(hw, SGE_INT_CAUSE2_A) << 32); 2850a3667aaeSNaresh Kumar Inna if (v) { 2851a3667aaeSNaresh Kumar Inna csio_fatal(hw, "SGE parity error (%#llx)\n", 2852a3667aaeSNaresh Kumar Inna (unsigned long long)v); 2853a3667aaeSNaresh Kumar Inna csio_wr_reg32(hw, (uint32_t)(v & 0xFFFFFFFF), 2854f612b815SHariprasad Shenai SGE_INT_CAUSE1_A); 2855f612b815SHariprasad Shenai csio_wr_reg32(hw, (uint32_t)(v >> 32), SGE_INT_CAUSE2_A); 2856a3667aaeSNaresh Kumar Inna } 2857a3667aaeSNaresh Kumar Inna 2858f612b815SHariprasad Shenai v |= csio_handle_intr_status(hw, SGE_INT_CAUSE3_A, sge_intr_info); 2859a3667aaeSNaresh Kumar Inna 2860f612b815SHariprasad Shenai if (csio_handle_intr_status(hw, SGE_INT_CAUSE3_A, sge_intr_info) || 2861a3667aaeSNaresh Kumar Inna v != 0) 2862a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 2863a3667aaeSNaresh Kumar Inna } 2864a3667aaeSNaresh Kumar Inna 286589c3a86cSHariprasad Shenai #define CIM_OBQ_INTR (OBQULP0PARERR_F | OBQULP1PARERR_F | OBQULP2PARERR_F |\ 286689c3a86cSHariprasad Shenai OBQULP3PARERR_F | OBQSGEPARERR_F | OBQNCSIPARERR_F) 286789c3a86cSHariprasad Shenai #define CIM_IBQ_INTR (IBQTP0PARERR_F | IBQTP1PARERR_F | IBQULPPARERR_F |\ 286889c3a86cSHariprasad Shenai IBQSGEHIPARERR_F | IBQSGELOPARERR_F | IBQNCSIPARERR_F) 2869a3667aaeSNaresh Kumar Inna 2870a3667aaeSNaresh Kumar Inna /* 2871a3667aaeSNaresh Kumar Inna * CIM interrupt handler. 2872a3667aaeSNaresh Kumar Inna */ 2873a3667aaeSNaresh Kumar Inna static void csio_cim_intr_handler(struct csio_hw *hw) 2874a3667aaeSNaresh Kumar Inna { 2875a3667aaeSNaresh Kumar Inna static struct intr_info cim_intr_info[] = { 287689c3a86cSHariprasad Shenai { PREFDROPINT_F, "CIM control register prefetch drop", -1, 1 }, 2877a3667aaeSNaresh Kumar Inna { CIM_OBQ_INTR, "CIM OBQ parity error", -1, 1 }, 2878a3667aaeSNaresh Kumar Inna { CIM_IBQ_INTR, "CIM IBQ parity error", -1, 1 }, 287989c3a86cSHariprasad Shenai { MBUPPARERR_F, "CIM mailbox uP parity error", -1, 1 }, 288089c3a86cSHariprasad Shenai { MBHOSTPARERR_F, "CIM mailbox host parity error", -1, 1 }, 288189c3a86cSHariprasad Shenai { TIEQINPARERRINT_F, "CIM TIEQ outgoing parity error", -1, 1 }, 288289c3a86cSHariprasad Shenai { TIEQOUTPARERRINT_F, "CIM TIEQ incoming parity error", -1, 1 }, 2883a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 2884a3667aaeSNaresh Kumar Inna }; 2885a3667aaeSNaresh Kumar Inna static struct intr_info cim_upintr_info[] = { 288689c3a86cSHariprasad Shenai { RSVDSPACEINT_F, "CIM reserved space access", -1, 1 }, 288789c3a86cSHariprasad Shenai { ILLTRANSINT_F, "CIM illegal transaction", -1, 1 }, 288889c3a86cSHariprasad Shenai { ILLWRINT_F, "CIM illegal write", -1, 1 }, 288989c3a86cSHariprasad Shenai { ILLRDINT_F, "CIM illegal read", -1, 1 }, 289089c3a86cSHariprasad Shenai { ILLRDBEINT_F, "CIM illegal read BE", -1, 1 }, 289189c3a86cSHariprasad Shenai { ILLWRBEINT_F, "CIM illegal write BE", -1, 1 }, 289289c3a86cSHariprasad Shenai { SGLRDBOOTINT_F, "CIM single read from boot space", -1, 1 }, 289389c3a86cSHariprasad Shenai { SGLWRBOOTINT_F, "CIM single write to boot space", -1, 1 }, 289489c3a86cSHariprasad Shenai { BLKWRBOOTINT_F, "CIM block write to boot space", -1, 1 }, 289589c3a86cSHariprasad Shenai { SGLRDFLASHINT_F, "CIM single read from flash space", -1, 1 }, 289689c3a86cSHariprasad Shenai { SGLWRFLASHINT_F, "CIM single write to flash space", -1, 1 }, 289789c3a86cSHariprasad Shenai { BLKWRFLASHINT_F, "CIM block write to flash space", -1, 1 }, 289889c3a86cSHariprasad Shenai { SGLRDEEPROMINT_F, "CIM single EEPROM read", -1, 1 }, 289989c3a86cSHariprasad Shenai { SGLWREEPROMINT_F, "CIM single EEPROM write", -1, 1 }, 290089c3a86cSHariprasad Shenai { BLKRDEEPROMINT_F, "CIM block EEPROM read", -1, 1 }, 290189c3a86cSHariprasad Shenai { BLKWREEPROMINT_F, "CIM block EEPROM write", -1, 1 }, 290289c3a86cSHariprasad Shenai { SGLRDCTLINT_F, "CIM single read from CTL space", -1, 1 }, 290389c3a86cSHariprasad Shenai { SGLWRCTLINT_F, "CIM single write to CTL space", -1, 1 }, 290489c3a86cSHariprasad Shenai { BLKRDCTLINT_F, "CIM block read from CTL space", -1, 1 }, 290589c3a86cSHariprasad Shenai { BLKWRCTLINT_F, "CIM block write to CTL space", -1, 1 }, 290689c3a86cSHariprasad Shenai { SGLRDPLINT_F, "CIM single read from PL space", -1, 1 }, 290789c3a86cSHariprasad Shenai { SGLWRPLINT_F, "CIM single write to PL space", -1, 1 }, 290889c3a86cSHariprasad Shenai { BLKRDPLINT_F, "CIM block read from PL space", -1, 1 }, 290989c3a86cSHariprasad Shenai { BLKWRPLINT_F, "CIM block write to PL space", -1, 1 }, 291089c3a86cSHariprasad Shenai { REQOVRLOOKUPINT_F, "CIM request FIFO overwrite", -1, 1 }, 291189c3a86cSHariprasad Shenai { RSPOVRLOOKUPINT_F, "CIM response FIFO overwrite", -1, 1 }, 291289c3a86cSHariprasad Shenai { TIMEOUTINT_F, "CIM PIF timeout", -1, 1 }, 291389c3a86cSHariprasad Shenai { TIMEOUTMAINT_F, "CIM PIF MA timeout", -1, 1 }, 2914a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 2915a3667aaeSNaresh Kumar Inna }; 2916a3667aaeSNaresh Kumar Inna 2917a3667aaeSNaresh Kumar Inna int fat; 2918a3667aaeSNaresh Kumar Inna 291989c3a86cSHariprasad Shenai fat = csio_handle_intr_status(hw, CIM_HOST_INT_CAUSE_A, 2920a3667aaeSNaresh Kumar Inna cim_intr_info) + 292189c3a86cSHariprasad Shenai csio_handle_intr_status(hw, CIM_HOST_UPACC_INT_CAUSE_A, 2922a3667aaeSNaresh Kumar Inna cim_upintr_info); 2923a3667aaeSNaresh Kumar Inna if (fat) 2924a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 2925a3667aaeSNaresh Kumar Inna } 2926a3667aaeSNaresh Kumar Inna 2927a3667aaeSNaresh Kumar Inna /* 2928a3667aaeSNaresh Kumar Inna * ULP RX interrupt handler. 2929a3667aaeSNaresh Kumar Inna */ 2930a3667aaeSNaresh Kumar Inna static void csio_ulprx_intr_handler(struct csio_hw *hw) 2931a3667aaeSNaresh Kumar Inna { 2932a3667aaeSNaresh Kumar Inna static struct intr_info ulprx_intr_info[] = { 2933a3667aaeSNaresh Kumar Inna { 0x1800000, "ULPRX context error", -1, 1 }, 2934a3667aaeSNaresh Kumar Inna { 0x7fffff, "ULPRX parity error", -1, 1 }, 2935a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 2936a3667aaeSNaresh Kumar Inna }; 2937a3667aaeSNaresh Kumar Inna 29380d804338SHariprasad Shenai if (csio_handle_intr_status(hw, ULP_RX_INT_CAUSE_A, ulprx_intr_info)) 2939a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 2940a3667aaeSNaresh Kumar Inna } 2941a3667aaeSNaresh Kumar Inna 2942a3667aaeSNaresh Kumar Inna /* 2943a3667aaeSNaresh Kumar Inna * ULP TX interrupt handler. 2944a3667aaeSNaresh Kumar Inna */ 2945a3667aaeSNaresh Kumar Inna static void csio_ulptx_intr_handler(struct csio_hw *hw) 2946a3667aaeSNaresh Kumar Inna { 2947a3667aaeSNaresh Kumar Inna static struct intr_info ulptx_intr_info[] = { 2948837e4a42SHariprasad Shenai { PBL_BOUND_ERR_CH3_F, "ULPTX channel 3 PBL out of bounds", -1, 2949a3667aaeSNaresh Kumar Inna 0 }, 2950837e4a42SHariprasad Shenai { PBL_BOUND_ERR_CH2_F, "ULPTX channel 2 PBL out of bounds", -1, 2951a3667aaeSNaresh Kumar Inna 0 }, 2952837e4a42SHariprasad Shenai { PBL_BOUND_ERR_CH1_F, "ULPTX channel 1 PBL out of bounds", -1, 2953a3667aaeSNaresh Kumar Inna 0 }, 2954837e4a42SHariprasad Shenai { PBL_BOUND_ERR_CH0_F, "ULPTX channel 0 PBL out of bounds", -1, 2955a3667aaeSNaresh Kumar Inna 0 }, 2956a3667aaeSNaresh Kumar Inna { 0xfffffff, "ULPTX parity error", -1, 1 }, 2957a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 2958a3667aaeSNaresh Kumar Inna }; 2959a3667aaeSNaresh Kumar Inna 2960837e4a42SHariprasad Shenai if (csio_handle_intr_status(hw, ULP_TX_INT_CAUSE_A, ulptx_intr_info)) 2961a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 2962a3667aaeSNaresh Kumar Inna } 2963a3667aaeSNaresh Kumar Inna 2964a3667aaeSNaresh Kumar Inna /* 2965a3667aaeSNaresh Kumar Inna * PM TX interrupt handler. 2966a3667aaeSNaresh Kumar Inna */ 2967a3667aaeSNaresh Kumar Inna static void csio_pmtx_intr_handler(struct csio_hw *hw) 2968a3667aaeSNaresh Kumar Inna { 2969a3667aaeSNaresh Kumar Inna static struct intr_info pmtx_intr_info[] = { 2970837e4a42SHariprasad Shenai { PCMD_LEN_OVFL0_F, "PMTX channel 0 pcmd too large", -1, 1 }, 2971837e4a42SHariprasad Shenai { PCMD_LEN_OVFL1_F, "PMTX channel 1 pcmd too large", -1, 1 }, 2972837e4a42SHariprasad Shenai { PCMD_LEN_OVFL2_F, "PMTX channel 2 pcmd too large", -1, 1 }, 2973837e4a42SHariprasad Shenai { ZERO_C_CMD_ERROR_F, "PMTX 0-length pcmd", -1, 1 }, 2974a3667aaeSNaresh Kumar Inna { 0xffffff0, "PMTX framing error", -1, 1 }, 2975837e4a42SHariprasad Shenai { OESPI_PAR_ERROR_F, "PMTX oespi parity error", -1, 1 }, 2976837e4a42SHariprasad Shenai { DB_OPTIONS_PAR_ERROR_F, "PMTX db_options parity error", -1, 2977a3667aaeSNaresh Kumar Inna 1 }, 2978837e4a42SHariprasad Shenai { ICSPI_PAR_ERROR_F, "PMTX icspi parity error", -1, 1 }, 2979837e4a42SHariprasad Shenai { PMTX_C_PCMD_PAR_ERROR_F, "PMTX c_pcmd parity error", -1, 1}, 2980a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 2981a3667aaeSNaresh Kumar Inna }; 2982a3667aaeSNaresh Kumar Inna 2983837e4a42SHariprasad Shenai if (csio_handle_intr_status(hw, PM_TX_INT_CAUSE_A, pmtx_intr_info)) 2984a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 2985a3667aaeSNaresh Kumar Inna } 2986a3667aaeSNaresh Kumar Inna 2987a3667aaeSNaresh Kumar Inna /* 2988a3667aaeSNaresh Kumar Inna * PM RX interrupt handler. 2989a3667aaeSNaresh Kumar Inna */ 2990a3667aaeSNaresh Kumar Inna static void csio_pmrx_intr_handler(struct csio_hw *hw) 2991a3667aaeSNaresh Kumar Inna { 2992a3667aaeSNaresh Kumar Inna static struct intr_info pmrx_intr_info[] = { 2993837e4a42SHariprasad Shenai { ZERO_E_CMD_ERROR_F, "PMRX 0-length pcmd", -1, 1 }, 2994a3667aaeSNaresh Kumar Inna { 0x3ffff0, "PMRX framing error", -1, 1 }, 2995837e4a42SHariprasad Shenai { OCSPI_PAR_ERROR_F, "PMRX ocspi parity error", -1, 1 }, 2996837e4a42SHariprasad Shenai { DB_OPTIONS_PAR_ERROR_F, "PMRX db_options parity error", -1, 2997a3667aaeSNaresh Kumar Inna 1 }, 2998837e4a42SHariprasad Shenai { IESPI_PAR_ERROR_F, "PMRX iespi parity error", -1, 1 }, 2999837e4a42SHariprasad Shenai { PMRX_E_PCMD_PAR_ERROR_F, "PMRX e_pcmd parity error", -1, 1}, 3000a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3001a3667aaeSNaresh Kumar Inna }; 3002a3667aaeSNaresh Kumar Inna 3003837e4a42SHariprasad Shenai if (csio_handle_intr_status(hw, PM_RX_INT_CAUSE_A, pmrx_intr_info)) 3004a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 3005a3667aaeSNaresh Kumar Inna } 3006a3667aaeSNaresh Kumar Inna 3007a3667aaeSNaresh Kumar Inna /* 3008a3667aaeSNaresh Kumar Inna * CPL switch interrupt handler. 3009a3667aaeSNaresh Kumar Inna */ 3010a3667aaeSNaresh Kumar Inna static void csio_cplsw_intr_handler(struct csio_hw *hw) 3011a3667aaeSNaresh Kumar Inna { 3012a3667aaeSNaresh Kumar Inna static struct intr_info cplsw_intr_info[] = { 30130d804338SHariprasad Shenai { CIM_OP_MAP_PERR_F, "CPLSW CIM op_map parity error", -1, 1 }, 30140d804338SHariprasad Shenai { CIM_OVFL_ERROR_F, "CPLSW CIM overflow", -1, 1 }, 30150d804338SHariprasad Shenai { TP_FRAMING_ERROR_F, "CPLSW TP framing error", -1, 1 }, 30160d804338SHariprasad Shenai { SGE_FRAMING_ERROR_F, "CPLSW SGE framing error", -1, 1 }, 30170d804338SHariprasad Shenai { CIM_FRAMING_ERROR_F, "CPLSW CIM framing error", -1, 1 }, 30180d804338SHariprasad Shenai { ZERO_SWITCH_ERROR_F, "CPLSW no-switch error", -1, 1 }, 3019a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3020a3667aaeSNaresh Kumar Inna }; 3021a3667aaeSNaresh Kumar Inna 30220d804338SHariprasad Shenai if (csio_handle_intr_status(hw, CPL_INTR_CAUSE_A, cplsw_intr_info)) 3023a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 3024a3667aaeSNaresh Kumar Inna } 3025a3667aaeSNaresh Kumar Inna 3026a3667aaeSNaresh Kumar Inna /* 3027a3667aaeSNaresh Kumar Inna * LE interrupt handler. 3028a3667aaeSNaresh Kumar Inna */ 3029a3667aaeSNaresh Kumar Inna static void csio_le_intr_handler(struct csio_hw *hw) 3030a3667aaeSNaresh Kumar Inna { 3031a3667aaeSNaresh Kumar Inna static struct intr_info le_intr_info[] = { 30320d804338SHariprasad Shenai { LIPMISS_F, "LE LIP miss", -1, 0 }, 30330d804338SHariprasad Shenai { LIP0_F, "LE 0 LIP error", -1, 0 }, 30340d804338SHariprasad Shenai { PARITYERR_F, "LE parity error", -1, 1 }, 30350d804338SHariprasad Shenai { UNKNOWNCMD_F, "LE unknown command", -1, 1 }, 30360d804338SHariprasad Shenai { REQQPARERR_F, "LE request queue parity error", -1, 1 }, 3037a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3038a3667aaeSNaresh Kumar Inna }; 3039a3667aaeSNaresh Kumar Inna 30400d804338SHariprasad Shenai if (csio_handle_intr_status(hw, LE_DB_INT_CAUSE_A, le_intr_info)) 3041a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 3042a3667aaeSNaresh Kumar Inna } 3043a3667aaeSNaresh Kumar Inna 3044a3667aaeSNaresh Kumar Inna /* 3045a3667aaeSNaresh Kumar Inna * MPS interrupt handler. 3046a3667aaeSNaresh Kumar Inna */ 3047a3667aaeSNaresh Kumar Inna static void csio_mps_intr_handler(struct csio_hw *hw) 3048a3667aaeSNaresh Kumar Inna { 3049a3667aaeSNaresh Kumar Inna static struct intr_info mps_rx_intr_info[] = { 3050a3667aaeSNaresh Kumar Inna { 0xffffff, "MPS Rx parity error", -1, 1 }, 3051a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3052a3667aaeSNaresh Kumar Inna }; 3053a3667aaeSNaresh Kumar Inna static struct intr_info mps_tx_intr_info[] = { 3054837e4a42SHariprasad Shenai { TPFIFO_V(TPFIFO_M), "MPS Tx TP FIFO parity error", -1, 1 }, 3055837e4a42SHariprasad Shenai { NCSIFIFO_F, "MPS Tx NC-SI FIFO parity error", -1, 1 }, 3056837e4a42SHariprasad Shenai { TXDATAFIFO_V(TXDATAFIFO_M), "MPS Tx data FIFO parity error", 3057837e4a42SHariprasad Shenai -1, 1 }, 3058837e4a42SHariprasad Shenai { TXDESCFIFO_V(TXDESCFIFO_M), "MPS Tx desc FIFO parity error", 3059837e4a42SHariprasad Shenai -1, 1 }, 3060837e4a42SHariprasad Shenai { BUBBLE_F, "MPS Tx underflow", -1, 1 }, 3061837e4a42SHariprasad Shenai { SECNTERR_F, "MPS Tx SOP/EOP error", -1, 1 }, 3062837e4a42SHariprasad Shenai { FRMERR_F, "MPS Tx framing error", -1, 1 }, 3063a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3064a3667aaeSNaresh Kumar Inna }; 3065a3667aaeSNaresh Kumar Inna static struct intr_info mps_trc_intr_info[] = { 3066837e4a42SHariprasad Shenai { FILTMEM_V(FILTMEM_M), "MPS TRC filter parity error", -1, 1 }, 3067837e4a42SHariprasad Shenai { PKTFIFO_V(PKTFIFO_M), "MPS TRC packet FIFO parity error", 3068837e4a42SHariprasad Shenai -1, 1 }, 3069837e4a42SHariprasad Shenai { MISCPERR_F, "MPS TRC misc parity error", -1, 1 }, 3070a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3071a3667aaeSNaresh Kumar Inna }; 3072a3667aaeSNaresh Kumar Inna static struct intr_info mps_stat_sram_intr_info[] = { 3073a3667aaeSNaresh Kumar Inna { 0x1fffff, "MPS statistics SRAM parity error", -1, 1 }, 3074a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3075a3667aaeSNaresh Kumar Inna }; 3076a3667aaeSNaresh Kumar Inna static struct intr_info mps_stat_tx_intr_info[] = { 3077a3667aaeSNaresh Kumar Inna { 0xfffff, "MPS statistics Tx FIFO parity error", -1, 1 }, 3078a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3079a3667aaeSNaresh Kumar Inna }; 3080a3667aaeSNaresh Kumar Inna static struct intr_info mps_stat_rx_intr_info[] = { 3081a3667aaeSNaresh Kumar Inna { 0xffffff, "MPS statistics Rx FIFO parity error", -1, 1 }, 3082a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3083a3667aaeSNaresh Kumar Inna }; 3084a3667aaeSNaresh Kumar Inna static struct intr_info mps_cls_intr_info[] = { 3085837e4a42SHariprasad Shenai { MATCHSRAM_F, "MPS match SRAM parity error", -1, 1 }, 3086837e4a42SHariprasad Shenai { MATCHTCAM_F, "MPS match TCAM parity error", -1, 1 }, 3087837e4a42SHariprasad Shenai { HASHSRAM_F, "MPS hash SRAM parity error", -1, 1 }, 3088a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3089a3667aaeSNaresh Kumar Inna }; 3090a3667aaeSNaresh Kumar Inna 3091a3667aaeSNaresh Kumar Inna int fat; 3092a3667aaeSNaresh Kumar Inna 3093837e4a42SHariprasad Shenai fat = csio_handle_intr_status(hw, MPS_RX_PERR_INT_CAUSE_A, 3094a3667aaeSNaresh Kumar Inna mps_rx_intr_info) + 3095837e4a42SHariprasad Shenai csio_handle_intr_status(hw, MPS_TX_INT_CAUSE_A, 3096a3667aaeSNaresh Kumar Inna mps_tx_intr_info) + 3097837e4a42SHariprasad Shenai csio_handle_intr_status(hw, MPS_TRC_INT_CAUSE_A, 3098a3667aaeSNaresh Kumar Inna mps_trc_intr_info) + 3099837e4a42SHariprasad Shenai csio_handle_intr_status(hw, MPS_STAT_PERR_INT_CAUSE_SRAM_A, 3100a3667aaeSNaresh Kumar Inna mps_stat_sram_intr_info) + 3101837e4a42SHariprasad Shenai csio_handle_intr_status(hw, MPS_STAT_PERR_INT_CAUSE_TX_FIFO_A, 3102a3667aaeSNaresh Kumar Inna mps_stat_tx_intr_info) + 3103837e4a42SHariprasad Shenai csio_handle_intr_status(hw, MPS_STAT_PERR_INT_CAUSE_RX_FIFO_A, 3104a3667aaeSNaresh Kumar Inna mps_stat_rx_intr_info) + 3105837e4a42SHariprasad Shenai csio_handle_intr_status(hw, MPS_CLS_INT_CAUSE_A, 3106a3667aaeSNaresh Kumar Inna mps_cls_intr_info); 3107a3667aaeSNaresh Kumar Inna 3108837e4a42SHariprasad Shenai csio_wr_reg32(hw, 0, MPS_INT_CAUSE_A); 3109837e4a42SHariprasad Shenai csio_rd_reg32(hw, MPS_INT_CAUSE_A); /* flush */ 3110a3667aaeSNaresh Kumar Inna if (fat) 3111a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 3112a3667aaeSNaresh Kumar Inna } 3113a3667aaeSNaresh Kumar Inna 311489c3a86cSHariprasad Shenai #define MEM_INT_MASK (PERR_INT_CAUSE_F | ECC_CE_INT_CAUSE_F | \ 311589c3a86cSHariprasad Shenai ECC_UE_INT_CAUSE_F) 3116a3667aaeSNaresh Kumar Inna 3117a3667aaeSNaresh Kumar Inna /* 3118a3667aaeSNaresh Kumar Inna * EDC/MC interrupt handler. 3119a3667aaeSNaresh Kumar Inna */ 3120a3667aaeSNaresh Kumar Inna static void csio_mem_intr_handler(struct csio_hw *hw, int idx) 3121a3667aaeSNaresh Kumar Inna { 3122a3667aaeSNaresh Kumar Inna static const char name[3][5] = { "EDC0", "EDC1", "MC" }; 3123a3667aaeSNaresh Kumar Inna 3124a3667aaeSNaresh Kumar Inna unsigned int addr, cnt_addr, v; 3125a3667aaeSNaresh Kumar Inna 3126a3667aaeSNaresh Kumar Inna if (idx <= MEM_EDC1) { 312789c3a86cSHariprasad Shenai addr = EDC_REG(EDC_INT_CAUSE_A, idx); 312889c3a86cSHariprasad Shenai cnt_addr = EDC_REG(EDC_ECC_STATUS_A, idx); 3129a3667aaeSNaresh Kumar Inna } else { 313089c3a86cSHariprasad Shenai addr = MC_INT_CAUSE_A; 313189c3a86cSHariprasad Shenai cnt_addr = MC_ECC_STATUS_A; 3132a3667aaeSNaresh Kumar Inna } 3133a3667aaeSNaresh Kumar Inna 3134a3667aaeSNaresh Kumar Inna v = csio_rd_reg32(hw, addr) & MEM_INT_MASK; 313589c3a86cSHariprasad Shenai if (v & PERR_INT_CAUSE_F) 3136a3667aaeSNaresh Kumar Inna csio_fatal(hw, "%s FIFO parity error\n", name[idx]); 313789c3a86cSHariprasad Shenai if (v & ECC_CE_INT_CAUSE_F) { 313889c3a86cSHariprasad Shenai uint32_t cnt = ECC_CECNT_G(csio_rd_reg32(hw, cnt_addr)); 3139a3667aaeSNaresh Kumar Inna 314089c3a86cSHariprasad Shenai csio_wr_reg32(hw, ECC_CECNT_V(ECC_CECNT_M), cnt_addr); 3141a3667aaeSNaresh Kumar Inna csio_warn(hw, "%u %s correctable ECC data error%s\n", 3142a3667aaeSNaresh Kumar Inna cnt, name[idx], cnt > 1 ? "s" : ""); 3143a3667aaeSNaresh Kumar Inna } 314489c3a86cSHariprasad Shenai if (v & ECC_UE_INT_CAUSE_F) 3145a3667aaeSNaresh Kumar Inna csio_fatal(hw, "%s uncorrectable ECC data error\n", name[idx]); 3146a3667aaeSNaresh Kumar Inna 3147a3667aaeSNaresh Kumar Inna csio_wr_reg32(hw, v, addr); 314889c3a86cSHariprasad Shenai if (v & (PERR_INT_CAUSE_F | ECC_UE_INT_CAUSE_F)) 3149a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 3150a3667aaeSNaresh Kumar Inna } 3151a3667aaeSNaresh Kumar Inna 3152a3667aaeSNaresh Kumar Inna /* 3153a3667aaeSNaresh Kumar Inna * MA interrupt handler. 3154a3667aaeSNaresh Kumar Inna */ 3155a3667aaeSNaresh Kumar Inna static void csio_ma_intr_handler(struct csio_hw *hw) 3156a3667aaeSNaresh Kumar Inna { 315789c3a86cSHariprasad Shenai uint32_t v, status = csio_rd_reg32(hw, MA_INT_CAUSE_A); 3158a3667aaeSNaresh Kumar Inna 315989c3a86cSHariprasad Shenai if (status & MEM_PERR_INT_CAUSE_F) 3160a3667aaeSNaresh Kumar Inna csio_fatal(hw, "MA parity error, parity status %#x\n", 316189c3a86cSHariprasad Shenai csio_rd_reg32(hw, MA_PARITY_ERROR_STATUS_A)); 316289c3a86cSHariprasad Shenai if (status & MEM_WRAP_INT_CAUSE_F) { 316389c3a86cSHariprasad Shenai v = csio_rd_reg32(hw, MA_INT_WRAP_STATUS_A); 3164a3667aaeSNaresh Kumar Inna csio_fatal(hw, 3165a3667aaeSNaresh Kumar Inna "MA address wrap-around error by client %u to address %#x\n", 316689c3a86cSHariprasad Shenai MEM_WRAP_CLIENT_NUM_G(v), MEM_WRAP_ADDRESS_G(v) << 4); 3167a3667aaeSNaresh Kumar Inna } 316889c3a86cSHariprasad Shenai csio_wr_reg32(hw, status, MA_INT_CAUSE_A); 3169a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 3170a3667aaeSNaresh Kumar Inna } 3171a3667aaeSNaresh Kumar Inna 3172a3667aaeSNaresh Kumar Inna /* 3173a3667aaeSNaresh Kumar Inna * SMB interrupt handler. 3174a3667aaeSNaresh Kumar Inna */ 3175a3667aaeSNaresh Kumar Inna static void csio_smb_intr_handler(struct csio_hw *hw) 3176a3667aaeSNaresh Kumar Inna { 3177a3667aaeSNaresh Kumar Inna static struct intr_info smb_intr_info[] = { 31780d804338SHariprasad Shenai { MSTTXFIFOPARINT_F, "SMB master Tx FIFO parity error", -1, 1 }, 31790d804338SHariprasad Shenai { MSTRXFIFOPARINT_F, "SMB master Rx FIFO parity error", -1, 1 }, 31800d804338SHariprasad Shenai { SLVFIFOPARINT_F, "SMB slave FIFO parity error", -1, 1 }, 3181a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3182a3667aaeSNaresh Kumar Inna }; 3183a3667aaeSNaresh Kumar Inna 31840d804338SHariprasad Shenai if (csio_handle_intr_status(hw, SMB_INT_CAUSE_A, smb_intr_info)) 3185a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 3186a3667aaeSNaresh Kumar Inna } 3187a3667aaeSNaresh Kumar Inna 3188a3667aaeSNaresh Kumar Inna /* 3189a3667aaeSNaresh Kumar Inna * NC-SI interrupt handler. 3190a3667aaeSNaresh Kumar Inna */ 3191a3667aaeSNaresh Kumar Inna static void csio_ncsi_intr_handler(struct csio_hw *hw) 3192a3667aaeSNaresh Kumar Inna { 3193a3667aaeSNaresh Kumar Inna static struct intr_info ncsi_intr_info[] = { 31940d804338SHariprasad Shenai { CIM_DM_PRTY_ERR_F, "NC-SI CIM parity error", -1, 1 }, 31950d804338SHariprasad Shenai { MPS_DM_PRTY_ERR_F, "NC-SI MPS parity error", -1, 1 }, 31960d804338SHariprasad Shenai { TXFIFO_PRTY_ERR_F, "NC-SI Tx FIFO parity error", -1, 1 }, 31970d804338SHariprasad Shenai { RXFIFO_PRTY_ERR_F, "NC-SI Rx FIFO parity error", -1, 1 }, 3198a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3199a3667aaeSNaresh Kumar Inna }; 3200a3667aaeSNaresh Kumar Inna 32010d804338SHariprasad Shenai if (csio_handle_intr_status(hw, NCSI_INT_CAUSE_A, ncsi_intr_info)) 3202a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 3203a3667aaeSNaresh Kumar Inna } 3204a3667aaeSNaresh Kumar Inna 3205a3667aaeSNaresh Kumar Inna /* 3206a3667aaeSNaresh Kumar Inna * XGMAC interrupt handler. 3207a3667aaeSNaresh Kumar Inna */ 3208a3667aaeSNaresh Kumar Inna static void csio_xgmac_intr_handler(struct csio_hw *hw, int port) 3209a3667aaeSNaresh Kumar Inna { 32107cc16380SArvind Bhushan uint32_t v = csio_rd_reg32(hw, CSIO_MAC_INT_CAUSE_REG(hw, port)); 3211a3667aaeSNaresh Kumar Inna 32120d804338SHariprasad Shenai v &= TXFIFO_PRTY_ERR_F | RXFIFO_PRTY_ERR_F; 3213a3667aaeSNaresh Kumar Inna if (!v) 3214a3667aaeSNaresh Kumar Inna return; 3215a3667aaeSNaresh Kumar Inna 32160d804338SHariprasad Shenai if (v & TXFIFO_PRTY_ERR_F) 3217a3667aaeSNaresh Kumar Inna csio_fatal(hw, "XGMAC %d Tx FIFO parity error\n", port); 32180d804338SHariprasad Shenai if (v & RXFIFO_PRTY_ERR_F) 3219a3667aaeSNaresh Kumar Inna csio_fatal(hw, "XGMAC %d Rx FIFO parity error\n", port); 32207cc16380SArvind Bhushan csio_wr_reg32(hw, v, CSIO_MAC_INT_CAUSE_REG(hw, port)); 3221a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 3222a3667aaeSNaresh Kumar Inna } 3223a3667aaeSNaresh Kumar Inna 3224a3667aaeSNaresh Kumar Inna /* 3225a3667aaeSNaresh Kumar Inna * PL interrupt handler. 3226a3667aaeSNaresh Kumar Inna */ 3227a3667aaeSNaresh Kumar Inna static void csio_pl_intr_handler(struct csio_hw *hw) 3228a3667aaeSNaresh Kumar Inna { 3229a3667aaeSNaresh Kumar Inna static struct intr_info pl_intr_info[] = { 32300d804338SHariprasad Shenai { FATALPERR_F, "T4 fatal parity error", -1, 1 }, 32310d804338SHariprasad Shenai { PERRVFID_F, "PL VFID_MAP parity error", -1, 1 }, 3232a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3233a3667aaeSNaresh Kumar Inna }; 3234a3667aaeSNaresh Kumar Inna 32350d804338SHariprasad Shenai if (csio_handle_intr_status(hw, PL_PL_INT_CAUSE_A, pl_intr_info)) 3236a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 3237a3667aaeSNaresh Kumar Inna } 3238a3667aaeSNaresh Kumar Inna 3239a3667aaeSNaresh Kumar Inna /* 3240a3667aaeSNaresh Kumar Inna * csio_hw_slow_intr_handler - control path interrupt handler 3241a3667aaeSNaresh Kumar Inna * @hw: HW module 3242a3667aaeSNaresh Kumar Inna * 3243a3667aaeSNaresh Kumar Inna * Interrupt handler for non-data global interrupt events, e.g., errors. 3244a3667aaeSNaresh Kumar Inna * The designation 'slow' is because it involves register reads, while 3245a3667aaeSNaresh Kumar Inna * data interrupts typically don't involve any MMIOs. 3246a3667aaeSNaresh Kumar Inna */ 3247a3667aaeSNaresh Kumar Inna int 3248a3667aaeSNaresh Kumar Inna csio_hw_slow_intr_handler(struct csio_hw *hw) 3249a3667aaeSNaresh Kumar Inna { 32500d804338SHariprasad Shenai uint32_t cause = csio_rd_reg32(hw, PL_INT_CAUSE_A); 3251a3667aaeSNaresh Kumar Inna 3252a3667aaeSNaresh Kumar Inna if (!(cause & CSIO_GLBL_INTR_MASK)) { 3253a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_plint_unexp); 3254a3667aaeSNaresh Kumar Inna return 0; 3255a3667aaeSNaresh Kumar Inna } 3256a3667aaeSNaresh Kumar Inna 3257a3667aaeSNaresh Kumar Inna csio_dbg(hw, "Slow interrupt! cause: 0x%x\n", cause); 3258a3667aaeSNaresh Kumar Inna 3259a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_plint_cnt); 3260a3667aaeSNaresh Kumar Inna 32610d804338SHariprasad Shenai if (cause & CIM_F) 3262a3667aaeSNaresh Kumar Inna csio_cim_intr_handler(hw); 3263a3667aaeSNaresh Kumar Inna 32640d804338SHariprasad Shenai if (cause & MPS_F) 3265a3667aaeSNaresh Kumar Inna csio_mps_intr_handler(hw); 3266a3667aaeSNaresh Kumar Inna 32670d804338SHariprasad Shenai if (cause & NCSI_F) 3268a3667aaeSNaresh Kumar Inna csio_ncsi_intr_handler(hw); 3269a3667aaeSNaresh Kumar Inna 32700d804338SHariprasad Shenai if (cause & PL_F) 3271a3667aaeSNaresh Kumar Inna csio_pl_intr_handler(hw); 3272a3667aaeSNaresh Kumar Inna 32730d804338SHariprasad Shenai if (cause & SMB_F) 3274a3667aaeSNaresh Kumar Inna csio_smb_intr_handler(hw); 3275a3667aaeSNaresh Kumar Inna 32760d804338SHariprasad Shenai if (cause & XGMAC0_F) 3277a3667aaeSNaresh Kumar Inna csio_xgmac_intr_handler(hw, 0); 3278a3667aaeSNaresh Kumar Inna 32790d804338SHariprasad Shenai if (cause & XGMAC1_F) 3280a3667aaeSNaresh Kumar Inna csio_xgmac_intr_handler(hw, 1); 3281a3667aaeSNaresh Kumar Inna 32820d804338SHariprasad Shenai if (cause & XGMAC_KR0_F) 3283a3667aaeSNaresh Kumar Inna csio_xgmac_intr_handler(hw, 2); 3284a3667aaeSNaresh Kumar Inna 32850d804338SHariprasad Shenai if (cause & XGMAC_KR1_F) 3286a3667aaeSNaresh Kumar Inna csio_xgmac_intr_handler(hw, 3); 3287a3667aaeSNaresh Kumar Inna 32880d804338SHariprasad Shenai if (cause & PCIE_F) 32897cc16380SArvind Bhushan hw->chip_ops->chip_pcie_intr_handler(hw); 3290a3667aaeSNaresh Kumar Inna 32910d804338SHariprasad Shenai if (cause & MC_F) 3292a3667aaeSNaresh Kumar Inna csio_mem_intr_handler(hw, MEM_MC); 3293a3667aaeSNaresh Kumar Inna 32940d804338SHariprasad Shenai if (cause & EDC0_F) 3295a3667aaeSNaresh Kumar Inna csio_mem_intr_handler(hw, MEM_EDC0); 3296a3667aaeSNaresh Kumar Inna 32970d804338SHariprasad Shenai if (cause & EDC1_F) 3298a3667aaeSNaresh Kumar Inna csio_mem_intr_handler(hw, MEM_EDC1); 3299a3667aaeSNaresh Kumar Inna 33000d804338SHariprasad Shenai if (cause & LE_F) 3301a3667aaeSNaresh Kumar Inna csio_le_intr_handler(hw); 3302a3667aaeSNaresh Kumar Inna 33030d804338SHariprasad Shenai if (cause & TP_F) 3304a3667aaeSNaresh Kumar Inna csio_tp_intr_handler(hw); 3305a3667aaeSNaresh Kumar Inna 33060d804338SHariprasad Shenai if (cause & MA_F) 3307a3667aaeSNaresh Kumar Inna csio_ma_intr_handler(hw); 3308a3667aaeSNaresh Kumar Inna 33090d804338SHariprasad Shenai if (cause & PM_TX_F) 3310a3667aaeSNaresh Kumar Inna csio_pmtx_intr_handler(hw); 3311a3667aaeSNaresh Kumar Inna 33120d804338SHariprasad Shenai if (cause & PM_RX_F) 3313a3667aaeSNaresh Kumar Inna csio_pmrx_intr_handler(hw); 3314a3667aaeSNaresh Kumar Inna 33150d804338SHariprasad Shenai if (cause & ULP_RX_F) 3316a3667aaeSNaresh Kumar Inna csio_ulprx_intr_handler(hw); 3317a3667aaeSNaresh Kumar Inna 33180d804338SHariprasad Shenai if (cause & CPL_SWITCH_F) 3319a3667aaeSNaresh Kumar Inna csio_cplsw_intr_handler(hw); 3320a3667aaeSNaresh Kumar Inna 33210d804338SHariprasad Shenai if (cause & SGE_F) 3322a3667aaeSNaresh Kumar Inna csio_sge_intr_handler(hw); 3323a3667aaeSNaresh Kumar Inna 33240d804338SHariprasad Shenai if (cause & ULP_TX_F) 3325a3667aaeSNaresh Kumar Inna csio_ulptx_intr_handler(hw); 3326a3667aaeSNaresh Kumar Inna 3327a3667aaeSNaresh Kumar Inna /* Clear the interrupts just processed for which we are the master. */ 33280d804338SHariprasad Shenai csio_wr_reg32(hw, cause & CSIO_GLBL_INTR_MASK, PL_INT_CAUSE_A); 33290d804338SHariprasad Shenai csio_rd_reg32(hw, PL_INT_CAUSE_A); /* flush */ 3330a3667aaeSNaresh Kumar Inna 3331a3667aaeSNaresh Kumar Inna return 1; 3332a3667aaeSNaresh Kumar Inna } 3333a3667aaeSNaresh Kumar Inna 3334a3667aaeSNaresh Kumar Inna /***************************************************************************** 3335a3667aaeSNaresh Kumar Inna * HW <--> mailbox interfacing routines. 3336a3667aaeSNaresh Kumar Inna ****************************************************************************/ 3337a3667aaeSNaresh Kumar Inna /* 3338a3667aaeSNaresh Kumar Inna * csio_mberr_worker - Worker thread (dpc) for mailbox/error completions 3339a3667aaeSNaresh Kumar Inna * 3340a3667aaeSNaresh Kumar Inna * @data: Private data pointer. 3341a3667aaeSNaresh Kumar Inna * 3342a3667aaeSNaresh Kumar Inna * Called from worker thread context. 3343a3667aaeSNaresh Kumar Inna */ 3344a3667aaeSNaresh Kumar Inna static void 3345a3667aaeSNaresh Kumar Inna csio_mberr_worker(void *data) 3346a3667aaeSNaresh Kumar Inna { 3347a3667aaeSNaresh Kumar Inna struct csio_hw *hw = (struct csio_hw *)data; 3348a3667aaeSNaresh Kumar Inna struct csio_mbm *mbm = &hw->mbm; 3349a3667aaeSNaresh Kumar Inna LIST_HEAD(cbfn_q); 3350a3667aaeSNaresh Kumar Inna struct csio_mb *mbp_next; 3351a3667aaeSNaresh Kumar Inna int rv; 3352a3667aaeSNaresh Kumar Inna 3353a3667aaeSNaresh Kumar Inna del_timer_sync(&mbm->timer); 3354a3667aaeSNaresh Kumar Inna 3355a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 3356a3667aaeSNaresh Kumar Inna if (list_empty(&mbm->cbfn_q)) { 3357a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 3358a3667aaeSNaresh Kumar Inna return; 3359a3667aaeSNaresh Kumar Inna } 3360a3667aaeSNaresh Kumar Inna 3361a3667aaeSNaresh Kumar Inna list_splice_tail_init(&mbm->cbfn_q, &cbfn_q); 3362a3667aaeSNaresh Kumar Inna mbm->stats.n_cbfnq = 0; 3363a3667aaeSNaresh Kumar Inna 3364a3667aaeSNaresh Kumar Inna /* Try to start waiting mailboxes */ 3365a3667aaeSNaresh Kumar Inna if (!list_empty(&mbm->req_q)) { 3366a3667aaeSNaresh Kumar Inna mbp_next = list_first_entry(&mbm->req_q, struct csio_mb, list); 3367a3667aaeSNaresh Kumar Inna list_del_init(&mbp_next->list); 3368a3667aaeSNaresh Kumar Inna 3369a3667aaeSNaresh Kumar Inna rv = csio_mb_issue(hw, mbp_next); 3370a3667aaeSNaresh Kumar Inna if (rv != 0) 3371a3667aaeSNaresh Kumar Inna list_add_tail(&mbp_next->list, &mbm->req_q); 3372a3667aaeSNaresh Kumar Inna else 3373a3667aaeSNaresh Kumar Inna CSIO_DEC_STATS(mbm, n_activeq); 3374a3667aaeSNaresh Kumar Inna } 3375a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 3376a3667aaeSNaresh Kumar Inna 3377a3667aaeSNaresh Kumar Inna /* Now callback completions */ 3378a3667aaeSNaresh Kumar Inna csio_mb_completions(hw, &cbfn_q); 3379a3667aaeSNaresh Kumar Inna } 3380a3667aaeSNaresh Kumar Inna 3381a3667aaeSNaresh Kumar Inna /* 3382a3667aaeSNaresh Kumar Inna * csio_hw_mb_timer - Top-level Mailbox timeout handler. 3383a3667aaeSNaresh Kumar Inna * 3384a3667aaeSNaresh Kumar Inna * @data: private data pointer 3385a3667aaeSNaresh Kumar Inna * 3386a3667aaeSNaresh Kumar Inna **/ 3387a3667aaeSNaresh Kumar Inna static void 3388a3667aaeSNaresh Kumar Inna csio_hw_mb_timer(uintptr_t data) 3389a3667aaeSNaresh Kumar Inna { 3390a3667aaeSNaresh Kumar Inna struct csio_hw *hw = (struct csio_hw *)data; 3391a3667aaeSNaresh Kumar Inna struct csio_mb *mbp = NULL; 3392a3667aaeSNaresh Kumar Inna 3393a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 3394a3667aaeSNaresh Kumar Inna mbp = csio_mb_tmo_handler(hw); 3395a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 3396a3667aaeSNaresh Kumar Inna 3397a3667aaeSNaresh Kumar Inna /* Call back the function for the timed-out Mailbox */ 3398a3667aaeSNaresh Kumar Inna if (mbp) 3399a3667aaeSNaresh Kumar Inna mbp->mb_cbfn(hw, mbp); 3400a3667aaeSNaresh Kumar Inna 3401a3667aaeSNaresh Kumar Inna } 3402a3667aaeSNaresh Kumar Inna 3403a3667aaeSNaresh Kumar Inna /* 3404a3667aaeSNaresh Kumar Inna * csio_hw_mbm_cleanup - Cleanup Mailbox module. 3405a3667aaeSNaresh Kumar Inna * @hw: HW module 3406a3667aaeSNaresh Kumar Inna * 3407a3667aaeSNaresh Kumar Inna * Called with lock held, should exit with lock held. 3408a3667aaeSNaresh Kumar Inna * Cancels outstanding mailboxes (waiting, in-flight) and gathers them 3409a3667aaeSNaresh Kumar Inna * into a local queue. Drops lock and calls the completions. Holds 3410a3667aaeSNaresh Kumar Inna * lock and returns. 3411a3667aaeSNaresh Kumar Inna */ 3412a3667aaeSNaresh Kumar Inna static void 3413a3667aaeSNaresh Kumar Inna csio_hw_mbm_cleanup(struct csio_hw *hw) 3414a3667aaeSNaresh Kumar Inna { 3415a3667aaeSNaresh Kumar Inna LIST_HEAD(cbfn_q); 3416a3667aaeSNaresh Kumar Inna 3417a3667aaeSNaresh Kumar Inna csio_mb_cancel_all(hw, &cbfn_q); 3418a3667aaeSNaresh Kumar Inna 3419a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 3420a3667aaeSNaresh Kumar Inna csio_mb_completions(hw, &cbfn_q); 3421a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 3422a3667aaeSNaresh Kumar Inna } 3423a3667aaeSNaresh Kumar Inna 3424a3667aaeSNaresh Kumar Inna /***************************************************************************** 3425a3667aaeSNaresh Kumar Inna * Event handling 3426a3667aaeSNaresh Kumar Inna ****************************************************************************/ 3427a3667aaeSNaresh Kumar Inna int 3428a3667aaeSNaresh Kumar Inna csio_enqueue_evt(struct csio_hw *hw, enum csio_evt type, void *evt_msg, 3429a3667aaeSNaresh Kumar Inna uint16_t len) 3430a3667aaeSNaresh Kumar Inna { 3431a3667aaeSNaresh Kumar Inna struct csio_evt_msg *evt_entry = NULL; 3432a3667aaeSNaresh Kumar Inna 3433a3667aaeSNaresh Kumar Inna if (type >= CSIO_EVT_MAX) 3434a3667aaeSNaresh Kumar Inna return -EINVAL; 3435a3667aaeSNaresh Kumar Inna 3436a3667aaeSNaresh Kumar Inna if (len > CSIO_EVT_MSG_SIZE) 3437a3667aaeSNaresh Kumar Inna return -EINVAL; 3438a3667aaeSNaresh Kumar Inna 3439a3667aaeSNaresh Kumar Inna if (hw->flags & CSIO_HWF_FWEVT_STOP) 3440a3667aaeSNaresh Kumar Inna return -EINVAL; 3441a3667aaeSNaresh Kumar Inna 3442a3667aaeSNaresh Kumar Inna if (list_empty(&hw->evt_free_q)) { 3443a3667aaeSNaresh Kumar Inna csio_err(hw, "Failed to alloc evt entry, msg type %d len %d\n", 3444a3667aaeSNaresh Kumar Inna type, len); 3445a3667aaeSNaresh Kumar Inna return -ENOMEM; 3446a3667aaeSNaresh Kumar Inna } 3447a3667aaeSNaresh Kumar Inna 3448a3667aaeSNaresh Kumar Inna evt_entry = list_first_entry(&hw->evt_free_q, 3449a3667aaeSNaresh Kumar Inna struct csio_evt_msg, list); 3450a3667aaeSNaresh Kumar Inna list_del_init(&evt_entry->list); 3451a3667aaeSNaresh Kumar Inna 3452a3667aaeSNaresh Kumar Inna /* copy event msg and queue the event */ 3453a3667aaeSNaresh Kumar Inna evt_entry->type = type; 3454a3667aaeSNaresh Kumar Inna memcpy((void *)evt_entry->data, evt_msg, len); 3455a3667aaeSNaresh Kumar Inna list_add_tail(&evt_entry->list, &hw->evt_active_q); 3456a3667aaeSNaresh Kumar Inna 3457a3667aaeSNaresh Kumar Inna CSIO_DEC_STATS(hw, n_evt_freeq); 3458a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_activeq); 3459a3667aaeSNaresh Kumar Inna 3460a3667aaeSNaresh Kumar Inna return 0; 3461a3667aaeSNaresh Kumar Inna } 3462a3667aaeSNaresh Kumar Inna 3463a3667aaeSNaresh Kumar Inna static int 3464a3667aaeSNaresh Kumar Inna csio_enqueue_evt_lock(struct csio_hw *hw, enum csio_evt type, void *evt_msg, 3465a3667aaeSNaresh Kumar Inna uint16_t len, bool msg_sg) 3466a3667aaeSNaresh Kumar Inna { 3467a3667aaeSNaresh Kumar Inna struct csio_evt_msg *evt_entry = NULL; 3468a3667aaeSNaresh Kumar Inna struct csio_fl_dma_buf *fl_sg; 3469a3667aaeSNaresh Kumar Inna uint32_t off = 0; 3470a3667aaeSNaresh Kumar Inna unsigned long flags; 3471a3667aaeSNaresh Kumar Inna int n, ret = 0; 3472a3667aaeSNaresh Kumar Inna 3473a3667aaeSNaresh Kumar Inna if (type >= CSIO_EVT_MAX) 3474a3667aaeSNaresh Kumar Inna return -EINVAL; 3475a3667aaeSNaresh Kumar Inna 3476a3667aaeSNaresh Kumar Inna if (len > CSIO_EVT_MSG_SIZE) 3477a3667aaeSNaresh Kumar Inna return -EINVAL; 3478a3667aaeSNaresh Kumar Inna 3479a3667aaeSNaresh Kumar Inna spin_lock_irqsave(&hw->lock, flags); 3480a3667aaeSNaresh Kumar Inna if (hw->flags & CSIO_HWF_FWEVT_STOP) { 3481a3667aaeSNaresh Kumar Inna ret = -EINVAL; 3482a3667aaeSNaresh Kumar Inna goto out; 3483a3667aaeSNaresh Kumar Inna } 3484a3667aaeSNaresh Kumar Inna 3485a3667aaeSNaresh Kumar Inna if (list_empty(&hw->evt_free_q)) { 3486a3667aaeSNaresh Kumar Inna csio_err(hw, "Failed to alloc evt entry, msg type %d len %d\n", 3487a3667aaeSNaresh Kumar Inna type, len); 3488a3667aaeSNaresh Kumar Inna ret = -ENOMEM; 3489a3667aaeSNaresh Kumar Inna goto out; 3490a3667aaeSNaresh Kumar Inna } 3491a3667aaeSNaresh Kumar Inna 3492a3667aaeSNaresh Kumar Inna evt_entry = list_first_entry(&hw->evt_free_q, 3493a3667aaeSNaresh Kumar Inna struct csio_evt_msg, list); 3494a3667aaeSNaresh Kumar Inna list_del_init(&evt_entry->list); 3495a3667aaeSNaresh Kumar Inna 3496a3667aaeSNaresh Kumar Inna /* copy event msg and queue the event */ 3497a3667aaeSNaresh Kumar Inna evt_entry->type = type; 3498a3667aaeSNaresh Kumar Inna 3499a3667aaeSNaresh Kumar Inna /* If Payload in SG list*/ 3500a3667aaeSNaresh Kumar Inna if (msg_sg) { 3501a3667aaeSNaresh Kumar Inna fl_sg = (struct csio_fl_dma_buf *) evt_msg; 3502a3667aaeSNaresh Kumar Inna for (n = 0; (n < CSIO_MAX_FLBUF_PER_IQWR && off < len); n++) { 3503a3667aaeSNaresh Kumar Inna memcpy((void *)((uintptr_t)evt_entry->data + off), 3504a3667aaeSNaresh Kumar Inna fl_sg->flbufs[n].vaddr, 3505a3667aaeSNaresh Kumar Inna fl_sg->flbufs[n].len); 3506a3667aaeSNaresh Kumar Inna off += fl_sg->flbufs[n].len; 3507a3667aaeSNaresh Kumar Inna } 3508a3667aaeSNaresh Kumar Inna } else 3509a3667aaeSNaresh Kumar Inna memcpy((void *)evt_entry->data, evt_msg, len); 3510a3667aaeSNaresh Kumar Inna 3511a3667aaeSNaresh Kumar Inna list_add_tail(&evt_entry->list, &hw->evt_active_q); 3512a3667aaeSNaresh Kumar Inna CSIO_DEC_STATS(hw, n_evt_freeq); 3513a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_activeq); 3514a3667aaeSNaresh Kumar Inna out: 3515a3667aaeSNaresh Kumar Inna spin_unlock_irqrestore(&hw->lock, flags); 3516a3667aaeSNaresh Kumar Inna return ret; 3517a3667aaeSNaresh Kumar Inna } 3518a3667aaeSNaresh Kumar Inna 3519a3667aaeSNaresh Kumar Inna static void 3520a3667aaeSNaresh Kumar Inna csio_free_evt(struct csio_hw *hw, struct csio_evt_msg *evt_entry) 3521a3667aaeSNaresh Kumar Inna { 3522a3667aaeSNaresh Kumar Inna if (evt_entry) { 3523a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 3524a3667aaeSNaresh Kumar Inna list_del_init(&evt_entry->list); 3525a3667aaeSNaresh Kumar Inna list_add_tail(&evt_entry->list, &hw->evt_free_q); 3526a3667aaeSNaresh Kumar Inna CSIO_DEC_STATS(hw, n_evt_activeq); 3527a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_freeq); 3528a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 3529a3667aaeSNaresh Kumar Inna } 3530a3667aaeSNaresh Kumar Inna } 3531a3667aaeSNaresh Kumar Inna 3532a3667aaeSNaresh Kumar Inna void 3533a3667aaeSNaresh Kumar Inna csio_evtq_flush(struct csio_hw *hw) 3534a3667aaeSNaresh Kumar Inna { 3535a3667aaeSNaresh Kumar Inna uint32_t count; 3536a3667aaeSNaresh Kumar Inna count = 30; 3537a3667aaeSNaresh Kumar Inna while (hw->flags & CSIO_HWF_FWEVT_PENDING && count--) { 3538a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 3539a3667aaeSNaresh Kumar Inna msleep(2000); 3540a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 3541a3667aaeSNaresh Kumar Inna } 3542a3667aaeSNaresh Kumar Inna 3543a3667aaeSNaresh Kumar Inna CSIO_DB_ASSERT(!(hw->flags & CSIO_HWF_FWEVT_PENDING)); 3544a3667aaeSNaresh Kumar Inna } 3545a3667aaeSNaresh Kumar Inna 3546a3667aaeSNaresh Kumar Inna static void 3547a3667aaeSNaresh Kumar Inna csio_evtq_stop(struct csio_hw *hw) 3548a3667aaeSNaresh Kumar Inna { 3549a3667aaeSNaresh Kumar Inna hw->flags |= CSIO_HWF_FWEVT_STOP; 3550a3667aaeSNaresh Kumar Inna } 3551a3667aaeSNaresh Kumar Inna 3552a3667aaeSNaresh Kumar Inna static void 3553a3667aaeSNaresh Kumar Inna csio_evtq_start(struct csio_hw *hw) 3554a3667aaeSNaresh Kumar Inna { 3555a3667aaeSNaresh Kumar Inna hw->flags &= ~CSIO_HWF_FWEVT_STOP; 3556a3667aaeSNaresh Kumar Inna } 3557a3667aaeSNaresh Kumar Inna 3558a3667aaeSNaresh Kumar Inna static void 3559a3667aaeSNaresh Kumar Inna csio_evtq_cleanup(struct csio_hw *hw) 3560a3667aaeSNaresh Kumar Inna { 3561a3667aaeSNaresh Kumar Inna struct list_head *evt_entry, *next_entry; 3562a3667aaeSNaresh Kumar Inna 3563a3667aaeSNaresh Kumar Inna /* Release outstanding events from activeq to freeq*/ 3564a3667aaeSNaresh Kumar Inna if (!list_empty(&hw->evt_active_q)) 3565a3667aaeSNaresh Kumar Inna list_splice_tail_init(&hw->evt_active_q, &hw->evt_free_q); 3566a3667aaeSNaresh Kumar Inna 3567a3667aaeSNaresh Kumar Inna hw->stats.n_evt_activeq = 0; 3568a3667aaeSNaresh Kumar Inna hw->flags &= ~CSIO_HWF_FWEVT_PENDING; 3569a3667aaeSNaresh Kumar Inna 3570a3667aaeSNaresh Kumar Inna /* Freeup event entry */ 3571a3667aaeSNaresh Kumar Inna list_for_each_safe(evt_entry, next_entry, &hw->evt_free_q) { 3572a3667aaeSNaresh Kumar Inna kfree(evt_entry); 3573a3667aaeSNaresh Kumar Inna CSIO_DEC_STATS(hw, n_evt_freeq); 3574a3667aaeSNaresh Kumar Inna } 3575a3667aaeSNaresh Kumar Inna 3576a3667aaeSNaresh Kumar Inna hw->stats.n_evt_freeq = 0; 3577a3667aaeSNaresh Kumar Inna } 3578a3667aaeSNaresh Kumar Inna 3579a3667aaeSNaresh Kumar Inna 3580a3667aaeSNaresh Kumar Inna static void 3581a3667aaeSNaresh Kumar Inna csio_process_fwevtq_entry(struct csio_hw *hw, void *wr, uint32_t len, 3582a3667aaeSNaresh Kumar Inna struct csio_fl_dma_buf *flb, void *priv) 3583a3667aaeSNaresh Kumar Inna { 3584a3667aaeSNaresh Kumar Inna __u8 op; 3585a3667aaeSNaresh Kumar Inna void *msg = NULL; 3586a3667aaeSNaresh Kumar Inna uint32_t msg_len = 0; 3587a3667aaeSNaresh Kumar Inna bool msg_sg = 0; 3588a3667aaeSNaresh Kumar Inna 3589a3667aaeSNaresh Kumar Inna op = ((struct rss_header *) wr)->opcode; 3590a3667aaeSNaresh Kumar Inna if (op == CPL_FW6_PLD) { 3591a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_cpl_fw6_pld); 3592a3667aaeSNaresh Kumar Inna if (!flb || !flb->totlen) { 3593a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_cpl_unexp); 3594a3667aaeSNaresh Kumar Inna return; 3595a3667aaeSNaresh Kumar Inna } 3596a3667aaeSNaresh Kumar Inna 3597a3667aaeSNaresh Kumar Inna msg = (void *) flb; 3598a3667aaeSNaresh Kumar Inna msg_len = flb->totlen; 3599a3667aaeSNaresh Kumar Inna msg_sg = 1; 3600a3667aaeSNaresh Kumar Inna } else if (op == CPL_FW6_MSG || op == CPL_FW4_MSG) { 3601a3667aaeSNaresh Kumar Inna 3602a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_cpl_fw6_msg); 3603a3667aaeSNaresh Kumar Inna /* skip RSS header */ 3604a3667aaeSNaresh Kumar Inna msg = (void *)((uintptr_t)wr + sizeof(__be64)); 3605a3667aaeSNaresh Kumar Inna msg_len = (op == CPL_FW6_MSG) ? sizeof(struct cpl_fw6_msg) : 3606a3667aaeSNaresh Kumar Inna sizeof(struct cpl_fw4_msg); 3607a3667aaeSNaresh Kumar Inna } else { 3608a3667aaeSNaresh Kumar Inna csio_warn(hw, "unexpected CPL %#x on FW event queue\n", op); 3609a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_cpl_unexp); 3610a3667aaeSNaresh Kumar Inna return; 3611a3667aaeSNaresh Kumar Inna } 3612a3667aaeSNaresh Kumar Inna 3613a3667aaeSNaresh Kumar Inna /* 3614a3667aaeSNaresh Kumar Inna * Enqueue event to EventQ. Events processing happens 3615a3667aaeSNaresh Kumar Inna * in Event worker thread context 3616a3667aaeSNaresh Kumar Inna */ 3617a3667aaeSNaresh Kumar Inna if (csio_enqueue_evt_lock(hw, CSIO_EVT_FW, msg, 3618a3667aaeSNaresh Kumar Inna (uint16_t)msg_len, msg_sg)) 3619a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_drop); 3620a3667aaeSNaresh Kumar Inna } 3621a3667aaeSNaresh Kumar Inna 3622a3667aaeSNaresh Kumar Inna void 3623a3667aaeSNaresh Kumar Inna csio_evtq_worker(struct work_struct *work) 3624a3667aaeSNaresh Kumar Inna { 3625a3667aaeSNaresh Kumar Inna struct csio_hw *hw = container_of(work, struct csio_hw, evtq_work); 3626a3667aaeSNaresh Kumar Inna struct list_head *evt_entry, *next_entry; 3627a3667aaeSNaresh Kumar Inna LIST_HEAD(evt_q); 3628a3667aaeSNaresh Kumar Inna struct csio_evt_msg *evt_msg; 3629a3667aaeSNaresh Kumar Inna struct cpl_fw6_msg *msg; 3630a3667aaeSNaresh Kumar Inna struct csio_rnode *rn; 3631a3667aaeSNaresh Kumar Inna int rv = 0; 3632a3667aaeSNaresh Kumar Inna uint8_t evtq_stop = 0; 3633a3667aaeSNaresh Kumar Inna 3634a3667aaeSNaresh Kumar Inna csio_dbg(hw, "event worker thread active evts#%d\n", 3635a3667aaeSNaresh Kumar Inna hw->stats.n_evt_activeq); 3636a3667aaeSNaresh Kumar Inna 3637a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 3638a3667aaeSNaresh Kumar Inna while (!list_empty(&hw->evt_active_q)) { 3639a3667aaeSNaresh Kumar Inna list_splice_tail_init(&hw->evt_active_q, &evt_q); 3640a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 3641a3667aaeSNaresh Kumar Inna 3642a3667aaeSNaresh Kumar Inna list_for_each_safe(evt_entry, next_entry, &evt_q) { 3643a3667aaeSNaresh Kumar Inna evt_msg = (struct csio_evt_msg *) evt_entry; 3644a3667aaeSNaresh Kumar Inna 3645a3667aaeSNaresh Kumar Inna /* Drop events if queue is STOPPED */ 3646a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 3647a3667aaeSNaresh Kumar Inna if (hw->flags & CSIO_HWF_FWEVT_STOP) 3648a3667aaeSNaresh Kumar Inna evtq_stop = 1; 3649a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 3650a3667aaeSNaresh Kumar Inna if (evtq_stop) { 3651a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_drop); 3652a3667aaeSNaresh Kumar Inna goto free_evt; 3653a3667aaeSNaresh Kumar Inna } 3654a3667aaeSNaresh Kumar Inna 3655a3667aaeSNaresh Kumar Inna switch (evt_msg->type) { 3656a3667aaeSNaresh Kumar Inna case CSIO_EVT_FW: 3657a3667aaeSNaresh Kumar Inna msg = (struct cpl_fw6_msg *)(evt_msg->data); 3658a3667aaeSNaresh Kumar Inna 3659a3667aaeSNaresh Kumar Inna if ((msg->opcode == CPL_FW6_MSG || 3660a3667aaeSNaresh Kumar Inna msg->opcode == CPL_FW4_MSG) && 3661a3667aaeSNaresh Kumar Inna !msg->type) { 3662a3667aaeSNaresh Kumar Inna rv = csio_mb_fwevt_handler(hw, 3663a3667aaeSNaresh Kumar Inna msg->data); 3664a3667aaeSNaresh Kumar Inna if (!rv) 3665a3667aaeSNaresh Kumar Inna break; 3666a3667aaeSNaresh Kumar Inna /* Handle any remaining fw events */ 3667a3667aaeSNaresh Kumar Inna csio_fcoe_fwevt_handler(hw, 3668a3667aaeSNaresh Kumar Inna msg->opcode, msg->data); 3669a3667aaeSNaresh Kumar Inna } else if (msg->opcode == CPL_FW6_PLD) { 3670a3667aaeSNaresh Kumar Inna 3671a3667aaeSNaresh Kumar Inna csio_fcoe_fwevt_handler(hw, 3672a3667aaeSNaresh Kumar Inna msg->opcode, msg->data); 3673a3667aaeSNaresh Kumar Inna } else { 3674a3667aaeSNaresh Kumar Inna csio_warn(hw, 3675a3667aaeSNaresh Kumar Inna "Unhandled FW msg op %x type %x\n", 3676a3667aaeSNaresh Kumar Inna msg->opcode, msg->type); 3677a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_drop); 3678a3667aaeSNaresh Kumar Inna } 3679a3667aaeSNaresh Kumar Inna break; 3680a3667aaeSNaresh Kumar Inna 3681a3667aaeSNaresh Kumar Inna case CSIO_EVT_MBX: 3682a3667aaeSNaresh Kumar Inna csio_mberr_worker(hw); 3683a3667aaeSNaresh Kumar Inna break; 3684a3667aaeSNaresh Kumar Inna 3685a3667aaeSNaresh Kumar Inna case CSIO_EVT_DEV_LOSS: 3686a3667aaeSNaresh Kumar Inna memcpy(&rn, evt_msg->data, sizeof(rn)); 3687a3667aaeSNaresh Kumar Inna csio_rnode_devloss_handler(rn); 3688a3667aaeSNaresh Kumar Inna break; 3689a3667aaeSNaresh Kumar Inna 3690a3667aaeSNaresh Kumar Inna default: 3691a3667aaeSNaresh Kumar Inna csio_warn(hw, "Unhandled event %x on evtq\n", 3692a3667aaeSNaresh Kumar Inna evt_msg->type); 3693a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_unexp); 3694a3667aaeSNaresh Kumar Inna break; 3695a3667aaeSNaresh Kumar Inna } 3696a3667aaeSNaresh Kumar Inna free_evt: 3697a3667aaeSNaresh Kumar Inna csio_free_evt(hw, evt_msg); 3698a3667aaeSNaresh Kumar Inna } 3699a3667aaeSNaresh Kumar Inna 3700a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 3701a3667aaeSNaresh Kumar Inna } 3702a3667aaeSNaresh Kumar Inna hw->flags &= ~CSIO_HWF_FWEVT_PENDING; 3703a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 3704a3667aaeSNaresh Kumar Inna } 3705a3667aaeSNaresh Kumar Inna 3706a3667aaeSNaresh Kumar Inna int 3707a3667aaeSNaresh Kumar Inna csio_fwevtq_handler(struct csio_hw *hw) 3708a3667aaeSNaresh Kumar Inna { 3709a3667aaeSNaresh Kumar Inna int rv; 3710a3667aaeSNaresh Kumar Inna 3711a3667aaeSNaresh Kumar Inna if (csio_q_iqid(hw, hw->fwevt_iq_idx) == CSIO_MAX_QID) { 3712a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_int_stray); 3713a3667aaeSNaresh Kumar Inna return -EINVAL; 3714a3667aaeSNaresh Kumar Inna } 3715a3667aaeSNaresh Kumar Inna 3716a3667aaeSNaresh Kumar Inna rv = csio_wr_process_iq_idx(hw, hw->fwevt_iq_idx, 3717a3667aaeSNaresh Kumar Inna csio_process_fwevtq_entry, NULL); 3718a3667aaeSNaresh Kumar Inna return rv; 3719a3667aaeSNaresh Kumar Inna } 3720a3667aaeSNaresh Kumar Inna 3721a3667aaeSNaresh Kumar Inna /**************************************************************************** 3722a3667aaeSNaresh Kumar Inna * Entry points 3723a3667aaeSNaresh Kumar Inna ****************************************************************************/ 3724a3667aaeSNaresh Kumar Inna 3725a3667aaeSNaresh Kumar Inna /* Management module */ 3726a3667aaeSNaresh Kumar Inna /* 3727a3667aaeSNaresh Kumar Inna * csio_mgmt_req_lookup - Lookup the given IO req exist in Active Q. 3728a3667aaeSNaresh Kumar Inna * mgmt - mgmt module 3729a3667aaeSNaresh Kumar Inna * @io_req - io request 3730a3667aaeSNaresh Kumar Inna * 3731a3667aaeSNaresh Kumar Inna * Return - 0:if given IO Req exists in active Q. 3732a3667aaeSNaresh Kumar Inna * -EINVAL :if lookup fails. 3733a3667aaeSNaresh Kumar Inna */ 3734a3667aaeSNaresh Kumar Inna int 3735a3667aaeSNaresh Kumar Inna csio_mgmt_req_lookup(struct csio_mgmtm *mgmtm, struct csio_ioreq *io_req) 3736a3667aaeSNaresh Kumar Inna { 3737a3667aaeSNaresh Kumar Inna struct list_head *tmp; 3738a3667aaeSNaresh Kumar Inna 3739a3667aaeSNaresh Kumar Inna /* Lookup ioreq in the ACTIVEQ */ 3740a3667aaeSNaresh Kumar Inna list_for_each(tmp, &mgmtm->active_q) { 3741a3667aaeSNaresh Kumar Inna if (io_req == (struct csio_ioreq *)tmp) 3742a3667aaeSNaresh Kumar Inna return 0; 3743a3667aaeSNaresh Kumar Inna } 3744a3667aaeSNaresh Kumar Inna return -EINVAL; 3745a3667aaeSNaresh Kumar Inna } 3746a3667aaeSNaresh Kumar Inna 3747a3667aaeSNaresh Kumar Inna #define ECM_MIN_TMO 1000 /* Minimum timeout value for req */ 3748a3667aaeSNaresh Kumar Inna 3749a3667aaeSNaresh Kumar Inna /* 3750a3667aaeSNaresh Kumar Inna * csio_mgmts_tmo_handler - MGMT IO Timeout handler. 3751a3667aaeSNaresh Kumar Inna * @data - Event data. 3752a3667aaeSNaresh Kumar Inna * 3753a3667aaeSNaresh Kumar Inna * Return - none. 3754a3667aaeSNaresh Kumar Inna */ 3755a3667aaeSNaresh Kumar Inna static void 3756a3667aaeSNaresh Kumar Inna csio_mgmt_tmo_handler(uintptr_t data) 3757a3667aaeSNaresh Kumar Inna { 3758a3667aaeSNaresh Kumar Inna struct csio_mgmtm *mgmtm = (struct csio_mgmtm *) data; 3759a3667aaeSNaresh Kumar Inna struct list_head *tmp; 3760a3667aaeSNaresh Kumar Inna struct csio_ioreq *io_req; 3761a3667aaeSNaresh Kumar Inna 3762a3667aaeSNaresh Kumar Inna csio_dbg(mgmtm->hw, "Mgmt timer invoked!\n"); 3763a3667aaeSNaresh Kumar Inna 3764a3667aaeSNaresh Kumar Inna spin_lock_irq(&mgmtm->hw->lock); 3765a3667aaeSNaresh Kumar Inna 3766a3667aaeSNaresh Kumar Inna list_for_each(tmp, &mgmtm->active_q) { 3767a3667aaeSNaresh Kumar Inna io_req = (struct csio_ioreq *) tmp; 3768a3667aaeSNaresh Kumar Inna io_req->tmo -= min_t(uint32_t, io_req->tmo, ECM_MIN_TMO); 3769a3667aaeSNaresh Kumar Inna 3770a3667aaeSNaresh Kumar Inna if (!io_req->tmo) { 3771a3667aaeSNaresh Kumar Inna /* Dequeue the request from retry Q. */ 3772a3667aaeSNaresh Kumar Inna tmp = csio_list_prev(tmp); 3773a3667aaeSNaresh Kumar Inna list_del_init(&io_req->sm.sm_list); 3774a3667aaeSNaresh Kumar Inna if (io_req->io_cbfn) { 3775a3667aaeSNaresh Kumar Inna /* io_req will be freed by completion handler */ 3776a3667aaeSNaresh Kumar Inna io_req->wr_status = -ETIMEDOUT; 3777a3667aaeSNaresh Kumar Inna io_req->io_cbfn(mgmtm->hw, io_req); 3778a3667aaeSNaresh Kumar Inna } else { 3779a3667aaeSNaresh Kumar Inna CSIO_DB_ASSERT(0); 3780a3667aaeSNaresh Kumar Inna } 3781a3667aaeSNaresh Kumar Inna } 3782a3667aaeSNaresh Kumar Inna } 3783a3667aaeSNaresh Kumar Inna 3784a3667aaeSNaresh Kumar Inna /* If retry queue is not empty, re-arm timer */ 3785a3667aaeSNaresh Kumar Inna if (!list_empty(&mgmtm->active_q)) 3786a3667aaeSNaresh Kumar Inna mod_timer(&mgmtm->mgmt_timer, 3787a3667aaeSNaresh Kumar Inna jiffies + msecs_to_jiffies(ECM_MIN_TMO)); 3788a3667aaeSNaresh Kumar Inna spin_unlock_irq(&mgmtm->hw->lock); 3789a3667aaeSNaresh Kumar Inna } 3790a3667aaeSNaresh Kumar Inna 3791a3667aaeSNaresh Kumar Inna static void 3792a3667aaeSNaresh Kumar Inna csio_mgmtm_cleanup(struct csio_mgmtm *mgmtm) 3793a3667aaeSNaresh Kumar Inna { 3794a3667aaeSNaresh Kumar Inna struct csio_hw *hw = mgmtm->hw; 3795a3667aaeSNaresh Kumar Inna struct csio_ioreq *io_req; 3796a3667aaeSNaresh Kumar Inna struct list_head *tmp; 3797a3667aaeSNaresh Kumar Inna uint32_t count; 3798a3667aaeSNaresh Kumar Inna 3799a3667aaeSNaresh Kumar Inna count = 30; 3800a3667aaeSNaresh Kumar Inna /* Wait for all outstanding req to complete gracefully */ 3801a3667aaeSNaresh Kumar Inna while ((!list_empty(&mgmtm->active_q)) && count--) { 3802a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 3803a3667aaeSNaresh Kumar Inna msleep(2000); 3804a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 3805a3667aaeSNaresh Kumar Inna } 3806a3667aaeSNaresh Kumar Inna 3807a3667aaeSNaresh Kumar Inna /* release outstanding req from ACTIVEQ */ 3808a3667aaeSNaresh Kumar Inna list_for_each(tmp, &mgmtm->active_q) { 3809a3667aaeSNaresh Kumar Inna io_req = (struct csio_ioreq *) tmp; 3810a3667aaeSNaresh Kumar Inna tmp = csio_list_prev(tmp); 3811a3667aaeSNaresh Kumar Inna list_del_init(&io_req->sm.sm_list); 3812a3667aaeSNaresh Kumar Inna mgmtm->stats.n_active--; 3813a3667aaeSNaresh Kumar Inna if (io_req->io_cbfn) { 3814a3667aaeSNaresh Kumar Inna /* io_req will be freed by completion handler */ 3815a3667aaeSNaresh Kumar Inna io_req->wr_status = -ETIMEDOUT; 3816a3667aaeSNaresh Kumar Inna io_req->io_cbfn(mgmtm->hw, io_req); 3817a3667aaeSNaresh Kumar Inna } 3818a3667aaeSNaresh Kumar Inna } 3819a3667aaeSNaresh Kumar Inna } 3820a3667aaeSNaresh Kumar Inna 3821a3667aaeSNaresh Kumar Inna /* 3822a3667aaeSNaresh Kumar Inna * csio_mgmt_init - Mgmt module init entry point 3823a3667aaeSNaresh Kumar Inna * @mgmtsm - mgmt module 3824a3667aaeSNaresh Kumar Inna * @hw - HW module 3825a3667aaeSNaresh Kumar Inna * 3826a3667aaeSNaresh Kumar Inna * Initialize mgmt timer, resource wait queue, active queue, 3827a3667aaeSNaresh Kumar Inna * completion q. Allocate Egress and Ingress 3828a3667aaeSNaresh Kumar Inna * WR queues and save off the queue index returned by the WR 3829a3667aaeSNaresh Kumar Inna * module for future use. Allocate and save off mgmt reqs in the 3830a3667aaeSNaresh Kumar Inna * mgmt_req_freelist for future use. Make sure their SM is initialized 3831a3667aaeSNaresh Kumar Inna * to uninit state. 3832a3667aaeSNaresh Kumar Inna * Returns: 0 - on success 3833a3667aaeSNaresh Kumar Inna * -ENOMEM - on error. 3834a3667aaeSNaresh Kumar Inna */ 3835a3667aaeSNaresh Kumar Inna static int 3836a3667aaeSNaresh Kumar Inna csio_mgmtm_init(struct csio_mgmtm *mgmtm, struct csio_hw *hw) 3837a3667aaeSNaresh Kumar Inna { 3838a3667aaeSNaresh Kumar Inna struct timer_list *timer = &mgmtm->mgmt_timer; 3839a3667aaeSNaresh Kumar Inna 3840a3667aaeSNaresh Kumar Inna init_timer(timer); 3841a3667aaeSNaresh Kumar Inna timer->function = csio_mgmt_tmo_handler; 3842a3667aaeSNaresh Kumar Inna timer->data = (unsigned long)mgmtm; 3843a3667aaeSNaresh Kumar Inna 3844a3667aaeSNaresh Kumar Inna INIT_LIST_HEAD(&mgmtm->active_q); 3845a3667aaeSNaresh Kumar Inna INIT_LIST_HEAD(&mgmtm->cbfn_q); 3846a3667aaeSNaresh Kumar Inna 3847a3667aaeSNaresh Kumar Inna mgmtm->hw = hw; 3848a3667aaeSNaresh Kumar Inna /*mgmtm->iq_idx = hw->fwevt_iq_idx;*/ 3849a3667aaeSNaresh Kumar Inna 3850a3667aaeSNaresh Kumar Inna return 0; 3851a3667aaeSNaresh Kumar Inna } 3852a3667aaeSNaresh Kumar Inna 3853a3667aaeSNaresh Kumar Inna /* 3854a3667aaeSNaresh Kumar Inna * csio_mgmtm_exit - MGMT module exit entry point 3855a3667aaeSNaresh Kumar Inna * @mgmtsm - mgmt module 3856a3667aaeSNaresh Kumar Inna * 3857a3667aaeSNaresh Kumar Inna * This function called during MGMT module uninit. 3858a3667aaeSNaresh Kumar Inna * Stop timers, free ioreqs allocated. 3859a3667aaeSNaresh Kumar Inna * Returns: None 3860a3667aaeSNaresh Kumar Inna * 3861a3667aaeSNaresh Kumar Inna */ 3862a3667aaeSNaresh Kumar Inna static void 3863a3667aaeSNaresh Kumar Inna csio_mgmtm_exit(struct csio_mgmtm *mgmtm) 3864a3667aaeSNaresh Kumar Inna { 3865a3667aaeSNaresh Kumar Inna del_timer_sync(&mgmtm->mgmt_timer); 3866a3667aaeSNaresh Kumar Inna } 3867a3667aaeSNaresh Kumar Inna 3868a3667aaeSNaresh Kumar Inna 3869a3667aaeSNaresh Kumar Inna /** 3870a3667aaeSNaresh Kumar Inna * csio_hw_start - Kicks off the HW State machine 3871a3667aaeSNaresh Kumar Inna * @hw: Pointer to HW module. 3872a3667aaeSNaresh Kumar Inna * 3873a3667aaeSNaresh Kumar Inna * It is assumed that the initialization is a synchronous operation. 3874a3667aaeSNaresh Kumar Inna * So when we return afer posting the event, the HW SM should be in 3875a3667aaeSNaresh Kumar Inna * the ready state, if there were no errors during init. 3876a3667aaeSNaresh Kumar Inna */ 3877a3667aaeSNaresh Kumar Inna int 3878a3667aaeSNaresh Kumar Inna csio_hw_start(struct csio_hw *hw) 3879a3667aaeSNaresh Kumar Inna { 3880a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 3881a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_CFG); 3882a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 3883a3667aaeSNaresh Kumar Inna 3884a3667aaeSNaresh Kumar Inna if (csio_is_hw_ready(hw)) 3885a3667aaeSNaresh Kumar Inna return 0; 3886a3667aaeSNaresh Kumar Inna else 3887a3667aaeSNaresh Kumar Inna return -EINVAL; 3888a3667aaeSNaresh Kumar Inna } 3889a3667aaeSNaresh Kumar Inna 3890a3667aaeSNaresh Kumar Inna int 3891a3667aaeSNaresh Kumar Inna csio_hw_stop(struct csio_hw *hw) 3892a3667aaeSNaresh Kumar Inna { 3893a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_PCI_REMOVE); 3894a3667aaeSNaresh Kumar Inna 3895a3667aaeSNaresh Kumar Inna if (csio_is_hw_removing(hw)) 3896a3667aaeSNaresh Kumar Inna return 0; 3897a3667aaeSNaresh Kumar Inna else 3898a3667aaeSNaresh Kumar Inna return -EINVAL; 3899a3667aaeSNaresh Kumar Inna } 3900a3667aaeSNaresh Kumar Inna 3901a3667aaeSNaresh Kumar Inna /* Max reset retries */ 3902a3667aaeSNaresh Kumar Inna #define CSIO_MAX_RESET_RETRIES 3 3903a3667aaeSNaresh Kumar Inna 3904a3667aaeSNaresh Kumar Inna /** 3905a3667aaeSNaresh Kumar Inna * csio_hw_reset - Reset the hardware 3906a3667aaeSNaresh Kumar Inna * @hw: HW module. 3907a3667aaeSNaresh Kumar Inna * 3908a3667aaeSNaresh Kumar Inna * Caller should hold lock across this function. 3909a3667aaeSNaresh Kumar Inna */ 3910a3667aaeSNaresh Kumar Inna int 3911a3667aaeSNaresh Kumar Inna csio_hw_reset(struct csio_hw *hw) 3912a3667aaeSNaresh Kumar Inna { 3913a3667aaeSNaresh Kumar Inna if (!csio_is_hw_master(hw)) 3914a3667aaeSNaresh Kumar Inna return -EPERM; 3915a3667aaeSNaresh Kumar Inna 3916a3667aaeSNaresh Kumar Inna if (hw->rst_retries >= CSIO_MAX_RESET_RETRIES) { 3917a3667aaeSNaresh Kumar Inna csio_dbg(hw, "Max hw reset attempts reached.."); 3918a3667aaeSNaresh Kumar Inna return -EINVAL; 3919a3667aaeSNaresh Kumar Inna } 3920a3667aaeSNaresh Kumar Inna 3921a3667aaeSNaresh Kumar Inna hw->rst_retries++; 3922a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_HBA_RESET); 3923a3667aaeSNaresh Kumar Inna 3924a3667aaeSNaresh Kumar Inna if (csio_is_hw_ready(hw)) { 3925a3667aaeSNaresh Kumar Inna hw->rst_retries = 0; 3926a3667aaeSNaresh Kumar Inna hw->stats.n_reset_start = jiffies_to_msecs(jiffies); 3927a3667aaeSNaresh Kumar Inna return 0; 3928a3667aaeSNaresh Kumar Inna } else 3929a3667aaeSNaresh Kumar Inna return -EINVAL; 3930a3667aaeSNaresh Kumar Inna } 3931a3667aaeSNaresh Kumar Inna 3932a3667aaeSNaresh Kumar Inna /* 3933a3667aaeSNaresh Kumar Inna * csio_hw_get_device_id - Caches the Adapter's vendor & device id. 3934a3667aaeSNaresh Kumar Inna * @hw: HW module. 3935a3667aaeSNaresh Kumar Inna */ 3936a3667aaeSNaresh Kumar Inna static void 3937a3667aaeSNaresh Kumar Inna csio_hw_get_device_id(struct csio_hw *hw) 3938a3667aaeSNaresh Kumar Inna { 3939a3667aaeSNaresh Kumar Inna /* Is the adapter device id cached already ?*/ 3940a3667aaeSNaresh Kumar Inna if (csio_is_dev_id_cached(hw)) 3941a3667aaeSNaresh Kumar Inna return; 3942a3667aaeSNaresh Kumar Inna 3943a3667aaeSNaresh Kumar Inna /* Get the PCI vendor & device id */ 3944a3667aaeSNaresh Kumar Inna pci_read_config_word(hw->pdev, PCI_VENDOR_ID, 3945a3667aaeSNaresh Kumar Inna &hw->params.pci.vendor_id); 3946a3667aaeSNaresh Kumar Inna pci_read_config_word(hw->pdev, PCI_DEVICE_ID, 3947a3667aaeSNaresh Kumar Inna &hw->params.pci.device_id); 3948a3667aaeSNaresh Kumar Inna 3949a3667aaeSNaresh Kumar Inna csio_dev_id_cached(hw); 39507cc16380SArvind Bhushan hw->chip_id = (hw->params.pci.device_id & CSIO_HW_CHIP_MASK); 3951a3667aaeSNaresh Kumar Inna 3952a3667aaeSNaresh Kumar Inna } /* csio_hw_get_device_id */ 3953a3667aaeSNaresh Kumar Inna 3954a3667aaeSNaresh Kumar Inna /* 3955a3667aaeSNaresh Kumar Inna * csio_hw_set_description - Set the model, description of the hw. 3956a3667aaeSNaresh Kumar Inna * @hw: HW module. 3957a3667aaeSNaresh Kumar Inna * @ven_id: PCI Vendor ID 3958a3667aaeSNaresh Kumar Inna * @dev_id: PCI Device ID 3959a3667aaeSNaresh Kumar Inna */ 3960a3667aaeSNaresh Kumar Inna static void 3961a3667aaeSNaresh Kumar Inna csio_hw_set_description(struct csio_hw *hw, uint16_t ven_id, uint16_t dev_id) 3962a3667aaeSNaresh Kumar Inna { 3963a3667aaeSNaresh Kumar Inna uint32_t adap_type, prot_type; 3964a3667aaeSNaresh Kumar Inna 3965a3667aaeSNaresh Kumar Inna if (ven_id == CSIO_VENDOR_ID) { 3966a3667aaeSNaresh Kumar Inna prot_type = (dev_id & CSIO_ASIC_DEVID_PROTO_MASK); 3967a3667aaeSNaresh Kumar Inna adap_type = (dev_id & CSIO_ASIC_DEVID_TYPE_MASK); 3968a3667aaeSNaresh Kumar Inna 39697cc16380SArvind Bhushan if (prot_type == CSIO_T4_FCOE_ASIC) { 3970a3667aaeSNaresh Kumar Inna memcpy(hw->hw_ver, 39717cc16380SArvind Bhushan csio_t4_fcoe_adapters[adap_type].model_no, 16); 3972a3667aaeSNaresh Kumar Inna memcpy(hw->model_desc, 39737cc16380SArvind Bhushan csio_t4_fcoe_adapters[adap_type].description, 39747cc16380SArvind Bhushan 32); 39757cc16380SArvind Bhushan } else if (prot_type == CSIO_T5_FCOE_ASIC) { 39767cc16380SArvind Bhushan memcpy(hw->hw_ver, 39777cc16380SArvind Bhushan csio_t5_fcoe_adapters[adap_type].model_no, 16); 39787cc16380SArvind Bhushan memcpy(hw->model_desc, 39797cc16380SArvind Bhushan csio_t5_fcoe_adapters[adap_type].description, 39807cc16380SArvind Bhushan 32); 3981a3667aaeSNaresh Kumar Inna } else { 3982a3667aaeSNaresh Kumar Inna char tempName[32] = "Chelsio FCoE Controller"; 3983a3667aaeSNaresh Kumar Inna memcpy(hw->model_desc, tempName, 32); 3984a3667aaeSNaresh Kumar Inna } 3985a3667aaeSNaresh Kumar Inna } 3986a3667aaeSNaresh Kumar Inna } /* csio_hw_set_description */ 3987a3667aaeSNaresh Kumar Inna 3988a3667aaeSNaresh Kumar Inna /** 3989a3667aaeSNaresh Kumar Inna * csio_hw_init - Initialize HW module. 3990a3667aaeSNaresh Kumar Inna * @hw: Pointer to HW module. 3991a3667aaeSNaresh Kumar Inna * 3992a3667aaeSNaresh Kumar Inna * Initialize the members of the HW module. 3993a3667aaeSNaresh Kumar Inna */ 3994a3667aaeSNaresh Kumar Inna int 3995a3667aaeSNaresh Kumar Inna csio_hw_init(struct csio_hw *hw) 3996a3667aaeSNaresh Kumar Inna { 3997a3667aaeSNaresh Kumar Inna int rv = -EINVAL; 3998a3667aaeSNaresh Kumar Inna uint32_t i; 3999a3667aaeSNaresh Kumar Inna uint16_t ven_id, dev_id; 4000a3667aaeSNaresh Kumar Inna struct csio_evt_msg *evt_entry; 4001a3667aaeSNaresh Kumar Inna 4002a3667aaeSNaresh Kumar Inna INIT_LIST_HEAD(&hw->sm.sm_list); 4003a3667aaeSNaresh Kumar Inna csio_init_state(&hw->sm, csio_hws_uninit); 4004a3667aaeSNaresh Kumar Inna spin_lock_init(&hw->lock); 4005a3667aaeSNaresh Kumar Inna INIT_LIST_HEAD(&hw->sln_head); 4006a3667aaeSNaresh Kumar Inna 4007a3667aaeSNaresh Kumar Inna /* Get the PCI vendor & device id */ 4008a3667aaeSNaresh Kumar Inna csio_hw_get_device_id(hw); 4009a3667aaeSNaresh Kumar Inna 4010a3667aaeSNaresh Kumar Inna strcpy(hw->name, CSIO_HW_NAME); 4011a3667aaeSNaresh Kumar Inna 40127cc16380SArvind Bhushan /* Initialize the HW chip ops with T4/T5 specific ops */ 40137cc16380SArvind Bhushan hw->chip_ops = csio_is_t4(hw->chip_id) ? &t4_ops : &t5_ops; 40147cc16380SArvind Bhushan 4015a3667aaeSNaresh Kumar Inna /* Set the model & its description */ 4016a3667aaeSNaresh Kumar Inna 4017a3667aaeSNaresh Kumar Inna ven_id = hw->params.pci.vendor_id; 4018a3667aaeSNaresh Kumar Inna dev_id = hw->params.pci.device_id; 4019a3667aaeSNaresh Kumar Inna 4020a3667aaeSNaresh Kumar Inna csio_hw_set_description(hw, ven_id, dev_id); 4021a3667aaeSNaresh Kumar Inna 4022a3667aaeSNaresh Kumar Inna /* Initialize default log level */ 4023a3667aaeSNaresh Kumar Inna hw->params.log_level = (uint32_t) csio_dbg_level; 4024a3667aaeSNaresh Kumar Inna 4025a3667aaeSNaresh Kumar Inna csio_set_fwevt_intr_idx(hw, -1); 4026a3667aaeSNaresh Kumar Inna csio_set_nondata_intr_idx(hw, -1); 4027a3667aaeSNaresh Kumar Inna 4028a3667aaeSNaresh Kumar Inna /* Init all the modules: Mailbox, WorkRequest and Transport */ 4029a3667aaeSNaresh Kumar Inna if (csio_mbm_init(csio_hw_to_mbm(hw), hw, csio_hw_mb_timer)) 4030a3667aaeSNaresh Kumar Inna goto err; 4031a3667aaeSNaresh Kumar Inna 4032a3667aaeSNaresh Kumar Inna rv = csio_wrm_init(csio_hw_to_wrm(hw), hw); 4033a3667aaeSNaresh Kumar Inna if (rv) 4034a3667aaeSNaresh Kumar Inna goto err_mbm_exit; 4035a3667aaeSNaresh Kumar Inna 4036a3667aaeSNaresh Kumar Inna rv = csio_scsim_init(csio_hw_to_scsim(hw), hw); 4037a3667aaeSNaresh Kumar Inna if (rv) 4038a3667aaeSNaresh Kumar Inna goto err_wrm_exit; 4039a3667aaeSNaresh Kumar Inna 4040a3667aaeSNaresh Kumar Inna rv = csio_mgmtm_init(csio_hw_to_mgmtm(hw), hw); 4041a3667aaeSNaresh Kumar Inna if (rv) 4042a3667aaeSNaresh Kumar Inna goto err_scsim_exit; 4043a3667aaeSNaresh Kumar Inna /* Pre-allocate evtq and initialize them */ 4044a3667aaeSNaresh Kumar Inna INIT_LIST_HEAD(&hw->evt_active_q); 4045a3667aaeSNaresh Kumar Inna INIT_LIST_HEAD(&hw->evt_free_q); 4046a3667aaeSNaresh Kumar Inna for (i = 0; i < csio_evtq_sz; i++) { 4047a3667aaeSNaresh Kumar Inna 4048a3667aaeSNaresh Kumar Inna evt_entry = kzalloc(sizeof(struct csio_evt_msg), GFP_KERNEL); 4049a3667aaeSNaresh Kumar Inna if (!evt_entry) { 4050a3667aaeSNaresh Kumar Inna csio_err(hw, "Failed to initialize eventq"); 4051a3667aaeSNaresh Kumar Inna goto err_evtq_cleanup; 4052a3667aaeSNaresh Kumar Inna } 4053a3667aaeSNaresh Kumar Inna 4054a3667aaeSNaresh Kumar Inna list_add_tail(&evt_entry->list, &hw->evt_free_q); 4055a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_freeq); 4056a3667aaeSNaresh Kumar Inna } 4057a3667aaeSNaresh Kumar Inna 4058a3667aaeSNaresh Kumar Inna hw->dev_num = dev_num; 4059a3667aaeSNaresh Kumar Inna dev_num++; 4060a3667aaeSNaresh Kumar Inna 4061a3667aaeSNaresh Kumar Inna return 0; 4062a3667aaeSNaresh Kumar Inna 4063a3667aaeSNaresh Kumar Inna err_evtq_cleanup: 4064a3667aaeSNaresh Kumar Inna csio_evtq_cleanup(hw); 4065a3667aaeSNaresh Kumar Inna csio_mgmtm_exit(csio_hw_to_mgmtm(hw)); 4066a3667aaeSNaresh Kumar Inna err_scsim_exit: 4067a3667aaeSNaresh Kumar Inna csio_scsim_exit(csio_hw_to_scsim(hw)); 4068a3667aaeSNaresh Kumar Inna err_wrm_exit: 4069a3667aaeSNaresh Kumar Inna csio_wrm_exit(csio_hw_to_wrm(hw), hw); 4070a3667aaeSNaresh Kumar Inna err_mbm_exit: 4071a3667aaeSNaresh Kumar Inna csio_mbm_exit(csio_hw_to_mbm(hw)); 4072a3667aaeSNaresh Kumar Inna err: 4073a3667aaeSNaresh Kumar Inna return rv; 4074a3667aaeSNaresh Kumar Inna } 4075a3667aaeSNaresh Kumar Inna 4076a3667aaeSNaresh Kumar Inna /** 4077a3667aaeSNaresh Kumar Inna * csio_hw_exit - Un-initialize HW module. 4078a3667aaeSNaresh Kumar Inna * @hw: Pointer to HW module. 4079a3667aaeSNaresh Kumar Inna * 4080a3667aaeSNaresh Kumar Inna */ 4081a3667aaeSNaresh Kumar Inna void 4082a3667aaeSNaresh Kumar Inna csio_hw_exit(struct csio_hw *hw) 4083a3667aaeSNaresh Kumar Inna { 4084a3667aaeSNaresh Kumar Inna csio_evtq_cleanup(hw); 4085a3667aaeSNaresh Kumar Inna csio_mgmtm_exit(csio_hw_to_mgmtm(hw)); 4086a3667aaeSNaresh Kumar Inna csio_scsim_exit(csio_hw_to_scsim(hw)); 4087a3667aaeSNaresh Kumar Inna csio_wrm_exit(csio_hw_to_wrm(hw), hw); 4088a3667aaeSNaresh Kumar Inna csio_mbm_exit(csio_hw_to_mbm(hw)); 4089a3667aaeSNaresh Kumar Inna } 4090