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_t5_fcoe_adapters[] = { 647cc16380SArvind Bhushan {"T580-Dbg 10G", "Chelsio T580-Dbg 10G [FCoE]"}, 657cc16380SArvind Bhushan {"T520-CR 10G", "Chelsio T520-CR 10G [FCoE]"}, 663fb4c22eSPraveen Madhavan {"T522-CR 10G/1G", "Chelsio T522-CR 10G/1G [FCoE]"}, 677cc16380SArvind Bhushan {"T540-CR 10G", "Chelsio T540-CR 10G [FCoE]"}, 687cc16380SArvind Bhushan {"T520-BCH 10G", "Chelsio T520-BCH 10G [FCoE]"}, 697cc16380SArvind Bhushan {"T540-BCH 10G", "Chelsio T540-BCH 10G [FCoE]"}, 707cc16380SArvind Bhushan {"T540-CH 10G", "Chelsio T540-CH 10G [FCoE]"}, 717cc16380SArvind Bhushan {"T520-SO 10G", "Chelsio T520-SO 10G [FCoE]"}, 727cc16380SArvind Bhushan {"T520-CX4 10G", "Chelsio T520-CX4 10G [FCoE]"}, 737cc16380SArvind Bhushan {"T520-BT 10G", "Chelsio T520-BT 10G [FCoE]"}, 747cc16380SArvind Bhushan {"T504-BT 1G", "Chelsio T504-BT 1G [FCoE]"}, 757cc16380SArvind Bhushan {"B520-SR 10G", "Chelsio B520-SR 10G [FCoE]"}, 767cc16380SArvind Bhushan {"B504-BT 1G", "Chelsio B504-BT 1G [FCoE]"}, 777cc16380SArvind Bhushan {"T580-CR 10G", "Chelsio T580-CR 10G [FCoE]"}, 787cc16380SArvind Bhushan {"T540-LP-CR 10G", "Chelsio T540-LP-CR 10G [FCoE]"}, 797cc16380SArvind Bhushan {"AMSTERDAM 10G", "Chelsio AMSTERDAM 10G [FCoE]"}, 807cc16380SArvind Bhushan {"T580-LP-CR 40G", "Chelsio T580-LP-CR 40G [FCoE]"}, 817cc16380SArvind Bhushan {"T520-LL-CR 10G", "Chelsio T520-LL-CR 10G [FCoE]"}, 827cc16380SArvind Bhushan {"T560-CR 40G", "Chelsio T560-CR 40G [FCoE]"}, 833fb4c22eSPraveen Madhavan {"T580-CR 40G", "Chelsio T580-CR 40G [FCoE]"}, 843fb4c22eSPraveen Madhavan {"T580-SO 40G", "Chelsio T580-SO 40G [FCoE]"}, 853fb4c22eSPraveen Madhavan {"T502-BT 1G", "Chelsio T502-BT 1G [FCoE]"} 86a3667aaeSNaresh Kumar Inna }; 87a3667aaeSNaresh Kumar Inna 88a3667aaeSNaresh Kumar Inna static void csio_mgmtm_cleanup(struct csio_mgmtm *); 89a3667aaeSNaresh Kumar Inna static void csio_hw_mbm_cleanup(struct csio_hw *); 90a3667aaeSNaresh Kumar Inna 91a3667aaeSNaresh Kumar Inna /* State machine forward declarations */ 92a3667aaeSNaresh Kumar Inna static void csio_hws_uninit(struct csio_hw *, enum csio_hw_ev); 93a3667aaeSNaresh Kumar Inna static void csio_hws_configuring(struct csio_hw *, enum csio_hw_ev); 94a3667aaeSNaresh Kumar Inna static void csio_hws_initializing(struct csio_hw *, enum csio_hw_ev); 95a3667aaeSNaresh Kumar Inna static void csio_hws_ready(struct csio_hw *, enum csio_hw_ev); 96a3667aaeSNaresh Kumar Inna static void csio_hws_quiescing(struct csio_hw *, enum csio_hw_ev); 97a3667aaeSNaresh Kumar Inna static void csio_hws_quiesced(struct csio_hw *, enum csio_hw_ev); 98a3667aaeSNaresh Kumar Inna static void csio_hws_resetting(struct csio_hw *, enum csio_hw_ev); 99a3667aaeSNaresh Kumar Inna static void csio_hws_removing(struct csio_hw *, enum csio_hw_ev); 100a3667aaeSNaresh Kumar Inna static void csio_hws_pcierr(struct csio_hw *, enum csio_hw_ev); 101a3667aaeSNaresh Kumar Inna 102a3667aaeSNaresh Kumar Inna static void csio_hw_initialize(struct csio_hw *hw); 103a3667aaeSNaresh Kumar Inna static void csio_evtq_stop(struct csio_hw *hw); 104a3667aaeSNaresh Kumar Inna static void csio_evtq_start(struct csio_hw *hw); 105a3667aaeSNaresh Kumar Inna 106a3667aaeSNaresh Kumar Inna int csio_is_hw_ready(struct csio_hw *hw) 107a3667aaeSNaresh Kumar Inna { 108a3667aaeSNaresh Kumar Inna return csio_match_state(hw, csio_hws_ready); 109a3667aaeSNaresh Kumar Inna } 110a3667aaeSNaresh Kumar Inna 111a3667aaeSNaresh Kumar Inna int csio_is_hw_removing(struct csio_hw *hw) 112a3667aaeSNaresh Kumar Inna { 113a3667aaeSNaresh Kumar Inna return csio_match_state(hw, csio_hws_removing); 114a3667aaeSNaresh Kumar Inna } 115a3667aaeSNaresh Kumar Inna 116a3667aaeSNaresh Kumar Inna 117a3667aaeSNaresh Kumar Inna /* 118a3667aaeSNaresh Kumar Inna * csio_hw_wait_op_done_val - wait until an operation is completed 119a3667aaeSNaresh Kumar Inna * @hw: the HW module 120a3667aaeSNaresh Kumar Inna * @reg: the register to check for completion 121a3667aaeSNaresh Kumar Inna * @mask: a single-bit field within @reg that indicates completion 122a3667aaeSNaresh Kumar Inna * @polarity: the value of the field when the operation is completed 123a3667aaeSNaresh Kumar Inna * @attempts: number of check iterations 124a3667aaeSNaresh Kumar Inna * @delay: delay in usecs between iterations 125a3667aaeSNaresh Kumar Inna * @valp: where to store the value of the register at completion time 126a3667aaeSNaresh Kumar Inna * 127a3667aaeSNaresh Kumar Inna * Wait until an operation is completed by checking a bit in a register 128a3667aaeSNaresh Kumar Inna * up to @attempts times. If @valp is not NULL the value of the register 129a3667aaeSNaresh Kumar Inna * at the time it indicated completion is stored there. Returns 0 if the 130a3667aaeSNaresh Kumar Inna * operation completes and -EAGAIN otherwise. 131a3667aaeSNaresh Kumar Inna */ 1327cc16380SArvind Bhushan int 133a3667aaeSNaresh Kumar Inna csio_hw_wait_op_done_val(struct csio_hw *hw, int reg, uint32_t mask, 134a3667aaeSNaresh Kumar Inna int polarity, int attempts, int delay, uint32_t *valp) 135a3667aaeSNaresh Kumar Inna { 136a3667aaeSNaresh Kumar Inna uint32_t val; 137a3667aaeSNaresh Kumar Inna while (1) { 138a3667aaeSNaresh Kumar Inna val = csio_rd_reg32(hw, reg); 139a3667aaeSNaresh Kumar Inna 140a3667aaeSNaresh Kumar Inna if (!!(val & mask) == polarity) { 141a3667aaeSNaresh Kumar Inna if (valp) 142a3667aaeSNaresh Kumar Inna *valp = val; 143a3667aaeSNaresh Kumar Inna return 0; 144a3667aaeSNaresh Kumar Inna } 145a3667aaeSNaresh Kumar Inna 146a3667aaeSNaresh Kumar Inna if (--attempts == 0) 147a3667aaeSNaresh Kumar Inna return -EAGAIN; 148a3667aaeSNaresh Kumar Inna if (delay) 149a3667aaeSNaresh Kumar Inna udelay(delay); 150a3667aaeSNaresh Kumar Inna } 151a3667aaeSNaresh Kumar Inna } 152a3667aaeSNaresh Kumar Inna 1537cc16380SArvind Bhushan /* 1547cc16380SArvind Bhushan * csio_hw_tp_wr_bits_indirect - set/clear bits in an indirect TP register 1557cc16380SArvind Bhushan * @hw: the adapter 1567cc16380SArvind Bhushan * @addr: the indirect TP register address 1577cc16380SArvind Bhushan * @mask: specifies the field within the register to modify 1587cc16380SArvind Bhushan * @val: new value for the field 1597cc16380SArvind Bhushan * 1607cc16380SArvind Bhushan * Sets a field of an indirect TP register to the given value. 1617cc16380SArvind Bhushan */ 1627cc16380SArvind Bhushan void 1637cc16380SArvind Bhushan csio_hw_tp_wr_bits_indirect(struct csio_hw *hw, unsigned int addr, 1647cc16380SArvind Bhushan unsigned int mask, unsigned int val) 1657cc16380SArvind Bhushan { 166837e4a42SHariprasad Shenai csio_wr_reg32(hw, addr, TP_PIO_ADDR_A); 167837e4a42SHariprasad Shenai val |= csio_rd_reg32(hw, TP_PIO_DATA_A) & ~mask; 168837e4a42SHariprasad Shenai csio_wr_reg32(hw, val, TP_PIO_DATA_A); 1697cc16380SArvind Bhushan } 1707cc16380SArvind Bhushan 171a3667aaeSNaresh Kumar Inna void 172a3667aaeSNaresh Kumar Inna csio_set_reg_field(struct csio_hw *hw, uint32_t reg, uint32_t mask, 173a3667aaeSNaresh Kumar Inna uint32_t value) 174a3667aaeSNaresh Kumar Inna { 175a3667aaeSNaresh Kumar Inna uint32_t val = csio_rd_reg32(hw, reg) & ~mask; 176a3667aaeSNaresh Kumar Inna 177a3667aaeSNaresh Kumar Inna csio_wr_reg32(hw, val | value, reg); 178a3667aaeSNaresh Kumar Inna /* Flush */ 179a3667aaeSNaresh Kumar Inna csio_rd_reg32(hw, reg); 180a3667aaeSNaresh Kumar Inna 181a3667aaeSNaresh Kumar Inna } 182a3667aaeSNaresh Kumar Inna 183a3667aaeSNaresh Kumar Inna static int 1845036f0a0SNaresh Kumar Inna csio_memory_write(struct csio_hw *hw, int mtype, u32 addr, u32 len, u32 *buf) 185a3667aaeSNaresh Kumar Inna { 1867cc16380SArvind Bhushan return hw->chip_ops->chip_memory_rw(hw, MEMWIN_CSIOSTOR, mtype, 1877cc16380SArvind Bhushan addr, len, buf, 0); 188a3667aaeSNaresh Kumar Inna } 189a3667aaeSNaresh Kumar Inna 190a3667aaeSNaresh Kumar Inna /* 191a3667aaeSNaresh Kumar Inna * EEPROM reads take a few tens of us while writes can take a bit over 5 ms. 192a3667aaeSNaresh Kumar Inna */ 193a3667aaeSNaresh Kumar Inna #define EEPROM_MAX_RD_POLL 40 194a3667aaeSNaresh Kumar Inna #define EEPROM_MAX_WR_POLL 6 195a3667aaeSNaresh Kumar Inna #define EEPROM_STAT_ADDR 0x7bfc 196a3667aaeSNaresh Kumar Inna #define VPD_BASE 0x400 197a3667aaeSNaresh Kumar Inna #define VPD_BASE_OLD 0 1987cc16380SArvind Bhushan #define VPD_LEN 1024 199a3667aaeSNaresh Kumar Inna #define VPD_INFO_FLD_HDR_SIZE 3 200a3667aaeSNaresh Kumar Inna 201a3667aaeSNaresh Kumar Inna /* 202a3667aaeSNaresh Kumar Inna * csio_hw_seeprom_read - read a serial EEPROM location 203a3667aaeSNaresh Kumar Inna * @hw: hw to read 204a3667aaeSNaresh Kumar Inna * @addr: EEPROM virtual address 205a3667aaeSNaresh Kumar Inna * @data: where to store the read data 206a3667aaeSNaresh Kumar Inna * 207a3667aaeSNaresh Kumar Inna * Read a 32-bit word from a location in serial EEPROM using the card's PCI 208a3667aaeSNaresh Kumar Inna * VPD capability. Note that this function must be called with a virtual 209a3667aaeSNaresh Kumar Inna * address. 210a3667aaeSNaresh Kumar Inna */ 211a3667aaeSNaresh Kumar Inna static int 212a3667aaeSNaresh Kumar Inna csio_hw_seeprom_read(struct csio_hw *hw, uint32_t addr, uint32_t *data) 213a3667aaeSNaresh Kumar Inna { 214a3667aaeSNaresh Kumar Inna uint16_t val = 0; 215a3667aaeSNaresh Kumar Inna int attempts = EEPROM_MAX_RD_POLL; 216a3667aaeSNaresh Kumar Inna uint32_t base = hw->params.pci.vpd_cap_addr; 217a3667aaeSNaresh Kumar Inna 218a3667aaeSNaresh Kumar Inna if (addr >= EEPROMVSIZE || (addr & 3)) 219a3667aaeSNaresh Kumar Inna return -EINVAL; 220a3667aaeSNaresh Kumar Inna 221a3667aaeSNaresh Kumar Inna pci_write_config_word(hw->pdev, base + PCI_VPD_ADDR, (uint16_t)addr); 222a3667aaeSNaresh Kumar Inna 223a3667aaeSNaresh Kumar Inna do { 224a3667aaeSNaresh Kumar Inna udelay(10); 225a3667aaeSNaresh Kumar Inna pci_read_config_word(hw->pdev, base + PCI_VPD_ADDR, &val); 226a3667aaeSNaresh Kumar Inna } while (!(val & PCI_VPD_ADDR_F) && --attempts); 227a3667aaeSNaresh Kumar Inna 228a3667aaeSNaresh Kumar Inna if (!(val & PCI_VPD_ADDR_F)) { 229a3667aaeSNaresh Kumar Inna csio_err(hw, "reading EEPROM address 0x%x failed\n", addr); 230a3667aaeSNaresh Kumar Inna return -EINVAL; 231a3667aaeSNaresh Kumar Inna } 232a3667aaeSNaresh Kumar Inna 233a3667aaeSNaresh Kumar Inna pci_read_config_dword(hw->pdev, base + PCI_VPD_DATA, data); 23478890ed7SPraveen Madhavan *data = le32_to_cpu(*(__le32 *)data); 2355036f0a0SNaresh Kumar Inna 236a3667aaeSNaresh Kumar Inna return 0; 237a3667aaeSNaresh Kumar Inna } 238a3667aaeSNaresh Kumar Inna 239a3667aaeSNaresh Kumar Inna /* 240a3667aaeSNaresh Kumar Inna * Partial EEPROM Vital Product Data structure. Includes only the ID and 241a3667aaeSNaresh Kumar Inna * VPD-R sections. 242a3667aaeSNaresh Kumar Inna */ 243a3667aaeSNaresh Kumar Inna struct t4_vpd_hdr { 244a3667aaeSNaresh Kumar Inna u8 id_tag; 245a3667aaeSNaresh Kumar Inna u8 id_len[2]; 246a3667aaeSNaresh Kumar Inna u8 id_data[ID_LEN]; 247a3667aaeSNaresh Kumar Inna u8 vpdr_tag; 248a3667aaeSNaresh Kumar Inna u8 vpdr_len[2]; 249a3667aaeSNaresh Kumar Inna }; 250a3667aaeSNaresh Kumar Inna 251a3667aaeSNaresh Kumar Inna /* 252a3667aaeSNaresh Kumar Inna * csio_hw_get_vpd_keyword_val - Locates an information field keyword in 253a3667aaeSNaresh Kumar Inna * the VPD 254a3667aaeSNaresh Kumar Inna * @v: Pointer to buffered vpd data structure 255a3667aaeSNaresh Kumar Inna * @kw: The keyword to search for 256a3667aaeSNaresh Kumar Inna * 257a3667aaeSNaresh Kumar Inna * Returns the value of the information field keyword or 258a3667aaeSNaresh Kumar Inna * -EINVAL otherwise. 259a3667aaeSNaresh Kumar Inna */ 260a3667aaeSNaresh Kumar Inna static int 261a3667aaeSNaresh Kumar Inna csio_hw_get_vpd_keyword_val(const struct t4_vpd_hdr *v, const char *kw) 262a3667aaeSNaresh Kumar Inna { 263a3667aaeSNaresh Kumar Inna int32_t i; 264a3667aaeSNaresh Kumar Inna int32_t offset , len; 265a3667aaeSNaresh Kumar Inna const uint8_t *buf = &v->id_tag; 266a3667aaeSNaresh Kumar Inna const uint8_t *vpdr_len = &v->vpdr_tag; 267a3667aaeSNaresh Kumar Inna offset = sizeof(struct t4_vpd_hdr); 268a3667aaeSNaresh Kumar Inna len = (uint16_t)vpdr_len[1] + ((uint16_t)vpdr_len[2] << 8); 269a3667aaeSNaresh Kumar Inna 270a3667aaeSNaresh Kumar Inna if (len + sizeof(struct t4_vpd_hdr) > VPD_LEN) 271a3667aaeSNaresh Kumar Inna return -EINVAL; 272a3667aaeSNaresh Kumar Inna 273a3667aaeSNaresh Kumar Inna for (i = offset; (i + VPD_INFO_FLD_HDR_SIZE) <= (offset + len);) { 274a3667aaeSNaresh Kumar Inna if (memcmp(buf + i , kw, 2) == 0) { 275a3667aaeSNaresh Kumar Inna i += VPD_INFO_FLD_HDR_SIZE; 276a3667aaeSNaresh Kumar Inna return i; 277a3667aaeSNaresh Kumar Inna } 278a3667aaeSNaresh Kumar Inna 279a3667aaeSNaresh Kumar Inna i += VPD_INFO_FLD_HDR_SIZE + buf[i+2]; 280a3667aaeSNaresh Kumar Inna } 281a3667aaeSNaresh Kumar Inna 282a3667aaeSNaresh Kumar Inna return -EINVAL; 283a3667aaeSNaresh Kumar Inna } 284a3667aaeSNaresh Kumar Inna 285a3667aaeSNaresh Kumar Inna static int 286a3667aaeSNaresh Kumar Inna csio_pci_capability(struct pci_dev *pdev, int cap, int *pos) 287a3667aaeSNaresh Kumar Inna { 288a3667aaeSNaresh Kumar Inna *pos = pci_find_capability(pdev, cap); 289a3667aaeSNaresh Kumar Inna if (*pos) 290a3667aaeSNaresh Kumar Inna return 0; 291a3667aaeSNaresh Kumar Inna 292a3667aaeSNaresh Kumar Inna return -1; 293a3667aaeSNaresh Kumar Inna } 294a3667aaeSNaresh Kumar Inna 295a3667aaeSNaresh Kumar Inna /* 296a3667aaeSNaresh Kumar Inna * csio_hw_get_vpd_params - read VPD parameters from VPD EEPROM 297a3667aaeSNaresh Kumar Inna * @hw: HW module 298a3667aaeSNaresh Kumar Inna * @p: where to store the parameters 299a3667aaeSNaresh Kumar Inna * 300a3667aaeSNaresh Kumar Inna * Reads card parameters stored in VPD EEPROM. 301a3667aaeSNaresh Kumar Inna */ 302a3667aaeSNaresh Kumar Inna static int 303a3667aaeSNaresh Kumar Inna csio_hw_get_vpd_params(struct csio_hw *hw, struct csio_vpd *p) 304a3667aaeSNaresh Kumar Inna { 305a3667aaeSNaresh Kumar Inna int i, ret, ec, sn, addr; 306a3667aaeSNaresh Kumar Inna uint8_t *vpd, csum; 307a3667aaeSNaresh Kumar Inna const struct t4_vpd_hdr *v; 308a3667aaeSNaresh Kumar Inna /* To get around compilation warning from strstrip */ 309a3667aaeSNaresh Kumar Inna char *s; 310a3667aaeSNaresh Kumar Inna 311a3667aaeSNaresh Kumar Inna if (csio_is_valid_vpd(hw)) 312a3667aaeSNaresh Kumar Inna return 0; 313a3667aaeSNaresh Kumar Inna 314a3667aaeSNaresh Kumar Inna ret = csio_pci_capability(hw->pdev, PCI_CAP_ID_VPD, 315a3667aaeSNaresh Kumar Inna &hw->params.pci.vpd_cap_addr); 316a3667aaeSNaresh Kumar Inna if (ret) 317a3667aaeSNaresh Kumar Inna return -EINVAL; 318a3667aaeSNaresh Kumar Inna 319a3667aaeSNaresh Kumar Inna vpd = kzalloc(VPD_LEN, GFP_ATOMIC); 320a3667aaeSNaresh Kumar Inna if (vpd == NULL) 321a3667aaeSNaresh Kumar Inna return -ENOMEM; 322a3667aaeSNaresh Kumar Inna 323a3667aaeSNaresh Kumar Inna /* 324a3667aaeSNaresh Kumar Inna * Card information normally starts at VPD_BASE but early cards had 325a3667aaeSNaresh Kumar Inna * it at 0. 326a3667aaeSNaresh Kumar Inna */ 327a3667aaeSNaresh Kumar Inna ret = csio_hw_seeprom_read(hw, VPD_BASE, (uint32_t *)(vpd)); 328a3667aaeSNaresh Kumar Inna addr = *vpd == 0x82 ? VPD_BASE : VPD_BASE_OLD; 329a3667aaeSNaresh Kumar Inna 330a3667aaeSNaresh Kumar Inna for (i = 0; i < VPD_LEN; i += 4) { 331a3667aaeSNaresh Kumar Inna ret = csio_hw_seeprom_read(hw, addr + i, (uint32_t *)(vpd + i)); 332a3667aaeSNaresh Kumar Inna if (ret) { 333a3667aaeSNaresh Kumar Inna kfree(vpd); 334a3667aaeSNaresh Kumar Inna return ret; 335a3667aaeSNaresh Kumar Inna } 336a3667aaeSNaresh Kumar Inna } 337a3667aaeSNaresh Kumar Inna 338a3667aaeSNaresh Kumar Inna /* Reset the VPD flag! */ 339a3667aaeSNaresh Kumar Inna hw->flags &= (~CSIO_HWF_VPD_VALID); 340a3667aaeSNaresh Kumar Inna 341a3667aaeSNaresh Kumar Inna v = (const struct t4_vpd_hdr *)vpd; 342a3667aaeSNaresh Kumar Inna 343a3667aaeSNaresh Kumar Inna #define FIND_VPD_KW(var, name) do { \ 344a3667aaeSNaresh Kumar Inna var = csio_hw_get_vpd_keyword_val(v, name); \ 345a3667aaeSNaresh Kumar Inna if (var < 0) { \ 346a3667aaeSNaresh Kumar Inna csio_err(hw, "missing VPD keyword " name "\n"); \ 347a3667aaeSNaresh Kumar Inna kfree(vpd); \ 348a3667aaeSNaresh Kumar Inna return -EINVAL; \ 349a3667aaeSNaresh Kumar Inna } \ 350a3667aaeSNaresh Kumar Inna } while (0) 351a3667aaeSNaresh Kumar Inna 352a3667aaeSNaresh Kumar Inna FIND_VPD_KW(i, "RV"); 353a3667aaeSNaresh Kumar Inna for (csum = 0; i >= 0; i--) 354a3667aaeSNaresh Kumar Inna csum += vpd[i]; 355a3667aaeSNaresh Kumar Inna 356a3667aaeSNaresh Kumar Inna if (csum) { 357a3667aaeSNaresh Kumar Inna csio_err(hw, "corrupted VPD EEPROM, actual csum %u\n", csum); 358a3667aaeSNaresh Kumar Inna kfree(vpd); 359a3667aaeSNaresh Kumar Inna return -EINVAL; 360a3667aaeSNaresh Kumar Inna } 361a3667aaeSNaresh Kumar Inna FIND_VPD_KW(ec, "EC"); 362a3667aaeSNaresh Kumar Inna FIND_VPD_KW(sn, "SN"); 363a3667aaeSNaresh Kumar Inna #undef FIND_VPD_KW 364a3667aaeSNaresh Kumar Inna 365a3667aaeSNaresh Kumar Inna memcpy(p->id, v->id_data, ID_LEN); 366a3667aaeSNaresh Kumar Inna s = strstrip(p->id); 367a3667aaeSNaresh Kumar Inna memcpy(p->ec, vpd + ec, EC_LEN); 368a3667aaeSNaresh Kumar Inna s = strstrip(p->ec); 369a3667aaeSNaresh Kumar Inna i = vpd[sn - VPD_INFO_FLD_HDR_SIZE + 2]; 370a3667aaeSNaresh Kumar Inna memcpy(p->sn, vpd + sn, min(i, SERNUM_LEN)); 371a3667aaeSNaresh Kumar Inna s = strstrip(p->sn); 372a3667aaeSNaresh Kumar Inna 373a3667aaeSNaresh Kumar Inna csio_valid_vpd_copied(hw); 374a3667aaeSNaresh Kumar Inna 375a3667aaeSNaresh Kumar Inna kfree(vpd); 376a3667aaeSNaresh Kumar Inna return 0; 377a3667aaeSNaresh Kumar Inna } 378a3667aaeSNaresh Kumar Inna 379a3667aaeSNaresh Kumar Inna /* 380a3667aaeSNaresh Kumar Inna * csio_hw_sf1_read - read data from the serial flash 381a3667aaeSNaresh Kumar Inna * @hw: the HW module 382a3667aaeSNaresh Kumar Inna * @byte_cnt: number of bytes to read 383a3667aaeSNaresh Kumar Inna * @cont: whether another operation will be chained 384a3667aaeSNaresh Kumar Inna * @lock: whether to lock SF for PL access only 385a3667aaeSNaresh Kumar Inna * @valp: where to store the read data 386a3667aaeSNaresh Kumar Inna * 387a3667aaeSNaresh Kumar Inna * Reads up to 4 bytes of data from the serial flash. The location of 388a3667aaeSNaresh Kumar Inna * the read needs to be specified prior to calling this by issuing the 389a3667aaeSNaresh Kumar Inna * appropriate commands to the serial flash. 390a3667aaeSNaresh Kumar Inna */ 391a3667aaeSNaresh Kumar Inna static int 392a3667aaeSNaresh Kumar Inna csio_hw_sf1_read(struct csio_hw *hw, uint32_t byte_cnt, int32_t cont, 393a3667aaeSNaresh Kumar Inna int32_t lock, uint32_t *valp) 394a3667aaeSNaresh Kumar Inna { 395a3667aaeSNaresh Kumar Inna int ret; 396a3667aaeSNaresh Kumar Inna 397a3667aaeSNaresh Kumar Inna if (!byte_cnt || byte_cnt > 4) 398a3667aaeSNaresh Kumar Inna return -EINVAL; 3990d804338SHariprasad Shenai if (csio_rd_reg32(hw, SF_OP_A) & SF_BUSY_F) 400a3667aaeSNaresh Kumar Inna return -EBUSY; 401a3667aaeSNaresh Kumar Inna 4020d804338SHariprasad Shenai csio_wr_reg32(hw, SF_LOCK_V(lock) | SF_CONT_V(cont) | 4030d804338SHariprasad Shenai BYTECNT_V(byte_cnt - 1), SF_OP_A); 4040d804338SHariprasad Shenai ret = csio_hw_wait_op_done_val(hw, SF_OP_A, SF_BUSY_F, 0, SF_ATTEMPTS, 405a3667aaeSNaresh Kumar Inna 10, NULL); 406a3667aaeSNaresh Kumar Inna if (!ret) 4070d804338SHariprasad Shenai *valp = csio_rd_reg32(hw, SF_DATA_A); 408a3667aaeSNaresh Kumar Inna return ret; 409a3667aaeSNaresh Kumar Inna } 410a3667aaeSNaresh Kumar Inna 411a3667aaeSNaresh Kumar Inna /* 412a3667aaeSNaresh Kumar Inna * csio_hw_sf1_write - write data to the serial flash 413a3667aaeSNaresh Kumar Inna * @hw: the HW module 414a3667aaeSNaresh Kumar Inna * @byte_cnt: number of bytes to write 415a3667aaeSNaresh Kumar Inna * @cont: whether another operation will be chained 416a3667aaeSNaresh Kumar Inna * @lock: whether to lock SF for PL access only 417a3667aaeSNaresh Kumar Inna * @val: value to write 418a3667aaeSNaresh Kumar Inna * 419a3667aaeSNaresh Kumar Inna * Writes up to 4 bytes of data to the serial flash. The location of 420a3667aaeSNaresh Kumar Inna * the write needs to be specified prior to calling this by issuing the 421a3667aaeSNaresh Kumar Inna * appropriate commands to the serial flash. 422a3667aaeSNaresh Kumar Inna */ 423a3667aaeSNaresh Kumar Inna static int 424a3667aaeSNaresh Kumar Inna csio_hw_sf1_write(struct csio_hw *hw, uint32_t byte_cnt, uint32_t cont, 425a3667aaeSNaresh Kumar Inna int32_t lock, uint32_t val) 426a3667aaeSNaresh Kumar Inna { 427a3667aaeSNaresh Kumar Inna if (!byte_cnt || byte_cnt > 4) 428a3667aaeSNaresh Kumar Inna return -EINVAL; 4290d804338SHariprasad Shenai if (csio_rd_reg32(hw, SF_OP_A) & SF_BUSY_F) 430a3667aaeSNaresh Kumar Inna return -EBUSY; 431a3667aaeSNaresh Kumar Inna 4320d804338SHariprasad Shenai csio_wr_reg32(hw, val, SF_DATA_A); 4330d804338SHariprasad Shenai csio_wr_reg32(hw, SF_CONT_V(cont) | BYTECNT_V(byte_cnt - 1) | 4340d804338SHariprasad Shenai OP_V(1) | SF_LOCK_V(lock), SF_OP_A); 435a3667aaeSNaresh Kumar Inna 4360d804338SHariprasad Shenai return csio_hw_wait_op_done_val(hw, SF_OP_A, SF_BUSY_F, 0, SF_ATTEMPTS, 437a3667aaeSNaresh Kumar Inna 10, NULL); 438a3667aaeSNaresh Kumar Inna } 439a3667aaeSNaresh Kumar Inna 440a3667aaeSNaresh Kumar Inna /* 441a3667aaeSNaresh Kumar Inna * csio_hw_flash_wait_op - wait for a flash operation to complete 442a3667aaeSNaresh Kumar Inna * @hw: the HW module 443a3667aaeSNaresh Kumar Inna * @attempts: max number of polls of the status register 444a3667aaeSNaresh Kumar Inna * @delay: delay between polls in ms 445a3667aaeSNaresh Kumar Inna * 446a3667aaeSNaresh Kumar Inna * Wait for a flash operation to complete by polling the status register. 447a3667aaeSNaresh Kumar Inna */ 448a3667aaeSNaresh Kumar Inna static int 449a3667aaeSNaresh Kumar Inna csio_hw_flash_wait_op(struct csio_hw *hw, int32_t attempts, int32_t delay) 450a3667aaeSNaresh Kumar Inna { 451a3667aaeSNaresh Kumar Inna int ret; 452a3667aaeSNaresh Kumar Inna uint32_t status; 453a3667aaeSNaresh Kumar Inna 454a3667aaeSNaresh Kumar Inna while (1) { 455a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_write(hw, 1, 1, 1, SF_RD_STATUS); 456a3667aaeSNaresh Kumar Inna if (ret != 0) 457a3667aaeSNaresh Kumar Inna return ret; 458a3667aaeSNaresh Kumar Inna 459a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_read(hw, 1, 0, 1, &status); 460a3667aaeSNaresh Kumar Inna if (ret != 0) 461a3667aaeSNaresh Kumar Inna return ret; 462a3667aaeSNaresh Kumar Inna 463a3667aaeSNaresh Kumar Inna if (!(status & 1)) 464a3667aaeSNaresh Kumar Inna return 0; 465a3667aaeSNaresh Kumar Inna if (--attempts == 0) 466a3667aaeSNaresh Kumar Inna return -EAGAIN; 467a3667aaeSNaresh Kumar Inna if (delay) 468a3667aaeSNaresh Kumar Inna msleep(delay); 469a3667aaeSNaresh Kumar Inna } 470a3667aaeSNaresh Kumar Inna } 471a3667aaeSNaresh Kumar Inna 472a3667aaeSNaresh Kumar Inna /* 473a3667aaeSNaresh Kumar Inna * csio_hw_read_flash - read words from serial flash 474a3667aaeSNaresh Kumar Inna * @hw: the HW module 475a3667aaeSNaresh Kumar Inna * @addr: the start address for the read 476a3667aaeSNaresh Kumar Inna * @nwords: how many 32-bit words to read 477a3667aaeSNaresh Kumar Inna * @data: where to store the read data 478a3667aaeSNaresh Kumar Inna * @byte_oriented: whether to store data as bytes or as words 479a3667aaeSNaresh Kumar Inna * 480a3667aaeSNaresh Kumar Inna * Read the specified number of 32-bit words from the serial flash. 481a3667aaeSNaresh Kumar Inna * If @byte_oriented is set the read data is stored as a byte array 482a3667aaeSNaresh Kumar Inna * (i.e., big-endian), otherwise as 32-bit words in the platform's 483a3667aaeSNaresh Kumar Inna * natural endianess. 484a3667aaeSNaresh Kumar Inna */ 485a3667aaeSNaresh Kumar Inna static int 486a3667aaeSNaresh Kumar Inna csio_hw_read_flash(struct csio_hw *hw, uint32_t addr, uint32_t nwords, 487a3667aaeSNaresh Kumar Inna uint32_t *data, int32_t byte_oriented) 488a3667aaeSNaresh Kumar Inna { 489a3667aaeSNaresh Kumar Inna int ret; 490a3667aaeSNaresh Kumar Inna 491a3667aaeSNaresh Kumar Inna if (addr + nwords * sizeof(uint32_t) > hw->params.sf_size || (addr & 3)) 492a3667aaeSNaresh Kumar Inna return -EINVAL; 493a3667aaeSNaresh Kumar Inna 494a3667aaeSNaresh Kumar Inna addr = swab32(addr) | SF_RD_DATA_FAST; 495a3667aaeSNaresh Kumar Inna 496a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_write(hw, 4, 1, 0, addr); 497a3667aaeSNaresh Kumar Inna if (ret != 0) 498a3667aaeSNaresh Kumar Inna return ret; 499a3667aaeSNaresh Kumar Inna 500a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_read(hw, 1, 1, 0, data); 501a3667aaeSNaresh Kumar Inna if (ret != 0) 502a3667aaeSNaresh Kumar Inna return ret; 503a3667aaeSNaresh Kumar Inna 504a3667aaeSNaresh Kumar Inna for ( ; nwords; nwords--, data++) { 505a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_read(hw, 4, nwords > 1, nwords == 1, data); 506a3667aaeSNaresh Kumar Inna if (nwords == 1) 5070d804338SHariprasad Shenai csio_wr_reg32(hw, 0, SF_OP_A); /* unlock SF */ 508a3667aaeSNaresh Kumar Inna if (ret) 509a3667aaeSNaresh Kumar Inna return ret; 510a3667aaeSNaresh Kumar Inna if (byte_oriented) 51178890ed7SPraveen Madhavan *data = (__force __u32) htonl(*data); 512a3667aaeSNaresh Kumar Inna } 513a3667aaeSNaresh Kumar Inna return 0; 514a3667aaeSNaresh Kumar Inna } 515a3667aaeSNaresh Kumar Inna 516a3667aaeSNaresh Kumar Inna /* 517a3667aaeSNaresh Kumar Inna * csio_hw_write_flash - write up to a page of data to the serial flash 518a3667aaeSNaresh Kumar Inna * @hw: the hw 519a3667aaeSNaresh Kumar Inna * @addr: the start address to write 520a3667aaeSNaresh Kumar Inna * @n: length of data to write in bytes 521a3667aaeSNaresh Kumar Inna * @data: the data to write 522a3667aaeSNaresh Kumar Inna * 523a3667aaeSNaresh Kumar Inna * Writes up to a page of data (256 bytes) to the serial flash starting 524a3667aaeSNaresh Kumar Inna * at the given address. All the data must be written to the same page. 525a3667aaeSNaresh Kumar Inna */ 526a3667aaeSNaresh Kumar Inna static int 527a3667aaeSNaresh Kumar Inna csio_hw_write_flash(struct csio_hw *hw, uint32_t addr, 528a3667aaeSNaresh Kumar Inna uint32_t n, const uint8_t *data) 529a3667aaeSNaresh Kumar Inna { 530a3667aaeSNaresh Kumar Inna int ret = -EINVAL; 531a3667aaeSNaresh Kumar Inna uint32_t buf[64]; 532a3667aaeSNaresh Kumar Inna uint32_t i, c, left, val, offset = addr & 0xff; 533a3667aaeSNaresh Kumar Inna 534a3667aaeSNaresh Kumar Inna if (addr >= hw->params.sf_size || offset + n > SF_PAGE_SIZE) 535a3667aaeSNaresh Kumar Inna return -EINVAL; 536a3667aaeSNaresh Kumar Inna 537a3667aaeSNaresh Kumar Inna val = swab32(addr) | SF_PROG_PAGE; 538a3667aaeSNaresh Kumar Inna 539a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_write(hw, 1, 0, 1, SF_WR_ENABLE); 540a3667aaeSNaresh Kumar Inna if (ret != 0) 541a3667aaeSNaresh Kumar Inna goto unlock; 542a3667aaeSNaresh Kumar Inna 543a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_write(hw, 4, 1, 1, val); 544a3667aaeSNaresh Kumar Inna if (ret != 0) 545a3667aaeSNaresh Kumar Inna goto unlock; 546a3667aaeSNaresh Kumar Inna 547a3667aaeSNaresh Kumar Inna for (left = n; left; left -= c) { 548a3667aaeSNaresh Kumar Inna c = min(left, 4U); 549a3667aaeSNaresh Kumar Inna for (val = 0, i = 0; i < c; ++i) 550a3667aaeSNaresh Kumar Inna val = (val << 8) + *data++; 551a3667aaeSNaresh Kumar Inna 552a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_write(hw, c, c != left, 1, val); 553a3667aaeSNaresh Kumar Inna if (ret) 554a3667aaeSNaresh Kumar Inna goto unlock; 555a3667aaeSNaresh Kumar Inna } 556a3667aaeSNaresh Kumar Inna ret = csio_hw_flash_wait_op(hw, 8, 1); 557a3667aaeSNaresh Kumar Inna if (ret) 558a3667aaeSNaresh Kumar Inna goto unlock; 559a3667aaeSNaresh Kumar Inna 5600d804338SHariprasad Shenai csio_wr_reg32(hw, 0, SF_OP_A); /* unlock SF */ 561a3667aaeSNaresh Kumar Inna 562a3667aaeSNaresh Kumar Inna /* Read the page to verify the write succeeded */ 563a3667aaeSNaresh Kumar Inna ret = csio_hw_read_flash(hw, addr & ~0xff, ARRAY_SIZE(buf), buf, 1); 564a3667aaeSNaresh Kumar Inna if (ret) 565a3667aaeSNaresh Kumar Inna return ret; 566a3667aaeSNaresh Kumar Inna 567a3667aaeSNaresh Kumar Inna if (memcmp(data - n, (uint8_t *)buf + offset, n)) { 568a3667aaeSNaresh Kumar Inna csio_err(hw, 569a3667aaeSNaresh Kumar Inna "failed to correctly write the flash page at %#x\n", 570a3667aaeSNaresh Kumar Inna addr); 571a3667aaeSNaresh Kumar Inna return -EINVAL; 572a3667aaeSNaresh Kumar Inna } 573a3667aaeSNaresh Kumar Inna 574a3667aaeSNaresh Kumar Inna return 0; 575a3667aaeSNaresh Kumar Inna 576a3667aaeSNaresh Kumar Inna unlock: 5770d804338SHariprasad Shenai csio_wr_reg32(hw, 0, SF_OP_A); /* unlock SF */ 578a3667aaeSNaresh Kumar Inna return ret; 579a3667aaeSNaresh Kumar Inna } 580a3667aaeSNaresh Kumar Inna 581a3667aaeSNaresh Kumar Inna /* 582a3667aaeSNaresh Kumar Inna * csio_hw_flash_erase_sectors - erase a range of flash sectors 583a3667aaeSNaresh Kumar Inna * @hw: the HW module 584a3667aaeSNaresh Kumar Inna * @start: the first sector to erase 585a3667aaeSNaresh Kumar Inna * @end: the last sector to erase 586a3667aaeSNaresh Kumar Inna * 587a3667aaeSNaresh Kumar Inna * Erases the sectors in the given inclusive range. 588a3667aaeSNaresh Kumar Inna */ 589a3667aaeSNaresh Kumar Inna static int 590a3667aaeSNaresh Kumar Inna csio_hw_flash_erase_sectors(struct csio_hw *hw, int32_t start, int32_t end) 591a3667aaeSNaresh Kumar Inna { 592a3667aaeSNaresh Kumar Inna int ret = 0; 593a3667aaeSNaresh Kumar Inna 594a3667aaeSNaresh Kumar Inna while (start <= end) { 595a3667aaeSNaresh Kumar Inna 596a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_write(hw, 1, 0, 1, SF_WR_ENABLE); 597a3667aaeSNaresh Kumar Inna if (ret != 0) 598a3667aaeSNaresh Kumar Inna goto out; 599a3667aaeSNaresh Kumar Inna 600a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_write(hw, 4, 0, 1, 601a3667aaeSNaresh Kumar Inna SF_ERASE_SECTOR | (start << 8)); 602a3667aaeSNaresh Kumar Inna if (ret != 0) 603a3667aaeSNaresh Kumar Inna goto out; 604a3667aaeSNaresh Kumar Inna 605a3667aaeSNaresh Kumar Inna ret = csio_hw_flash_wait_op(hw, 14, 500); 606a3667aaeSNaresh Kumar Inna if (ret != 0) 607a3667aaeSNaresh Kumar Inna goto out; 608a3667aaeSNaresh Kumar Inna 609a3667aaeSNaresh Kumar Inna start++; 610a3667aaeSNaresh Kumar Inna } 611a3667aaeSNaresh Kumar Inna out: 612a3667aaeSNaresh Kumar Inna if (ret) 613a3667aaeSNaresh Kumar Inna csio_err(hw, "erase of flash sector %d failed, error %d\n", 614a3667aaeSNaresh Kumar Inna start, ret); 6150d804338SHariprasad Shenai csio_wr_reg32(hw, 0, SF_OP_A); /* unlock SF */ 616a3667aaeSNaresh Kumar Inna return 0; 617a3667aaeSNaresh Kumar Inna } 618a3667aaeSNaresh Kumar Inna 619a3667aaeSNaresh Kumar Inna static void 620a3667aaeSNaresh Kumar Inna csio_hw_print_fw_version(struct csio_hw *hw, char *str) 621a3667aaeSNaresh Kumar Inna { 622a3667aaeSNaresh Kumar Inna csio_info(hw, "%s: %u.%u.%u.%u\n", str, 623b2e1a3f0SHariprasad Shenai FW_HDR_FW_VER_MAJOR_G(hw->fwrev), 624b2e1a3f0SHariprasad Shenai FW_HDR_FW_VER_MINOR_G(hw->fwrev), 625b2e1a3f0SHariprasad Shenai FW_HDR_FW_VER_MICRO_G(hw->fwrev), 626b2e1a3f0SHariprasad Shenai FW_HDR_FW_VER_BUILD_G(hw->fwrev)); 627a3667aaeSNaresh Kumar Inna } 628a3667aaeSNaresh Kumar Inna 629a3667aaeSNaresh Kumar Inna /* 630a3667aaeSNaresh Kumar Inna * csio_hw_get_fw_version - read the firmware version 631a3667aaeSNaresh Kumar Inna * @hw: HW module 632a3667aaeSNaresh Kumar Inna * @vers: where to place the version 633a3667aaeSNaresh Kumar Inna * 634a3667aaeSNaresh Kumar Inna * Reads the FW version from flash. 635a3667aaeSNaresh Kumar Inna */ 636a3667aaeSNaresh Kumar Inna static int 637a3667aaeSNaresh Kumar Inna csio_hw_get_fw_version(struct csio_hw *hw, uint32_t *vers) 638a3667aaeSNaresh Kumar Inna { 639216ce69cSPraveen Madhavan return csio_hw_read_flash(hw, FLASH_FW_START + 640a3667aaeSNaresh Kumar Inna offsetof(struct fw_hdr, fw_ver), 1, 641a3667aaeSNaresh Kumar Inna vers, 0); 642a3667aaeSNaresh Kumar Inna } 643a3667aaeSNaresh Kumar Inna 644a3667aaeSNaresh Kumar Inna /* 645a3667aaeSNaresh Kumar Inna * csio_hw_get_tp_version - read the TP microcode version 646a3667aaeSNaresh Kumar Inna * @hw: HW module 647a3667aaeSNaresh Kumar Inna * @vers: where to place the version 648a3667aaeSNaresh Kumar Inna * 649a3667aaeSNaresh Kumar Inna * Reads the TP microcode version from flash. 650a3667aaeSNaresh Kumar Inna */ 651a3667aaeSNaresh Kumar Inna static int 652a3667aaeSNaresh Kumar Inna csio_hw_get_tp_version(struct csio_hw *hw, u32 *vers) 653a3667aaeSNaresh Kumar Inna { 654a3667aaeSNaresh Kumar Inna return csio_hw_read_flash(hw, FLASH_FW_START + 655a3667aaeSNaresh Kumar Inna offsetof(struct fw_hdr, tp_microcode_ver), 1, 656a3667aaeSNaresh Kumar Inna vers, 0); 657a3667aaeSNaresh Kumar Inna } 658a3667aaeSNaresh Kumar Inna 659a3667aaeSNaresh Kumar Inna /* 660a3667aaeSNaresh Kumar Inna * csio_hw_fw_dload - download firmware. 661a3667aaeSNaresh Kumar Inna * @hw: HW module 662a3667aaeSNaresh Kumar Inna * @fw_data: firmware image to write. 663a3667aaeSNaresh Kumar Inna * @size: image size 664a3667aaeSNaresh Kumar Inna * 665a3667aaeSNaresh Kumar Inna * Write the supplied firmware image to the card's serial flash. 666a3667aaeSNaresh Kumar Inna */ 667a3667aaeSNaresh Kumar Inna static int 668a3667aaeSNaresh Kumar Inna csio_hw_fw_dload(struct csio_hw *hw, uint8_t *fw_data, uint32_t size) 669a3667aaeSNaresh Kumar Inna { 670a3667aaeSNaresh Kumar Inna uint32_t csum; 671a3667aaeSNaresh Kumar Inna int32_t addr; 672a3667aaeSNaresh Kumar Inna int ret; 673a3667aaeSNaresh Kumar Inna uint32_t i; 674a3667aaeSNaresh Kumar Inna uint8_t first_page[SF_PAGE_SIZE]; 6755036f0a0SNaresh Kumar Inna const __be32 *p = (const __be32 *)fw_data; 676a3667aaeSNaresh Kumar Inna struct fw_hdr *hdr = (struct fw_hdr *)fw_data; 677a3667aaeSNaresh Kumar Inna uint32_t sf_sec_size; 678a3667aaeSNaresh Kumar Inna 679a3667aaeSNaresh Kumar Inna if ((!hw->params.sf_size) || (!hw->params.sf_nsec)) { 680a3667aaeSNaresh Kumar Inna csio_err(hw, "Serial Flash data invalid\n"); 681a3667aaeSNaresh Kumar Inna return -EINVAL; 682a3667aaeSNaresh Kumar Inna } 683a3667aaeSNaresh Kumar Inna 684a3667aaeSNaresh Kumar Inna if (!size) { 685a3667aaeSNaresh Kumar Inna csio_err(hw, "FW image has no data\n"); 686a3667aaeSNaresh Kumar Inna return -EINVAL; 687a3667aaeSNaresh Kumar Inna } 688a3667aaeSNaresh Kumar Inna 689a3667aaeSNaresh Kumar Inna if (size & 511) { 690a3667aaeSNaresh Kumar Inna csio_err(hw, "FW image size not multiple of 512 bytes\n"); 691a3667aaeSNaresh Kumar Inna return -EINVAL; 692a3667aaeSNaresh Kumar Inna } 693a3667aaeSNaresh Kumar Inna 694a3667aaeSNaresh Kumar Inna if (ntohs(hdr->len512) * 512 != size) { 695a3667aaeSNaresh Kumar Inna csio_err(hw, "FW image size differs from size in FW header\n"); 696a3667aaeSNaresh Kumar Inna return -EINVAL; 697a3667aaeSNaresh Kumar Inna } 698a3667aaeSNaresh Kumar Inna 699216ce69cSPraveen Madhavan if (size > FLASH_FW_MAX_SIZE) { 700a3667aaeSNaresh Kumar Inna csio_err(hw, "FW image too large, max is %u bytes\n", 701216ce69cSPraveen Madhavan FLASH_FW_MAX_SIZE); 702a3667aaeSNaresh Kumar Inna return -EINVAL; 703a3667aaeSNaresh Kumar Inna } 704a3667aaeSNaresh Kumar Inna 705a3667aaeSNaresh Kumar Inna for (csum = 0, i = 0; i < size / sizeof(csum); i++) 706a3667aaeSNaresh Kumar Inna csum += ntohl(p[i]); 707a3667aaeSNaresh Kumar Inna 708a3667aaeSNaresh Kumar Inna if (csum != 0xffffffff) { 709a3667aaeSNaresh Kumar Inna csio_err(hw, "corrupted firmware image, checksum %#x\n", csum); 710a3667aaeSNaresh Kumar Inna return -EINVAL; 711a3667aaeSNaresh Kumar Inna } 712a3667aaeSNaresh Kumar Inna 713a3667aaeSNaresh Kumar Inna sf_sec_size = hw->params.sf_size / hw->params.sf_nsec; 714a3667aaeSNaresh Kumar Inna i = DIV_ROUND_UP(size, sf_sec_size); /* # of sectors spanned */ 715a3667aaeSNaresh Kumar Inna 716a3667aaeSNaresh Kumar Inna csio_dbg(hw, "Erasing sectors... start:%d end:%d\n", 717216ce69cSPraveen Madhavan FLASH_FW_START_SEC, FLASH_FW_START_SEC + i - 1); 718a3667aaeSNaresh Kumar Inna 719216ce69cSPraveen Madhavan ret = csio_hw_flash_erase_sectors(hw, FLASH_FW_START_SEC, 720216ce69cSPraveen Madhavan FLASH_FW_START_SEC + i - 1); 721a3667aaeSNaresh Kumar Inna if (ret) { 722a3667aaeSNaresh Kumar Inna csio_err(hw, "Flash Erase failed\n"); 723a3667aaeSNaresh Kumar Inna goto out; 724a3667aaeSNaresh Kumar Inna } 725a3667aaeSNaresh Kumar Inna 726a3667aaeSNaresh Kumar Inna /* 727a3667aaeSNaresh Kumar Inna * We write the correct version at the end so the driver can see a bad 728a3667aaeSNaresh Kumar Inna * version if the FW write fails. Start by writing a copy of the 729a3667aaeSNaresh Kumar Inna * first page with a bad version. 730a3667aaeSNaresh Kumar Inna */ 731a3667aaeSNaresh Kumar Inna memcpy(first_page, fw_data, SF_PAGE_SIZE); 732a3667aaeSNaresh Kumar Inna ((struct fw_hdr *)first_page)->fw_ver = htonl(0xffffffff); 733216ce69cSPraveen Madhavan ret = csio_hw_write_flash(hw, FLASH_FW_START, SF_PAGE_SIZE, first_page); 734a3667aaeSNaresh Kumar Inna if (ret) 735a3667aaeSNaresh Kumar Inna goto out; 736a3667aaeSNaresh Kumar Inna 737a3667aaeSNaresh Kumar Inna csio_dbg(hw, "Writing Flash .. start:%d end:%d\n", 738a3667aaeSNaresh Kumar Inna FW_IMG_START, FW_IMG_START + size); 739a3667aaeSNaresh Kumar Inna 740216ce69cSPraveen Madhavan addr = FLASH_FW_START; 741a3667aaeSNaresh Kumar Inna for (size -= SF_PAGE_SIZE; size; size -= SF_PAGE_SIZE) { 742a3667aaeSNaresh Kumar Inna addr += SF_PAGE_SIZE; 743a3667aaeSNaresh Kumar Inna fw_data += SF_PAGE_SIZE; 744a3667aaeSNaresh Kumar Inna ret = csio_hw_write_flash(hw, addr, SF_PAGE_SIZE, fw_data); 745a3667aaeSNaresh Kumar Inna if (ret) 746a3667aaeSNaresh Kumar Inna goto out; 747a3667aaeSNaresh Kumar Inna } 748a3667aaeSNaresh Kumar Inna 749a3667aaeSNaresh Kumar Inna ret = csio_hw_write_flash(hw, 750216ce69cSPraveen Madhavan FLASH_FW_START + 751a3667aaeSNaresh Kumar Inna offsetof(struct fw_hdr, fw_ver), 752a3667aaeSNaresh Kumar Inna sizeof(hdr->fw_ver), 753a3667aaeSNaresh Kumar Inna (const uint8_t *)&hdr->fw_ver); 754a3667aaeSNaresh Kumar Inna 755a3667aaeSNaresh Kumar Inna out: 756a3667aaeSNaresh Kumar Inna if (ret) 757a3667aaeSNaresh Kumar Inna csio_err(hw, "firmware download failed, error %d\n", ret); 758a3667aaeSNaresh Kumar Inna return ret; 759a3667aaeSNaresh Kumar Inna } 760a3667aaeSNaresh Kumar Inna 761a3667aaeSNaresh Kumar Inna static int 762a3667aaeSNaresh Kumar Inna csio_hw_get_flash_params(struct csio_hw *hw) 763a3667aaeSNaresh Kumar Inna { 764a3667aaeSNaresh Kumar Inna int ret; 765a3667aaeSNaresh Kumar Inna uint32_t info = 0; 766a3667aaeSNaresh Kumar Inna 767a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_write(hw, 1, 1, 0, SF_RD_ID); 768a3667aaeSNaresh Kumar Inna if (!ret) 769a3667aaeSNaresh Kumar Inna ret = csio_hw_sf1_read(hw, 3, 0, 1, &info); 7700d804338SHariprasad Shenai csio_wr_reg32(hw, 0, SF_OP_A); /* unlock SF */ 771a3667aaeSNaresh Kumar Inna if (ret != 0) 772a3667aaeSNaresh Kumar Inna return ret; 773a3667aaeSNaresh Kumar Inna 774a3667aaeSNaresh Kumar Inna if ((info & 0xff) != 0x20) /* not a Numonix flash */ 775a3667aaeSNaresh Kumar Inna return -EINVAL; 776a3667aaeSNaresh Kumar Inna info >>= 16; /* log2 of size */ 777a3667aaeSNaresh Kumar Inna if (info >= 0x14 && info < 0x18) 778a3667aaeSNaresh Kumar Inna hw->params.sf_nsec = 1 << (info - 16); 779a3667aaeSNaresh Kumar Inna else if (info == 0x18) 780a3667aaeSNaresh Kumar Inna hw->params.sf_nsec = 64; 781a3667aaeSNaresh Kumar Inna else 782a3667aaeSNaresh Kumar Inna return -EINVAL; 783a3667aaeSNaresh Kumar Inna hw->params.sf_size = 1 << info; 784a3667aaeSNaresh Kumar Inna 785a3667aaeSNaresh Kumar Inna return 0; 786a3667aaeSNaresh Kumar Inna } 787a3667aaeSNaresh Kumar Inna 788a3667aaeSNaresh Kumar Inna /*****************************************************************************/ 789a3667aaeSNaresh Kumar Inna /* HW State machine assists */ 790a3667aaeSNaresh Kumar Inna /*****************************************************************************/ 791a3667aaeSNaresh Kumar Inna 792a3667aaeSNaresh Kumar Inna static int 793a3667aaeSNaresh Kumar Inna csio_hw_dev_ready(struct csio_hw *hw) 794a3667aaeSNaresh Kumar Inna { 795a3667aaeSNaresh Kumar Inna uint32_t reg; 796a3667aaeSNaresh Kumar Inna int cnt = 6; 7974bbd458eSVarun Prakash int src_pf; 798a3667aaeSNaresh Kumar Inna 7990d804338SHariprasad Shenai while (((reg = csio_rd_reg32(hw, PL_WHOAMI_A)) == 0xFFFFFFFF) && 800a3667aaeSNaresh Kumar Inna (--cnt != 0)) 801a3667aaeSNaresh Kumar Inna mdelay(100); 802a3667aaeSNaresh Kumar Inna 8034bbd458eSVarun Prakash if (csio_is_t5(hw->pdev->device & CSIO_HW_CHIP_MASK)) 8044bbd458eSVarun Prakash src_pf = SOURCEPF_G(reg); 8054bbd458eSVarun Prakash else 8064bbd458eSVarun Prakash src_pf = T6_SOURCEPF_G(reg); 8074bbd458eSVarun Prakash 8084bbd458eSVarun Prakash if ((cnt == 0) && (((int32_t)(src_pf) < 0) || 8094bbd458eSVarun Prakash (src_pf >= CSIO_MAX_PFN))) { 810a3667aaeSNaresh Kumar Inna csio_err(hw, "PL_WHOAMI returned 0x%x, cnt:%d\n", reg, cnt); 811a3667aaeSNaresh Kumar Inna return -EIO; 812a3667aaeSNaresh Kumar Inna } 813a3667aaeSNaresh Kumar Inna 8144bbd458eSVarun Prakash hw->pfn = src_pf; 815a3667aaeSNaresh Kumar Inna 816a3667aaeSNaresh Kumar Inna return 0; 817a3667aaeSNaresh Kumar Inna } 818a3667aaeSNaresh Kumar Inna 819a3667aaeSNaresh Kumar Inna /* 820a3667aaeSNaresh Kumar Inna * csio_do_hello - Perform the HELLO FW Mailbox command and process response. 821a3667aaeSNaresh Kumar Inna * @hw: HW module 822a3667aaeSNaresh Kumar Inna * @state: Device state 823a3667aaeSNaresh Kumar Inna * 824a3667aaeSNaresh Kumar Inna * FW_HELLO_CMD has to be polled for completion. 825a3667aaeSNaresh Kumar Inna */ 826a3667aaeSNaresh Kumar Inna static int 827a3667aaeSNaresh Kumar Inna csio_do_hello(struct csio_hw *hw, enum csio_dev_state *state) 828a3667aaeSNaresh Kumar Inna { 829a3667aaeSNaresh Kumar Inna struct csio_mb *mbp; 830a3667aaeSNaresh Kumar Inna int rv = 0; 831a3667aaeSNaresh Kumar Inna enum fw_retval retval; 832a3667aaeSNaresh Kumar Inna uint8_t mpfn; 833a3667aaeSNaresh Kumar Inna char state_str[16]; 834a3667aaeSNaresh Kumar Inna int retries = FW_CMD_HELLO_RETRIES; 835a3667aaeSNaresh Kumar Inna 836a3667aaeSNaresh Kumar Inna memset(state_str, 0, sizeof(state_str)); 837a3667aaeSNaresh Kumar Inna 838a3667aaeSNaresh Kumar Inna mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 839a3667aaeSNaresh Kumar Inna if (!mbp) { 840a3667aaeSNaresh Kumar Inna rv = -ENOMEM; 841a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_nomem); 842a3667aaeSNaresh Kumar Inna goto out; 843a3667aaeSNaresh Kumar Inna } 844a3667aaeSNaresh Kumar Inna 845a3667aaeSNaresh Kumar Inna retry: 846a3667aaeSNaresh Kumar Inna csio_mb_hello(hw, mbp, CSIO_MB_DEFAULT_TMO, hw->pfn, 847666224d4SHariprasad Shenai hw->pfn, CSIO_MASTER_MAY, NULL); 848a3667aaeSNaresh Kumar Inna 849a3667aaeSNaresh Kumar Inna rv = csio_mb_issue(hw, mbp); 850a3667aaeSNaresh Kumar Inna if (rv) { 851a3667aaeSNaresh Kumar Inna csio_err(hw, "failed to issue HELLO cmd. ret:%d.\n", rv); 852a3667aaeSNaresh Kumar Inna goto out_free_mb; 853a3667aaeSNaresh Kumar Inna } 854a3667aaeSNaresh Kumar Inna 855a3667aaeSNaresh Kumar Inna csio_mb_process_hello_rsp(hw, mbp, &retval, state, &mpfn); 856a3667aaeSNaresh Kumar Inna if (retval != FW_SUCCESS) { 857a3667aaeSNaresh Kumar Inna csio_err(hw, "HELLO cmd failed with ret: %d\n", retval); 858a3667aaeSNaresh Kumar Inna rv = -EINVAL; 859a3667aaeSNaresh Kumar Inna goto out_free_mb; 860a3667aaeSNaresh Kumar Inna } 861a3667aaeSNaresh Kumar Inna 862a3667aaeSNaresh Kumar Inna /* Firmware has designated us to be master */ 863a3667aaeSNaresh Kumar Inna if (hw->pfn == mpfn) { 864a3667aaeSNaresh Kumar Inna hw->flags |= CSIO_HWF_MASTER; 865a3667aaeSNaresh Kumar Inna } else if (*state == CSIO_DEV_STATE_UNINIT) { 866a3667aaeSNaresh Kumar Inna /* 867a3667aaeSNaresh Kumar Inna * If we're not the Master PF then we need to wait around for 868a3667aaeSNaresh Kumar Inna * the Master PF Driver to finish setting up the adapter. 869a3667aaeSNaresh Kumar Inna * 870a3667aaeSNaresh Kumar Inna * Note that we also do this wait if we're a non-Master-capable 871a3667aaeSNaresh Kumar Inna * PF and there is no current Master PF; a Master PF may show up 872a3667aaeSNaresh Kumar Inna * momentarily and we wouldn't want to fail pointlessly. (This 873a3667aaeSNaresh Kumar Inna * can happen when an OS loads lots of different drivers rapidly 874a3667aaeSNaresh Kumar Inna * at the same time). In this case, the Master PF returned by 875a3667aaeSNaresh Kumar Inna * the firmware will be PCIE_FW_MASTER_MASK so the test below 876a3667aaeSNaresh Kumar Inna * will work ... 877a3667aaeSNaresh Kumar Inna */ 878a3667aaeSNaresh Kumar Inna 879a3667aaeSNaresh Kumar Inna int waiting = FW_CMD_HELLO_TIMEOUT; 880a3667aaeSNaresh Kumar Inna 881a3667aaeSNaresh Kumar Inna /* 882a3667aaeSNaresh Kumar Inna * Wait for the firmware to either indicate an error or 883a3667aaeSNaresh Kumar Inna * initialized state. If we see either of these we bail out 884a3667aaeSNaresh Kumar Inna * and report the issue to the caller. If we exhaust the 885a3667aaeSNaresh Kumar Inna * "hello timeout" and we haven't exhausted our retries, try 886a3667aaeSNaresh Kumar Inna * again. Otherwise bail with a timeout error. 887a3667aaeSNaresh Kumar Inna */ 888a3667aaeSNaresh Kumar Inna for (;;) { 889a3667aaeSNaresh Kumar Inna uint32_t pcie_fw; 890a3667aaeSNaresh Kumar Inna 8917cc16380SArvind Bhushan spin_unlock_irq(&hw->lock); 892a3667aaeSNaresh Kumar Inna msleep(50); 8937cc16380SArvind Bhushan spin_lock_irq(&hw->lock); 894a3667aaeSNaresh Kumar Inna waiting -= 50; 895a3667aaeSNaresh Kumar Inna 896a3667aaeSNaresh Kumar Inna /* 897a3667aaeSNaresh Kumar Inna * If neither Error nor Initialialized are indicated 898a3667aaeSNaresh Kumar Inna * by the firmware keep waiting till we exaust our 899a3667aaeSNaresh Kumar Inna * timeout ... and then retry if we haven't exhausted 900a3667aaeSNaresh Kumar Inna * our retries ... 901a3667aaeSNaresh Kumar Inna */ 902f061de42SHariprasad Shenai pcie_fw = csio_rd_reg32(hw, PCIE_FW_A); 903f061de42SHariprasad Shenai if (!(pcie_fw & (PCIE_FW_ERR_F|PCIE_FW_INIT_F))) { 904a3667aaeSNaresh Kumar Inna if (waiting <= 0) { 905a3667aaeSNaresh Kumar Inna if (retries-- > 0) 906a3667aaeSNaresh Kumar Inna goto retry; 907a3667aaeSNaresh Kumar Inna 908a3667aaeSNaresh Kumar Inna rv = -ETIMEDOUT; 909a3667aaeSNaresh Kumar Inna break; 910a3667aaeSNaresh Kumar Inna } 911a3667aaeSNaresh Kumar Inna continue; 912a3667aaeSNaresh Kumar Inna } 913a3667aaeSNaresh Kumar Inna 914a3667aaeSNaresh Kumar Inna /* 915a3667aaeSNaresh Kumar Inna * We either have an Error or Initialized condition 916a3667aaeSNaresh Kumar Inna * report errors preferentially. 917a3667aaeSNaresh Kumar Inna */ 918a3667aaeSNaresh Kumar Inna if (state) { 919f061de42SHariprasad Shenai if (pcie_fw & PCIE_FW_ERR_F) { 920a3667aaeSNaresh Kumar Inna *state = CSIO_DEV_STATE_ERR; 921a3667aaeSNaresh Kumar Inna rv = -ETIMEDOUT; 922f061de42SHariprasad Shenai } else if (pcie_fw & PCIE_FW_INIT_F) 923a3667aaeSNaresh Kumar Inna *state = CSIO_DEV_STATE_INIT; 924a3667aaeSNaresh Kumar Inna } 925a3667aaeSNaresh Kumar Inna 926a3667aaeSNaresh Kumar Inna /* 927a3667aaeSNaresh Kumar Inna * If we arrived before a Master PF was selected and 928a3667aaeSNaresh Kumar Inna * there's not a valid Master PF, grab its identity 929a3667aaeSNaresh Kumar Inna * for our caller. 930a3667aaeSNaresh Kumar Inna */ 931f061de42SHariprasad Shenai if (mpfn == PCIE_FW_MASTER_M && 932f061de42SHariprasad Shenai (pcie_fw & PCIE_FW_MASTER_VLD_F)) 933f061de42SHariprasad Shenai mpfn = PCIE_FW_MASTER_G(pcie_fw); 934a3667aaeSNaresh Kumar Inna break; 935a3667aaeSNaresh Kumar Inna } 936a3667aaeSNaresh Kumar Inna hw->flags &= ~CSIO_HWF_MASTER; 937a3667aaeSNaresh Kumar Inna } 938a3667aaeSNaresh Kumar Inna 939a3667aaeSNaresh Kumar Inna switch (*state) { 940a3667aaeSNaresh Kumar Inna case CSIO_DEV_STATE_UNINIT: 941a3667aaeSNaresh Kumar Inna strcpy(state_str, "Initializing"); 942a3667aaeSNaresh Kumar Inna break; 943a3667aaeSNaresh Kumar Inna case CSIO_DEV_STATE_INIT: 944a3667aaeSNaresh Kumar Inna strcpy(state_str, "Initialized"); 945a3667aaeSNaresh Kumar Inna break; 946a3667aaeSNaresh Kumar Inna case CSIO_DEV_STATE_ERR: 947a3667aaeSNaresh Kumar Inna strcpy(state_str, "Error"); 948a3667aaeSNaresh Kumar Inna break; 949a3667aaeSNaresh Kumar Inna default: 950a3667aaeSNaresh Kumar Inna strcpy(state_str, "Unknown"); 951a3667aaeSNaresh Kumar Inna break; 952a3667aaeSNaresh Kumar Inna } 953a3667aaeSNaresh Kumar Inna 954a3667aaeSNaresh Kumar Inna if (hw->pfn == mpfn) 955a3667aaeSNaresh Kumar Inna csio_info(hw, "PF: %d, Coming up as MASTER, HW state: %s\n", 956a3667aaeSNaresh Kumar Inna hw->pfn, state_str); 957a3667aaeSNaresh Kumar Inna else 958a3667aaeSNaresh Kumar Inna csio_info(hw, 959a3667aaeSNaresh Kumar Inna "PF: %d, Coming up as SLAVE, Master PF: %d, HW state: %s\n", 960a3667aaeSNaresh Kumar Inna hw->pfn, mpfn, state_str); 961a3667aaeSNaresh Kumar Inna 962a3667aaeSNaresh Kumar Inna out_free_mb: 963a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 964a3667aaeSNaresh Kumar Inna out: 965a3667aaeSNaresh Kumar Inna return rv; 966a3667aaeSNaresh Kumar Inna } 967a3667aaeSNaresh Kumar Inna 968a3667aaeSNaresh Kumar Inna /* 969a3667aaeSNaresh Kumar Inna * csio_do_bye - Perform the BYE FW Mailbox command and process response. 970a3667aaeSNaresh Kumar Inna * @hw: HW module 971a3667aaeSNaresh Kumar Inna * 972a3667aaeSNaresh Kumar Inna */ 973a3667aaeSNaresh Kumar Inna static int 974a3667aaeSNaresh Kumar Inna csio_do_bye(struct csio_hw *hw) 975a3667aaeSNaresh Kumar Inna { 976a3667aaeSNaresh Kumar Inna struct csio_mb *mbp; 977a3667aaeSNaresh Kumar Inna enum fw_retval retval; 978a3667aaeSNaresh Kumar Inna 979a3667aaeSNaresh Kumar Inna mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 980a3667aaeSNaresh Kumar Inna if (!mbp) { 981a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_nomem); 982a3667aaeSNaresh Kumar Inna return -ENOMEM; 983a3667aaeSNaresh Kumar Inna } 984a3667aaeSNaresh Kumar Inna 985a3667aaeSNaresh Kumar Inna csio_mb_bye(hw, mbp, CSIO_MB_DEFAULT_TMO, NULL); 986a3667aaeSNaresh Kumar Inna 987a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 988a3667aaeSNaresh Kumar Inna csio_err(hw, "Issue of BYE command failed\n"); 989a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 990a3667aaeSNaresh Kumar Inna return -EINVAL; 991a3667aaeSNaresh Kumar Inna } 992a3667aaeSNaresh Kumar Inna 993a3667aaeSNaresh Kumar Inna retval = csio_mb_fw_retval(mbp); 994a3667aaeSNaresh Kumar Inna if (retval != FW_SUCCESS) { 995a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 996a3667aaeSNaresh Kumar Inna return -EINVAL; 997a3667aaeSNaresh Kumar Inna } 998a3667aaeSNaresh Kumar Inna 999a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1000a3667aaeSNaresh Kumar Inna 1001a3667aaeSNaresh Kumar Inna return 0; 1002a3667aaeSNaresh Kumar Inna } 1003a3667aaeSNaresh Kumar Inna 1004a3667aaeSNaresh Kumar Inna /* 1005a3667aaeSNaresh Kumar Inna * csio_do_reset- Perform the device reset. 1006a3667aaeSNaresh Kumar Inna * @hw: HW module 1007a3667aaeSNaresh Kumar Inna * @fw_rst: FW reset 1008a3667aaeSNaresh Kumar Inna * 1009a3667aaeSNaresh Kumar Inna * If fw_rst is set, issues FW reset mbox cmd otherwise 1010a3667aaeSNaresh Kumar Inna * does PIO reset. 1011a3667aaeSNaresh Kumar Inna * Performs reset of the function. 1012a3667aaeSNaresh Kumar Inna */ 1013a3667aaeSNaresh Kumar Inna static int 1014a3667aaeSNaresh Kumar Inna csio_do_reset(struct csio_hw *hw, bool fw_rst) 1015a3667aaeSNaresh Kumar Inna { 1016a3667aaeSNaresh Kumar Inna struct csio_mb *mbp; 1017a3667aaeSNaresh Kumar Inna enum fw_retval retval; 1018a3667aaeSNaresh Kumar Inna 1019a3667aaeSNaresh Kumar Inna if (!fw_rst) { 1020a3667aaeSNaresh Kumar Inna /* PIO reset */ 10210d804338SHariprasad Shenai csio_wr_reg32(hw, PIORSTMODE_F | PIORST_F, PL_RST_A); 1022a3667aaeSNaresh Kumar Inna mdelay(2000); 1023a3667aaeSNaresh Kumar Inna return 0; 1024a3667aaeSNaresh Kumar Inna } 1025a3667aaeSNaresh Kumar Inna 1026a3667aaeSNaresh Kumar Inna mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 1027a3667aaeSNaresh Kumar Inna if (!mbp) { 1028a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_nomem); 1029a3667aaeSNaresh Kumar Inna return -ENOMEM; 1030a3667aaeSNaresh Kumar Inna } 1031a3667aaeSNaresh Kumar Inna 1032a3667aaeSNaresh Kumar Inna csio_mb_reset(hw, mbp, CSIO_MB_DEFAULT_TMO, 10330d804338SHariprasad Shenai PIORSTMODE_F | PIORST_F, 0, NULL); 1034a3667aaeSNaresh Kumar Inna 1035a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 1036a3667aaeSNaresh Kumar Inna csio_err(hw, "Issue of RESET command failed.n"); 1037a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1038a3667aaeSNaresh Kumar Inna return -EINVAL; 1039a3667aaeSNaresh Kumar Inna } 1040a3667aaeSNaresh Kumar Inna 1041a3667aaeSNaresh Kumar Inna retval = csio_mb_fw_retval(mbp); 1042a3667aaeSNaresh Kumar Inna if (retval != FW_SUCCESS) { 1043a3667aaeSNaresh Kumar Inna csio_err(hw, "RESET cmd failed with ret:0x%x.\n", retval); 1044a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1045a3667aaeSNaresh Kumar Inna return -EINVAL; 1046a3667aaeSNaresh Kumar Inna } 1047a3667aaeSNaresh Kumar Inna 1048a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1049a3667aaeSNaresh Kumar Inna 1050a3667aaeSNaresh Kumar Inna return 0; 1051a3667aaeSNaresh Kumar Inna } 1052a3667aaeSNaresh Kumar Inna 1053a3667aaeSNaresh Kumar Inna static int 1054a3667aaeSNaresh Kumar Inna csio_hw_validate_caps(struct csio_hw *hw, struct csio_mb *mbp) 1055a3667aaeSNaresh Kumar Inna { 1056a3667aaeSNaresh Kumar Inna struct fw_caps_config_cmd *rsp = (struct fw_caps_config_cmd *)mbp->mb; 1057a3667aaeSNaresh Kumar Inna uint16_t caps; 1058a3667aaeSNaresh Kumar Inna 1059a3667aaeSNaresh Kumar Inna caps = ntohs(rsp->fcoecaps); 1060a3667aaeSNaresh Kumar Inna 1061a3667aaeSNaresh Kumar Inna if (!(caps & FW_CAPS_CONFIG_FCOE_INITIATOR)) { 1062a3667aaeSNaresh Kumar Inna csio_err(hw, "No FCoE Initiator capability in the firmware.\n"); 1063a3667aaeSNaresh Kumar Inna return -EINVAL; 1064a3667aaeSNaresh Kumar Inna } 1065a3667aaeSNaresh Kumar Inna 1066a3667aaeSNaresh Kumar Inna if (!(caps & FW_CAPS_CONFIG_FCOE_CTRL_OFLD)) { 1067a3667aaeSNaresh Kumar Inna csio_err(hw, "No FCoE Control Offload capability\n"); 1068a3667aaeSNaresh Kumar Inna return -EINVAL; 1069a3667aaeSNaresh Kumar Inna } 1070a3667aaeSNaresh Kumar Inna 1071a3667aaeSNaresh Kumar Inna return 0; 1072a3667aaeSNaresh Kumar Inna } 1073a3667aaeSNaresh Kumar Inna 1074a3667aaeSNaresh Kumar Inna /* 1075a3667aaeSNaresh Kumar Inna * csio_hw_fw_halt - issue a reset/halt to FW and put uP into RESET 1076a3667aaeSNaresh Kumar Inna * @hw: the HW module 1077a3667aaeSNaresh Kumar Inna * @mbox: mailbox to use for the FW RESET command (if desired) 1078a3667aaeSNaresh Kumar Inna * @force: force uP into RESET even if FW RESET command fails 1079a3667aaeSNaresh Kumar Inna * 1080a3667aaeSNaresh Kumar Inna * Issues a RESET command to firmware (if desired) with a HALT indication 1081a3667aaeSNaresh Kumar Inna * and then puts the microprocessor into RESET state. The RESET command 1082a3667aaeSNaresh Kumar Inna * will only be issued if a legitimate mailbox is provided (mbox <= 1083a3667aaeSNaresh Kumar Inna * PCIE_FW_MASTER_MASK). 1084a3667aaeSNaresh Kumar Inna * 1085a3667aaeSNaresh Kumar Inna * This is generally used in order for the host to safely manipulate the 1086a3667aaeSNaresh Kumar Inna * adapter without fear of conflicting with whatever the firmware might 1087a3667aaeSNaresh Kumar Inna * be doing. The only way out of this state is to RESTART the firmware 1088a3667aaeSNaresh Kumar Inna * ... 1089a3667aaeSNaresh Kumar Inna */ 1090a3667aaeSNaresh Kumar Inna static int 1091a3667aaeSNaresh Kumar Inna csio_hw_fw_halt(struct csio_hw *hw, uint32_t mbox, int32_t force) 1092a3667aaeSNaresh Kumar Inna { 1093a3667aaeSNaresh Kumar Inna enum fw_retval retval = 0; 1094a3667aaeSNaresh Kumar Inna 1095a3667aaeSNaresh Kumar Inna /* 1096a3667aaeSNaresh Kumar Inna * If a legitimate mailbox is provided, issue a RESET command 1097a3667aaeSNaresh Kumar Inna * with a HALT indication. 1098a3667aaeSNaresh Kumar Inna */ 1099f061de42SHariprasad Shenai if (mbox <= PCIE_FW_MASTER_M) { 1100a3667aaeSNaresh Kumar Inna struct csio_mb *mbp; 1101a3667aaeSNaresh Kumar Inna 1102a3667aaeSNaresh Kumar Inna mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 1103a3667aaeSNaresh Kumar Inna if (!mbp) { 1104a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_nomem); 1105a3667aaeSNaresh Kumar Inna return -ENOMEM; 1106a3667aaeSNaresh Kumar Inna } 1107a3667aaeSNaresh Kumar Inna 1108a3667aaeSNaresh Kumar Inna csio_mb_reset(hw, mbp, CSIO_MB_DEFAULT_TMO, 11090d804338SHariprasad Shenai PIORSTMODE_F | PIORST_F, FW_RESET_CMD_HALT_F, 1110a3667aaeSNaresh Kumar Inna NULL); 1111a3667aaeSNaresh Kumar Inna 1112a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 1113a3667aaeSNaresh Kumar Inna csio_err(hw, "Issue of RESET command failed!\n"); 1114a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1115a3667aaeSNaresh Kumar Inna return -EINVAL; 1116a3667aaeSNaresh Kumar Inna } 1117a3667aaeSNaresh Kumar Inna 1118a3667aaeSNaresh Kumar Inna retval = csio_mb_fw_retval(mbp); 1119a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1120a3667aaeSNaresh Kumar Inna } 1121a3667aaeSNaresh Kumar Inna 1122a3667aaeSNaresh Kumar Inna /* 1123a3667aaeSNaresh Kumar Inna * Normally we won't complete the operation if the firmware RESET 1124a3667aaeSNaresh Kumar Inna * command fails but if our caller insists we'll go ahead and put the 1125a3667aaeSNaresh Kumar Inna * uP into RESET. This can be useful if the firmware is hung or even 1126a3667aaeSNaresh Kumar Inna * missing ... We'll have to take the risk of putting the uP into 1127a3667aaeSNaresh Kumar Inna * RESET without the cooperation of firmware in that case. 1128a3667aaeSNaresh Kumar Inna * 1129a3667aaeSNaresh Kumar Inna * We also force the firmware's HALT flag to be on in case we bypassed 1130a3667aaeSNaresh Kumar Inna * the firmware RESET command above or we're dealing with old firmware 1131a3667aaeSNaresh Kumar Inna * which doesn't have the HALT capability. This will serve as a flag 1132a3667aaeSNaresh Kumar Inna * for the incoming firmware to know that it's coming out of a HALT 1133a3667aaeSNaresh Kumar Inna * rather than a RESET ... if it's new enough to understand that ... 1134a3667aaeSNaresh Kumar Inna */ 1135a3667aaeSNaresh Kumar Inna if (retval == 0 || force) { 113689c3a86cSHariprasad Shenai csio_set_reg_field(hw, CIM_BOOT_CFG_A, UPCRST_F, UPCRST_F); 1137f061de42SHariprasad Shenai csio_set_reg_field(hw, PCIE_FW_A, PCIE_FW_HALT_F, 1138f061de42SHariprasad Shenai PCIE_FW_HALT_F); 1139a3667aaeSNaresh Kumar Inna } 1140a3667aaeSNaresh Kumar Inna 1141a3667aaeSNaresh Kumar Inna /* 1142a3667aaeSNaresh Kumar Inna * And we always return the result of the firmware RESET command 1143a3667aaeSNaresh Kumar Inna * even when we force the uP into RESET ... 1144a3667aaeSNaresh Kumar Inna */ 1145a3667aaeSNaresh Kumar Inna return retval ? -EINVAL : 0; 1146a3667aaeSNaresh Kumar Inna } 1147a3667aaeSNaresh Kumar Inna 1148a3667aaeSNaresh Kumar Inna /* 1149a3667aaeSNaresh Kumar Inna * csio_hw_fw_restart - restart the firmware by taking the uP out of RESET 1150a3667aaeSNaresh Kumar Inna * @hw: the HW module 1151a3667aaeSNaresh Kumar Inna * @reset: if we want to do a RESET to restart things 1152a3667aaeSNaresh Kumar Inna * 1153a3667aaeSNaresh Kumar Inna * Restart firmware previously halted by csio_hw_fw_halt(). On successful 1154a3667aaeSNaresh Kumar Inna * return the previous PF Master remains as the new PF Master and there 1155a3667aaeSNaresh Kumar Inna * is no need to issue a new HELLO command, etc. 1156a3667aaeSNaresh Kumar Inna * 1157a3667aaeSNaresh Kumar Inna * We do this in two ways: 1158a3667aaeSNaresh Kumar Inna * 1159a3667aaeSNaresh Kumar Inna * 1. If we're dealing with newer firmware we'll simply want to take 1160a3667aaeSNaresh Kumar Inna * the chip's microprocessor out of RESET. This will cause the 1161a3667aaeSNaresh Kumar Inna * firmware to start up from its start vector. And then we'll loop 1162a3667aaeSNaresh Kumar Inna * until the firmware indicates it's started again (PCIE_FW.HALT 1163a3667aaeSNaresh Kumar Inna * reset to 0) or we timeout. 1164a3667aaeSNaresh Kumar Inna * 1165a3667aaeSNaresh Kumar Inna * 2. If we're dealing with older firmware then we'll need to RESET 1166a3667aaeSNaresh Kumar Inna * the chip since older firmware won't recognize the PCIE_FW.HALT 1167a3667aaeSNaresh Kumar Inna * flag and automatically RESET itself on startup. 1168a3667aaeSNaresh Kumar Inna */ 1169a3667aaeSNaresh Kumar Inna static int 1170a3667aaeSNaresh Kumar Inna csio_hw_fw_restart(struct csio_hw *hw, uint32_t mbox, int32_t reset) 1171a3667aaeSNaresh Kumar Inna { 1172a3667aaeSNaresh Kumar Inna if (reset) { 1173a3667aaeSNaresh Kumar Inna /* 1174a3667aaeSNaresh Kumar Inna * Since we're directing the RESET instead of the firmware 1175a3667aaeSNaresh Kumar Inna * doing it automatically, we need to clear the PCIE_FW.HALT 1176a3667aaeSNaresh Kumar Inna * bit. 1177a3667aaeSNaresh Kumar Inna */ 1178f061de42SHariprasad Shenai csio_set_reg_field(hw, PCIE_FW_A, PCIE_FW_HALT_F, 0); 1179a3667aaeSNaresh Kumar Inna 1180a3667aaeSNaresh Kumar Inna /* 1181a3667aaeSNaresh Kumar Inna * If we've been given a valid mailbox, first try to get the 1182a3667aaeSNaresh Kumar Inna * firmware to do the RESET. If that works, great and we can 1183a3667aaeSNaresh Kumar Inna * return success. Otherwise, if we haven't been given a 1184a3667aaeSNaresh Kumar Inna * valid mailbox or the RESET command failed, fall back to 1185a3667aaeSNaresh Kumar Inna * hitting the chip with a hammer. 1186a3667aaeSNaresh Kumar Inna */ 1187f061de42SHariprasad Shenai if (mbox <= PCIE_FW_MASTER_M) { 118889c3a86cSHariprasad Shenai csio_set_reg_field(hw, CIM_BOOT_CFG_A, UPCRST_F, 0); 1189a3667aaeSNaresh Kumar Inna msleep(100); 1190a3667aaeSNaresh Kumar Inna if (csio_do_reset(hw, true) == 0) 1191a3667aaeSNaresh Kumar Inna return 0; 1192a3667aaeSNaresh Kumar Inna } 1193a3667aaeSNaresh Kumar Inna 11940d804338SHariprasad Shenai csio_wr_reg32(hw, PIORSTMODE_F | PIORST_F, PL_RST_A); 1195a3667aaeSNaresh Kumar Inna msleep(2000); 1196a3667aaeSNaresh Kumar Inna } else { 1197a3667aaeSNaresh Kumar Inna int ms; 1198a3667aaeSNaresh Kumar Inna 119989c3a86cSHariprasad Shenai csio_set_reg_field(hw, CIM_BOOT_CFG_A, UPCRST_F, 0); 1200a3667aaeSNaresh Kumar Inna for (ms = 0; ms < FW_CMD_MAX_TIMEOUT; ) { 1201f061de42SHariprasad Shenai if (!(csio_rd_reg32(hw, PCIE_FW_A) & PCIE_FW_HALT_F)) 1202a3667aaeSNaresh Kumar Inna return 0; 1203a3667aaeSNaresh Kumar Inna msleep(100); 1204a3667aaeSNaresh Kumar Inna ms += 100; 1205a3667aaeSNaresh Kumar Inna } 1206a3667aaeSNaresh Kumar Inna return -ETIMEDOUT; 1207a3667aaeSNaresh Kumar Inna } 1208a3667aaeSNaresh Kumar Inna return 0; 1209a3667aaeSNaresh Kumar Inna } 1210a3667aaeSNaresh Kumar Inna 1211a3667aaeSNaresh Kumar Inna /* 1212a3667aaeSNaresh Kumar Inna * csio_hw_fw_upgrade - perform all of the steps necessary to upgrade FW 1213a3667aaeSNaresh Kumar Inna * @hw: the HW module 1214a3667aaeSNaresh Kumar Inna * @mbox: mailbox to use for the FW RESET command (if desired) 1215a3667aaeSNaresh Kumar Inna * @fw_data: the firmware image to write 1216a3667aaeSNaresh Kumar Inna * @size: image size 1217a3667aaeSNaresh Kumar Inna * @force: force upgrade even if firmware doesn't cooperate 1218a3667aaeSNaresh Kumar Inna * 1219a3667aaeSNaresh Kumar Inna * Perform all of the steps necessary for upgrading an adapter's 1220a3667aaeSNaresh Kumar Inna * firmware image. Normally this requires the cooperation of the 1221a3667aaeSNaresh Kumar Inna * existing firmware in order to halt all existing activities 1222a3667aaeSNaresh Kumar Inna * but if an invalid mailbox token is passed in we skip that step 1223a3667aaeSNaresh Kumar Inna * (though we'll still put the adapter microprocessor into RESET in 1224a3667aaeSNaresh Kumar Inna * that case). 1225a3667aaeSNaresh Kumar Inna * 1226a3667aaeSNaresh Kumar Inna * On successful return the new firmware will have been loaded and 1227a3667aaeSNaresh Kumar Inna * the adapter will have been fully RESET losing all previous setup 1228a3667aaeSNaresh Kumar Inna * state. On unsuccessful return the adapter may be completely hosed ... 1229a3667aaeSNaresh Kumar Inna * positive errno indicates that the adapter is ~probably~ intact, a 1230a3667aaeSNaresh Kumar Inna * negative errno indicates that things are looking bad ... 1231a3667aaeSNaresh Kumar Inna */ 1232a3667aaeSNaresh Kumar Inna static int 1233a3667aaeSNaresh Kumar Inna csio_hw_fw_upgrade(struct csio_hw *hw, uint32_t mbox, 1234a3667aaeSNaresh Kumar Inna const u8 *fw_data, uint32_t size, int32_t force) 1235a3667aaeSNaresh Kumar Inna { 1236a3667aaeSNaresh Kumar Inna const struct fw_hdr *fw_hdr = (const struct fw_hdr *)fw_data; 1237a3667aaeSNaresh Kumar Inna int reset, ret; 1238a3667aaeSNaresh Kumar Inna 1239a3667aaeSNaresh Kumar Inna ret = csio_hw_fw_halt(hw, mbox, force); 1240a3667aaeSNaresh Kumar Inna if (ret != 0 && !force) 1241a3667aaeSNaresh Kumar Inna return ret; 1242a3667aaeSNaresh Kumar Inna 1243a3667aaeSNaresh Kumar Inna ret = csio_hw_fw_dload(hw, (uint8_t *) fw_data, size); 1244a3667aaeSNaresh Kumar Inna if (ret != 0) 1245a3667aaeSNaresh Kumar Inna return ret; 1246a3667aaeSNaresh Kumar Inna 1247a3667aaeSNaresh Kumar Inna /* 1248a3667aaeSNaresh Kumar Inna * Older versions of the firmware don't understand the new 1249a3667aaeSNaresh Kumar Inna * PCIE_FW.HALT flag and so won't know to perform a RESET when they 1250a3667aaeSNaresh Kumar Inna * restart. So for newly loaded older firmware we'll have to do the 1251a3667aaeSNaresh Kumar Inna * RESET for it so it starts up on a clean slate. We can tell if 1252a3667aaeSNaresh Kumar Inna * the newly loaded firmware will handle this right by checking 1253a3667aaeSNaresh Kumar Inna * its header flags to see if it advertises the capability. 1254a3667aaeSNaresh Kumar Inna */ 1255a3667aaeSNaresh Kumar Inna reset = ((ntohl(fw_hdr->flags) & FW_HDR_FLAGS_RESET_HALT) == 0); 1256a3667aaeSNaresh Kumar Inna return csio_hw_fw_restart(hw, mbox, reset); 1257a3667aaeSNaresh Kumar Inna } 1258a3667aaeSNaresh Kumar Inna 1259a3667aaeSNaresh Kumar Inna /* 1260a3667aaeSNaresh Kumar Inna * csio_get_device_params - Get device parameters. 1261a3667aaeSNaresh Kumar Inna * @hw: HW module 1262a3667aaeSNaresh Kumar Inna * 1263a3667aaeSNaresh Kumar Inna */ 1264a3667aaeSNaresh Kumar Inna static int 1265a3667aaeSNaresh Kumar Inna csio_get_device_params(struct csio_hw *hw) 1266a3667aaeSNaresh Kumar Inna { 1267a3667aaeSNaresh Kumar Inna struct csio_wrm *wrm = csio_hw_to_wrm(hw); 1268a3667aaeSNaresh Kumar Inna struct csio_mb *mbp; 1269a3667aaeSNaresh Kumar Inna enum fw_retval retval; 1270a3667aaeSNaresh Kumar Inna u32 param[6]; 1271a3667aaeSNaresh Kumar Inna int i, j = 0; 1272a3667aaeSNaresh Kumar Inna 1273a3667aaeSNaresh Kumar Inna /* Initialize portids to -1 */ 1274a3667aaeSNaresh Kumar Inna for (i = 0; i < CSIO_MAX_PPORTS; i++) 1275a3667aaeSNaresh Kumar Inna hw->pport[i].portid = -1; 1276a3667aaeSNaresh Kumar Inna 1277a3667aaeSNaresh Kumar Inna mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 1278a3667aaeSNaresh Kumar Inna if (!mbp) { 1279a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_nomem); 1280a3667aaeSNaresh Kumar Inna return -ENOMEM; 1281a3667aaeSNaresh Kumar Inna } 1282a3667aaeSNaresh Kumar Inna 1283a3667aaeSNaresh Kumar Inna /* Get port vec information. */ 1284a3667aaeSNaresh Kumar Inna param[0] = FW_PARAM_DEV(PORTVEC); 1285a3667aaeSNaresh Kumar Inna 1286a3667aaeSNaresh Kumar Inna /* Get Core clock. */ 1287a3667aaeSNaresh Kumar Inna param[1] = FW_PARAM_DEV(CCLK); 1288a3667aaeSNaresh Kumar Inna 1289a3667aaeSNaresh Kumar Inna /* Get EQ id start and end. */ 1290a3667aaeSNaresh Kumar Inna param[2] = FW_PARAM_PFVF(EQ_START); 1291a3667aaeSNaresh Kumar Inna param[3] = FW_PARAM_PFVF(EQ_END); 1292a3667aaeSNaresh Kumar Inna 1293a3667aaeSNaresh Kumar Inna /* Get IQ id start and end. */ 1294a3667aaeSNaresh Kumar Inna param[4] = FW_PARAM_PFVF(IQFLINT_START); 1295a3667aaeSNaresh Kumar Inna param[5] = FW_PARAM_PFVF(IQFLINT_END); 1296a3667aaeSNaresh Kumar Inna 1297a3667aaeSNaresh Kumar Inna csio_mb_params(hw, mbp, CSIO_MB_DEFAULT_TMO, hw->pfn, 0, 1298a3667aaeSNaresh Kumar Inna ARRAY_SIZE(param), param, NULL, false, NULL); 1299a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 1300a3667aaeSNaresh Kumar Inna csio_err(hw, "Issue of FW_PARAMS_CMD(read) failed!\n"); 1301a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1302a3667aaeSNaresh Kumar Inna return -EINVAL; 1303a3667aaeSNaresh Kumar Inna } 1304a3667aaeSNaresh Kumar Inna 1305a3667aaeSNaresh Kumar Inna csio_mb_process_read_params_rsp(hw, mbp, &retval, 1306a3667aaeSNaresh Kumar Inna ARRAY_SIZE(param), param); 1307a3667aaeSNaresh Kumar Inna if (retval != FW_SUCCESS) { 1308a3667aaeSNaresh Kumar Inna csio_err(hw, "FW_PARAMS_CMD(read) failed with ret:0x%x!\n", 1309a3667aaeSNaresh Kumar Inna retval); 1310a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1311a3667aaeSNaresh Kumar Inna return -EINVAL; 1312a3667aaeSNaresh Kumar Inna } 1313a3667aaeSNaresh Kumar Inna 1314a3667aaeSNaresh Kumar Inna /* cache the information. */ 1315a3667aaeSNaresh Kumar Inna hw->port_vec = param[0]; 1316a3667aaeSNaresh Kumar Inna hw->vpd.cclk = param[1]; 1317a3667aaeSNaresh Kumar Inna wrm->fw_eq_start = param[2]; 1318a3667aaeSNaresh Kumar Inna wrm->fw_iq_start = param[4]; 1319a3667aaeSNaresh Kumar Inna 1320a3667aaeSNaresh Kumar Inna /* Using FW configured max iqs & eqs */ 1321a3667aaeSNaresh Kumar Inna if ((hw->flags & CSIO_HWF_USING_SOFT_PARAMS) || 1322a3667aaeSNaresh Kumar Inna !csio_is_hw_master(hw)) { 1323a3667aaeSNaresh Kumar Inna hw->cfg_niq = param[5] - param[4] + 1; 1324a3667aaeSNaresh Kumar Inna hw->cfg_neq = param[3] - param[2] + 1; 1325a3667aaeSNaresh Kumar Inna csio_dbg(hw, "Using fwconfig max niqs %d neqs %d\n", 1326a3667aaeSNaresh Kumar Inna hw->cfg_niq, hw->cfg_neq); 1327a3667aaeSNaresh Kumar Inna } 1328a3667aaeSNaresh Kumar Inna 1329a3667aaeSNaresh Kumar Inna hw->port_vec &= csio_port_mask; 1330a3667aaeSNaresh Kumar Inna 1331a3667aaeSNaresh Kumar Inna hw->num_pports = hweight32(hw->port_vec); 1332a3667aaeSNaresh Kumar Inna 1333a3667aaeSNaresh Kumar Inna csio_dbg(hw, "Port vector: 0x%x, #ports: %d\n", 1334a3667aaeSNaresh Kumar Inna hw->port_vec, hw->num_pports); 1335a3667aaeSNaresh Kumar Inna 1336a3667aaeSNaresh Kumar Inna for (i = 0; i < hw->num_pports; i++) { 1337a3667aaeSNaresh Kumar Inna while ((hw->port_vec & (1 << j)) == 0) 1338a3667aaeSNaresh Kumar Inna j++; 1339a3667aaeSNaresh Kumar Inna hw->pport[i].portid = j++; 1340a3667aaeSNaresh Kumar Inna csio_dbg(hw, "Found Port:%d\n", hw->pport[i].portid); 1341a3667aaeSNaresh Kumar Inna } 1342a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1343a3667aaeSNaresh Kumar Inna 1344a3667aaeSNaresh Kumar Inna return 0; 1345a3667aaeSNaresh Kumar Inna } 1346a3667aaeSNaresh Kumar Inna 1347a3667aaeSNaresh Kumar Inna 1348a3667aaeSNaresh Kumar Inna /* 1349a3667aaeSNaresh Kumar Inna * csio_config_device_caps - Get and set device capabilities. 1350a3667aaeSNaresh Kumar Inna * @hw: HW module 1351a3667aaeSNaresh Kumar Inna * 1352a3667aaeSNaresh Kumar Inna */ 1353a3667aaeSNaresh Kumar Inna static int 1354a3667aaeSNaresh Kumar Inna csio_config_device_caps(struct csio_hw *hw) 1355a3667aaeSNaresh Kumar Inna { 1356a3667aaeSNaresh Kumar Inna struct csio_mb *mbp; 1357a3667aaeSNaresh Kumar Inna enum fw_retval retval; 1358a3667aaeSNaresh Kumar Inna int rv = -EINVAL; 1359a3667aaeSNaresh Kumar Inna 1360a3667aaeSNaresh Kumar Inna mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 1361a3667aaeSNaresh Kumar Inna if (!mbp) { 1362a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_nomem); 1363a3667aaeSNaresh Kumar Inna return -ENOMEM; 1364a3667aaeSNaresh Kumar Inna } 1365a3667aaeSNaresh Kumar Inna 1366a3667aaeSNaresh Kumar Inna /* Get device capabilities */ 1367a3667aaeSNaresh Kumar Inna csio_mb_caps_config(hw, mbp, CSIO_MB_DEFAULT_TMO, 0, 0, 0, 0, NULL); 1368a3667aaeSNaresh Kumar Inna 1369a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 1370a3667aaeSNaresh Kumar Inna csio_err(hw, "Issue of FW_CAPS_CONFIG_CMD(r) failed!\n"); 1371a3667aaeSNaresh Kumar Inna goto out; 1372a3667aaeSNaresh Kumar Inna } 1373a3667aaeSNaresh Kumar Inna 1374a3667aaeSNaresh Kumar Inna retval = csio_mb_fw_retval(mbp); 1375a3667aaeSNaresh Kumar Inna if (retval != FW_SUCCESS) { 1376a3667aaeSNaresh Kumar Inna csio_err(hw, "FW_CAPS_CONFIG_CMD(r) returned %d!\n", retval); 1377a3667aaeSNaresh Kumar Inna goto out; 1378a3667aaeSNaresh Kumar Inna } 1379a3667aaeSNaresh Kumar Inna 1380a3667aaeSNaresh Kumar Inna /* Validate device capabilities */ 1381541c571fSPraveen Madhavan rv = csio_hw_validate_caps(hw, mbp); 1382541c571fSPraveen Madhavan if (rv != 0) 1383a3667aaeSNaresh Kumar Inna goto out; 1384a3667aaeSNaresh Kumar Inna 1385a3667aaeSNaresh Kumar Inna /* Don't config device capabilities if already configured */ 1386a3667aaeSNaresh Kumar Inna if (hw->fw_state == CSIO_DEV_STATE_INIT) { 1387a3667aaeSNaresh Kumar Inna rv = 0; 1388a3667aaeSNaresh Kumar Inna goto out; 1389a3667aaeSNaresh Kumar Inna } 1390a3667aaeSNaresh Kumar Inna 1391a3667aaeSNaresh Kumar Inna /* Write back desired device capabilities */ 1392a3667aaeSNaresh Kumar Inna csio_mb_caps_config(hw, mbp, CSIO_MB_DEFAULT_TMO, true, true, 1393a3667aaeSNaresh Kumar Inna false, true, NULL); 1394a3667aaeSNaresh Kumar Inna 1395a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 1396a3667aaeSNaresh Kumar Inna csio_err(hw, "Issue of FW_CAPS_CONFIG_CMD(w) failed!\n"); 1397a3667aaeSNaresh Kumar Inna goto out; 1398a3667aaeSNaresh Kumar Inna } 1399a3667aaeSNaresh Kumar Inna 1400a3667aaeSNaresh Kumar Inna retval = csio_mb_fw_retval(mbp); 1401a3667aaeSNaresh Kumar Inna if (retval != FW_SUCCESS) { 1402a3667aaeSNaresh Kumar Inna csio_err(hw, "FW_CAPS_CONFIG_CMD(w) returned %d!\n", retval); 1403a3667aaeSNaresh Kumar Inna goto out; 1404a3667aaeSNaresh Kumar Inna } 1405a3667aaeSNaresh Kumar Inna 1406a3667aaeSNaresh Kumar Inna rv = 0; 1407a3667aaeSNaresh Kumar Inna out: 1408a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1409a3667aaeSNaresh Kumar Inna return rv; 1410a3667aaeSNaresh Kumar Inna } 1411a3667aaeSNaresh Kumar Inna 1412*e1735d9aSVarun Prakash static inline enum cc_fec fwcap_to_cc_fec(fw_port_cap32_t fw_fec) 1413*e1735d9aSVarun Prakash { 1414*e1735d9aSVarun Prakash enum cc_fec cc_fec = 0; 1415*e1735d9aSVarun Prakash 1416*e1735d9aSVarun Prakash if (fw_fec & FW_PORT_CAP32_FEC_RS) 1417*e1735d9aSVarun Prakash cc_fec |= FEC_RS; 1418*e1735d9aSVarun Prakash if (fw_fec & FW_PORT_CAP32_FEC_BASER_RS) 1419*e1735d9aSVarun Prakash cc_fec |= FEC_BASER_RS; 1420*e1735d9aSVarun Prakash 1421*e1735d9aSVarun Prakash return cc_fec; 1422*e1735d9aSVarun Prakash } 1423*e1735d9aSVarun Prakash 1424*e1735d9aSVarun Prakash static inline fw_port_cap32_t cc_to_fwcap_pause(enum cc_pause cc_pause) 1425*e1735d9aSVarun Prakash { 1426*e1735d9aSVarun Prakash fw_port_cap32_t fw_pause = 0; 1427*e1735d9aSVarun Prakash 1428*e1735d9aSVarun Prakash if (cc_pause & PAUSE_RX) 1429*e1735d9aSVarun Prakash fw_pause |= FW_PORT_CAP32_FC_RX; 1430*e1735d9aSVarun Prakash if (cc_pause & PAUSE_TX) 1431*e1735d9aSVarun Prakash fw_pause |= FW_PORT_CAP32_FC_TX; 1432*e1735d9aSVarun Prakash 1433*e1735d9aSVarun Prakash return fw_pause; 1434*e1735d9aSVarun Prakash } 1435*e1735d9aSVarun Prakash 1436*e1735d9aSVarun Prakash static inline fw_port_cap32_t cc_to_fwcap_fec(enum cc_fec cc_fec) 1437*e1735d9aSVarun Prakash { 1438*e1735d9aSVarun Prakash fw_port_cap32_t fw_fec = 0; 1439*e1735d9aSVarun Prakash 1440*e1735d9aSVarun Prakash if (cc_fec & FEC_RS) 1441*e1735d9aSVarun Prakash fw_fec |= FW_PORT_CAP32_FEC_RS; 1442*e1735d9aSVarun Prakash if (cc_fec & FEC_BASER_RS) 1443*e1735d9aSVarun Prakash fw_fec |= FW_PORT_CAP32_FEC_BASER_RS; 1444*e1735d9aSVarun Prakash 1445*e1735d9aSVarun Prakash return fw_fec; 1446*e1735d9aSVarun Prakash } 1447*e1735d9aSVarun Prakash 1448*e1735d9aSVarun Prakash /** 1449*e1735d9aSVarun Prakash * fwcap_to_fwspeed - return highest speed in Port Capabilities 1450*e1735d9aSVarun Prakash * @acaps: advertised Port Capabilities 1451*e1735d9aSVarun Prakash * 1452*e1735d9aSVarun Prakash * Get the highest speed for the port from the advertised Port 1453*e1735d9aSVarun Prakash * Capabilities. 1454*e1735d9aSVarun Prakash */ 1455*e1735d9aSVarun Prakash fw_port_cap32_t fwcap_to_fwspeed(fw_port_cap32_t acaps) 1456*e1735d9aSVarun Prakash { 1457*e1735d9aSVarun Prakash #define TEST_SPEED_RETURN(__caps_speed) \ 1458*e1735d9aSVarun Prakash do { \ 1459*e1735d9aSVarun Prakash if (acaps & FW_PORT_CAP32_SPEED_##__caps_speed) \ 1460*e1735d9aSVarun Prakash return FW_PORT_CAP32_SPEED_##__caps_speed; \ 1461*e1735d9aSVarun Prakash } while (0) 1462*e1735d9aSVarun Prakash 1463*e1735d9aSVarun Prakash TEST_SPEED_RETURN(400G); 1464*e1735d9aSVarun Prakash TEST_SPEED_RETURN(200G); 1465*e1735d9aSVarun Prakash TEST_SPEED_RETURN(100G); 1466*e1735d9aSVarun Prakash TEST_SPEED_RETURN(50G); 1467*e1735d9aSVarun Prakash TEST_SPEED_RETURN(40G); 1468*e1735d9aSVarun Prakash TEST_SPEED_RETURN(25G); 1469*e1735d9aSVarun Prakash TEST_SPEED_RETURN(10G); 1470*e1735d9aSVarun Prakash TEST_SPEED_RETURN(1G); 1471*e1735d9aSVarun Prakash TEST_SPEED_RETURN(100M); 1472*e1735d9aSVarun Prakash 1473*e1735d9aSVarun Prakash #undef TEST_SPEED_RETURN 1474*e1735d9aSVarun Prakash 1475*e1735d9aSVarun Prakash return 0; 1476*e1735d9aSVarun Prakash } 1477*e1735d9aSVarun Prakash 1478*e1735d9aSVarun Prakash /** 1479*e1735d9aSVarun Prakash * fwcaps16_to_caps32 - convert 16-bit Port Capabilities to 32-bits 1480*e1735d9aSVarun Prakash * @caps16: a 16-bit Port Capabilities value 1481*e1735d9aSVarun Prakash * 1482*e1735d9aSVarun Prakash * Returns the equivalent 32-bit Port Capabilities value. 1483*e1735d9aSVarun Prakash */ 1484*e1735d9aSVarun Prakash fw_port_cap32_t fwcaps16_to_caps32(fw_port_cap16_t caps16) 1485*e1735d9aSVarun Prakash { 1486*e1735d9aSVarun Prakash fw_port_cap32_t caps32 = 0; 1487*e1735d9aSVarun Prakash 1488*e1735d9aSVarun Prakash #define CAP16_TO_CAP32(__cap) \ 1489*e1735d9aSVarun Prakash do { \ 1490*e1735d9aSVarun Prakash if (caps16 & FW_PORT_CAP_##__cap) \ 1491*e1735d9aSVarun Prakash caps32 |= FW_PORT_CAP32_##__cap; \ 1492*e1735d9aSVarun Prakash } while (0) 1493*e1735d9aSVarun Prakash 1494*e1735d9aSVarun Prakash CAP16_TO_CAP32(SPEED_100M); 1495*e1735d9aSVarun Prakash CAP16_TO_CAP32(SPEED_1G); 1496*e1735d9aSVarun Prakash CAP16_TO_CAP32(SPEED_25G); 1497*e1735d9aSVarun Prakash CAP16_TO_CAP32(SPEED_10G); 1498*e1735d9aSVarun Prakash CAP16_TO_CAP32(SPEED_40G); 1499*e1735d9aSVarun Prakash CAP16_TO_CAP32(SPEED_100G); 1500*e1735d9aSVarun Prakash CAP16_TO_CAP32(FC_RX); 1501*e1735d9aSVarun Prakash CAP16_TO_CAP32(FC_TX); 1502*e1735d9aSVarun Prakash CAP16_TO_CAP32(ANEG); 1503*e1735d9aSVarun Prakash CAP16_TO_CAP32(MDIX); 1504*e1735d9aSVarun Prakash CAP16_TO_CAP32(MDIAUTO); 1505*e1735d9aSVarun Prakash CAP16_TO_CAP32(FEC_RS); 1506*e1735d9aSVarun Prakash CAP16_TO_CAP32(FEC_BASER_RS); 1507*e1735d9aSVarun Prakash CAP16_TO_CAP32(802_3_PAUSE); 1508*e1735d9aSVarun Prakash CAP16_TO_CAP32(802_3_ASM_DIR); 1509*e1735d9aSVarun Prakash 1510*e1735d9aSVarun Prakash #undef CAP16_TO_CAP32 1511*e1735d9aSVarun Prakash 1512*e1735d9aSVarun Prakash return caps32; 1513*e1735d9aSVarun Prakash } 1514*e1735d9aSVarun Prakash 1515*e1735d9aSVarun Prakash /** 1516*e1735d9aSVarun Prakash * lstatus_to_fwcap - translate old lstatus to 32-bit Port Capabilities 1517*e1735d9aSVarun Prakash * @lstatus: old FW_PORT_ACTION_GET_PORT_INFO lstatus value 1518*e1735d9aSVarun Prakash * 1519*e1735d9aSVarun Prakash * Translates old FW_PORT_ACTION_GET_PORT_INFO lstatus field into new 1520*e1735d9aSVarun Prakash * 32-bit Port Capabilities value. 1521*e1735d9aSVarun Prakash */ 1522*e1735d9aSVarun Prakash fw_port_cap32_t lstatus_to_fwcap(u32 lstatus) 1523*e1735d9aSVarun Prakash { 1524*e1735d9aSVarun Prakash fw_port_cap32_t linkattr = 0; 1525*e1735d9aSVarun Prakash 1526*e1735d9aSVarun Prakash /* The format of the Link Status in the old 1527*e1735d9aSVarun Prakash * 16-bit Port Information message isn't the same as the 1528*e1735d9aSVarun Prakash * 16-bit Port Capabilities bitfield used everywhere else. 1529*e1735d9aSVarun Prakash */ 1530*e1735d9aSVarun Prakash if (lstatus & FW_PORT_CMD_RXPAUSE_F) 1531*e1735d9aSVarun Prakash linkattr |= FW_PORT_CAP32_FC_RX; 1532*e1735d9aSVarun Prakash if (lstatus & FW_PORT_CMD_TXPAUSE_F) 1533*e1735d9aSVarun Prakash linkattr |= FW_PORT_CAP32_FC_TX; 1534*e1735d9aSVarun Prakash if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100M)) 1535*e1735d9aSVarun Prakash linkattr |= FW_PORT_CAP32_SPEED_100M; 1536*e1735d9aSVarun Prakash if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_1G)) 1537*e1735d9aSVarun Prakash linkattr |= FW_PORT_CAP32_SPEED_1G; 1538*e1735d9aSVarun Prakash if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_10G)) 1539*e1735d9aSVarun Prakash linkattr |= FW_PORT_CAP32_SPEED_10G; 1540*e1735d9aSVarun Prakash if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_25G)) 1541*e1735d9aSVarun Prakash linkattr |= FW_PORT_CAP32_SPEED_25G; 1542*e1735d9aSVarun Prakash if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_40G)) 1543*e1735d9aSVarun Prakash linkattr |= FW_PORT_CAP32_SPEED_40G; 1544*e1735d9aSVarun Prakash if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100G)) 1545*e1735d9aSVarun Prakash linkattr |= FW_PORT_CAP32_SPEED_100G; 1546*e1735d9aSVarun Prakash 1547*e1735d9aSVarun Prakash return linkattr; 1548*e1735d9aSVarun Prakash } 1549*e1735d9aSVarun Prakash 1550*e1735d9aSVarun Prakash /** 1551*e1735d9aSVarun Prakash * csio_init_link_config - initialize a link's SW state 1552*e1735d9aSVarun Prakash * @lc: pointer to structure holding the link state 1553*e1735d9aSVarun Prakash * @pcaps: link Port Capabilities 1554*e1735d9aSVarun Prakash * @acaps: link current Advertised Port Capabilities 1555*e1735d9aSVarun Prakash * 1556*e1735d9aSVarun Prakash * Initializes the SW state maintained for each link, including the link's 1557*e1735d9aSVarun Prakash * capabilities and default speed/flow-control/autonegotiation settings. 1558*e1735d9aSVarun Prakash */ 1559*e1735d9aSVarun Prakash static void csio_init_link_config(struct link_config *lc, fw_port_cap32_t pcaps, 1560*e1735d9aSVarun Prakash fw_port_cap32_t acaps) 1561*e1735d9aSVarun Prakash { 1562*e1735d9aSVarun Prakash lc->pcaps = pcaps; 1563*e1735d9aSVarun Prakash lc->def_acaps = acaps; 1564*e1735d9aSVarun Prakash lc->lpacaps = 0; 1565*e1735d9aSVarun Prakash lc->speed_caps = 0; 1566*e1735d9aSVarun Prakash lc->speed = 0; 1567*e1735d9aSVarun Prakash lc->requested_fc = PAUSE_RX | PAUSE_TX; 1568*e1735d9aSVarun Prakash lc->fc = lc->requested_fc; 1569*e1735d9aSVarun Prakash 1570*e1735d9aSVarun Prakash /* 1571*e1735d9aSVarun Prakash * For Forward Error Control, we default to whatever the Firmware 1572*e1735d9aSVarun Prakash * tells us the Link is currently advertising. 1573*e1735d9aSVarun Prakash */ 1574*e1735d9aSVarun Prakash lc->requested_fec = FEC_AUTO; 1575*e1735d9aSVarun Prakash lc->fec = fwcap_to_cc_fec(lc->def_acaps); 1576*e1735d9aSVarun Prakash 1577*e1735d9aSVarun Prakash /* If the Port is capable of Auto-Negtotiation, initialize it as 1578*e1735d9aSVarun Prakash * "enabled" and copy over all of the Physical Port Capabilities 1579*e1735d9aSVarun Prakash * to the Advertised Port Capabilities. Otherwise mark it as 1580*e1735d9aSVarun Prakash * Auto-Negotiate disabled and select the highest supported speed 1581*e1735d9aSVarun Prakash * for the link. Note parallel structure in t4_link_l1cfg_core() 1582*e1735d9aSVarun Prakash * and t4_handle_get_port_info(). 1583*e1735d9aSVarun Prakash */ 1584*e1735d9aSVarun Prakash if (lc->pcaps & FW_PORT_CAP32_ANEG) { 1585*e1735d9aSVarun Prakash lc->acaps = lc->pcaps & ADVERT_MASK; 1586*e1735d9aSVarun Prakash lc->autoneg = AUTONEG_ENABLE; 1587*e1735d9aSVarun Prakash lc->requested_fc |= PAUSE_AUTONEG; 1588*e1735d9aSVarun Prakash } else { 1589*e1735d9aSVarun Prakash lc->acaps = 0; 1590*e1735d9aSVarun Prakash lc->autoneg = AUTONEG_DISABLE; 1591*e1735d9aSVarun Prakash } 1592*e1735d9aSVarun Prakash } 1593*e1735d9aSVarun Prakash 1594*e1735d9aSVarun Prakash static void csio_link_l1cfg(struct link_config *lc, uint16_t fw_caps, 1595*e1735d9aSVarun Prakash uint32_t *rcaps) 1596*e1735d9aSVarun Prakash { 1597*e1735d9aSVarun Prakash unsigned int fw_mdi = FW_PORT_CAP32_MDI_V(FW_PORT_CAP32_MDI_AUTO); 1598*e1735d9aSVarun Prakash fw_port_cap32_t fw_fc, cc_fec, fw_fec, lrcap; 1599*e1735d9aSVarun Prakash 1600*e1735d9aSVarun Prakash lc->link_ok = 0; 1601*e1735d9aSVarun Prakash 1602*e1735d9aSVarun Prakash /* 1603*e1735d9aSVarun Prakash * Convert driver coding of Pause Frame Flow Control settings into the 1604*e1735d9aSVarun Prakash * Firmware's API. 1605*e1735d9aSVarun Prakash */ 1606*e1735d9aSVarun Prakash fw_fc = cc_to_fwcap_pause(lc->requested_fc); 1607*e1735d9aSVarun Prakash 1608*e1735d9aSVarun Prakash /* 1609*e1735d9aSVarun Prakash * Convert Common Code Forward Error Control settings into the 1610*e1735d9aSVarun Prakash * Firmware's API. If the current Requested FEC has "Automatic" 1611*e1735d9aSVarun Prakash * (IEEE 802.3) specified, then we use whatever the Firmware 1612*e1735d9aSVarun Prakash * sent us as part of it's IEEE 802.3-based interpratation of 1613*e1735d9aSVarun Prakash * the Transceiver Module EPROM FEC parameters. Otherwise we 1614*e1735d9aSVarun Prakash * use whatever is in the current Requested FEC settings. 1615*e1735d9aSVarun Prakash */ 1616*e1735d9aSVarun Prakash if (lc->requested_fec & FEC_AUTO) 1617*e1735d9aSVarun Prakash cc_fec = fwcap_to_cc_fec(lc->def_acaps); 1618*e1735d9aSVarun Prakash else 1619*e1735d9aSVarun Prakash cc_fec = lc->requested_fec; 1620*e1735d9aSVarun Prakash fw_fec = cc_to_fwcap_fec(cc_fec); 1621*e1735d9aSVarun Prakash 1622*e1735d9aSVarun Prakash /* Figure out what our Requested Port Capabilities are going to be. 1623*e1735d9aSVarun Prakash * Note parallel structure in t4_handle_get_port_info() and 1624*e1735d9aSVarun Prakash * init_link_config(). 1625*e1735d9aSVarun Prakash */ 1626*e1735d9aSVarun Prakash if (!(lc->pcaps & FW_PORT_CAP32_ANEG)) { 1627*e1735d9aSVarun Prakash lrcap = (lc->pcaps & ADVERT_MASK) | fw_fc | fw_fec; 1628*e1735d9aSVarun Prakash lc->fc = lc->requested_fc & ~PAUSE_AUTONEG; 1629*e1735d9aSVarun Prakash lc->fec = cc_fec; 1630*e1735d9aSVarun Prakash } else if (lc->autoneg == AUTONEG_DISABLE) { 1631*e1735d9aSVarun Prakash lrcap = lc->speed_caps | fw_fc | fw_fec | fw_mdi; 1632*e1735d9aSVarun Prakash lc->fc = lc->requested_fc & ~PAUSE_AUTONEG; 1633*e1735d9aSVarun Prakash lc->fec = cc_fec; 1634*e1735d9aSVarun Prakash } else { 1635*e1735d9aSVarun Prakash lrcap = lc->acaps | fw_fc | fw_fec | fw_mdi; 1636*e1735d9aSVarun Prakash } 1637*e1735d9aSVarun Prakash 1638*e1735d9aSVarun Prakash *rcaps = lrcap; 1639*e1735d9aSVarun Prakash } 1640*e1735d9aSVarun Prakash 1641a3667aaeSNaresh Kumar Inna /* 1642a3667aaeSNaresh Kumar Inna * csio_enable_ports - Bring up all available ports. 1643a3667aaeSNaresh Kumar Inna * @hw: HW module. 1644a3667aaeSNaresh Kumar Inna * 1645a3667aaeSNaresh Kumar Inna */ 1646a3667aaeSNaresh Kumar Inna static int 1647a3667aaeSNaresh Kumar Inna csio_enable_ports(struct csio_hw *hw) 1648a3667aaeSNaresh Kumar Inna { 1649a3667aaeSNaresh Kumar Inna struct csio_mb *mbp; 1650*e1735d9aSVarun Prakash u16 fw_caps = FW_CAPS_UNKNOWN; 1651a3667aaeSNaresh Kumar Inna enum fw_retval retval; 1652a3667aaeSNaresh Kumar Inna uint8_t portid; 1653*e1735d9aSVarun Prakash fw_port_cap32_t pcaps, acaps, rcaps; 1654a3667aaeSNaresh Kumar Inna int i; 1655a3667aaeSNaresh Kumar Inna 1656a3667aaeSNaresh Kumar Inna mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 1657a3667aaeSNaresh Kumar Inna if (!mbp) { 1658a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_nomem); 1659a3667aaeSNaresh Kumar Inna return -ENOMEM; 1660a3667aaeSNaresh Kumar Inna } 1661a3667aaeSNaresh Kumar Inna 1662a3667aaeSNaresh Kumar Inna for (i = 0; i < hw->num_pports; i++) { 1663a3667aaeSNaresh Kumar Inna portid = hw->pport[i].portid; 1664a3667aaeSNaresh Kumar Inna 1665*e1735d9aSVarun Prakash if (fw_caps == FW_CAPS_UNKNOWN) { 1666*e1735d9aSVarun Prakash u32 param, val; 1667*e1735d9aSVarun Prakash 1668*e1735d9aSVarun Prakash param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_PFVF) | 1669*e1735d9aSVarun Prakash FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_PFVF_PORT_CAPS32)); 1670*e1735d9aSVarun Prakash val = 1; 1671*e1735d9aSVarun Prakash 1672*e1735d9aSVarun Prakash csio_mb_params(hw, mbp, CSIO_MB_DEFAULT_TMO, 1673*e1735d9aSVarun Prakash hw->pfn, 0, 1, ¶m, &val, false, 1674*e1735d9aSVarun Prakash NULL); 1675*e1735d9aSVarun Prakash 1676*e1735d9aSVarun Prakash if (csio_mb_issue(hw, mbp)) { 1677*e1735d9aSVarun Prakash csio_err(hw, "failed to issue FW_PARAMS_CMD(r) port:%d\n", 1678*e1735d9aSVarun Prakash portid); 1679*e1735d9aSVarun Prakash mempool_free(mbp, hw->mb_mempool); 1680*e1735d9aSVarun Prakash return -EINVAL; 1681*e1735d9aSVarun Prakash } 1682*e1735d9aSVarun Prakash 1683*e1735d9aSVarun Prakash csio_mb_process_read_params_rsp(hw, mbp, &retval, 1, 1684*e1735d9aSVarun Prakash &val); 1685*e1735d9aSVarun Prakash if (retval != FW_SUCCESS) { 1686*e1735d9aSVarun Prakash csio_err(hw, "FW_PARAMS_CMD(r) port:%d failed: 0x%x\n", 1687*e1735d9aSVarun Prakash portid, retval); 1688*e1735d9aSVarun Prakash mempool_free(mbp, hw->mb_mempool); 1689*e1735d9aSVarun Prakash return -EINVAL; 1690*e1735d9aSVarun Prakash } 1691*e1735d9aSVarun Prakash 1692*e1735d9aSVarun Prakash fw_caps = val; 1693*e1735d9aSVarun Prakash } 1694*e1735d9aSVarun Prakash 1695a3667aaeSNaresh Kumar Inna /* Read PORT information */ 1696a3667aaeSNaresh Kumar Inna csio_mb_port(hw, mbp, CSIO_MB_DEFAULT_TMO, portid, 1697*e1735d9aSVarun Prakash false, 0, fw_caps, NULL); 1698a3667aaeSNaresh Kumar Inna 1699a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 1700a3667aaeSNaresh Kumar Inna csio_err(hw, "failed to issue FW_PORT_CMD(r) port:%d\n", 1701a3667aaeSNaresh Kumar Inna portid); 1702a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1703a3667aaeSNaresh Kumar Inna return -EINVAL; 1704a3667aaeSNaresh Kumar Inna } 1705a3667aaeSNaresh Kumar Inna 1706*e1735d9aSVarun Prakash csio_mb_process_read_port_rsp(hw, mbp, &retval, fw_caps, 1707*e1735d9aSVarun Prakash &pcaps, &acaps); 1708a3667aaeSNaresh Kumar Inna if (retval != FW_SUCCESS) { 1709a3667aaeSNaresh Kumar Inna csio_err(hw, "FW_PORT_CMD(r) port:%d failed: 0x%x\n", 1710a3667aaeSNaresh Kumar Inna portid, retval); 1711a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1712a3667aaeSNaresh Kumar Inna return -EINVAL; 1713a3667aaeSNaresh Kumar Inna } 1714a3667aaeSNaresh Kumar Inna 1715*e1735d9aSVarun Prakash csio_init_link_config(&hw->pport[i].link_cfg, pcaps, acaps); 1716*e1735d9aSVarun Prakash 1717*e1735d9aSVarun Prakash csio_link_l1cfg(&hw->pport[i].link_cfg, fw_caps, &rcaps); 1718*e1735d9aSVarun Prakash 1719a3667aaeSNaresh Kumar Inna /* Write back PORT information */ 1720*e1735d9aSVarun Prakash csio_mb_port(hw, mbp, CSIO_MB_DEFAULT_TMO, portid, 1721*e1735d9aSVarun Prakash true, rcaps, fw_caps, NULL); 1722a3667aaeSNaresh Kumar Inna 1723a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 1724a3667aaeSNaresh Kumar Inna csio_err(hw, "failed to issue FW_PORT_CMD(w) port:%d\n", 1725a3667aaeSNaresh Kumar Inna portid); 1726a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1727a3667aaeSNaresh Kumar Inna return -EINVAL; 1728a3667aaeSNaresh Kumar Inna } 1729a3667aaeSNaresh Kumar Inna 1730a3667aaeSNaresh Kumar Inna retval = csio_mb_fw_retval(mbp); 1731a3667aaeSNaresh Kumar Inna if (retval != FW_SUCCESS) { 1732a3667aaeSNaresh Kumar Inna csio_err(hw, "FW_PORT_CMD(w) port:%d failed :0x%x\n", 1733a3667aaeSNaresh Kumar Inna portid, retval); 1734a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1735a3667aaeSNaresh Kumar Inna return -EINVAL; 1736a3667aaeSNaresh Kumar Inna } 1737a3667aaeSNaresh Kumar Inna 1738a3667aaeSNaresh Kumar Inna } /* For all ports */ 1739a3667aaeSNaresh Kumar Inna 1740a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1741a3667aaeSNaresh Kumar Inna 1742a3667aaeSNaresh Kumar Inna return 0; 1743a3667aaeSNaresh Kumar Inna } 1744a3667aaeSNaresh Kumar Inna 1745a3667aaeSNaresh Kumar Inna /* 1746a3667aaeSNaresh Kumar Inna * csio_get_fcoe_resinfo - Read fcoe fw resource info. 1747a3667aaeSNaresh Kumar Inna * @hw: HW module 1748a3667aaeSNaresh Kumar Inna * Issued with lock held. 1749a3667aaeSNaresh Kumar Inna */ 1750a3667aaeSNaresh Kumar Inna static int 1751a3667aaeSNaresh Kumar Inna csio_get_fcoe_resinfo(struct csio_hw *hw) 1752a3667aaeSNaresh Kumar Inna { 1753a3667aaeSNaresh Kumar Inna struct csio_fcoe_res_info *res_info = &hw->fres_info; 1754a3667aaeSNaresh Kumar Inna struct fw_fcoe_res_info_cmd *rsp; 1755a3667aaeSNaresh Kumar Inna struct csio_mb *mbp; 1756a3667aaeSNaresh Kumar Inna enum fw_retval retval; 1757a3667aaeSNaresh Kumar Inna 1758a3667aaeSNaresh Kumar Inna mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 1759a3667aaeSNaresh Kumar Inna if (!mbp) { 1760a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_nomem); 1761a3667aaeSNaresh Kumar Inna return -ENOMEM; 1762a3667aaeSNaresh Kumar Inna } 1763a3667aaeSNaresh Kumar Inna 1764a3667aaeSNaresh Kumar Inna /* Get FCoE FW resource information */ 1765a3667aaeSNaresh Kumar Inna csio_fcoe_read_res_info_init_mb(hw, mbp, CSIO_MB_DEFAULT_TMO, NULL); 1766a3667aaeSNaresh Kumar Inna 1767a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 1768a3667aaeSNaresh Kumar Inna csio_err(hw, "failed to issue FW_FCOE_RES_INFO_CMD\n"); 1769a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1770a3667aaeSNaresh Kumar Inna return -EINVAL; 1771a3667aaeSNaresh Kumar Inna } 1772a3667aaeSNaresh Kumar Inna 1773a3667aaeSNaresh Kumar Inna rsp = (struct fw_fcoe_res_info_cmd *)(mbp->mb); 1774e2ac9628SHariprasad Shenai retval = FW_CMD_RETVAL_G(ntohl(rsp->retval_len16)); 1775a3667aaeSNaresh Kumar Inna if (retval != FW_SUCCESS) { 1776a3667aaeSNaresh Kumar Inna csio_err(hw, "FW_FCOE_RES_INFO_CMD failed with ret x%x\n", 1777a3667aaeSNaresh Kumar Inna retval); 1778a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1779a3667aaeSNaresh Kumar Inna return -EINVAL; 1780a3667aaeSNaresh Kumar Inna } 1781a3667aaeSNaresh Kumar Inna 1782a3667aaeSNaresh Kumar Inna res_info->e_d_tov = ntohs(rsp->e_d_tov); 1783a3667aaeSNaresh Kumar Inna res_info->r_a_tov_seq = ntohs(rsp->r_a_tov_seq); 1784a3667aaeSNaresh Kumar Inna res_info->r_a_tov_els = ntohs(rsp->r_a_tov_els); 1785a3667aaeSNaresh Kumar Inna res_info->r_r_tov = ntohs(rsp->r_r_tov); 1786a3667aaeSNaresh Kumar Inna res_info->max_xchgs = ntohl(rsp->max_xchgs); 1787a3667aaeSNaresh Kumar Inna res_info->max_ssns = ntohl(rsp->max_ssns); 1788a3667aaeSNaresh Kumar Inna res_info->used_xchgs = ntohl(rsp->used_xchgs); 1789a3667aaeSNaresh Kumar Inna res_info->used_ssns = ntohl(rsp->used_ssns); 1790a3667aaeSNaresh Kumar Inna res_info->max_fcfs = ntohl(rsp->max_fcfs); 1791a3667aaeSNaresh Kumar Inna res_info->max_vnps = ntohl(rsp->max_vnps); 1792a3667aaeSNaresh Kumar Inna res_info->used_fcfs = ntohl(rsp->used_fcfs); 1793a3667aaeSNaresh Kumar Inna res_info->used_vnps = ntohl(rsp->used_vnps); 1794a3667aaeSNaresh Kumar Inna 1795a3667aaeSNaresh Kumar Inna csio_dbg(hw, "max ssns:%d max xchgs:%d\n", res_info->max_ssns, 1796a3667aaeSNaresh Kumar Inna res_info->max_xchgs); 1797a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1798a3667aaeSNaresh Kumar Inna 1799a3667aaeSNaresh Kumar Inna return 0; 1800a3667aaeSNaresh Kumar Inna } 1801a3667aaeSNaresh Kumar Inna 1802a3667aaeSNaresh Kumar Inna static int 1803a3667aaeSNaresh Kumar Inna csio_hw_check_fwconfig(struct csio_hw *hw, u32 *param) 1804a3667aaeSNaresh Kumar Inna { 1805a3667aaeSNaresh Kumar Inna struct csio_mb *mbp; 1806a3667aaeSNaresh Kumar Inna enum fw_retval retval; 1807a3667aaeSNaresh Kumar Inna u32 _param[1]; 1808a3667aaeSNaresh Kumar Inna 1809a3667aaeSNaresh Kumar Inna mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 1810a3667aaeSNaresh Kumar Inna if (!mbp) { 1811a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_nomem); 1812a3667aaeSNaresh Kumar Inna return -ENOMEM; 1813a3667aaeSNaresh Kumar Inna } 1814a3667aaeSNaresh Kumar Inna 1815a3667aaeSNaresh Kumar Inna /* 1816a3667aaeSNaresh Kumar Inna * Find out whether we're dealing with a version of 1817a3667aaeSNaresh Kumar Inna * the firmware which has configuration file support. 1818a3667aaeSNaresh Kumar Inna */ 18195167865aSHariprasad Shenai _param[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | 18205167865aSHariprasad Shenai FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_CF)); 1821a3667aaeSNaresh Kumar Inna 1822a3667aaeSNaresh Kumar Inna csio_mb_params(hw, mbp, CSIO_MB_DEFAULT_TMO, hw->pfn, 0, 1823a3667aaeSNaresh Kumar Inna ARRAY_SIZE(_param), _param, NULL, false, NULL); 1824a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 1825a3667aaeSNaresh Kumar Inna csio_err(hw, "Issue of FW_PARAMS_CMD(read) failed!\n"); 1826a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1827a3667aaeSNaresh Kumar Inna return -EINVAL; 1828a3667aaeSNaresh Kumar Inna } 1829a3667aaeSNaresh Kumar Inna 1830a3667aaeSNaresh Kumar Inna csio_mb_process_read_params_rsp(hw, mbp, &retval, 1831a3667aaeSNaresh Kumar Inna ARRAY_SIZE(_param), _param); 1832a3667aaeSNaresh Kumar Inna if (retval != FW_SUCCESS) { 1833a3667aaeSNaresh Kumar Inna csio_err(hw, "FW_PARAMS_CMD(read) failed with ret:0x%x!\n", 1834a3667aaeSNaresh Kumar Inna retval); 1835a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1836a3667aaeSNaresh Kumar Inna return -EINVAL; 1837a3667aaeSNaresh Kumar Inna } 1838a3667aaeSNaresh Kumar Inna 1839a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 1840a3667aaeSNaresh Kumar Inna *param = _param[0]; 1841a3667aaeSNaresh Kumar Inna 1842a3667aaeSNaresh Kumar Inna return 0; 1843a3667aaeSNaresh Kumar Inna } 1844a3667aaeSNaresh Kumar Inna 1845a3667aaeSNaresh Kumar Inna static int 1846a3667aaeSNaresh Kumar Inna csio_hw_flash_config(struct csio_hw *hw, u32 *fw_cfg_param, char *path) 1847a3667aaeSNaresh Kumar Inna { 1848a3667aaeSNaresh Kumar Inna int ret = 0; 1849a3667aaeSNaresh Kumar Inna const struct firmware *cf; 1850a3667aaeSNaresh Kumar Inna struct pci_dev *pci_dev = hw->pdev; 1851a3667aaeSNaresh Kumar Inna struct device *dev = &pci_dev->dev; 1852a3667aaeSNaresh Kumar Inna unsigned int mtype = 0, maddr = 0; 1853a3667aaeSNaresh Kumar Inna uint32_t *cfg_data; 1854a3667aaeSNaresh Kumar Inna int value_to_add = 0; 18554bbd458eSVarun Prakash const char *fw_cfg_file; 1856a3667aaeSNaresh Kumar Inna 18574bbd458eSVarun Prakash if (csio_is_t5(pci_dev->device & CSIO_HW_CHIP_MASK)) 18584bbd458eSVarun Prakash fw_cfg_file = FW_CFG_NAME_T5; 18594bbd458eSVarun Prakash else 18604bbd458eSVarun Prakash fw_cfg_file = FW_CFG_NAME_T6; 18614bbd458eSVarun Prakash 18624bbd458eSVarun Prakash if (request_firmware(&cf, fw_cfg_file, dev) < 0) { 18637cc16380SArvind Bhushan csio_err(hw, "could not find config file %s, err: %d\n", 18644bbd458eSVarun Prakash fw_cfg_file, ret); 1865a3667aaeSNaresh Kumar Inna return -ENOENT; 1866a3667aaeSNaresh Kumar Inna } 1867a3667aaeSNaresh Kumar Inna 1868a3667aaeSNaresh Kumar Inna if (cf->size%4 != 0) 1869a3667aaeSNaresh Kumar Inna value_to_add = 4 - (cf->size % 4); 1870a3667aaeSNaresh Kumar Inna 1871a3667aaeSNaresh Kumar Inna cfg_data = kzalloc(cf->size+value_to_add, GFP_KERNEL); 187202db3db5SJesper Juhl if (cfg_data == NULL) { 187302db3db5SJesper Juhl ret = -ENOMEM; 187402db3db5SJesper Juhl goto leave; 187502db3db5SJesper Juhl } 1876a3667aaeSNaresh Kumar Inna 1877a3667aaeSNaresh Kumar Inna memcpy((void *)cfg_data, (const void *)cf->data, cf->size); 187802db3db5SJesper Juhl if (csio_hw_check_fwconfig(hw, fw_cfg_param) != 0) { 187902db3db5SJesper Juhl ret = -EINVAL; 188002db3db5SJesper Juhl goto leave; 188102db3db5SJesper Juhl } 1882a3667aaeSNaresh Kumar Inna 18835167865aSHariprasad Shenai mtype = FW_PARAMS_PARAM_Y_G(*fw_cfg_param); 18845167865aSHariprasad Shenai maddr = FW_PARAMS_PARAM_Z_G(*fw_cfg_param) << 16; 1885a3667aaeSNaresh Kumar Inna 1886a3667aaeSNaresh Kumar Inna ret = csio_memory_write(hw, mtype, maddr, 1887a3667aaeSNaresh Kumar Inna cf->size + value_to_add, cfg_data); 18887cc16380SArvind Bhushan 18897cc16380SArvind Bhushan if ((ret == 0) && (value_to_add != 0)) { 18907cc16380SArvind Bhushan union { 18917cc16380SArvind Bhushan u32 word; 18927cc16380SArvind Bhushan char buf[4]; 18937cc16380SArvind Bhushan } last; 18947cc16380SArvind Bhushan size_t size = cf->size & ~0x3; 18957cc16380SArvind Bhushan int i; 18967cc16380SArvind Bhushan 18977cc16380SArvind Bhushan last.word = cfg_data[size >> 2]; 18987cc16380SArvind Bhushan for (i = value_to_add; i < 4; i++) 18997cc16380SArvind Bhushan last.buf[i] = 0; 19007cc16380SArvind Bhushan ret = csio_memory_write(hw, mtype, maddr + size, 4, &last.word); 19017cc16380SArvind Bhushan } 1902a3667aaeSNaresh Kumar Inna if (ret == 0) { 19034bbd458eSVarun Prakash csio_info(hw, "config file upgraded to %s\n", fw_cfg_file); 19044bbd458eSVarun Prakash snprintf(path, 64, "%s%s", "/lib/firmware/", fw_cfg_file); 1905a3667aaeSNaresh Kumar Inna } 1906a3667aaeSNaresh Kumar Inna 190702db3db5SJesper Juhl leave: 1908a3667aaeSNaresh Kumar Inna kfree(cfg_data); 1909a3667aaeSNaresh Kumar Inna release_firmware(cf); 1910a3667aaeSNaresh Kumar Inna return ret; 1911a3667aaeSNaresh Kumar Inna } 1912a3667aaeSNaresh Kumar Inna 1913a3667aaeSNaresh Kumar Inna /* 1914a3667aaeSNaresh Kumar Inna * HW initialization: contact FW, obtain config, perform basic init. 1915a3667aaeSNaresh Kumar Inna * 1916a3667aaeSNaresh Kumar Inna * If the firmware we're dealing with has Configuration File support, then 1917a3667aaeSNaresh Kumar Inna * we use that to perform all configuration -- either using the configuration 1918a3667aaeSNaresh Kumar Inna * file stored in flash on the adapter or using a filesystem-local file 1919a3667aaeSNaresh Kumar Inna * if available. 1920a3667aaeSNaresh Kumar Inna * 1921a3667aaeSNaresh Kumar Inna * If we don't have configuration file support in the firmware, then we'll 1922a3667aaeSNaresh Kumar Inna * have to set things up the old fashioned way with hard-coded register 1923a3667aaeSNaresh Kumar Inna * writes and firmware commands ... 1924a3667aaeSNaresh Kumar Inna */ 1925a3667aaeSNaresh Kumar Inna 1926a3667aaeSNaresh Kumar Inna /* 1927a3667aaeSNaresh Kumar Inna * Attempt to initialize the HW via a Firmware Configuration File. 1928a3667aaeSNaresh Kumar Inna */ 1929a3667aaeSNaresh Kumar Inna static int 1930a3667aaeSNaresh Kumar Inna csio_hw_use_fwconfig(struct csio_hw *hw, int reset, u32 *fw_cfg_param) 1931a3667aaeSNaresh Kumar Inna { 1932216ce69cSPraveen Madhavan struct csio_mb *mbp = NULL; 1933216ce69cSPraveen Madhavan struct fw_caps_config_cmd *caps_cmd; 1934a3667aaeSNaresh Kumar Inna unsigned int mtype, maddr; 1935216ce69cSPraveen Madhavan int rv = -EINVAL; 19367cc16380SArvind Bhushan uint32_t finiver = 0, finicsum = 0, cfcsum = 0; 1937a3667aaeSNaresh Kumar Inna char path[64]; 1938216ce69cSPraveen Madhavan char *config_name = NULL; 1939a3667aaeSNaresh Kumar Inna 1940a3667aaeSNaresh Kumar Inna /* 1941a3667aaeSNaresh Kumar Inna * Reset device if necessary 1942a3667aaeSNaresh Kumar Inna */ 1943a3667aaeSNaresh Kumar Inna if (reset) { 1944a3667aaeSNaresh Kumar Inna rv = csio_do_reset(hw, true); 1945a3667aaeSNaresh Kumar Inna if (rv != 0) 1946a3667aaeSNaresh Kumar Inna goto bye; 1947a3667aaeSNaresh Kumar Inna } 1948a3667aaeSNaresh Kumar Inna 1949a3667aaeSNaresh Kumar Inna /* 1950a3667aaeSNaresh Kumar Inna * If we have a configuration file in host , 1951a3667aaeSNaresh Kumar Inna * then use that. Otherwise, use the configuration file stored 1952a3667aaeSNaresh Kumar Inna * in the HW flash ... 1953a3667aaeSNaresh Kumar Inna */ 1954a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 1955a3667aaeSNaresh Kumar Inna rv = csio_hw_flash_config(hw, fw_cfg_param, path); 1956a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 1957a3667aaeSNaresh Kumar Inna if (rv != 0) { 1958a3667aaeSNaresh Kumar Inna /* 1959a3667aaeSNaresh Kumar Inna * config file was not found. Use default 1960a3667aaeSNaresh Kumar Inna * config file from flash. 1961a3667aaeSNaresh Kumar Inna */ 1962216ce69cSPraveen Madhavan config_name = "On FLASH"; 1963a3667aaeSNaresh Kumar Inna mtype = FW_MEMTYPE_CF_FLASH; 19647cc16380SArvind Bhushan maddr = hw->chip_ops->chip_flash_cfg_addr(hw); 1965a3667aaeSNaresh Kumar Inna } else { 1966216ce69cSPraveen Madhavan config_name = path; 19675167865aSHariprasad Shenai mtype = FW_PARAMS_PARAM_Y_G(*fw_cfg_param); 19685167865aSHariprasad Shenai maddr = FW_PARAMS_PARAM_Z_G(*fw_cfg_param) << 16; 1969a3667aaeSNaresh Kumar Inna } 1970a3667aaeSNaresh Kumar Inna 1971216ce69cSPraveen Madhavan mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 1972216ce69cSPraveen Madhavan if (!mbp) { 1973216ce69cSPraveen Madhavan CSIO_INC_STATS(hw, n_err_nomem); 1974216ce69cSPraveen Madhavan return -ENOMEM; 1975216ce69cSPraveen Madhavan } 1976a3667aaeSNaresh Kumar Inna /* 1977216ce69cSPraveen Madhavan * Tell the firmware to process the indicated Configuration File. 1978216ce69cSPraveen Madhavan * If there are no errors and the caller has provided return value 1979216ce69cSPraveen Madhavan * pointers for the [fini] section version, checksum and computed 1980216ce69cSPraveen Madhavan * checksum, pass those back to the caller. 1981a3667aaeSNaresh Kumar Inna */ 1982216ce69cSPraveen Madhavan caps_cmd = (struct fw_caps_config_cmd *)(mbp->mb); 1983216ce69cSPraveen Madhavan CSIO_INIT_MBP(mbp, caps_cmd, CSIO_MB_DEFAULT_TMO, hw, NULL, 1); 1984216ce69cSPraveen Madhavan caps_cmd->op_to_write = 1985216ce69cSPraveen Madhavan htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) | 1986216ce69cSPraveen Madhavan FW_CMD_REQUEST_F | 1987216ce69cSPraveen Madhavan FW_CMD_READ_F); 1988216ce69cSPraveen Madhavan caps_cmd->cfvalid_to_len16 = 1989216ce69cSPraveen Madhavan htonl(FW_CAPS_CONFIG_CMD_CFVALID_F | 1990216ce69cSPraveen Madhavan FW_CAPS_CONFIG_CMD_MEMTYPE_CF_V(mtype) | 1991216ce69cSPraveen Madhavan FW_CAPS_CONFIG_CMD_MEMADDR64K_CF_V(maddr >> 16) | 1992216ce69cSPraveen Madhavan FW_LEN16(*caps_cmd)); 1993216ce69cSPraveen Madhavan 1994216ce69cSPraveen Madhavan if (csio_mb_issue(hw, mbp)) { 1995216ce69cSPraveen Madhavan rv = -EINVAL; 1996216ce69cSPraveen Madhavan goto bye; 1997216ce69cSPraveen Madhavan } 1998216ce69cSPraveen Madhavan 1999216ce69cSPraveen Madhavan rv = csio_mb_fw_retval(mbp); 2000216ce69cSPraveen Madhavan /* If the CAPS_CONFIG failed with an ENOENT (for a Firmware 2001216ce69cSPraveen Madhavan * Configuration File in FLASH), our last gasp effort is to use the 2002216ce69cSPraveen Madhavan * Firmware Configuration File which is embedded in the 2003216ce69cSPraveen Madhavan * firmware. A very few early versions of the firmware didn't 2004216ce69cSPraveen Madhavan * have one embedded but we can ignore those. 2005216ce69cSPraveen Madhavan */ 2006216ce69cSPraveen Madhavan if (rv == ENOENT) { 2007216ce69cSPraveen Madhavan CSIO_INIT_MBP(mbp, caps_cmd, CSIO_MB_DEFAULT_TMO, hw, NULL, 1); 2008216ce69cSPraveen Madhavan caps_cmd->op_to_write = htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) | 2009216ce69cSPraveen Madhavan FW_CMD_REQUEST_F | 2010216ce69cSPraveen Madhavan FW_CMD_READ_F); 2011216ce69cSPraveen Madhavan caps_cmd->cfvalid_to_len16 = htonl(FW_LEN16(*caps_cmd)); 2012216ce69cSPraveen Madhavan 2013216ce69cSPraveen Madhavan if (csio_mb_issue(hw, mbp)) { 2014216ce69cSPraveen Madhavan rv = -EINVAL; 2015216ce69cSPraveen Madhavan goto bye; 2016216ce69cSPraveen Madhavan } 2017216ce69cSPraveen Madhavan 2018216ce69cSPraveen Madhavan rv = csio_mb_fw_retval(mbp); 2019216ce69cSPraveen Madhavan config_name = "Firmware Default"; 2020216ce69cSPraveen Madhavan } 2021216ce69cSPraveen Madhavan if (rv != FW_SUCCESS) 2022a3667aaeSNaresh Kumar Inna goto bye; 2023a3667aaeSNaresh Kumar Inna 2024216ce69cSPraveen Madhavan finiver = ntohl(caps_cmd->finiver); 2025216ce69cSPraveen Madhavan finicsum = ntohl(caps_cmd->finicsum); 2026216ce69cSPraveen Madhavan cfcsum = ntohl(caps_cmd->cfcsum); 2027a3667aaeSNaresh Kumar Inna 2028216ce69cSPraveen Madhavan /* 2029216ce69cSPraveen Madhavan * And now tell the firmware to use the configuration we just loaded. 2030216ce69cSPraveen Madhavan */ 2031216ce69cSPraveen Madhavan caps_cmd->op_to_write = 2032216ce69cSPraveen Madhavan htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) | 2033216ce69cSPraveen Madhavan FW_CMD_REQUEST_F | 2034216ce69cSPraveen Madhavan FW_CMD_WRITE_F); 2035216ce69cSPraveen Madhavan caps_cmd->cfvalid_to_len16 = htonl(FW_LEN16(*caps_cmd)); 2036216ce69cSPraveen Madhavan 2037216ce69cSPraveen Madhavan if (csio_mb_issue(hw, mbp)) { 2038216ce69cSPraveen Madhavan rv = -EINVAL; 2039216ce69cSPraveen Madhavan goto bye; 2040216ce69cSPraveen Madhavan } 2041216ce69cSPraveen Madhavan 2042216ce69cSPraveen Madhavan rv = csio_mb_fw_retval(mbp); 2043216ce69cSPraveen Madhavan if (rv != FW_SUCCESS) { 2044216ce69cSPraveen Madhavan csio_dbg(hw, "FW_CAPS_CONFIG_CMD returned %d!\n", rv); 2045216ce69cSPraveen Madhavan goto bye; 2046216ce69cSPraveen Madhavan } 2047216ce69cSPraveen Madhavan 2048a3667aaeSNaresh Kumar Inna if (finicsum != cfcsum) { 2049a3667aaeSNaresh Kumar Inna csio_warn(hw, 2050a3667aaeSNaresh Kumar Inna "Config File checksum mismatch: csum=%#x, computed=%#x\n", 2051a3667aaeSNaresh Kumar Inna finicsum, cfcsum); 2052a3667aaeSNaresh Kumar Inna } 2053a3667aaeSNaresh Kumar Inna 2054216ce69cSPraveen Madhavan /* Validate device capabilities */ 2055541c571fSPraveen Madhavan rv = csio_hw_validate_caps(hw, mbp); 2056541c571fSPraveen Madhavan if (rv != 0) 2057216ce69cSPraveen Madhavan goto bye; 2058a351e40bSVarun Prakash 2059a351e40bSVarun Prakash mempool_free(mbp, hw->mb_mempool); 2060a351e40bSVarun Prakash mbp = NULL; 2061a351e40bSVarun Prakash 2062a3667aaeSNaresh Kumar Inna /* 2063a3667aaeSNaresh Kumar Inna * Note that we're operating with parameters 2064a3667aaeSNaresh Kumar Inna * not supplied by the driver, rather than from hard-wired 2065a3667aaeSNaresh Kumar Inna * initialization constants buried in the driver. 2066a3667aaeSNaresh Kumar Inna */ 2067a3667aaeSNaresh Kumar Inna hw->flags |= CSIO_HWF_USING_SOFT_PARAMS; 2068a3667aaeSNaresh Kumar Inna 2069a3667aaeSNaresh Kumar Inna /* device parameters */ 2070a3667aaeSNaresh Kumar Inna rv = csio_get_device_params(hw); 2071a3667aaeSNaresh Kumar Inna if (rv != 0) 2072a3667aaeSNaresh Kumar Inna goto bye; 2073a3667aaeSNaresh Kumar Inna 2074a3667aaeSNaresh Kumar Inna /* Configure SGE */ 2075a3667aaeSNaresh Kumar Inna csio_wr_sge_init(hw); 2076a3667aaeSNaresh Kumar Inna 2077a3667aaeSNaresh Kumar Inna /* 2078a3667aaeSNaresh Kumar Inna * And finally tell the firmware to initialize itself using the 2079a3667aaeSNaresh Kumar Inna * parameters from the Configuration File. 2080a3667aaeSNaresh Kumar Inna */ 2081a3667aaeSNaresh Kumar Inna /* Post event to notify completion of configuration */ 2082a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_INIT); 2083a3667aaeSNaresh Kumar Inna 2084216ce69cSPraveen Madhavan csio_info(hw, "Successfully configure using Firmware " 2085216ce69cSPraveen Madhavan "Configuration File %s, version %#x, computed checksum %#x\n", 2086216ce69cSPraveen Madhavan config_name, finiver, cfcsum); 2087a3667aaeSNaresh Kumar Inna return 0; 2088a3667aaeSNaresh Kumar Inna 2089a3667aaeSNaresh Kumar Inna /* 2090a3667aaeSNaresh Kumar Inna * Something bad happened. Return the error ... 2091a3667aaeSNaresh Kumar Inna */ 2092a3667aaeSNaresh Kumar Inna bye: 2093216ce69cSPraveen Madhavan if (mbp) 2094216ce69cSPraveen Madhavan mempool_free(mbp, hw->mb_mempool); 2095a3667aaeSNaresh Kumar Inna hw->flags &= ~CSIO_HWF_USING_SOFT_PARAMS; 2096216ce69cSPraveen Madhavan csio_warn(hw, "Configuration file error %d\n", rv); 2097a3667aaeSNaresh Kumar Inna return rv; 2098a3667aaeSNaresh Kumar Inna } 2099a3667aaeSNaresh Kumar Inna 2100f40e74ffSPraveen Madhavan /* Is the given firmware API compatible with the one the driver was compiled 2101f40e74ffSPraveen Madhavan * with? 2102f40e74ffSPraveen Madhavan */ 2103f40e74ffSPraveen Madhavan static int fw_compatible(const struct fw_hdr *hdr1, const struct fw_hdr *hdr2) 2104f40e74ffSPraveen Madhavan { 2105f40e74ffSPraveen Madhavan 2106f40e74ffSPraveen Madhavan /* short circuit if it's the exact same firmware version */ 2107f40e74ffSPraveen Madhavan if (hdr1->chip == hdr2->chip && hdr1->fw_ver == hdr2->fw_ver) 2108f40e74ffSPraveen Madhavan return 1; 2109f40e74ffSPraveen Madhavan 2110f40e74ffSPraveen Madhavan #define SAME_INTF(x) (hdr1->intfver_##x == hdr2->intfver_##x) 2111f40e74ffSPraveen Madhavan if (hdr1->chip == hdr2->chip && SAME_INTF(nic) && SAME_INTF(vnic) && 2112f40e74ffSPraveen Madhavan SAME_INTF(ri) && SAME_INTF(iscsi) && SAME_INTF(fcoe)) 2113f40e74ffSPraveen Madhavan return 1; 2114f40e74ffSPraveen Madhavan #undef SAME_INTF 2115f40e74ffSPraveen Madhavan 2116f40e74ffSPraveen Madhavan return 0; 2117f40e74ffSPraveen Madhavan } 2118f40e74ffSPraveen Madhavan 2119f40e74ffSPraveen Madhavan /* The firmware in the filesystem is usable, but should it be installed? 2120f40e74ffSPraveen Madhavan * This routine explains itself in detail if it indicates the filesystem 2121f40e74ffSPraveen Madhavan * firmware should be installed. 2122f40e74ffSPraveen Madhavan */ 2123f40e74ffSPraveen Madhavan static int csio_should_install_fs_fw(struct csio_hw *hw, int card_fw_usable, 2124f40e74ffSPraveen Madhavan int k, int c) 2125f40e74ffSPraveen Madhavan { 2126f40e74ffSPraveen Madhavan const char *reason; 2127f40e74ffSPraveen Madhavan 2128f40e74ffSPraveen Madhavan if (!card_fw_usable) { 2129f40e74ffSPraveen Madhavan reason = "incompatible or unusable"; 2130f40e74ffSPraveen Madhavan goto install; 2131f40e74ffSPraveen Madhavan } 2132f40e74ffSPraveen Madhavan 2133f40e74ffSPraveen Madhavan if (k > c) { 2134f40e74ffSPraveen Madhavan reason = "older than the version supported with this driver"; 2135f40e74ffSPraveen Madhavan goto install; 2136f40e74ffSPraveen Madhavan } 2137f40e74ffSPraveen Madhavan 2138f40e74ffSPraveen Madhavan return 0; 2139f40e74ffSPraveen Madhavan 2140f40e74ffSPraveen Madhavan install: 2141f40e74ffSPraveen Madhavan csio_err(hw, "firmware on card (%u.%u.%u.%u) is %s, " 2142f40e74ffSPraveen Madhavan "installing firmware %u.%u.%u.%u on card.\n", 2143f40e74ffSPraveen Madhavan FW_HDR_FW_VER_MAJOR_G(c), FW_HDR_FW_VER_MINOR_G(c), 2144f40e74ffSPraveen Madhavan FW_HDR_FW_VER_MICRO_G(c), FW_HDR_FW_VER_BUILD_G(c), reason, 2145f40e74ffSPraveen Madhavan FW_HDR_FW_VER_MAJOR_G(k), FW_HDR_FW_VER_MINOR_G(k), 2146f40e74ffSPraveen Madhavan FW_HDR_FW_VER_MICRO_G(k), FW_HDR_FW_VER_BUILD_G(k)); 2147f40e74ffSPraveen Madhavan 2148f40e74ffSPraveen Madhavan return 1; 2149f40e74ffSPraveen Madhavan } 2150f40e74ffSPraveen Madhavan 2151f40e74ffSPraveen Madhavan static struct fw_info fw_info_array[] = { 2152f40e74ffSPraveen Madhavan { 2153f40e74ffSPraveen Madhavan .chip = CHELSIO_T5, 2154f40e74ffSPraveen Madhavan .fs_name = FW_CFG_NAME_T5, 2155f40e74ffSPraveen Madhavan .fw_mod_name = FW_FNAME_T5, 2156f40e74ffSPraveen Madhavan .fw_hdr = { 2157f40e74ffSPraveen Madhavan .chip = FW_HDR_CHIP_T5, 2158f40e74ffSPraveen Madhavan .fw_ver = __cpu_to_be32(FW_VERSION(T5)), 2159f40e74ffSPraveen Madhavan .intfver_nic = FW_INTFVER(T5, NIC), 2160f40e74ffSPraveen Madhavan .intfver_vnic = FW_INTFVER(T5, VNIC), 2161f40e74ffSPraveen Madhavan .intfver_ri = FW_INTFVER(T5, RI), 2162f40e74ffSPraveen Madhavan .intfver_iscsi = FW_INTFVER(T5, ISCSI), 2163f40e74ffSPraveen Madhavan .intfver_fcoe = FW_INTFVER(T5, FCOE), 2164f40e74ffSPraveen Madhavan }, 21654bbd458eSVarun Prakash }, { 21664bbd458eSVarun Prakash .chip = CHELSIO_T6, 21674bbd458eSVarun Prakash .fs_name = FW_CFG_NAME_T6, 21684bbd458eSVarun Prakash .fw_mod_name = FW_FNAME_T6, 21694bbd458eSVarun Prakash .fw_hdr = { 21704bbd458eSVarun Prakash .chip = FW_HDR_CHIP_T6, 21714bbd458eSVarun Prakash .fw_ver = __cpu_to_be32(FW_VERSION(T6)), 21724bbd458eSVarun Prakash .intfver_nic = FW_INTFVER(T6, NIC), 21734bbd458eSVarun Prakash .intfver_vnic = FW_INTFVER(T6, VNIC), 21744bbd458eSVarun Prakash .intfver_ri = FW_INTFVER(T6, RI), 21754bbd458eSVarun Prakash .intfver_iscsi = FW_INTFVER(T6, ISCSI), 21764bbd458eSVarun Prakash .intfver_fcoe = FW_INTFVER(T6, FCOE), 21774bbd458eSVarun Prakash }, 2178f40e74ffSPraveen Madhavan } 2179f40e74ffSPraveen Madhavan }; 2180f40e74ffSPraveen Madhavan 2181f40e74ffSPraveen Madhavan static struct fw_info *find_fw_info(int chip) 2182f40e74ffSPraveen Madhavan { 2183f40e74ffSPraveen Madhavan int i; 2184f40e74ffSPraveen Madhavan 2185f40e74ffSPraveen Madhavan for (i = 0; i < ARRAY_SIZE(fw_info_array); i++) { 2186f40e74ffSPraveen Madhavan if (fw_info_array[i].chip == chip) 2187f40e74ffSPraveen Madhavan return &fw_info_array[i]; 2188f40e74ffSPraveen Madhavan } 2189f40e74ffSPraveen Madhavan return NULL; 2190f40e74ffSPraveen Madhavan } 2191f40e74ffSPraveen Madhavan 219278890ed7SPraveen Madhavan static int csio_hw_prep_fw(struct csio_hw *hw, struct fw_info *fw_info, 2193f40e74ffSPraveen Madhavan const u8 *fw_data, unsigned int fw_size, 2194f40e74ffSPraveen Madhavan struct fw_hdr *card_fw, enum csio_dev_state state, 2195f40e74ffSPraveen Madhavan int *reset) 2196f40e74ffSPraveen Madhavan { 2197f40e74ffSPraveen Madhavan int ret, card_fw_usable, fs_fw_usable; 2198f40e74ffSPraveen Madhavan const struct fw_hdr *fs_fw; 2199f40e74ffSPraveen Madhavan const struct fw_hdr *drv_fw; 2200f40e74ffSPraveen Madhavan 2201f40e74ffSPraveen Madhavan drv_fw = &fw_info->fw_hdr; 2202f40e74ffSPraveen Madhavan 2203f40e74ffSPraveen Madhavan /* Read the header of the firmware on the card */ 2204f40e74ffSPraveen Madhavan ret = csio_hw_read_flash(hw, FLASH_FW_START, 2205f40e74ffSPraveen Madhavan sizeof(*card_fw) / sizeof(uint32_t), 2206f40e74ffSPraveen Madhavan (uint32_t *)card_fw, 1); 2207f40e74ffSPraveen Madhavan if (ret == 0) { 2208f40e74ffSPraveen Madhavan card_fw_usable = fw_compatible(drv_fw, (const void *)card_fw); 2209f40e74ffSPraveen Madhavan } else { 2210f40e74ffSPraveen Madhavan csio_err(hw, 2211f40e74ffSPraveen Madhavan "Unable to read card's firmware header: %d\n", ret); 2212f40e74ffSPraveen Madhavan card_fw_usable = 0; 2213f40e74ffSPraveen Madhavan } 2214f40e74ffSPraveen Madhavan 2215f40e74ffSPraveen Madhavan if (fw_data != NULL) { 2216f40e74ffSPraveen Madhavan fs_fw = (const void *)fw_data; 2217f40e74ffSPraveen Madhavan fs_fw_usable = fw_compatible(drv_fw, fs_fw); 2218f40e74ffSPraveen Madhavan } else { 2219f40e74ffSPraveen Madhavan fs_fw = NULL; 2220f40e74ffSPraveen Madhavan fs_fw_usable = 0; 2221f40e74ffSPraveen Madhavan } 2222f40e74ffSPraveen Madhavan 2223f40e74ffSPraveen Madhavan if (card_fw_usable && card_fw->fw_ver == drv_fw->fw_ver && 2224f40e74ffSPraveen Madhavan (!fs_fw_usable || fs_fw->fw_ver == drv_fw->fw_ver)) { 2225f40e74ffSPraveen Madhavan /* Common case: the firmware on the card is an exact match and 2226f40e74ffSPraveen Madhavan * the filesystem one is an exact match too, or the filesystem 2227f40e74ffSPraveen Madhavan * one is absent/incompatible. 2228f40e74ffSPraveen Madhavan */ 2229f40e74ffSPraveen Madhavan } else if (fs_fw_usable && state == CSIO_DEV_STATE_UNINIT && 2230f40e74ffSPraveen Madhavan csio_should_install_fs_fw(hw, card_fw_usable, 2231f40e74ffSPraveen Madhavan be32_to_cpu(fs_fw->fw_ver), 2232f40e74ffSPraveen Madhavan be32_to_cpu(card_fw->fw_ver))) { 2233f40e74ffSPraveen Madhavan ret = csio_hw_fw_upgrade(hw, hw->pfn, fw_data, 2234f40e74ffSPraveen Madhavan fw_size, 0); 2235f40e74ffSPraveen Madhavan if (ret != 0) { 2236f40e74ffSPraveen Madhavan csio_err(hw, 2237f40e74ffSPraveen Madhavan "failed to install firmware: %d\n", ret); 2238f40e74ffSPraveen Madhavan goto bye; 2239f40e74ffSPraveen Madhavan } 2240f40e74ffSPraveen Madhavan 2241f40e74ffSPraveen Madhavan /* Installed successfully, update the cached header too. */ 2242f40e74ffSPraveen Madhavan memcpy(card_fw, fs_fw, sizeof(*card_fw)); 2243f40e74ffSPraveen Madhavan card_fw_usable = 1; 2244f40e74ffSPraveen Madhavan *reset = 0; /* already reset as part of load_fw */ 2245f40e74ffSPraveen Madhavan } 2246f40e74ffSPraveen Madhavan 2247f40e74ffSPraveen Madhavan if (!card_fw_usable) { 2248f40e74ffSPraveen Madhavan uint32_t d, c, k; 2249f40e74ffSPraveen Madhavan 2250f40e74ffSPraveen Madhavan d = be32_to_cpu(drv_fw->fw_ver); 2251f40e74ffSPraveen Madhavan c = be32_to_cpu(card_fw->fw_ver); 2252f40e74ffSPraveen Madhavan k = fs_fw ? be32_to_cpu(fs_fw->fw_ver) : 0; 2253f40e74ffSPraveen Madhavan 2254f40e74ffSPraveen Madhavan csio_err(hw, "Cannot find a usable firmware: " 2255f40e74ffSPraveen Madhavan "chip state %d, " 2256f40e74ffSPraveen Madhavan "driver compiled with %d.%d.%d.%d, " 2257f40e74ffSPraveen Madhavan "card has %d.%d.%d.%d, filesystem has %d.%d.%d.%d\n", 2258f40e74ffSPraveen Madhavan state, 2259f40e74ffSPraveen Madhavan FW_HDR_FW_VER_MAJOR_G(d), FW_HDR_FW_VER_MINOR_G(d), 2260f40e74ffSPraveen Madhavan FW_HDR_FW_VER_MICRO_G(d), FW_HDR_FW_VER_BUILD_G(d), 2261f40e74ffSPraveen Madhavan FW_HDR_FW_VER_MAJOR_G(c), FW_HDR_FW_VER_MINOR_G(c), 2262f40e74ffSPraveen Madhavan FW_HDR_FW_VER_MICRO_G(c), FW_HDR_FW_VER_BUILD_G(c), 2263f40e74ffSPraveen Madhavan FW_HDR_FW_VER_MAJOR_G(k), FW_HDR_FW_VER_MINOR_G(k), 2264f40e74ffSPraveen Madhavan FW_HDR_FW_VER_MICRO_G(k), FW_HDR_FW_VER_BUILD_G(k)); 2265f40e74ffSPraveen Madhavan ret = EINVAL; 2266f40e74ffSPraveen Madhavan goto bye; 2267f40e74ffSPraveen Madhavan } 2268f40e74ffSPraveen Madhavan 2269f40e74ffSPraveen Madhavan /* We're using whatever's on the card and it's known to be good. */ 2270f40e74ffSPraveen Madhavan hw->fwrev = be32_to_cpu(card_fw->fw_ver); 2271f40e74ffSPraveen Madhavan hw->tp_vers = be32_to_cpu(card_fw->tp_microcode_ver); 2272f40e74ffSPraveen Madhavan 2273f40e74ffSPraveen Madhavan bye: 2274f40e74ffSPraveen Madhavan return ret; 2275f40e74ffSPraveen Madhavan } 2276f40e74ffSPraveen Madhavan 2277a3667aaeSNaresh Kumar Inna /* 2278a3667aaeSNaresh Kumar Inna * Returns -EINVAL if attempts to flash the firmware failed 2279a3667aaeSNaresh Kumar Inna * else returns 0, 2280a3667aaeSNaresh Kumar Inna * if flashing was not attempted because the card had the 2281a3667aaeSNaresh Kumar Inna * latest firmware ECANCELED is returned 2282a3667aaeSNaresh Kumar Inna */ 2283a3667aaeSNaresh Kumar Inna static int 2284f40e74ffSPraveen Madhavan csio_hw_flash_fw(struct csio_hw *hw, int *reset) 2285a3667aaeSNaresh Kumar Inna { 2286a3667aaeSNaresh Kumar Inna int ret = -ECANCELED; 2287a3667aaeSNaresh Kumar Inna const struct firmware *fw; 2288f40e74ffSPraveen Madhavan struct fw_info *fw_info; 2289f40e74ffSPraveen Madhavan struct fw_hdr *card_fw; 2290a3667aaeSNaresh Kumar Inna struct pci_dev *pci_dev = hw->pdev; 2291a3667aaeSNaresh Kumar Inna struct device *dev = &pci_dev->dev ; 2292f40e74ffSPraveen Madhavan const u8 *fw_data = NULL; 2293f40e74ffSPraveen Madhavan unsigned int fw_size = 0; 22944bbd458eSVarun Prakash const char *fw_bin_file; 2295f40e74ffSPraveen Madhavan 2296f40e74ffSPraveen Madhavan /* This is the firmware whose headers the driver was compiled 2297f40e74ffSPraveen Madhavan * against 2298f40e74ffSPraveen Madhavan */ 2299f40e74ffSPraveen Madhavan fw_info = find_fw_info(CHELSIO_CHIP_VERSION(hw->chip_id)); 2300f40e74ffSPraveen Madhavan if (fw_info == NULL) { 2301f40e74ffSPraveen Madhavan csio_err(hw, 2302f40e74ffSPraveen Madhavan "unable to get firmware info for chip %d.\n", 2303f40e74ffSPraveen Madhavan CHELSIO_CHIP_VERSION(hw->chip_id)); 2304f40e74ffSPraveen Madhavan return -EINVAL; 2305f40e74ffSPraveen Madhavan } 2306a3667aaeSNaresh Kumar Inna 23074bbd458eSVarun Prakash if (csio_is_t5(pci_dev->device & CSIO_HW_CHIP_MASK)) 23084bbd458eSVarun Prakash fw_bin_file = FW_FNAME_T5; 23094bbd458eSVarun Prakash else 23104bbd458eSVarun Prakash fw_bin_file = FW_FNAME_T6; 23114bbd458eSVarun Prakash 23124bbd458eSVarun Prakash if (request_firmware(&fw, fw_bin_file, dev) < 0) { 23137cc16380SArvind Bhushan csio_err(hw, "could not find firmware image %s, err: %d\n", 23144bbd458eSVarun Prakash fw_bin_file, ret); 2315216ce69cSPraveen Madhavan } else { 2316216ce69cSPraveen Madhavan fw_data = fw->data; 2317216ce69cSPraveen Madhavan fw_size = fw->size; 2318a3667aaeSNaresh Kumar Inna } 2319a3667aaeSNaresh Kumar Inna 2320f40e74ffSPraveen Madhavan /* allocate memory to read the header of the firmware on the 2321f40e74ffSPraveen Madhavan * card 2322a3667aaeSNaresh Kumar Inna */ 2323f40e74ffSPraveen Madhavan card_fw = kmalloc(sizeof(*card_fw), GFP_KERNEL); 2324a3667aaeSNaresh Kumar Inna 2325f40e74ffSPraveen Madhavan /* upgrade FW logic */ 2326f40e74ffSPraveen Madhavan ret = csio_hw_prep_fw(hw, fw_info, fw_data, fw_size, card_fw, 2327f40e74ffSPraveen Madhavan hw->fw_state, reset); 2328f40e74ffSPraveen Madhavan 2329f40e74ffSPraveen Madhavan /* Cleaning up */ 2330f40e74ffSPraveen Madhavan if (fw != NULL) 2331a3667aaeSNaresh Kumar Inna release_firmware(fw); 2332f40e74ffSPraveen Madhavan kfree(card_fw); 2333a3667aaeSNaresh Kumar Inna return ret; 2334a3667aaeSNaresh Kumar Inna } 2335a3667aaeSNaresh Kumar Inna 233696e6c633SVarun Prakash static int csio_hw_check_fwver(struct csio_hw *hw) 233796e6c633SVarun Prakash { 233896e6c633SVarun Prakash if (csio_is_t6(hw->pdev->device & CSIO_HW_CHIP_MASK) && 233996e6c633SVarun Prakash (hw->fwrev < CSIO_MIN_T6_FW)) { 234096e6c633SVarun Prakash csio_hw_print_fw_version(hw, "T6 unsupported fw"); 234196e6c633SVarun Prakash return -1; 234296e6c633SVarun Prakash } 234396e6c633SVarun Prakash 234496e6c633SVarun Prakash return 0; 234596e6c633SVarun Prakash } 234696e6c633SVarun Prakash 2347a3667aaeSNaresh Kumar Inna /* 2348a3667aaeSNaresh Kumar Inna * csio_hw_configure - Configure HW 2349a3667aaeSNaresh Kumar Inna * @hw - HW module 2350a3667aaeSNaresh Kumar Inna * 2351a3667aaeSNaresh Kumar Inna */ 2352a3667aaeSNaresh Kumar Inna static void 2353a3667aaeSNaresh Kumar Inna csio_hw_configure(struct csio_hw *hw) 2354a3667aaeSNaresh Kumar Inna { 2355a3667aaeSNaresh Kumar Inna int reset = 1; 2356a3667aaeSNaresh Kumar Inna int rv; 2357a3667aaeSNaresh Kumar Inna u32 param[1]; 2358a3667aaeSNaresh Kumar Inna 2359a3667aaeSNaresh Kumar Inna rv = csio_hw_dev_ready(hw); 2360a3667aaeSNaresh Kumar Inna if (rv != 0) { 2361a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_fatal); 2362a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_FATAL); 2363a3667aaeSNaresh Kumar Inna goto out; 2364a3667aaeSNaresh Kumar Inna } 2365a3667aaeSNaresh Kumar Inna 2366a3667aaeSNaresh Kumar Inna /* HW version */ 23670d804338SHariprasad Shenai hw->chip_ver = (char)csio_rd_reg32(hw, PL_REV_A); 2368a3667aaeSNaresh Kumar Inna 2369a3667aaeSNaresh Kumar Inna /* Needed for FW download */ 2370a3667aaeSNaresh Kumar Inna rv = csio_hw_get_flash_params(hw); 2371a3667aaeSNaresh Kumar Inna if (rv != 0) { 2372a3667aaeSNaresh Kumar Inna csio_err(hw, "Failed to get serial flash params rv:%d\n", rv); 2373a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_FATAL); 2374a3667aaeSNaresh Kumar Inna goto out; 2375a3667aaeSNaresh Kumar Inna } 2376a3667aaeSNaresh Kumar Inna 2377ad4d35f8SYijing Wang /* Set PCIe completion timeout to 4 seconds */ 2378ad4d35f8SYijing Wang if (pci_is_pcie(hw->pdev)) 2379ad4d35f8SYijing Wang pcie_capability_clear_and_set_word(hw->pdev, PCI_EXP_DEVCTL2, 2380ad4d35f8SYijing Wang PCI_EXP_DEVCTL2_COMP_TIMEOUT, 0xd); 2381a3667aaeSNaresh Kumar Inna 23827cc16380SArvind Bhushan hw->chip_ops->chip_set_mem_win(hw, MEMWIN_CSIOSTOR); 2383a3667aaeSNaresh Kumar Inna 2384a3667aaeSNaresh Kumar Inna rv = csio_hw_get_fw_version(hw, &hw->fwrev); 2385a3667aaeSNaresh Kumar Inna if (rv != 0) 2386a3667aaeSNaresh Kumar Inna goto out; 2387a3667aaeSNaresh Kumar Inna 2388a3667aaeSNaresh Kumar Inna csio_hw_print_fw_version(hw, "Firmware revision"); 2389a3667aaeSNaresh Kumar Inna 2390a3667aaeSNaresh Kumar Inna rv = csio_do_hello(hw, &hw->fw_state); 2391a3667aaeSNaresh Kumar Inna if (rv != 0) { 2392a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_err_fatal); 2393a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_FATAL); 2394a3667aaeSNaresh Kumar Inna goto out; 2395a3667aaeSNaresh Kumar Inna } 2396a3667aaeSNaresh Kumar Inna 2397a3667aaeSNaresh Kumar Inna /* Read vpd */ 2398a3667aaeSNaresh Kumar Inna rv = csio_hw_get_vpd_params(hw, &hw->vpd); 2399a3667aaeSNaresh Kumar Inna if (rv != 0) 2400a3667aaeSNaresh Kumar Inna goto out; 2401a3667aaeSNaresh Kumar Inna 2402f40e74ffSPraveen Madhavan csio_hw_get_fw_version(hw, &hw->fwrev); 2403f40e74ffSPraveen Madhavan csio_hw_get_tp_version(hw, &hw->tp_vers); 2404a3667aaeSNaresh Kumar Inna if (csio_is_hw_master(hw) && hw->fw_state != CSIO_DEV_STATE_INIT) { 2405a3667aaeSNaresh Kumar Inna 2406a3667aaeSNaresh Kumar Inna /* Do firmware update */ 2407a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 2408f40e74ffSPraveen Madhavan rv = csio_hw_flash_fw(hw, &reset); 2409a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 2410a3667aaeSNaresh Kumar Inna 2411f40e74ffSPraveen Madhavan if (rv != 0) 2412f40e74ffSPraveen Madhavan goto out; 2413f40e74ffSPraveen Madhavan 241496e6c633SVarun Prakash rv = csio_hw_check_fwver(hw); 241596e6c633SVarun Prakash if (rv < 0) 241696e6c633SVarun Prakash goto out; 241796e6c633SVarun Prakash 2418216ce69cSPraveen Madhavan /* If the firmware doesn't support Configuration Files, 2419216ce69cSPraveen Madhavan * return an error. 2420a3667aaeSNaresh Kumar Inna */ 2421216ce69cSPraveen Madhavan rv = csio_hw_check_fwconfig(hw, param); 2422a3667aaeSNaresh Kumar Inna if (rv != 0) { 2423216ce69cSPraveen Madhavan csio_info(hw, "Firmware doesn't support " 2424216ce69cSPraveen Madhavan "Firmware Configuration files\n"); 2425216ce69cSPraveen Madhavan goto out; 2426a3667aaeSNaresh Kumar Inna } 2427a3667aaeSNaresh Kumar Inna 2428216ce69cSPraveen Madhavan /* The firmware provides us with a memory buffer where we can 2429216ce69cSPraveen Madhavan * load a Configuration File from the host if we want to 2430216ce69cSPraveen Madhavan * override the Configuration File in flash. 2431216ce69cSPraveen Madhavan */ 2432216ce69cSPraveen Madhavan rv = csio_hw_use_fwconfig(hw, reset, param); 2433216ce69cSPraveen Madhavan if (rv == -ENOENT) { 2434216ce69cSPraveen Madhavan csio_info(hw, "Could not initialize " 2435216ce69cSPraveen Madhavan "adapter, error%d\n", rv); 2436a3667aaeSNaresh Kumar Inna goto out; 2437216ce69cSPraveen Madhavan } 2438216ce69cSPraveen Madhavan if (rv != 0) { 2439216ce69cSPraveen Madhavan csio_info(hw, "Could not initialize " 2440216ce69cSPraveen Madhavan "adapter, error%d\n", rv); 2441216ce69cSPraveen Madhavan goto out; 2442216ce69cSPraveen Madhavan } 2443a3667aaeSNaresh Kumar Inna 2444a3667aaeSNaresh Kumar Inna } else { 244596e6c633SVarun Prakash rv = csio_hw_check_fwver(hw); 244696e6c633SVarun Prakash if (rv < 0) 244796e6c633SVarun Prakash goto out; 244896e6c633SVarun Prakash 2449a3667aaeSNaresh Kumar Inna if (hw->fw_state == CSIO_DEV_STATE_INIT) { 2450a3667aaeSNaresh Kumar Inna 24517cc16380SArvind Bhushan hw->flags |= CSIO_HWF_USING_SOFT_PARAMS; 24527cc16380SArvind Bhushan 2453a3667aaeSNaresh Kumar Inna /* device parameters */ 2454a3667aaeSNaresh Kumar Inna rv = csio_get_device_params(hw); 2455a3667aaeSNaresh Kumar Inna if (rv != 0) 2456a3667aaeSNaresh Kumar Inna goto out; 2457a3667aaeSNaresh Kumar Inna 2458a3667aaeSNaresh Kumar Inna /* Get device capabilities */ 2459a3667aaeSNaresh Kumar Inna rv = csio_config_device_caps(hw); 2460a3667aaeSNaresh Kumar Inna if (rv != 0) 2461a3667aaeSNaresh Kumar Inna goto out; 2462a3667aaeSNaresh Kumar Inna 2463a3667aaeSNaresh Kumar Inna /* Configure SGE */ 2464a3667aaeSNaresh Kumar Inna csio_wr_sge_init(hw); 2465a3667aaeSNaresh Kumar Inna 2466a3667aaeSNaresh Kumar Inna /* Post event to notify completion of configuration */ 2467a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_INIT); 2468a3667aaeSNaresh Kumar Inna goto out; 2469a3667aaeSNaresh Kumar Inna } 2470a3667aaeSNaresh Kumar Inna } /* if not master */ 2471a3667aaeSNaresh Kumar Inna 2472a3667aaeSNaresh Kumar Inna out: 2473a3667aaeSNaresh Kumar Inna return; 2474a3667aaeSNaresh Kumar Inna } 2475a3667aaeSNaresh Kumar Inna 2476a3667aaeSNaresh Kumar Inna /* 2477a3667aaeSNaresh Kumar Inna * csio_hw_initialize - Initialize HW 2478a3667aaeSNaresh Kumar Inna * @hw - HW module 2479a3667aaeSNaresh Kumar Inna * 2480a3667aaeSNaresh Kumar Inna */ 2481a3667aaeSNaresh Kumar Inna static void 2482a3667aaeSNaresh Kumar Inna csio_hw_initialize(struct csio_hw *hw) 2483a3667aaeSNaresh Kumar Inna { 2484a3667aaeSNaresh Kumar Inna struct csio_mb *mbp; 2485a3667aaeSNaresh Kumar Inna enum fw_retval retval; 2486a3667aaeSNaresh Kumar Inna int rv; 2487a3667aaeSNaresh Kumar Inna int i; 2488a3667aaeSNaresh Kumar Inna 2489a3667aaeSNaresh Kumar Inna if (csio_is_hw_master(hw) && hw->fw_state != CSIO_DEV_STATE_INIT) { 2490a3667aaeSNaresh Kumar Inna mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 2491a3667aaeSNaresh Kumar Inna if (!mbp) 2492a3667aaeSNaresh Kumar Inna goto out; 2493a3667aaeSNaresh Kumar Inna 2494a3667aaeSNaresh Kumar Inna csio_mb_initialize(hw, mbp, CSIO_MB_DEFAULT_TMO, NULL); 2495a3667aaeSNaresh Kumar Inna 2496a3667aaeSNaresh Kumar Inna if (csio_mb_issue(hw, mbp)) { 2497a3667aaeSNaresh Kumar Inna csio_err(hw, "Issue of FW_INITIALIZE_CMD failed!\n"); 2498a3667aaeSNaresh Kumar Inna goto free_and_out; 2499a3667aaeSNaresh Kumar Inna } 2500a3667aaeSNaresh Kumar Inna 2501a3667aaeSNaresh Kumar Inna retval = csio_mb_fw_retval(mbp); 2502a3667aaeSNaresh Kumar Inna if (retval != FW_SUCCESS) { 2503a3667aaeSNaresh Kumar Inna csio_err(hw, "FW_INITIALIZE_CMD returned 0x%x!\n", 2504a3667aaeSNaresh Kumar Inna retval); 2505a3667aaeSNaresh Kumar Inna goto free_and_out; 2506a3667aaeSNaresh Kumar Inna } 2507a3667aaeSNaresh Kumar Inna 2508a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 2509a3667aaeSNaresh Kumar Inna } 2510a3667aaeSNaresh Kumar Inna 2511a3667aaeSNaresh Kumar Inna rv = csio_get_fcoe_resinfo(hw); 2512a3667aaeSNaresh Kumar Inna if (rv != 0) { 2513a3667aaeSNaresh Kumar Inna csio_err(hw, "Failed to read fcoe resource info: %d\n", rv); 2514a3667aaeSNaresh Kumar Inna goto out; 2515a3667aaeSNaresh Kumar Inna } 2516a3667aaeSNaresh Kumar Inna 2517a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 2518a3667aaeSNaresh Kumar Inna rv = csio_config_queues(hw); 2519a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 2520a3667aaeSNaresh Kumar Inna 2521a3667aaeSNaresh Kumar Inna if (rv != 0) { 2522a3667aaeSNaresh Kumar Inna csio_err(hw, "Config of queues failed!: %d\n", rv); 2523a3667aaeSNaresh Kumar Inna goto out; 2524a3667aaeSNaresh Kumar Inna } 2525a3667aaeSNaresh Kumar Inna 2526a3667aaeSNaresh Kumar Inna for (i = 0; i < hw->num_pports; i++) 2527a3667aaeSNaresh Kumar Inna hw->pport[i].mod_type = FW_PORT_MOD_TYPE_NA; 2528a3667aaeSNaresh Kumar Inna 2529a3667aaeSNaresh Kumar Inna if (csio_is_hw_master(hw) && hw->fw_state != CSIO_DEV_STATE_INIT) { 2530a3667aaeSNaresh Kumar Inna rv = csio_enable_ports(hw); 2531a3667aaeSNaresh Kumar Inna if (rv != 0) { 2532a3667aaeSNaresh Kumar Inna csio_err(hw, "Failed to enable ports: %d\n", rv); 2533a3667aaeSNaresh Kumar Inna goto out; 2534a3667aaeSNaresh Kumar Inna } 2535a3667aaeSNaresh Kumar Inna } 2536a3667aaeSNaresh Kumar Inna 2537a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_INIT_DONE); 2538a3667aaeSNaresh Kumar Inna return; 2539a3667aaeSNaresh Kumar Inna 2540a3667aaeSNaresh Kumar Inna free_and_out: 2541a3667aaeSNaresh Kumar Inna mempool_free(mbp, hw->mb_mempool); 2542a3667aaeSNaresh Kumar Inna out: 2543a3667aaeSNaresh Kumar Inna return; 2544a3667aaeSNaresh Kumar Inna } 2545a3667aaeSNaresh Kumar Inna 25460d804338SHariprasad Shenai #define PF_INTR_MASK (PFSW_F | PFCIM_F) 2547a3667aaeSNaresh Kumar Inna 2548a3667aaeSNaresh Kumar Inna /* 2549a3667aaeSNaresh Kumar Inna * csio_hw_intr_enable - Enable HW interrupts 2550a3667aaeSNaresh Kumar Inna * @hw: Pointer to HW module. 2551a3667aaeSNaresh Kumar Inna * 2552a3667aaeSNaresh Kumar Inna * Enable interrupts in HW registers. 2553a3667aaeSNaresh Kumar Inna */ 2554a3667aaeSNaresh Kumar Inna static void 2555a3667aaeSNaresh Kumar Inna csio_hw_intr_enable(struct csio_hw *hw) 2556a3667aaeSNaresh Kumar Inna { 2557a3667aaeSNaresh Kumar Inna uint16_t vec = (uint16_t)csio_get_mb_intr_idx(csio_hw_to_mbm(hw)); 25584bbd458eSVarun Prakash u32 pf = 0; 25590d804338SHariprasad Shenai uint32_t pl = csio_rd_reg32(hw, PL_INT_ENABLE_A); 2560a3667aaeSNaresh Kumar Inna 25614bbd458eSVarun Prakash if (csio_is_t5(hw->pdev->device & CSIO_HW_CHIP_MASK)) 25624bbd458eSVarun Prakash pf = SOURCEPF_G(csio_rd_reg32(hw, PL_WHOAMI_A)); 25634bbd458eSVarun Prakash else 25644bbd458eSVarun Prakash pf = T6_SOURCEPF_G(csio_rd_reg32(hw, PL_WHOAMI_A)); 25654bbd458eSVarun Prakash 2566a3667aaeSNaresh Kumar Inna /* 2567a3667aaeSNaresh Kumar Inna * Set aivec for MSI/MSIX. PCIE_PF_CFG.INTXType is set up 2568a3667aaeSNaresh Kumar Inna * by FW, so do nothing for INTX. 2569a3667aaeSNaresh Kumar Inna */ 2570a3667aaeSNaresh Kumar Inna if (hw->intr_mode == CSIO_IM_MSIX) 2571f061de42SHariprasad Shenai csio_set_reg_field(hw, MYPF_REG(PCIE_PF_CFG_A), 2572f061de42SHariprasad Shenai AIVEC_V(AIVEC_M), vec); 2573a3667aaeSNaresh Kumar Inna else if (hw->intr_mode == CSIO_IM_MSI) 2574f061de42SHariprasad Shenai csio_set_reg_field(hw, MYPF_REG(PCIE_PF_CFG_A), 2575f061de42SHariprasad Shenai AIVEC_V(AIVEC_M), 0); 2576a3667aaeSNaresh Kumar Inna 25770d804338SHariprasad Shenai csio_wr_reg32(hw, PF_INTR_MASK, MYPF_REG(PL_PF_INT_ENABLE_A)); 2578a3667aaeSNaresh Kumar Inna 2579a3667aaeSNaresh Kumar Inna /* Turn on MB interrupts - this will internally flush PIO as well */ 2580a3667aaeSNaresh Kumar Inna csio_mb_intr_enable(hw); 2581a3667aaeSNaresh Kumar Inna 2582a3667aaeSNaresh Kumar Inna /* These are common registers - only a master can modify them */ 2583a3667aaeSNaresh Kumar Inna if (csio_is_hw_master(hw)) { 2584a3667aaeSNaresh Kumar Inna /* 2585a3667aaeSNaresh Kumar Inna * Disable the Serial FLASH interrupt, if enabled! 2586a3667aaeSNaresh Kumar Inna */ 25870d804338SHariprasad Shenai pl &= (~SF_F); 25880d804338SHariprasad Shenai csio_wr_reg32(hw, pl, PL_INT_ENABLE_A); 2589a3667aaeSNaresh Kumar Inna 2590f612b815SHariprasad Shenai csio_wr_reg32(hw, ERR_CPL_EXCEED_IQE_SIZE_F | 2591f612b815SHariprasad Shenai EGRESS_SIZE_ERR_F | ERR_INVALID_CIDX_INC_F | 2592f612b815SHariprasad Shenai ERR_CPL_OPCODE_0_F | ERR_DROPPED_DB_F | 2593f612b815SHariprasad Shenai ERR_DATA_CPL_ON_HIGH_QID1_F | 2594f612b815SHariprasad Shenai ERR_DATA_CPL_ON_HIGH_QID0_F | ERR_BAD_DB_PIDX3_F | 2595f612b815SHariprasad Shenai ERR_BAD_DB_PIDX2_F | ERR_BAD_DB_PIDX1_F | 2596f612b815SHariprasad Shenai ERR_BAD_DB_PIDX0_F | ERR_ING_CTXT_PRIO_F | 2597f612b815SHariprasad Shenai ERR_EGR_CTXT_PRIO_F | INGRESS_SIZE_ERR_F, 2598f612b815SHariprasad Shenai SGE_INT_ENABLE3_A); 25990d804338SHariprasad Shenai csio_set_reg_field(hw, PL_INT_MAP0_A, 0, 1 << pf); 2600a3667aaeSNaresh Kumar Inna } 2601a3667aaeSNaresh Kumar Inna 2602a3667aaeSNaresh Kumar Inna hw->flags |= CSIO_HWF_HW_INTR_ENABLED; 2603a3667aaeSNaresh Kumar Inna 2604a3667aaeSNaresh Kumar Inna } 2605a3667aaeSNaresh Kumar Inna 2606a3667aaeSNaresh Kumar Inna /* 2607a3667aaeSNaresh Kumar Inna * csio_hw_intr_disable - Disable HW interrupts 2608a3667aaeSNaresh Kumar Inna * @hw: Pointer to HW module. 2609a3667aaeSNaresh Kumar Inna * 2610a3667aaeSNaresh Kumar Inna * Turn off Mailbox and PCI_PF_CFG interrupts. 2611a3667aaeSNaresh Kumar Inna */ 2612a3667aaeSNaresh Kumar Inna void 2613a3667aaeSNaresh Kumar Inna csio_hw_intr_disable(struct csio_hw *hw) 2614a3667aaeSNaresh Kumar Inna { 26154bbd458eSVarun Prakash u32 pf = 0; 26164bbd458eSVarun Prakash 26174bbd458eSVarun Prakash if (csio_is_t5(hw->pdev->device & CSIO_HW_CHIP_MASK)) 26184bbd458eSVarun Prakash pf = SOURCEPF_G(csio_rd_reg32(hw, PL_WHOAMI_A)); 26194bbd458eSVarun Prakash else 26204bbd458eSVarun Prakash pf = T6_SOURCEPF_G(csio_rd_reg32(hw, PL_WHOAMI_A)); 2621a3667aaeSNaresh Kumar Inna 2622a3667aaeSNaresh Kumar Inna if (!(hw->flags & CSIO_HWF_HW_INTR_ENABLED)) 2623a3667aaeSNaresh Kumar Inna return; 2624a3667aaeSNaresh Kumar Inna 2625a3667aaeSNaresh Kumar Inna hw->flags &= ~CSIO_HWF_HW_INTR_ENABLED; 2626a3667aaeSNaresh Kumar Inna 26270d804338SHariprasad Shenai csio_wr_reg32(hw, 0, MYPF_REG(PL_PF_INT_ENABLE_A)); 2628a3667aaeSNaresh Kumar Inna if (csio_is_hw_master(hw)) 26290d804338SHariprasad Shenai csio_set_reg_field(hw, PL_INT_MAP0_A, 1 << pf, 0); 2630a3667aaeSNaresh Kumar Inna 2631a3667aaeSNaresh Kumar Inna /* Turn off MB interrupts */ 2632a3667aaeSNaresh Kumar Inna csio_mb_intr_disable(hw); 2633a3667aaeSNaresh Kumar Inna 2634a3667aaeSNaresh Kumar Inna } 2635a3667aaeSNaresh Kumar Inna 26367cc16380SArvind Bhushan void 2637a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(struct csio_hw *hw) 2638a3667aaeSNaresh Kumar Inna { 2639f612b815SHariprasad Shenai csio_set_reg_field(hw, SGE_CONTROL_A, GLOBALENABLE_F, 0); 2640a3667aaeSNaresh Kumar Inna csio_hw_intr_disable(hw); 2641a3667aaeSNaresh Kumar Inna 2642a3667aaeSNaresh Kumar Inna /* Do not reset HW, we may need FW state for debugging */ 2643a3667aaeSNaresh Kumar Inna csio_fatal(hw, "HW Fatal error encountered!\n"); 2644a3667aaeSNaresh Kumar Inna } 2645a3667aaeSNaresh Kumar Inna 2646a3667aaeSNaresh Kumar Inna /*****************************************************************************/ 2647a3667aaeSNaresh Kumar Inna /* START: HW SM */ 2648a3667aaeSNaresh Kumar Inna /*****************************************************************************/ 2649a3667aaeSNaresh Kumar Inna /* 2650a3667aaeSNaresh Kumar Inna * csio_hws_uninit - Uninit state 2651a3667aaeSNaresh Kumar Inna * @hw - HW module 2652a3667aaeSNaresh Kumar Inna * @evt - Event 2653a3667aaeSNaresh Kumar Inna * 2654a3667aaeSNaresh Kumar Inna */ 2655a3667aaeSNaresh Kumar Inna static void 2656a3667aaeSNaresh Kumar Inna csio_hws_uninit(struct csio_hw *hw, enum csio_hw_ev evt) 2657a3667aaeSNaresh Kumar Inna { 2658a3667aaeSNaresh Kumar Inna hw->prev_evt = hw->cur_evt; 2659a3667aaeSNaresh Kumar Inna hw->cur_evt = evt; 2660a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_sm[evt]); 2661a3667aaeSNaresh Kumar Inna 2662a3667aaeSNaresh Kumar Inna switch (evt) { 2663a3667aaeSNaresh Kumar Inna case CSIO_HWE_CFG: 2664a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_configuring); 2665a3667aaeSNaresh Kumar Inna csio_hw_configure(hw); 2666a3667aaeSNaresh Kumar Inna break; 2667a3667aaeSNaresh Kumar Inna 2668a3667aaeSNaresh Kumar Inna default: 2669a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_unexp); 2670a3667aaeSNaresh Kumar Inna break; 2671a3667aaeSNaresh Kumar Inna } 2672a3667aaeSNaresh Kumar Inna } 2673a3667aaeSNaresh Kumar Inna 2674a3667aaeSNaresh Kumar Inna /* 2675a3667aaeSNaresh Kumar Inna * csio_hws_configuring - Configuring state 2676a3667aaeSNaresh Kumar Inna * @hw - HW module 2677a3667aaeSNaresh Kumar Inna * @evt - Event 2678a3667aaeSNaresh Kumar Inna * 2679a3667aaeSNaresh Kumar Inna */ 2680a3667aaeSNaresh Kumar Inna static void 2681a3667aaeSNaresh Kumar Inna csio_hws_configuring(struct csio_hw *hw, enum csio_hw_ev evt) 2682a3667aaeSNaresh Kumar Inna { 2683a3667aaeSNaresh Kumar Inna hw->prev_evt = hw->cur_evt; 2684a3667aaeSNaresh Kumar Inna hw->cur_evt = evt; 2685a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_sm[evt]); 2686a3667aaeSNaresh Kumar Inna 2687a3667aaeSNaresh Kumar Inna switch (evt) { 2688a3667aaeSNaresh Kumar Inna case CSIO_HWE_INIT: 2689a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_initializing); 2690a3667aaeSNaresh Kumar Inna csio_hw_initialize(hw); 2691a3667aaeSNaresh Kumar Inna break; 2692a3667aaeSNaresh Kumar Inna 2693a3667aaeSNaresh Kumar Inna case CSIO_HWE_INIT_DONE: 2694a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_ready); 2695a3667aaeSNaresh Kumar Inna /* Fan out event to all lnode SMs */ 2696a3667aaeSNaresh Kumar Inna csio_notify_lnodes(hw, CSIO_LN_NOTIFY_HWREADY); 2697a3667aaeSNaresh Kumar Inna break; 2698a3667aaeSNaresh Kumar Inna 2699a3667aaeSNaresh Kumar Inna case CSIO_HWE_FATAL: 2700a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_uninit); 2701a3667aaeSNaresh Kumar Inna break; 2702a3667aaeSNaresh Kumar Inna 2703a3667aaeSNaresh Kumar Inna case CSIO_HWE_PCI_REMOVE: 2704a3667aaeSNaresh Kumar Inna csio_do_bye(hw); 2705a3667aaeSNaresh Kumar Inna break; 2706a3667aaeSNaresh Kumar Inna default: 2707a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_unexp); 2708a3667aaeSNaresh Kumar Inna break; 2709a3667aaeSNaresh Kumar Inna } 2710a3667aaeSNaresh Kumar Inna } 2711a3667aaeSNaresh Kumar Inna 2712a3667aaeSNaresh Kumar Inna /* 2713a3667aaeSNaresh Kumar Inna * csio_hws_initializing - Initialiazing state 2714a3667aaeSNaresh Kumar Inna * @hw - HW module 2715a3667aaeSNaresh Kumar Inna * @evt - Event 2716a3667aaeSNaresh Kumar Inna * 2717a3667aaeSNaresh Kumar Inna */ 2718a3667aaeSNaresh Kumar Inna static void 2719a3667aaeSNaresh Kumar Inna csio_hws_initializing(struct csio_hw *hw, enum csio_hw_ev evt) 2720a3667aaeSNaresh Kumar Inna { 2721a3667aaeSNaresh Kumar Inna hw->prev_evt = hw->cur_evt; 2722a3667aaeSNaresh Kumar Inna hw->cur_evt = evt; 2723a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_sm[evt]); 2724a3667aaeSNaresh Kumar Inna 2725a3667aaeSNaresh Kumar Inna switch (evt) { 2726a3667aaeSNaresh Kumar Inna case CSIO_HWE_INIT_DONE: 2727a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_ready); 2728a3667aaeSNaresh Kumar Inna 2729a3667aaeSNaresh Kumar Inna /* Fan out event to all lnode SMs */ 2730a3667aaeSNaresh Kumar Inna csio_notify_lnodes(hw, CSIO_LN_NOTIFY_HWREADY); 2731a3667aaeSNaresh Kumar Inna 2732a3667aaeSNaresh Kumar Inna /* Enable interrupts */ 2733a3667aaeSNaresh Kumar Inna csio_hw_intr_enable(hw); 2734a3667aaeSNaresh Kumar Inna break; 2735a3667aaeSNaresh Kumar Inna 2736a3667aaeSNaresh Kumar Inna case CSIO_HWE_FATAL: 2737a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_uninit); 2738a3667aaeSNaresh Kumar Inna break; 2739a3667aaeSNaresh Kumar Inna 2740a3667aaeSNaresh Kumar Inna case CSIO_HWE_PCI_REMOVE: 2741a3667aaeSNaresh Kumar Inna csio_do_bye(hw); 2742a3667aaeSNaresh Kumar Inna break; 2743a3667aaeSNaresh Kumar Inna 2744a3667aaeSNaresh Kumar Inna default: 2745a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_unexp); 2746a3667aaeSNaresh Kumar Inna break; 2747a3667aaeSNaresh Kumar Inna } 2748a3667aaeSNaresh Kumar Inna } 2749a3667aaeSNaresh Kumar Inna 2750a3667aaeSNaresh Kumar Inna /* 2751a3667aaeSNaresh Kumar Inna * csio_hws_ready - Ready state 2752a3667aaeSNaresh Kumar Inna * @hw - HW module 2753a3667aaeSNaresh Kumar Inna * @evt - Event 2754a3667aaeSNaresh Kumar Inna * 2755a3667aaeSNaresh Kumar Inna */ 2756a3667aaeSNaresh Kumar Inna static void 2757a3667aaeSNaresh Kumar Inna csio_hws_ready(struct csio_hw *hw, enum csio_hw_ev evt) 2758a3667aaeSNaresh Kumar Inna { 2759a3667aaeSNaresh Kumar Inna /* Remember the event */ 2760a3667aaeSNaresh Kumar Inna hw->evtflag = evt; 2761a3667aaeSNaresh Kumar Inna 2762a3667aaeSNaresh Kumar Inna hw->prev_evt = hw->cur_evt; 2763a3667aaeSNaresh Kumar Inna hw->cur_evt = evt; 2764a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_sm[evt]); 2765a3667aaeSNaresh Kumar Inna 2766a3667aaeSNaresh Kumar Inna switch (evt) { 2767a3667aaeSNaresh Kumar Inna case CSIO_HWE_HBA_RESET: 2768a3667aaeSNaresh Kumar Inna case CSIO_HWE_FW_DLOAD: 2769a3667aaeSNaresh Kumar Inna case CSIO_HWE_SUSPEND: 2770a3667aaeSNaresh Kumar Inna case CSIO_HWE_PCI_REMOVE: 2771a3667aaeSNaresh Kumar Inna case CSIO_HWE_PCIERR_DETECTED: 2772a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_quiescing); 2773a3667aaeSNaresh Kumar Inna /* cleanup all outstanding cmds */ 2774a3667aaeSNaresh Kumar Inna if (evt == CSIO_HWE_HBA_RESET || 2775a3667aaeSNaresh Kumar Inna evt == CSIO_HWE_PCIERR_DETECTED) 2776a3667aaeSNaresh Kumar Inna csio_scsim_cleanup_io(csio_hw_to_scsim(hw), false); 2777a3667aaeSNaresh Kumar Inna else 2778a3667aaeSNaresh Kumar Inna csio_scsim_cleanup_io(csio_hw_to_scsim(hw), true); 2779a3667aaeSNaresh Kumar Inna 2780a3667aaeSNaresh Kumar Inna csio_hw_intr_disable(hw); 2781a3667aaeSNaresh Kumar Inna csio_hw_mbm_cleanup(hw); 2782a3667aaeSNaresh Kumar Inna csio_evtq_stop(hw); 2783a3667aaeSNaresh Kumar Inna csio_notify_lnodes(hw, CSIO_LN_NOTIFY_HWSTOP); 2784a3667aaeSNaresh Kumar Inna csio_evtq_flush(hw); 2785a3667aaeSNaresh Kumar Inna csio_mgmtm_cleanup(csio_hw_to_mgmtm(hw)); 2786a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_QUIESCED); 2787a3667aaeSNaresh Kumar Inna break; 2788a3667aaeSNaresh Kumar Inna 2789a3667aaeSNaresh Kumar Inna case CSIO_HWE_FATAL: 2790a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_uninit); 2791a3667aaeSNaresh Kumar Inna break; 2792a3667aaeSNaresh Kumar Inna 2793a3667aaeSNaresh Kumar Inna default: 2794a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_unexp); 2795a3667aaeSNaresh Kumar Inna break; 2796a3667aaeSNaresh Kumar Inna } 2797a3667aaeSNaresh Kumar Inna } 2798a3667aaeSNaresh Kumar Inna 2799a3667aaeSNaresh Kumar Inna /* 2800a3667aaeSNaresh Kumar Inna * csio_hws_quiescing - Quiescing state 2801a3667aaeSNaresh Kumar Inna * @hw - HW module 2802a3667aaeSNaresh Kumar Inna * @evt - Event 2803a3667aaeSNaresh Kumar Inna * 2804a3667aaeSNaresh Kumar Inna */ 2805a3667aaeSNaresh Kumar Inna static void 2806a3667aaeSNaresh Kumar Inna csio_hws_quiescing(struct csio_hw *hw, enum csio_hw_ev evt) 2807a3667aaeSNaresh Kumar Inna { 2808a3667aaeSNaresh Kumar Inna hw->prev_evt = hw->cur_evt; 2809a3667aaeSNaresh Kumar Inna hw->cur_evt = evt; 2810a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_sm[evt]); 2811a3667aaeSNaresh Kumar Inna 2812a3667aaeSNaresh Kumar Inna switch (evt) { 2813a3667aaeSNaresh Kumar Inna case CSIO_HWE_QUIESCED: 2814a3667aaeSNaresh Kumar Inna switch (hw->evtflag) { 2815a3667aaeSNaresh Kumar Inna case CSIO_HWE_FW_DLOAD: 2816a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_resetting); 2817a3667aaeSNaresh Kumar Inna /* Download firmware */ 2818a3667aaeSNaresh Kumar Inna /* Fall through */ 2819a3667aaeSNaresh Kumar Inna 2820a3667aaeSNaresh Kumar Inna case CSIO_HWE_HBA_RESET: 2821a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_resetting); 2822a3667aaeSNaresh Kumar Inna /* Start reset of the HBA */ 2823a3667aaeSNaresh Kumar Inna csio_notify_lnodes(hw, CSIO_LN_NOTIFY_HWRESET); 2824a3667aaeSNaresh Kumar Inna csio_wr_destroy_queues(hw, false); 2825a3667aaeSNaresh Kumar Inna csio_do_reset(hw, false); 2826a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_HBA_RESET_DONE); 2827a3667aaeSNaresh Kumar Inna break; 2828a3667aaeSNaresh Kumar Inna 2829a3667aaeSNaresh Kumar Inna case CSIO_HWE_PCI_REMOVE: 2830a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_removing); 2831a3667aaeSNaresh Kumar Inna csio_notify_lnodes(hw, CSIO_LN_NOTIFY_HWREMOVE); 2832a3667aaeSNaresh Kumar Inna csio_wr_destroy_queues(hw, true); 2833a3667aaeSNaresh Kumar Inna /* Now send the bye command */ 2834a3667aaeSNaresh Kumar Inna csio_do_bye(hw); 2835a3667aaeSNaresh Kumar Inna break; 2836a3667aaeSNaresh Kumar Inna 2837a3667aaeSNaresh Kumar Inna case CSIO_HWE_SUSPEND: 2838a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_quiesced); 2839a3667aaeSNaresh Kumar Inna break; 2840a3667aaeSNaresh Kumar Inna 2841a3667aaeSNaresh Kumar Inna case CSIO_HWE_PCIERR_DETECTED: 2842a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_pcierr); 2843a3667aaeSNaresh Kumar Inna csio_wr_destroy_queues(hw, false); 2844a3667aaeSNaresh Kumar Inna break; 2845a3667aaeSNaresh Kumar Inna 2846a3667aaeSNaresh Kumar Inna default: 2847a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_unexp); 2848a3667aaeSNaresh Kumar Inna break; 2849a3667aaeSNaresh Kumar Inna 2850a3667aaeSNaresh Kumar Inna } 2851a3667aaeSNaresh Kumar Inna break; 2852a3667aaeSNaresh Kumar Inna 2853a3667aaeSNaresh Kumar Inna default: 2854a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_unexp); 2855a3667aaeSNaresh Kumar Inna break; 2856a3667aaeSNaresh Kumar Inna } 2857a3667aaeSNaresh Kumar Inna } 2858a3667aaeSNaresh Kumar Inna 2859a3667aaeSNaresh Kumar Inna /* 2860a3667aaeSNaresh Kumar Inna * csio_hws_quiesced - Quiesced state 2861a3667aaeSNaresh Kumar Inna * @hw - HW module 2862a3667aaeSNaresh Kumar Inna * @evt - Event 2863a3667aaeSNaresh Kumar Inna * 2864a3667aaeSNaresh Kumar Inna */ 2865a3667aaeSNaresh Kumar Inna static void 2866a3667aaeSNaresh Kumar Inna csio_hws_quiesced(struct csio_hw *hw, enum csio_hw_ev evt) 2867a3667aaeSNaresh Kumar Inna { 2868a3667aaeSNaresh Kumar Inna hw->prev_evt = hw->cur_evt; 2869a3667aaeSNaresh Kumar Inna hw->cur_evt = evt; 2870a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_sm[evt]); 2871a3667aaeSNaresh Kumar Inna 2872a3667aaeSNaresh Kumar Inna switch (evt) { 2873a3667aaeSNaresh Kumar Inna case CSIO_HWE_RESUME: 2874a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_configuring); 2875a3667aaeSNaresh Kumar Inna csio_hw_configure(hw); 2876a3667aaeSNaresh Kumar Inna break; 2877a3667aaeSNaresh Kumar Inna 2878a3667aaeSNaresh Kumar Inna default: 2879a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_unexp); 2880a3667aaeSNaresh Kumar Inna break; 2881a3667aaeSNaresh Kumar Inna } 2882a3667aaeSNaresh Kumar Inna } 2883a3667aaeSNaresh Kumar Inna 2884a3667aaeSNaresh Kumar Inna /* 2885a3667aaeSNaresh Kumar Inna * csio_hws_resetting - HW Resetting state 2886a3667aaeSNaresh Kumar Inna * @hw - HW module 2887a3667aaeSNaresh Kumar Inna * @evt - Event 2888a3667aaeSNaresh Kumar Inna * 2889a3667aaeSNaresh Kumar Inna */ 2890a3667aaeSNaresh Kumar Inna static void 2891a3667aaeSNaresh Kumar Inna csio_hws_resetting(struct csio_hw *hw, enum csio_hw_ev evt) 2892a3667aaeSNaresh Kumar Inna { 2893a3667aaeSNaresh Kumar Inna hw->prev_evt = hw->cur_evt; 2894a3667aaeSNaresh Kumar Inna hw->cur_evt = evt; 2895a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_sm[evt]); 2896a3667aaeSNaresh Kumar Inna 2897a3667aaeSNaresh Kumar Inna switch (evt) { 2898a3667aaeSNaresh Kumar Inna case CSIO_HWE_HBA_RESET_DONE: 2899a3667aaeSNaresh Kumar Inna csio_evtq_start(hw); 2900a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_configuring); 2901a3667aaeSNaresh Kumar Inna csio_hw_configure(hw); 2902a3667aaeSNaresh Kumar Inna break; 2903a3667aaeSNaresh Kumar Inna 2904a3667aaeSNaresh Kumar Inna default: 2905a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_unexp); 2906a3667aaeSNaresh Kumar Inna break; 2907a3667aaeSNaresh Kumar Inna } 2908a3667aaeSNaresh Kumar Inna } 2909a3667aaeSNaresh Kumar Inna 2910a3667aaeSNaresh Kumar Inna /* 2911a3667aaeSNaresh Kumar Inna * csio_hws_removing - PCI Hotplug removing state 2912a3667aaeSNaresh Kumar Inna * @hw - HW module 2913a3667aaeSNaresh Kumar Inna * @evt - Event 2914a3667aaeSNaresh Kumar Inna * 2915a3667aaeSNaresh Kumar Inna */ 2916a3667aaeSNaresh Kumar Inna static void 2917a3667aaeSNaresh Kumar Inna csio_hws_removing(struct csio_hw *hw, enum csio_hw_ev evt) 2918a3667aaeSNaresh Kumar Inna { 2919a3667aaeSNaresh Kumar Inna hw->prev_evt = hw->cur_evt; 2920a3667aaeSNaresh Kumar Inna hw->cur_evt = evt; 2921a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_sm[evt]); 2922a3667aaeSNaresh Kumar Inna 2923a3667aaeSNaresh Kumar Inna switch (evt) { 2924a3667aaeSNaresh Kumar Inna case CSIO_HWE_HBA_RESET: 2925a3667aaeSNaresh Kumar Inna if (!csio_is_hw_master(hw)) 2926a3667aaeSNaresh Kumar Inna break; 2927a3667aaeSNaresh Kumar Inna /* 2928a3667aaeSNaresh Kumar Inna * The BYE should have alerady been issued, so we cant 2929a3667aaeSNaresh Kumar Inna * use the mailbox interface. Hence we use the PL_RST 2930a3667aaeSNaresh Kumar Inna * register directly. 2931a3667aaeSNaresh Kumar Inna */ 2932a3667aaeSNaresh Kumar Inna csio_err(hw, "Resetting HW and waiting 2 seconds...\n"); 29330d804338SHariprasad Shenai csio_wr_reg32(hw, PIORSTMODE_F | PIORST_F, PL_RST_A); 2934a3667aaeSNaresh Kumar Inna mdelay(2000); 2935a3667aaeSNaresh Kumar Inna break; 2936a3667aaeSNaresh Kumar Inna 2937a3667aaeSNaresh Kumar Inna /* Should never receive any new events */ 2938a3667aaeSNaresh Kumar Inna default: 2939a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_unexp); 2940a3667aaeSNaresh Kumar Inna break; 2941a3667aaeSNaresh Kumar Inna 2942a3667aaeSNaresh Kumar Inna } 2943a3667aaeSNaresh Kumar Inna } 2944a3667aaeSNaresh Kumar Inna 2945a3667aaeSNaresh Kumar Inna /* 2946a3667aaeSNaresh Kumar Inna * csio_hws_pcierr - PCI Error state 2947a3667aaeSNaresh Kumar Inna * @hw - HW module 2948a3667aaeSNaresh Kumar Inna * @evt - Event 2949a3667aaeSNaresh Kumar Inna * 2950a3667aaeSNaresh Kumar Inna */ 2951a3667aaeSNaresh Kumar Inna static void 2952a3667aaeSNaresh Kumar Inna csio_hws_pcierr(struct csio_hw *hw, enum csio_hw_ev evt) 2953a3667aaeSNaresh Kumar Inna { 2954a3667aaeSNaresh Kumar Inna hw->prev_evt = hw->cur_evt; 2955a3667aaeSNaresh Kumar Inna hw->cur_evt = evt; 2956a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_sm[evt]); 2957a3667aaeSNaresh Kumar Inna 2958a3667aaeSNaresh Kumar Inna switch (evt) { 2959a3667aaeSNaresh Kumar Inna case CSIO_HWE_PCIERR_SLOT_RESET: 2960a3667aaeSNaresh Kumar Inna csio_evtq_start(hw); 2961a3667aaeSNaresh Kumar Inna csio_set_state(&hw->sm, csio_hws_configuring); 2962a3667aaeSNaresh Kumar Inna csio_hw_configure(hw); 2963a3667aaeSNaresh Kumar Inna break; 2964a3667aaeSNaresh Kumar Inna 2965a3667aaeSNaresh Kumar Inna default: 2966a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_unexp); 2967a3667aaeSNaresh Kumar Inna break; 2968a3667aaeSNaresh Kumar Inna } 2969a3667aaeSNaresh Kumar Inna } 2970a3667aaeSNaresh Kumar Inna 2971a3667aaeSNaresh Kumar Inna /*****************************************************************************/ 2972a3667aaeSNaresh Kumar Inna /* END: HW SM */ 2973a3667aaeSNaresh Kumar Inna /*****************************************************************************/ 2974a3667aaeSNaresh Kumar Inna 2975a3667aaeSNaresh Kumar Inna /* 2976a3667aaeSNaresh Kumar Inna * csio_handle_intr_status - table driven interrupt handler 2977a3667aaeSNaresh Kumar Inna * @hw: HW instance 2978a3667aaeSNaresh Kumar Inna * @reg: the interrupt status register to process 2979a3667aaeSNaresh Kumar Inna * @acts: table of interrupt actions 2980a3667aaeSNaresh Kumar Inna * 2981a3667aaeSNaresh Kumar Inna * A table driven interrupt handler that applies a set of masks to an 2982a3667aaeSNaresh Kumar Inna * interrupt status word and performs the corresponding actions if the 2983a3667aaeSNaresh Kumar Inna * interrupts described by the mask have occured. The actions include 2984a3667aaeSNaresh Kumar Inna * optionally emitting a warning or alert message. The table is terminated 2985a3667aaeSNaresh Kumar Inna * by an entry specifying mask 0. Returns the number of fatal interrupt 2986a3667aaeSNaresh Kumar Inna * conditions. 2987a3667aaeSNaresh Kumar Inna */ 29887cc16380SArvind Bhushan int 2989a3667aaeSNaresh Kumar Inna csio_handle_intr_status(struct csio_hw *hw, unsigned int reg, 2990a3667aaeSNaresh Kumar Inna const struct intr_info *acts) 2991a3667aaeSNaresh Kumar Inna { 2992a3667aaeSNaresh Kumar Inna int fatal = 0; 2993a3667aaeSNaresh Kumar Inna unsigned int mask = 0; 2994a3667aaeSNaresh Kumar Inna unsigned int status = csio_rd_reg32(hw, reg); 2995a3667aaeSNaresh Kumar Inna 2996a3667aaeSNaresh Kumar Inna for ( ; acts->mask; ++acts) { 2997a3667aaeSNaresh Kumar Inna if (!(status & acts->mask)) 2998a3667aaeSNaresh Kumar Inna continue; 2999a3667aaeSNaresh Kumar Inna if (acts->fatal) { 3000a3667aaeSNaresh Kumar Inna fatal++; 3001a3667aaeSNaresh Kumar Inna csio_fatal(hw, "Fatal %s (0x%x)\n", 3002a3667aaeSNaresh Kumar Inna acts->msg, status & acts->mask); 3003a3667aaeSNaresh Kumar Inna } else if (acts->msg) 3004a3667aaeSNaresh Kumar Inna csio_info(hw, "%s (0x%x)\n", 3005a3667aaeSNaresh Kumar Inna acts->msg, status & acts->mask); 3006a3667aaeSNaresh Kumar Inna mask |= acts->mask; 3007a3667aaeSNaresh Kumar Inna } 3008a3667aaeSNaresh Kumar Inna status &= mask; 3009a3667aaeSNaresh Kumar Inna if (status) /* clear processed interrupts */ 3010a3667aaeSNaresh Kumar Inna csio_wr_reg32(hw, status, reg); 3011a3667aaeSNaresh Kumar Inna return fatal; 3012a3667aaeSNaresh Kumar Inna } 3013a3667aaeSNaresh Kumar Inna 3014a3667aaeSNaresh Kumar Inna /* 3015a3667aaeSNaresh Kumar Inna * TP interrupt handler. 3016a3667aaeSNaresh Kumar Inna */ 3017a3667aaeSNaresh Kumar Inna static void csio_tp_intr_handler(struct csio_hw *hw) 3018a3667aaeSNaresh Kumar Inna { 3019a3667aaeSNaresh Kumar Inna static struct intr_info tp_intr_info[] = { 3020a3667aaeSNaresh Kumar Inna { 0x3fffffff, "TP parity error", -1, 1 }, 3021837e4a42SHariprasad Shenai { FLMTXFLSTEMPTY_F, "TP out of Tx pages", -1, 1 }, 3022a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3023a3667aaeSNaresh Kumar Inna }; 3024a3667aaeSNaresh Kumar Inna 3025837e4a42SHariprasad Shenai if (csio_handle_intr_status(hw, TP_INT_CAUSE_A, tp_intr_info)) 3026a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 3027a3667aaeSNaresh Kumar Inna } 3028a3667aaeSNaresh Kumar Inna 3029a3667aaeSNaresh Kumar Inna /* 3030a3667aaeSNaresh Kumar Inna * SGE interrupt handler. 3031a3667aaeSNaresh Kumar Inna */ 3032a3667aaeSNaresh Kumar Inna static void csio_sge_intr_handler(struct csio_hw *hw) 3033a3667aaeSNaresh Kumar Inna { 3034a3667aaeSNaresh Kumar Inna uint64_t v; 3035a3667aaeSNaresh Kumar Inna 3036a3667aaeSNaresh Kumar Inna static struct intr_info sge_intr_info[] = { 3037f612b815SHariprasad Shenai { ERR_CPL_EXCEED_IQE_SIZE_F, 3038a3667aaeSNaresh Kumar Inna "SGE received CPL exceeding IQE size", -1, 1 }, 3039f612b815SHariprasad Shenai { ERR_INVALID_CIDX_INC_F, 3040a3667aaeSNaresh Kumar Inna "SGE GTS CIDX increment too large", -1, 0 }, 3041f612b815SHariprasad Shenai { ERR_CPL_OPCODE_0_F, "SGE received 0-length CPL", -1, 0 }, 3042f612b815SHariprasad Shenai { ERR_DROPPED_DB_F, "SGE doorbell dropped", -1, 0 }, 3043f612b815SHariprasad Shenai { ERR_DATA_CPL_ON_HIGH_QID1_F | ERR_DATA_CPL_ON_HIGH_QID0_F, 3044a3667aaeSNaresh Kumar Inna "SGE IQID > 1023 received CPL for FL", -1, 0 }, 3045f612b815SHariprasad Shenai { ERR_BAD_DB_PIDX3_F, "SGE DBP 3 pidx increment too large", -1, 3046a3667aaeSNaresh Kumar Inna 0 }, 3047f612b815SHariprasad Shenai { ERR_BAD_DB_PIDX2_F, "SGE DBP 2 pidx increment too large", -1, 3048a3667aaeSNaresh Kumar Inna 0 }, 3049f612b815SHariprasad Shenai { ERR_BAD_DB_PIDX1_F, "SGE DBP 1 pidx increment too large", -1, 3050a3667aaeSNaresh Kumar Inna 0 }, 3051f612b815SHariprasad Shenai { ERR_BAD_DB_PIDX0_F, "SGE DBP 0 pidx increment too large", -1, 3052a3667aaeSNaresh Kumar Inna 0 }, 3053f612b815SHariprasad Shenai { ERR_ING_CTXT_PRIO_F, 3054a3667aaeSNaresh Kumar Inna "SGE too many priority ingress contexts", -1, 0 }, 3055f612b815SHariprasad Shenai { ERR_EGR_CTXT_PRIO_F, 3056a3667aaeSNaresh Kumar Inna "SGE too many priority egress contexts", -1, 0 }, 3057f612b815SHariprasad Shenai { INGRESS_SIZE_ERR_F, "SGE illegal ingress QID", -1, 0 }, 3058f612b815SHariprasad Shenai { EGRESS_SIZE_ERR_F, "SGE illegal egress QID", -1, 0 }, 3059a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3060a3667aaeSNaresh Kumar Inna }; 3061a3667aaeSNaresh Kumar Inna 3062f612b815SHariprasad Shenai v = (uint64_t)csio_rd_reg32(hw, SGE_INT_CAUSE1_A) | 3063f612b815SHariprasad Shenai ((uint64_t)csio_rd_reg32(hw, SGE_INT_CAUSE2_A) << 32); 3064a3667aaeSNaresh Kumar Inna if (v) { 3065a3667aaeSNaresh Kumar Inna csio_fatal(hw, "SGE parity error (%#llx)\n", 3066a3667aaeSNaresh Kumar Inna (unsigned long long)v); 3067a3667aaeSNaresh Kumar Inna csio_wr_reg32(hw, (uint32_t)(v & 0xFFFFFFFF), 3068f612b815SHariprasad Shenai SGE_INT_CAUSE1_A); 3069f612b815SHariprasad Shenai csio_wr_reg32(hw, (uint32_t)(v >> 32), SGE_INT_CAUSE2_A); 3070a3667aaeSNaresh Kumar Inna } 3071a3667aaeSNaresh Kumar Inna 3072f612b815SHariprasad Shenai v |= csio_handle_intr_status(hw, SGE_INT_CAUSE3_A, sge_intr_info); 3073a3667aaeSNaresh Kumar Inna 3074f612b815SHariprasad Shenai if (csio_handle_intr_status(hw, SGE_INT_CAUSE3_A, sge_intr_info) || 3075a3667aaeSNaresh Kumar Inna v != 0) 3076a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 3077a3667aaeSNaresh Kumar Inna } 3078a3667aaeSNaresh Kumar Inna 307989c3a86cSHariprasad Shenai #define CIM_OBQ_INTR (OBQULP0PARERR_F | OBQULP1PARERR_F | OBQULP2PARERR_F |\ 308089c3a86cSHariprasad Shenai OBQULP3PARERR_F | OBQSGEPARERR_F | OBQNCSIPARERR_F) 308189c3a86cSHariprasad Shenai #define CIM_IBQ_INTR (IBQTP0PARERR_F | IBQTP1PARERR_F | IBQULPPARERR_F |\ 308289c3a86cSHariprasad Shenai IBQSGEHIPARERR_F | IBQSGELOPARERR_F | IBQNCSIPARERR_F) 3083a3667aaeSNaresh Kumar Inna 3084a3667aaeSNaresh Kumar Inna /* 3085a3667aaeSNaresh Kumar Inna * CIM interrupt handler. 3086a3667aaeSNaresh Kumar Inna */ 3087a3667aaeSNaresh Kumar Inna static void csio_cim_intr_handler(struct csio_hw *hw) 3088a3667aaeSNaresh Kumar Inna { 3089a3667aaeSNaresh Kumar Inna static struct intr_info cim_intr_info[] = { 309089c3a86cSHariprasad Shenai { PREFDROPINT_F, "CIM control register prefetch drop", -1, 1 }, 3091a3667aaeSNaresh Kumar Inna { CIM_OBQ_INTR, "CIM OBQ parity error", -1, 1 }, 3092a3667aaeSNaresh Kumar Inna { CIM_IBQ_INTR, "CIM IBQ parity error", -1, 1 }, 309389c3a86cSHariprasad Shenai { MBUPPARERR_F, "CIM mailbox uP parity error", -1, 1 }, 309489c3a86cSHariprasad Shenai { MBHOSTPARERR_F, "CIM mailbox host parity error", -1, 1 }, 309589c3a86cSHariprasad Shenai { TIEQINPARERRINT_F, "CIM TIEQ outgoing parity error", -1, 1 }, 309689c3a86cSHariprasad Shenai { TIEQOUTPARERRINT_F, "CIM TIEQ incoming parity error", -1, 1 }, 3097a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3098a3667aaeSNaresh Kumar Inna }; 3099a3667aaeSNaresh Kumar Inna static struct intr_info cim_upintr_info[] = { 310089c3a86cSHariprasad Shenai { RSVDSPACEINT_F, "CIM reserved space access", -1, 1 }, 310189c3a86cSHariprasad Shenai { ILLTRANSINT_F, "CIM illegal transaction", -1, 1 }, 310289c3a86cSHariprasad Shenai { ILLWRINT_F, "CIM illegal write", -1, 1 }, 310389c3a86cSHariprasad Shenai { ILLRDINT_F, "CIM illegal read", -1, 1 }, 310489c3a86cSHariprasad Shenai { ILLRDBEINT_F, "CIM illegal read BE", -1, 1 }, 310589c3a86cSHariprasad Shenai { ILLWRBEINT_F, "CIM illegal write BE", -1, 1 }, 310689c3a86cSHariprasad Shenai { SGLRDBOOTINT_F, "CIM single read from boot space", -1, 1 }, 310789c3a86cSHariprasad Shenai { SGLWRBOOTINT_F, "CIM single write to boot space", -1, 1 }, 310889c3a86cSHariprasad Shenai { BLKWRBOOTINT_F, "CIM block write to boot space", -1, 1 }, 310989c3a86cSHariprasad Shenai { SGLRDFLASHINT_F, "CIM single read from flash space", -1, 1 }, 311089c3a86cSHariprasad Shenai { SGLWRFLASHINT_F, "CIM single write to flash space", -1, 1 }, 311189c3a86cSHariprasad Shenai { BLKWRFLASHINT_F, "CIM block write to flash space", -1, 1 }, 311289c3a86cSHariprasad Shenai { SGLRDEEPROMINT_F, "CIM single EEPROM read", -1, 1 }, 311389c3a86cSHariprasad Shenai { SGLWREEPROMINT_F, "CIM single EEPROM write", -1, 1 }, 311489c3a86cSHariprasad Shenai { BLKRDEEPROMINT_F, "CIM block EEPROM read", -1, 1 }, 311589c3a86cSHariprasad Shenai { BLKWREEPROMINT_F, "CIM block EEPROM write", -1, 1 }, 311689c3a86cSHariprasad Shenai { SGLRDCTLINT_F, "CIM single read from CTL space", -1, 1 }, 311789c3a86cSHariprasad Shenai { SGLWRCTLINT_F, "CIM single write to CTL space", -1, 1 }, 311889c3a86cSHariprasad Shenai { BLKRDCTLINT_F, "CIM block read from CTL space", -1, 1 }, 311989c3a86cSHariprasad Shenai { BLKWRCTLINT_F, "CIM block write to CTL space", -1, 1 }, 312089c3a86cSHariprasad Shenai { SGLRDPLINT_F, "CIM single read from PL space", -1, 1 }, 312189c3a86cSHariprasad Shenai { SGLWRPLINT_F, "CIM single write to PL space", -1, 1 }, 312289c3a86cSHariprasad Shenai { BLKRDPLINT_F, "CIM block read from PL space", -1, 1 }, 312389c3a86cSHariprasad Shenai { BLKWRPLINT_F, "CIM block write to PL space", -1, 1 }, 312489c3a86cSHariprasad Shenai { REQOVRLOOKUPINT_F, "CIM request FIFO overwrite", -1, 1 }, 312589c3a86cSHariprasad Shenai { RSPOVRLOOKUPINT_F, "CIM response FIFO overwrite", -1, 1 }, 312689c3a86cSHariprasad Shenai { TIMEOUTINT_F, "CIM PIF timeout", -1, 1 }, 312789c3a86cSHariprasad Shenai { TIMEOUTMAINT_F, "CIM PIF MA timeout", -1, 1 }, 3128a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3129a3667aaeSNaresh Kumar Inna }; 3130a3667aaeSNaresh Kumar Inna 3131a3667aaeSNaresh Kumar Inna int fat; 3132a3667aaeSNaresh Kumar Inna 313389c3a86cSHariprasad Shenai fat = csio_handle_intr_status(hw, CIM_HOST_INT_CAUSE_A, 3134a3667aaeSNaresh Kumar Inna cim_intr_info) + 313589c3a86cSHariprasad Shenai csio_handle_intr_status(hw, CIM_HOST_UPACC_INT_CAUSE_A, 3136a3667aaeSNaresh Kumar Inna cim_upintr_info); 3137a3667aaeSNaresh Kumar Inna if (fat) 3138a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 3139a3667aaeSNaresh Kumar Inna } 3140a3667aaeSNaresh Kumar Inna 3141a3667aaeSNaresh Kumar Inna /* 3142a3667aaeSNaresh Kumar Inna * ULP RX interrupt handler. 3143a3667aaeSNaresh Kumar Inna */ 3144a3667aaeSNaresh Kumar Inna static void csio_ulprx_intr_handler(struct csio_hw *hw) 3145a3667aaeSNaresh Kumar Inna { 3146a3667aaeSNaresh Kumar Inna static struct intr_info ulprx_intr_info[] = { 3147a3667aaeSNaresh Kumar Inna { 0x1800000, "ULPRX context error", -1, 1 }, 3148a3667aaeSNaresh Kumar Inna { 0x7fffff, "ULPRX parity error", -1, 1 }, 3149a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3150a3667aaeSNaresh Kumar Inna }; 3151a3667aaeSNaresh Kumar Inna 31520d804338SHariprasad Shenai if (csio_handle_intr_status(hw, ULP_RX_INT_CAUSE_A, ulprx_intr_info)) 3153a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 3154a3667aaeSNaresh Kumar Inna } 3155a3667aaeSNaresh Kumar Inna 3156a3667aaeSNaresh Kumar Inna /* 3157a3667aaeSNaresh Kumar Inna * ULP TX interrupt handler. 3158a3667aaeSNaresh Kumar Inna */ 3159a3667aaeSNaresh Kumar Inna static void csio_ulptx_intr_handler(struct csio_hw *hw) 3160a3667aaeSNaresh Kumar Inna { 3161a3667aaeSNaresh Kumar Inna static struct intr_info ulptx_intr_info[] = { 3162837e4a42SHariprasad Shenai { PBL_BOUND_ERR_CH3_F, "ULPTX channel 3 PBL out of bounds", -1, 3163a3667aaeSNaresh Kumar Inna 0 }, 3164837e4a42SHariprasad Shenai { PBL_BOUND_ERR_CH2_F, "ULPTX channel 2 PBL out of bounds", -1, 3165a3667aaeSNaresh Kumar Inna 0 }, 3166837e4a42SHariprasad Shenai { PBL_BOUND_ERR_CH1_F, "ULPTX channel 1 PBL out of bounds", -1, 3167a3667aaeSNaresh Kumar Inna 0 }, 3168837e4a42SHariprasad Shenai { PBL_BOUND_ERR_CH0_F, "ULPTX channel 0 PBL out of bounds", -1, 3169a3667aaeSNaresh Kumar Inna 0 }, 3170a3667aaeSNaresh Kumar Inna { 0xfffffff, "ULPTX parity error", -1, 1 }, 3171a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3172a3667aaeSNaresh Kumar Inna }; 3173a3667aaeSNaresh Kumar Inna 3174837e4a42SHariprasad Shenai if (csio_handle_intr_status(hw, ULP_TX_INT_CAUSE_A, ulptx_intr_info)) 3175a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 3176a3667aaeSNaresh Kumar Inna } 3177a3667aaeSNaresh Kumar Inna 3178a3667aaeSNaresh Kumar Inna /* 3179a3667aaeSNaresh Kumar Inna * PM TX interrupt handler. 3180a3667aaeSNaresh Kumar Inna */ 3181a3667aaeSNaresh Kumar Inna static void csio_pmtx_intr_handler(struct csio_hw *hw) 3182a3667aaeSNaresh Kumar Inna { 3183a3667aaeSNaresh Kumar Inna static struct intr_info pmtx_intr_info[] = { 3184837e4a42SHariprasad Shenai { PCMD_LEN_OVFL0_F, "PMTX channel 0 pcmd too large", -1, 1 }, 3185837e4a42SHariprasad Shenai { PCMD_LEN_OVFL1_F, "PMTX channel 1 pcmd too large", -1, 1 }, 3186837e4a42SHariprasad Shenai { PCMD_LEN_OVFL2_F, "PMTX channel 2 pcmd too large", -1, 1 }, 3187837e4a42SHariprasad Shenai { ZERO_C_CMD_ERROR_F, "PMTX 0-length pcmd", -1, 1 }, 3188a3667aaeSNaresh Kumar Inna { 0xffffff0, "PMTX framing error", -1, 1 }, 3189837e4a42SHariprasad Shenai { OESPI_PAR_ERROR_F, "PMTX oespi parity error", -1, 1 }, 3190837e4a42SHariprasad Shenai { DB_OPTIONS_PAR_ERROR_F, "PMTX db_options parity error", -1, 3191a3667aaeSNaresh Kumar Inna 1 }, 3192837e4a42SHariprasad Shenai { ICSPI_PAR_ERROR_F, "PMTX icspi parity error", -1, 1 }, 3193837e4a42SHariprasad Shenai { PMTX_C_PCMD_PAR_ERROR_F, "PMTX c_pcmd parity error", -1, 1}, 3194a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3195a3667aaeSNaresh Kumar Inna }; 3196a3667aaeSNaresh Kumar Inna 3197837e4a42SHariprasad Shenai if (csio_handle_intr_status(hw, PM_TX_INT_CAUSE_A, pmtx_intr_info)) 3198a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 3199a3667aaeSNaresh Kumar Inna } 3200a3667aaeSNaresh Kumar Inna 3201a3667aaeSNaresh Kumar Inna /* 3202a3667aaeSNaresh Kumar Inna * PM RX interrupt handler. 3203a3667aaeSNaresh Kumar Inna */ 3204a3667aaeSNaresh Kumar Inna static void csio_pmrx_intr_handler(struct csio_hw *hw) 3205a3667aaeSNaresh Kumar Inna { 3206a3667aaeSNaresh Kumar Inna static struct intr_info pmrx_intr_info[] = { 3207837e4a42SHariprasad Shenai { ZERO_E_CMD_ERROR_F, "PMRX 0-length pcmd", -1, 1 }, 3208a3667aaeSNaresh Kumar Inna { 0x3ffff0, "PMRX framing error", -1, 1 }, 3209837e4a42SHariprasad Shenai { OCSPI_PAR_ERROR_F, "PMRX ocspi parity error", -1, 1 }, 3210837e4a42SHariprasad Shenai { DB_OPTIONS_PAR_ERROR_F, "PMRX db_options parity error", -1, 3211a3667aaeSNaresh Kumar Inna 1 }, 3212837e4a42SHariprasad Shenai { IESPI_PAR_ERROR_F, "PMRX iespi parity error", -1, 1 }, 3213837e4a42SHariprasad Shenai { PMRX_E_PCMD_PAR_ERROR_F, "PMRX e_pcmd parity error", -1, 1}, 3214a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3215a3667aaeSNaresh Kumar Inna }; 3216a3667aaeSNaresh Kumar Inna 3217837e4a42SHariprasad Shenai if (csio_handle_intr_status(hw, PM_RX_INT_CAUSE_A, pmrx_intr_info)) 3218a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 3219a3667aaeSNaresh Kumar Inna } 3220a3667aaeSNaresh Kumar Inna 3221a3667aaeSNaresh Kumar Inna /* 3222a3667aaeSNaresh Kumar Inna * CPL switch interrupt handler. 3223a3667aaeSNaresh Kumar Inna */ 3224a3667aaeSNaresh Kumar Inna static void csio_cplsw_intr_handler(struct csio_hw *hw) 3225a3667aaeSNaresh Kumar Inna { 3226a3667aaeSNaresh Kumar Inna static struct intr_info cplsw_intr_info[] = { 32270d804338SHariprasad Shenai { CIM_OP_MAP_PERR_F, "CPLSW CIM op_map parity error", -1, 1 }, 32280d804338SHariprasad Shenai { CIM_OVFL_ERROR_F, "CPLSW CIM overflow", -1, 1 }, 32290d804338SHariprasad Shenai { TP_FRAMING_ERROR_F, "CPLSW TP framing error", -1, 1 }, 32300d804338SHariprasad Shenai { SGE_FRAMING_ERROR_F, "CPLSW SGE framing error", -1, 1 }, 32310d804338SHariprasad Shenai { CIM_FRAMING_ERROR_F, "CPLSW CIM framing error", -1, 1 }, 32320d804338SHariprasad Shenai { ZERO_SWITCH_ERROR_F, "CPLSW no-switch error", -1, 1 }, 3233a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3234a3667aaeSNaresh Kumar Inna }; 3235a3667aaeSNaresh Kumar Inna 32360d804338SHariprasad Shenai if (csio_handle_intr_status(hw, CPL_INTR_CAUSE_A, cplsw_intr_info)) 3237a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 3238a3667aaeSNaresh Kumar Inna } 3239a3667aaeSNaresh Kumar Inna 3240a3667aaeSNaresh Kumar Inna /* 3241a3667aaeSNaresh Kumar Inna * LE interrupt handler. 3242a3667aaeSNaresh Kumar Inna */ 3243a3667aaeSNaresh Kumar Inna static void csio_le_intr_handler(struct csio_hw *hw) 3244a3667aaeSNaresh Kumar Inna { 32454bbd458eSVarun Prakash enum chip_type chip = CHELSIO_CHIP_VERSION(hw->chip_id); 32464bbd458eSVarun Prakash 3247a3667aaeSNaresh Kumar Inna static struct intr_info le_intr_info[] = { 32480d804338SHariprasad Shenai { LIPMISS_F, "LE LIP miss", -1, 0 }, 32490d804338SHariprasad Shenai { LIP0_F, "LE 0 LIP error", -1, 0 }, 32500d804338SHariprasad Shenai { PARITYERR_F, "LE parity error", -1, 1 }, 32510d804338SHariprasad Shenai { UNKNOWNCMD_F, "LE unknown command", -1, 1 }, 32520d804338SHariprasad Shenai { REQQPARERR_F, "LE request queue parity error", -1, 1 }, 3253a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3254a3667aaeSNaresh Kumar Inna }; 3255a3667aaeSNaresh Kumar Inna 32564bbd458eSVarun Prakash static struct intr_info t6_le_intr_info[] = { 32574bbd458eSVarun Prakash { T6_LIPMISS_F, "LE LIP miss", -1, 0 }, 32584bbd458eSVarun Prakash { T6_LIP0_F, "LE 0 LIP error", -1, 0 }, 32594bbd458eSVarun Prakash { TCAMINTPERR_F, "LE parity error", -1, 1 }, 32604bbd458eSVarun Prakash { T6_UNKNOWNCMD_F, "LE unknown command", -1, 1 }, 32614bbd458eSVarun Prakash { SSRAMINTPERR_F, "LE request queue parity error", -1, 1 }, 32624bbd458eSVarun Prakash { 0, NULL, 0, 0 } 32634bbd458eSVarun Prakash }; 32644bbd458eSVarun Prakash 32654bbd458eSVarun Prakash if (csio_handle_intr_status(hw, LE_DB_INT_CAUSE_A, 32664bbd458eSVarun Prakash (chip == CHELSIO_T5) ? 32674bbd458eSVarun Prakash le_intr_info : t6_le_intr_info)) 3268a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 3269a3667aaeSNaresh Kumar Inna } 3270a3667aaeSNaresh Kumar Inna 3271a3667aaeSNaresh Kumar Inna /* 3272a3667aaeSNaresh Kumar Inna * MPS interrupt handler. 3273a3667aaeSNaresh Kumar Inna */ 3274a3667aaeSNaresh Kumar Inna static void csio_mps_intr_handler(struct csio_hw *hw) 3275a3667aaeSNaresh Kumar Inna { 3276a3667aaeSNaresh Kumar Inna static struct intr_info mps_rx_intr_info[] = { 3277a3667aaeSNaresh Kumar Inna { 0xffffff, "MPS Rx parity error", -1, 1 }, 3278a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3279a3667aaeSNaresh Kumar Inna }; 3280a3667aaeSNaresh Kumar Inna static struct intr_info mps_tx_intr_info[] = { 3281837e4a42SHariprasad Shenai { TPFIFO_V(TPFIFO_M), "MPS Tx TP FIFO parity error", -1, 1 }, 3282837e4a42SHariprasad Shenai { NCSIFIFO_F, "MPS Tx NC-SI FIFO parity error", -1, 1 }, 3283837e4a42SHariprasad Shenai { TXDATAFIFO_V(TXDATAFIFO_M), "MPS Tx data FIFO parity error", 3284837e4a42SHariprasad Shenai -1, 1 }, 3285837e4a42SHariprasad Shenai { TXDESCFIFO_V(TXDESCFIFO_M), "MPS Tx desc FIFO parity error", 3286837e4a42SHariprasad Shenai -1, 1 }, 3287837e4a42SHariprasad Shenai { BUBBLE_F, "MPS Tx underflow", -1, 1 }, 3288837e4a42SHariprasad Shenai { SECNTERR_F, "MPS Tx SOP/EOP error", -1, 1 }, 3289837e4a42SHariprasad Shenai { FRMERR_F, "MPS Tx framing error", -1, 1 }, 3290a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3291a3667aaeSNaresh Kumar Inna }; 3292a3667aaeSNaresh Kumar Inna static struct intr_info mps_trc_intr_info[] = { 3293837e4a42SHariprasad Shenai { FILTMEM_V(FILTMEM_M), "MPS TRC filter parity error", -1, 1 }, 3294837e4a42SHariprasad Shenai { PKTFIFO_V(PKTFIFO_M), "MPS TRC packet FIFO parity error", 3295837e4a42SHariprasad Shenai -1, 1 }, 3296837e4a42SHariprasad Shenai { MISCPERR_F, "MPS TRC misc parity error", -1, 1 }, 3297a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3298a3667aaeSNaresh Kumar Inna }; 3299a3667aaeSNaresh Kumar Inna static struct intr_info mps_stat_sram_intr_info[] = { 3300a3667aaeSNaresh Kumar Inna { 0x1fffff, "MPS statistics SRAM parity error", -1, 1 }, 3301a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3302a3667aaeSNaresh Kumar Inna }; 3303a3667aaeSNaresh Kumar Inna static struct intr_info mps_stat_tx_intr_info[] = { 3304a3667aaeSNaresh Kumar Inna { 0xfffff, "MPS statistics Tx FIFO parity error", -1, 1 }, 3305a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3306a3667aaeSNaresh Kumar Inna }; 3307a3667aaeSNaresh Kumar Inna static struct intr_info mps_stat_rx_intr_info[] = { 3308a3667aaeSNaresh Kumar Inna { 0xffffff, "MPS statistics Rx FIFO parity error", -1, 1 }, 3309a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3310a3667aaeSNaresh Kumar Inna }; 3311a3667aaeSNaresh Kumar Inna static struct intr_info mps_cls_intr_info[] = { 3312837e4a42SHariprasad Shenai { MATCHSRAM_F, "MPS match SRAM parity error", -1, 1 }, 3313837e4a42SHariprasad Shenai { MATCHTCAM_F, "MPS match TCAM parity error", -1, 1 }, 3314837e4a42SHariprasad Shenai { HASHSRAM_F, "MPS hash SRAM parity error", -1, 1 }, 3315a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3316a3667aaeSNaresh Kumar Inna }; 3317a3667aaeSNaresh Kumar Inna 3318a3667aaeSNaresh Kumar Inna int fat; 3319a3667aaeSNaresh Kumar Inna 3320837e4a42SHariprasad Shenai fat = csio_handle_intr_status(hw, MPS_RX_PERR_INT_CAUSE_A, 3321a3667aaeSNaresh Kumar Inna mps_rx_intr_info) + 3322837e4a42SHariprasad Shenai csio_handle_intr_status(hw, MPS_TX_INT_CAUSE_A, 3323a3667aaeSNaresh Kumar Inna mps_tx_intr_info) + 3324837e4a42SHariprasad Shenai csio_handle_intr_status(hw, MPS_TRC_INT_CAUSE_A, 3325a3667aaeSNaresh Kumar Inna mps_trc_intr_info) + 3326837e4a42SHariprasad Shenai csio_handle_intr_status(hw, MPS_STAT_PERR_INT_CAUSE_SRAM_A, 3327a3667aaeSNaresh Kumar Inna mps_stat_sram_intr_info) + 3328837e4a42SHariprasad Shenai csio_handle_intr_status(hw, MPS_STAT_PERR_INT_CAUSE_TX_FIFO_A, 3329a3667aaeSNaresh Kumar Inna mps_stat_tx_intr_info) + 3330837e4a42SHariprasad Shenai csio_handle_intr_status(hw, MPS_STAT_PERR_INT_CAUSE_RX_FIFO_A, 3331a3667aaeSNaresh Kumar Inna mps_stat_rx_intr_info) + 3332837e4a42SHariprasad Shenai csio_handle_intr_status(hw, MPS_CLS_INT_CAUSE_A, 3333a3667aaeSNaresh Kumar Inna mps_cls_intr_info); 3334a3667aaeSNaresh Kumar Inna 3335837e4a42SHariprasad Shenai csio_wr_reg32(hw, 0, MPS_INT_CAUSE_A); 3336837e4a42SHariprasad Shenai csio_rd_reg32(hw, MPS_INT_CAUSE_A); /* flush */ 3337a3667aaeSNaresh Kumar Inna if (fat) 3338a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 3339a3667aaeSNaresh Kumar Inna } 3340a3667aaeSNaresh Kumar Inna 334189c3a86cSHariprasad Shenai #define MEM_INT_MASK (PERR_INT_CAUSE_F | ECC_CE_INT_CAUSE_F | \ 334289c3a86cSHariprasad Shenai ECC_UE_INT_CAUSE_F) 3343a3667aaeSNaresh Kumar Inna 3344a3667aaeSNaresh Kumar Inna /* 3345a3667aaeSNaresh Kumar Inna * EDC/MC interrupt handler. 3346a3667aaeSNaresh Kumar Inna */ 3347a3667aaeSNaresh Kumar Inna static void csio_mem_intr_handler(struct csio_hw *hw, int idx) 3348a3667aaeSNaresh Kumar Inna { 3349a3667aaeSNaresh Kumar Inna static const char name[3][5] = { "EDC0", "EDC1", "MC" }; 3350a3667aaeSNaresh Kumar Inna 3351a3667aaeSNaresh Kumar Inna unsigned int addr, cnt_addr, v; 3352a3667aaeSNaresh Kumar Inna 3353a3667aaeSNaresh Kumar Inna if (idx <= MEM_EDC1) { 335489c3a86cSHariprasad Shenai addr = EDC_REG(EDC_INT_CAUSE_A, idx); 335589c3a86cSHariprasad Shenai cnt_addr = EDC_REG(EDC_ECC_STATUS_A, idx); 3356a3667aaeSNaresh Kumar Inna } else { 335789c3a86cSHariprasad Shenai addr = MC_INT_CAUSE_A; 335889c3a86cSHariprasad Shenai cnt_addr = MC_ECC_STATUS_A; 3359a3667aaeSNaresh Kumar Inna } 3360a3667aaeSNaresh Kumar Inna 3361a3667aaeSNaresh Kumar Inna v = csio_rd_reg32(hw, addr) & MEM_INT_MASK; 336289c3a86cSHariprasad Shenai if (v & PERR_INT_CAUSE_F) 3363a3667aaeSNaresh Kumar Inna csio_fatal(hw, "%s FIFO parity error\n", name[idx]); 336489c3a86cSHariprasad Shenai if (v & ECC_CE_INT_CAUSE_F) { 336589c3a86cSHariprasad Shenai uint32_t cnt = ECC_CECNT_G(csio_rd_reg32(hw, cnt_addr)); 3366a3667aaeSNaresh Kumar Inna 336789c3a86cSHariprasad Shenai csio_wr_reg32(hw, ECC_CECNT_V(ECC_CECNT_M), cnt_addr); 3368a3667aaeSNaresh Kumar Inna csio_warn(hw, "%u %s correctable ECC data error%s\n", 3369a3667aaeSNaresh Kumar Inna cnt, name[idx], cnt > 1 ? "s" : ""); 3370a3667aaeSNaresh Kumar Inna } 337189c3a86cSHariprasad Shenai if (v & ECC_UE_INT_CAUSE_F) 3372a3667aaeSNaresh Kumar Inna csio_fatal(hw, "%s uncorrectable ECC data error\n", name[idx]); 3373a3667aaeSNaresh Kumar Inna 3374a3667aaeSNaresh Kumar Inna csio_wr_reg32(hw, v, addr); 337589c3a86cSHariprasad Shenai if (v & (PERR_INT_CAUSE_F | ECC_UE_INT_CAUSE_F)) 3376a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 3377a3667aaeSNaresh Kumar Inna } 3378a3667aaeSNaresh Kumar Inna 3379a3667aaeSNaresh Kumar Inna /* 3380a3667aaeSNaresh Kumar Inna * MA interrupt handler. 3381a3667aaeSNaresh Kumar Inna */ 3382a3667aaeSNaresh Kumar Inna static void csio_ma_intr_handler(struct csio_hw *hw) 3383a3667aaeSNaresh Kumar Inna { 338489c3a86cSHariprasad Shenai uint32_t v, status = csio_rd_reg32(hw, MA_INT_CAUSE_A); 3385a3667aaeSNaresh Kumar Inna 338689c3a86cSHariprasad Shenai if (status & MEM_PERR_INT_CAUSE_F) 3387a3667aaeSNaresh Kumar Inna csio_fatal(hw, "MA parity error, parity status %#x\n", 338889c3a86cSHariprasad Shenai csio_rd_reg32(hw, MA_PARITY_ERROR_STATUS_A)); 338989c3a86cSHariprasad Shenai if (status & MEM_WRAP_INT_CAUSE_F) { 339089c3a86cSHariprasad Shenai v = csio_rd_reg32(hw, MA_INT_WRAP_STATUS_A); 3391a3667aaeSNaresh Kumar Inna csio_fatal(hw, 3392a3667aaeSNaresh Kumar Inna "MA address wrap-around error by client %u to address %#x\n", 339389c3a86cSHariprasad Shenai MEM_WRAP_CLIENT_NUM_G(v), MEM_WRAP_ADDRESS_G(v) << 4); 3394a3667aaeSNaresh Kumar Inna } 339589c3a86cSHariprasad Shenai csio_wr_reg32(hw, status, MA_INT_CAUSE_A); 3396a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 3397a3667aaeSNaresh Kumar Inna } 3398a3667aaeSNaresh Kumar Inna 3399a3667aaeSNaresh Kumar Inna /* 3400a3667aaeSNaresh Kumar Inna * SMB interrupt handler. 3401a3667aaeSNaresh Kumar Inna */ 3402a3667aaeSNaresh Kumar Inna static void csio_smb_intr_handler(struct csio_hw *hw) 3403a3667aaeSNaresh Kumar Inna { 3404a3667aaeSNaresh Kumar Inna static struct intr_info smb_intr_info[] = { 34050d804338SHariprasad Shenai { MSTTXFIFOPARINT_F, "SMB master Tx FIFO parity error", -1, 1 }, 34060d804338SHariprasad Shenai { MSTRXFIFOPARINT_F, "SMB master Rx FIFO parity error", -1, 1 }, 34070d804338SHariprasad Shenai { SLVFIFOPARINT_F, "SMB slave FIFO parity error", -1, 1 }, 3408a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3409a3667aaeSNaresh Kumar Inna }; 3410a3667aaeSNaresh Kumar Inna 34110d804338SHariprasad Shenai if (csio_handle_intr_status(hw, SMB_INT_CAUSE_A, smb_intr_info)) 3412a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 3413a3667aaeSNaresh Kumar Inna } 3414a3667aaeSNaresh Kumar Inna 3415a3667aaeSNaresh Kumar Inna /* 3416a3667aaeSNaresh Kumar Inna * NC-SI interrupt handler. 3417a3667aaeSNaresh Kumar Inna */ 3418a3667aaeSNaresh Kumar Inna static void csio_ncsi_intr_handler(struct csio_hw *hw) 3419a3667aaeSNaresh Kumar Inna { 3420a3667aaeSNaresh Kumar Inna static struct intr_info ncsi_intr_info[] = { 34210d804338SHariprasad Shenai { CIM_DM_PRTY_ERR_F, "NC-SI CIM parity error", -1, 1 }, 34220d804338SHariprasad Shenai { MPS_DM_PRTY_ERR_F, "NC-SI MPS parity error", -1, 1 }, 34230d804338SHariprasad Shenai { TXFIFO_PRTY_ERR_F, "NC-SI Tx FIFO parity error", -1, 1 }, 34240d804338SHariprasad Shenai { RXFIFO_PRTY_ERR_F, "NC-SI Rx FIFO parity error", -1, 1 }, 3425a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3426a3667aaeSNaresh Kumar Inna }; 3427a3667aaeSNaresh Kumar Inna 34280d804338SHariprasad Shenai if (csio_handle_intr_status(hw, NCSI_INT_CAUSE_A, ncsi_intr_info)) 3429a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 3430a3667aaeSNaresh Kumar Inna } 3431a3667aaeSNaresh Kumar Inna 3432a3667aaeSNaresh Kumar Inna /* 3433a3667aaeSNaresh Kumar Inna * XGMAC interrupt handler. 3434a3667aaeSNaresh Kumar Inna */ 3435a3667aaeSNaresh Kumar Inna static void csio_xgmac_intr_handler(struct csio_hw *hw, int port) 3436a3667aaeSNaresh Kumar Inna { 34373fb4c22eSPraveen Madhavan uint32_t v = csio_rd_reg32(hw, T5_PORT_REG(port, MAC_PORT_INT_CAUSE_A)); 3438a3667aaeSNaresh Kumar Inna 34390d804338SHariprasad Shenai v &= TXFIFO_PRTY_ERR_F | RXFIFO_PRTY_ERR_F; 3440a3667aaeSNaresh Kumar Inna if (!v) 3441a3667aaeSNaresh Kumar Inna return; 3442a3667aaeSNaresh Kumar Inna 34430d804338SHariprasad Shenai if (v & TXFIFO_PRTY_ERR_F) 3444a3667aaeSNaresh Kumar Inna csio_fatal(hw, "XGMAC %d Tx FIFO parity error\n", port); 34450d804338SHariprasad Shenai if (v & RXFIFO_PRTY_ERR_F) 3446a3667aaeSNaresh Kumar Inna csio_fatal(hw, "XGMAC %d Rx FIFO parity error\n", port); 34473fb4c22eSPraveen Madhavan csio_wr_reg32(hw, v, T5_PORT_REG(port, MAC_PORT_INT_CAUSE_A)); 3448a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 3449a3667aaeSNaresh Kumar Inna } 3450a3667aaeSNaresh Kumar Inna 3451a3667aaeSNaresh Kumar Inna /* 3452a3667aaeSNaresh Kumar Inna * PL interrupt handler. 3453a3667aaeSNaresh Kumar Inna */ 3454a3667aaeSNaresh Kumar Inna static void csio_pl_intr_handler(struct csio_hw *hw) 3455a3667aaeSNaresh Kumar Inna { 3456a3667aaeSNaresh Kumar Inna static struct intr_info pl_intr_info[] = { 34570d804338SHariprasad Shenai { FATALPERR_F, "T4 fatal parity error", -1, 1 }, 34580d804338SHariprasad Shenai { PERRVFID_F, "PL VFID_MAP parity error", -1, 1 }, 3459a3667aaeSNaresh Kumar Inna { 0, NULL, 0, 0 } 3460a3667aaeSNaresh Kumar Inna }; 3461a3667aaeSNaresh Kumar Inna 34620d804338SHariprasad Shenai if (csio_handle_intr_status(hw, PL_PL_INT_CAUSE_A, pl_intr_info)) 3463a3667aaeSNaresh Kumar Inna csio_hw_fatal_err(hw); 3464a3667aaeSNaresh Kumar Inna } 3465a3667aaeSNaresh Kumar Inna 3466a3667aaeSNaresh Kumar Inna /* 3467a3667aaeSNaresh Kumar Inna * csio_hw_slow_intr_handler - control path interrupt handler 3468a3667aaeSNaresh Kumar Inna * @hw: HW module 3469a3667aaeSNaresh Kumar Inna * 3470a3667aaeSNaresh Kumar Inna * Interrupt handler for non-data global interrupt events, e.g., errors. 3471a3667aaeSNaresh Kumar Inna * The designation 'slow' is because it involves register reads, while 3472a3667aaeSNaresh Kumar Inna * data interrupts typically don't involve any MMIOs. 3473a3667aaeSNaresh Kumar Inna */ 3474a3667aaeSNaresh Kumar Inna int 3475a3667aaeSNaresh Kumar Inna csio_hw_slow_intr_handler(struct csio_hw *hw) 3476a3667aaeSNaresh Kumar Inna { 34770d804338SHariprasad Shenai uint32_t cause = csio_rd_reg32(hw, PL_INT_CAUSE_A); 3478a3667aaeSNaresh Kumar Inna 3479a3667aaeSNaresh Kumar Inna if (!(cause & CSIO_GLBL_INTR_MASK)) { 3480a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_plint_unexp); 3481a3667aaeSNaresh Kumar Inna return 0; 3482a3667aaeSNaresh Kumar Inna } 3483a3667aaeSNaresh Kumar Inna 3484a3667aaeSNaresh Kumar Inna csio_dbg(hw, "Slow interrupt! cause: 0x%x\n", cause); 3485a3667aaeSNaresh Kumar Inna 3486a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_plint_cnt); 3487a3667aaeSNaresh Kumar Inna 34880d804338SHariprasad Shenai if (cause & CIM_F) 3489a3667aaeSNaresh Kumar Inna csio_cim_intr_handler(hw); 3490a3667aaeSNaresh Kumar Inna 34910d804338SHariprasad Shenai if (cause & MPS_F) 3492a3667aaeSNaresh Kumar Inna csio_mps_intr_handler(hw); 3493a3667aaeSNaresh Kumar Inna 34940d804338SHariprasad Shenai if (cause & NCSI_F) 3495a3667aaeSNaresh Kumar Inna csio_ncsi_intr_handler(hw); 3496a3667aaeSNaresh Kumar Inna 34970d804338SHariprasad Shenai if (cause & PL_F) 3498a3667aaeSNaresh Kumar Inna csio_pl_intr_handler(hw); 3499a3667aaeSNaresh Kumar Inna 35000d804338SHariprasad Shenai if (cause & SMB_F) 3501a3667aaeSNaresh Kumar Inna csio_smb_intr_handler(hw); 3502a3667aaeSNaresh Kumar Inna 35030d804338SHariprasad Shenai if (cause & XGMAC0_F) 3504a3667aaeSNaresh Kumar Inna csio_xgmac_intr_handler(hw, 0); 3505a3667aaeSNaresh Kumar Inna 35060d804338SHariprasad Shenai if (cause & XGMAC1_F) 3507a3667aaeSNaresh Kumar Inna csio_xgmac_intr_handler(hw, 1); 3508a3667aaeSNaresh Kumar Inna 35090d804338SHariprasad Shenai if (cause & XGMAC_KR0_F) 3510a3667aaeSNaresh Kumar Inna csio_xgmac_intr_handler(hw, 2); 3511a3667aaeSNaresh Kumar Inna 35120d804338SHariprasad Shenai if (cause & XGMAC_KR1_F) 3513a3667aaeSNaresh Kumar Inna csio_xgmac_intr_handler(hw, 3); 3514a3667aaeSNaresh Kumar Inna 35150d804338SHariprasad Shenai if (cause & PCIE_F) 35167cc16380SArvind Bhushan hw->chip_ops->chip_pcie_intr_handler(hw); 3517a3667aaeSNaresh Kumar Inna 35180d804338SHariprasad Shenai if (cause & MC_F) 3519a3667aaeSNaresh Kumar Inna csio_mem_intr_handler(hw, MEM_MC); 3520a3667aaeSNaresh Kumar Inna 35210d804338SHariprasad Shenai if (cause & EDC0_F) 3522a3667aaeSNaresh Kumar Inna csio_mem_intr_handler(hw, MEM_EDC0); 3523a3667aaeSNaresh Kumar Inna 35240d804338SHariprasad Shenai if (cause & EDC1_F) 3525a3667aaeSNaresh Kumar Inna csio_mem_intr_handler(hw, MEM_EDC1); 3526a3667aaeSNaresh Kumar Inna 35270d804338SHariprasad Shenai if (cause & LE_F) 3528a3667aaeSNaresh Kumar Inna csio_le_intr_handler(hw); 3529a3667aaeSNaresh Kumar Inna 35300d804338SHariprasad Shenai if (cause & TP_F) 3531a3667aaeSNaresh Kumar Inna csio_tp_intr_handler(hw); 3532a3667aaeSNaresh Kumar Inna 35330d804338SHariprasad Shenai if (cause & MA_F) 3534a3667aaeSNaresh Kumar Inna csio_ma_intr_handler(hw); 3535a3667aaeSNaresh Kumar Inna 35360d804338SHariprasad Shenai if (cause & PM_TX_F) 3537a3667aaeSNaresh Kumar Inna csio_pmtx_intr_handler(hw); 3538a3667aaeSNaresh Kumar Inna 35390d804338SHariprasad Shenai if (cause & PM_RX_F) 3540a3667aaeSNaresh Kumar Inna csio_pmrx_intr_handler(hw); 3541a3667aaeSNaresh Kumar Inna 35420d804338SHariprasad Shenai if (cause & ULP_RX_F) 3543a3667aaeSNaresh Kumar Inna csio_ulprx_intr_handler(hw); 3544a3667aaeSNaresh Kumar Inna 35450d804338SHariprasad Shenai if (cause & CPL_SWITCH_F) 3546a3667aaeSNaresh Kumar Inna csio_cplsw_intr_handler(hw); 3547a3667aaeSNaresh Kumar Inna 35480d804338SHariprasad Shenai if (cause & SGE_F) 3549a3667aaeSNaresh Kumar Inna csio_sge_intr_handler(hw); 3550a3667aaeSNaresh Kumar Inna 35510d804338SHariprasad Shenai if (cause & ULP_TX_F) 3552a3667aaeSNaresh Kumar Inna csio_ulptx_intr_handler(hw); 3553a3667aaeSNaresh Kumar Inna 3554a3667aaeSNaresh Kumar Inna /* Clear the interrupts just processed for which we are the master. */ 35550d804338SHariprasad Shenai csio_wr_reg32(hw, cause & CSIO_GLBL_INTR_MASK, PL_INT_CAUSE_A); 35560d804338SHariprasad Shenai csio_rd_reg32(hw, PL_INT_CAUSE_A); /* flush */ 3557a3667aaeSNaresh Kumar Inna 3558a3667aaeSNaresh Kumar Inna return 1; 3559a3667aaeSNaresh Kumar Inna } 3560a3667aaeSNaresh Kumar Inna 3561a3667aaeSNaresh Kumar Inna /***************************************************************************** 3562a3667aaeSNaresh Kumar Inna * HW <--> mailbox interfacing routines. 3563a3667aaeSNaresh Kumar Inna ****************************************************************************/ 3564a3667aaeSNaresh Kumar Inna /* 3565a3667aaeSNaresh Kumar Inna * csio_mberr_worker - Worker thread (dpc) for mailbox/error completions 3566a3667aaeSNaresh Kumar Inna * 3567a3667aaeSNaresh Kumar Inna * @data: Private data pointer. 3568a3667aaeSNaresh Kumar Inna * 3569a3667aaeSNaresh Kumar Inna * Called from worker thread context. 3570a3667aaeSNaresh Kumar Inna */ 3571a3667aaeSNaresh Kumar Inna static void 3572a3667aaeSNaresh Kumar Inna csio_mberr_worker(void *data) 3573a3667aaeSNaresh Kumar Inna { 3574a3667aaeSNaresh Kumar Inna struct csio_hw *hw = (struct csio_hw *)data; 3575a3667aaeSNaresh Kumar Inna struct csio_mbm *mbm = &hw->mbm; 3576a3667aaeSNaresh Kumar Inna LIST_HEAD(cbfn_q); 3577a3667aaeSNaresh Kumar Inna struct csio_mb *mbp_next; 3578a3667aaeSNaresh Kumar Inna int rv; 3579a3667aaeSNaresh Kumar Inna 3580a3667aaeSNaresh Kumar Inna del_timer_sync(&mbm->timer); 3581a3667aaeSNaresh Kumar Inna 3582a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 3583a3667aaeSNaresh Kumar Inna if (list_empty(&mbm->cbfn_q)) { 3584a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 3585a3667aaeSNaresh Kumar Inna return; 3586a3667aaeSNaresh Kumar Inna } 3587a3667aaeSNaresh Kumar Inna 3588a3667aaeSNaresh Kumar Inna list_splice_tail_init(&mbm->cbfn_q, &cbfn_q); 3589a3667aaeSNaresh Kumar Inna mbm->stats.n_cbfnq = 0; 3590a3667aaeSNaresh Kumar Inna 3591a3667aaeSNaresh Kumar Inna /* Try to start waiting mailboxes */ 3592a3667aaeSNaresh Kumar Inna if (!list_empty(&mbm->req_q)) { 3593a3667aaeSNaresh Kumar Inna mbp_next = list_first_entry(&mbm->req_q, struct csio_mb, list); 3594a3667aaeSNaresh Kumar Inna list_del_init(&mbp_next->list); 3595a3667aaeSNaresh Kumar Inna 3596a3667aaeSNaresh Kumar Inna rv = csio_mb_issue(hw, mbp_next); 3597a3667aaeSNaresh Kumar Inna if (rv != 0) 3598a3667aaeSNaresh Kumar Inna list_add_tail(&mbp_next->list, &mbm->req_q); 3599a3667aaeSNaresh Kumar Inna else 3600a3667aaeSNaresh Kumar Inna CSIO_DEC_STATS(mbm, n_activeq); 3601a3667aaeSNaresh Kumar Inna } 3602a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 3603a3667aaeSNaresh Kumar Inna 3604a3667aaeSNaresh Kumar Inna /* Now callback completions */ 3605a3667aaeSNaresh Kumar Inna csio_mb_completions(hw, &cbfn_q); 3606a3667aaeSNaresh Kumar Inna } 3607a3667aaeSNaresh Kumar Inna 3608a3667aaeSNaresh Kumar Inna /* 3609a3667aaeSNaresh Kumar Inna * csio_hw_mb_timer - Top-level Mailbox timeout handler. 3610a3667aaeSNaresh Kumar Inna * 3611a3667aaeSNaresh Kumar Inna * @data: private data pointer 3612a3667aaeSNaresh Kumar Inna * 3613a3667aaeSNaresh Kumar Inna **/ 3614a3667aaeSNaresh Kumar Inna static void 3615fa60a31bSKees Cook csio_hw_mb_timer(struct timer_list *t) 3616a3667aaeSNaresh Kumar Inna { 3617fa60a31bSKees Cook struct csio_mbm *mbm = from_timer(mbm, t, timer); 3618fa60a31bSKees Cook struct csio_hw *hw = mbm->hw; 3619a3667aaeSNaresh Kumar Inna struct csio_mb *mbp = NULL; 3620a3667aaeSNaresh Kumar Inna 3621a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 3622a3667aaeSNaresh Kumar Inna mbp = csio_mb_tmo_handler(hw); 3623a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 3624a3667aaeSNaresh Kumar Inna 3625a3667aaeSNaresh Kumar Inna /* Call back the function for the timed-out Mailbox */ 3626a3667aaeSNaresh Kumar Inna if (mbp) 3627a3667aaeSNaresh Kumar Inna mbp->mb_cbfn(hw, mbp); 3628a3667aaeSNaresh Kumar Inna 3629a3667aaeSNaresh Kumar Inna } 3630a3667aaeSNaresh Kumar Inna 3631a3667aaeSNaresh Kumar Inna /* 3632a3667aaeSNaresh Kumar Inna * csio_hw_mbm_cleanup - Cleanup Mailbox module. 3633a3667aaeSNaresh Kumar Inna * @hw: HW module 3634a3667aaeSNaresh Kumar Inna * 3635a3667aaeSNaresh Kumar Inna * Called with lock held, should exit with lock held. 3636a3667aaeSNaresh Kumar Inna * Cancels outstanding mailboxes (waiting, in-flight) and gathers them 3637a3667aaeSNaresh Kumar Inna * into a local queue. Drops lock and calls the completions. Holds 3638a3667aaeSNaresh Kumar Inna * lock and returns. 3639a3667aaeSNaresh Kumar Inna */ 3640a3667aaeSNaresh Kumar Inna static void 3641a3667aaeSNaresh Kumar Inna csio_hw_mbm_cleanup(struct csio_hw *hw) 3642a3667aaeSNaresh Kumar Inna { 3643a3667aaeSNaresh Kumar Inna LIST_HEAD(cbfn_q); 3644a3667aaeSNaresh Kumar Inna 3645a3667aaeSNaresh Kumar Inna csio_mb_cancel_all(hw, &cbfn_q); 3646a3667aaeSNaresh Kumar Inna 3647a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 3648a3667aaeSNaresh Kumar Inna csio_mb_completions(hw, &cbfn_q); 3649a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 3650a3667aaeSNaresh Kumar Inna } 3651a3667aaeSNaresh Kumar Inna 3652a3667aaeSNaresh Kumar Inna /***************************************************************************** 3653a3667aaeSNaresh Kumar Inna * Event handling 3654a3667aaeSNaresh Kumar Inna ****************************************************************************/ 3655a3667aaeSNaresh Kumar Inna int 3656a3667aaeSNaresh Kumar Inna csio_enqueue_evt(struct csio_hw *hw, enum csio_evt type, void *evt_msg, 3657a3667aaeSNaresh Kumar Inna uint16_t len) 3658a3667aaeSNaresh Kumar Inna { 3659a3667aaeSNaresh Kumar Inna struct csio_evt_msg *evt_entry = NULL; 3660a3667aaeSNaresh Kumar Inna 3661a3667aaeSNaresh Kumar Inna if (type >= CSIO_EVT_MAX) 3662a3667aaeSNaresh Kumar Inna return -EINVAL; 3663a3667aaeSNaresh Kumar Inna 3664a3667aaeSNaresh Kumar Inna if (len > CSIO_EVT_MSG_SIZE) 3665a3667aaeSNaresh Kumar Inna return -EINVAL; 3666a3667aaeSNaresh Kumar Inna 3667a3667aaeSNaresh Kumar Inna if (hw->flags & CSIO_HWF_FWEVT_STOP) 3668a3667aaeSNaresh Kumar Inna return -EINVAL; 3669a3667aaeSNaresh Kumar Inna 3670a3667aaeSNaresh Kumar Inna if (list_empty(&hw->evt_free_q)) { 3671a3667aaeSNaresh Kumar Inna csio_err(hw, "Failed to alloc evt entry, msg type %d len %d\n", 3672a3667aaeSNaresh Kumar Inna type, len); 3673a3667aaeSNaresh Kumar Inna return -ENOMEM; 3674a3667aaeSNaresh Kumar Inna } 3675a3667aaeSNaresh Kumar Inna 3676a3667aaeSNaresh Kumar Inna evt_entry = list_first_entry(&hw->evt_free_q, 3677a3667aaeSNaresh Kumar Inna struct csio_evt_msg, list); 3678a3667aaeSNaresh Kumar Inna list_del_init(&evt_entry->list); 3679a3667aaeSNaresh Kumar Inna 3680a3667aaeSNaresh Kumar Inna /* copy event msg and queue the event */ 3681a3667aaeSNaresh Kumar Inna evt_entry->type = type; 3682a3667aaeSNaresh Kumar Inna memcpy((void *)evt_entry->data, evt_msg, len); 3683a3667aaeSNaresh Kumar Inna list_add_tail(&evt_entry->list, &hw->evt_active_q); 3684a3667aaeSNaresh Kumar Inna 3685a3667aaeSNaresh Kumar Inna CSIO_DEC_STATS(hw, n_evt_freeq); 3686a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_activeq); 3687a3667aaeSNaresh Kumar Inna 3688a3667aaeSNaresh Kumar Inna return 0; 3689a3667aaeSNaresh Kumar Inna } 3690a3667aaeSNaresh Kumar Inna 3691a3667aaeSNaresh Kumar Inna static int 3692a3667aaeSNaresh Kumar Inna csio_enqueue_evt_lock(struct csio_hw *hw, enum csio_evt type, void *evt_msg, 3693a3667aaeSNaresh Kumar Inna uint16_t len, bool msg_sg) 3694a3667aaeSNaresh Kumar Inna { 3695a3667aaeSNaresh Kumar Inna struct csio_evt_msg *evt_entry = NULL; 3696a3667aaeSNaresh Kumar Inna struct csio_fl_dma_buf *fl_sg; 3697a3667aaeSNaresh Kumar Inna uint32_t off = 0; 3698a3667aaeSNaresh Kumar Inna unsigned long flags; 3699a3667aaeSNaresh Kumar Inna int n, ret = 0; 3700a3667aaeSNaresh Kumar Inna 3701a3667aaeSNaresh Kumar Inna if (type >= CSIO_EVT_MAX) 3702a3667aaeSNaresh Kumar Inna return -EINVAL; 3703a3667aaeSNaresh Kumar Inna 3704a3667aaeSNaresh Kumar Inna if (len > CSIO_EVT_MSG_SIZE) 3705a3667aaeSNaresh Kumar Inna return -EINVAL; 3706a3667aaeSNaresh Kumar Inna 3707a3667aaeSNaresh Kumar Inna spin_lock_irqsave(&hw->lock, flags); 3708a3667aaeSNaresh Kumar Inna if (hw->flags & CSIO_HWF_FWEVT_STOP) { 3709a3667aaeSNaresh Kumar Inna ret = -EINVAL; 3710a3667aaeSNaresh Kumar Inna goto out; 3711a3667aaeSNaresh Kumar Inna } 3712a3667aaeSNaresh Kumar Inna 3713a3667aaeSNaresh Kumar Inna if (list_empty(&hw->evt_free_q)) { 3714a3667aaeSNaresh Kumar Inna csio_err(hw, "Failed to alloc evt entry, msg type %d len %d\n", 3715a3667aaeSNaresh Kumar Inna type, len); 3716a3667aaeSNaresh Kumar Inna ret = -ENOMEM; 3717a3667aaeSNaresh Kumar Inna goto out; 3718a3667aaeSNaresh Kumar Inna } 3719a3667aaeSNaresh Kumar Inna 3720a3667aaeSNaresh Kumar Inna evt_entry = list_first_entry(&hw->evt_free_q, 3721a3667aaeSNaresh Kumar Inna struct csio_evt_msg, list); 3722a3667aaeSNaresh Kumar Inna list_del_init(&evt_entry->list); 3723a3667aaeSNaresh Kumar Inna 3724a3667aaeSNaresh Kumar Inna /* copy event msg and queue the event */ 3725a3667aaeSNaresh Kumar Inna evt_entry->type = type; 3726a3667aaeSNaresh Kumar Inna 3727a3667aaeSNaresh Kumar Inna /* If Payload in SG list*/ 3728a3667aaeSNaresh Kumar Inna if (msg_sg) { 3729a3667aaeSNaresh Kumar Inna fl_sg = (struct csio_fl_dma_buf *) evt_msg; 3730a3667aaeSNaresh Kumar Inna for (n = 0; (n < CSIO_MAX_FLBUF_PER_IQWR && off < len); n++) { 3731a3667aaeSNaresh Kumar Inna memcpy((void *)((uintptr_t)evt_entry->data + off), 3732a3667aaeSNaresh Kumar Inna fl_sg->flbufs[n].vaddr, 3733a3667aaeSNaresh Kumar Inna fl_sg->flbufs[n].len); 3734a3667aaeSNaresh Kumar Inna off += fl_sg->flbufs[n].len; 3735a3667aaeSNaresh Kumar Inna } 3736a3667aaeSNaresh Kumar Inna } else 3737a3667aaeSNaresh Kumar Inna memcpy((void *)evt_entry->data, evt_msg, len); 3738a3667aaeSNaresh Kumar Inna 3739a3667aaeSNaresh Kumar Inna list_add_tail(&evt_entry->list, &hw->evt_active_q); 3740a3667aaeSNaresh Kumar Inna CSIO_DEC_STATS(hw, n_evt_freeq); 3741a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_activeq); 3742a3667aaeSNaresh Kumar Inna out: 3743a3667aaeSNaresh Kumar Inna spin_unlock_irqrestore(&hw->lock, flags); 3744a3667aaeSNaresh Kumar Inna return ret; 3745a3667aaeSNaresh Kumar Inna } 3746a3667aaeSNaresh Kumar Inna 3747a3667aaeSNaresh Kumar Inna static void 3748a3667aaeSNaresh Kumar Inna csio_free_evt(struct csio_hw *hw, struct csio_evt_msg *evt_entry) 3749a3667aaeSNaresh Kumar Inna { 3750a3667aaeSNaresh Kumar Inna if (evt_entry) { 3751a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 3752a3667aaeSNaresh Kumar Inna list_del_init(&evt_entry->list); 3753a3667aaeSNaresh Kumar Inna list_add_tail(&evt_entry->list, &hw->evt_free_q); 3754a3667aaeSNaresh Kumar Inna CSIO_DEC_STATS(hw, n_evt_activeq); 3755a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_freeq); 3756a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 3757a3667aaeSNaresh Kumar Inna } 3758a3667aaeSNaresh Kumar Inna } 3759a3667aaeSNaresh Kumar Inna 3760a3667aaeSNaresh Kumar Inna void 3761a3667aaeSNaresh Kumar Inna csio_evtq_flush(struct csio_hw *hw) 3762a3667aaeSNaresh Kumar Inna { 3763a3667aaeSNaresh Kumar Inna uint32_t count; 3764a3667aaeSNaresh Kumar Inna count = 30; 3765a3667aaeSNaresh Kumar Inna while (hw->flags & CSIO_HWF_FWEVT_PENDING && count--) { 3766a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 3767a3667aaeSNaresh Kumar Inna msleep(2000); 3768a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 3769a3667aaeSNaresh Kumar Inna } 3770a3667aaeSNaresh Kumar Inna 3771a3667aaeSNaresh Kumar Inna CSIO_DB_ASSERT(!(hw->flags & CSIO_HWF_FWEVT_PENDING)); 3772a3667aaeSNaresh Kumar Inna } 3773a3667aaeSNaresh Kumar Inna 3774a3667aaeSNaresh Kumar Inna static void 3775a3667aaeSNaresh Kumar Inna csio_evtq_stop(struct csio_hw *hw) 3776a3667aaeSNaresh Kumar Inna { 3777a3667aaeSNaresh Kumar Inna hw->flags |= CSIO_HWF_FWEVT_STOP; 3778a3667aaeSNaresh Kumar Inna } 3779a3667aaeSNaresh Kumar Inna 3780a3667aaeSNaresh Kumar Inna static void 3781a3667aaeSNaresh Kumar Inna csio_evtq_start(struct csio_hw *hw) 3782a3667aaeSNaresh Kumar Inna { 3783a3667aaeSNaresh Kumar Inna hw->flags &= ~CSIO_HWF_FWEVT_STOP; 3784a3667aaeSNaresh Kumar Inna } 3785a3667aaeSNaresh Kumar Inna 3786a3667aaeSNaresh Kumar Inna static void 3787a3667aaeSNaresh Kumar Inna csio_evtq_cleanup(struct csio_hw *hw) 3788a3667aaeSNaresh Kumar Inna { 3789a3667aaeSNaresh Kumar Inna struct list_head *evt_entry, *next_entry; 3790a3667aaeSNaresh Kumar Inna 3791a3667aaeSNaresh Kumar Inna /* Release outstanding events from activeq to freeq*/ 3792a3667aaeSNaresh Kumar Inna if (!list_empty(&hw->evt_active_q)) 3793a3667aaeSNaresh Kumar Inna list_splice_tail_init(&hw->evt_active_q, &hw->evt_free_q); 3794a3667aaeSNaresh Kumar Inna 3795a3667aaeSNaresh Kumar Inna hw->stats.n_evt_activeq = 0; 3796a3667aaeSNaresh Kumar Inna hw->flags &= ~CSIO_HWF_FWEVT_PENDING; 3797a3667aaeSNaresh Kumar Inna 3798a3667aaeSNaresh Kumar Inna /* Freeup event entry */ 3799a3667aaeSNaresh Kumar Inna list_for_each_safe(evt_entry, next_entry, &hw->evt_free_q) { 3800a3667aaeSNaresh Kumar Inna kfree(evt_entry); 3801a3667aaeSNaresh Kumar Inna CSIO_DEC_STATS(hw, n_evt_freeq); 3802a3667aaeSNaresh Kumar Inna } 3803a3667aaeSNaresh Kumar Inna 3804a3667aaeSNaresh Kumar Inna hw->stats.n_evt_freeq = 0; 3805a3667aaeSNaresh Kumar Inna } 3806a3667aaeSNaresh Kumar Inna 3807a3667aaeSNaresh Kumar Inna 3808a3667aaeSNaresh Kumar Inna static void 3809a3667aaeSNaresh Kumar Inna csio_process_fwevtq_entry(struct csio_hw *hw, void *wr, uint32_t len, 3810a3667aaeSNaresh Kumar Inna struct csio_fl_dma_buf *flb, void *priv) 3811a3667aaeSNaresh Kumar Inna { 3812a3667aaeSNaresh Kumar Inna __u8 op; 3813a3667aaeSNaresh Kumar Inna void *msg = NULL; 3814a3667aaeSNaresh Kumar Inna uint32_t msg_len = 0; 3815a3667aaeSNaresh Kumar Inna bool msg_sg = 0; 3816a3667aaeSNaresh Kumar Inna 3817a3667aaeSNaresh Kumar Inna op = ((struct rss_header *) wr)->opcode; 3818a3667aaeSNaresh Kumar Inna if (op == CPL_FW6_PLD) { 3819a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_cpl_fw6_pld); 3820a3667aaeSNaresh Kumar Inna if (!flb || !flb->totlen) { 3821a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_cpl_unexp); 3822a3667aaeSNaresh Kumar Inna return; 3823a3667aaeSNaresh Kumar Inna } 3824a3667aaeSNaresh Kumar Inna 3825a3667aaeSNaresh Kumar Inna msg = (void *) flb; 3826a3667aaeSNaresh Kumar Inna msg_len = flb->totlen; 3827a3667aaeSNaresh Kumar Inna msg_sg = 1; 3828a3667aaeSNaresh Kumar Inna } else if (op == CPL_FW6_MSG || op == CPL_FW4_MSG) { 3829a3667aaeSNaresh Kumar Inna 3830a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_cpl_fw6_msg); 3831a3667aaeSNaresh Kumar Inna /* skip RSS header */ 3832a3667aaeSNaresh Kumar Inna msg = (void *)((uintptr_t)wr + sizeof(__be64)); 3833a3667aaeSNaresh Kumar Inna msg_len = (op == CPL_FW6_MSG) ? sizeof(struct cpl_fw6_msg) : 3834a3667aaeSNaresh Kumar Inna sizeof(struct cpl_fw4_msg); 3835a3667aaeSNaresh Kumar Inna } else { 3836a3667aaeSNaresh Kumar Inna csio_warn(hw, "unexpected CPL %#x on FW event queue\n", op); 3837a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_cpl_unexp); 3838a3667aaeSNaresh Kumar Inna return; 3839a3667aaeSNaresh Kumar Inna } 3840a3667aaeSNaresh Kumar Inna 3841a3667aaeSNaresh Kumar Inna /* 3842a3667aaeSNaresh Kumar Inna * Enqueue event to EventQ. Events processing happens 3843a3667aaeSNaresh Kumar Inna * in Event worker thread context 3844a3667aaeSNaresh Kumar Inna */ 3845a3667aaeSNaresh Kumar Inna if (csio_enqueue_evt_lock(hw, CSIO_EVT_FW, msg, 3846a3667aaeSNaresh Kumar Inna (uint16_t)msg_len, msg_sg)) 3847a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_drop); 3848a3667aaeSNaresh Kumar Inna } 3849a3667aaeSNaresh Kumar Inna 3850a3667aaeSNaresh Kumar Inna void 3851a3667aaeSNaresh Kumar Inna csio_evtq_worker(struct work_struct *work) 3852a3667aaeSNaresh Kumar Inna { 3853a3667aaeSNaresh Kumar Inna struct csio_hw *hw = container_of(work, struct csio_hw, evtq_work); 3854a3667aaeSNaresh Kumar Inna struct list_head *evt_entry, *next_entry; 3855a3667aaeSNaresh Kumar Inna LIST_HEAD(evt_q); 3856a3667aaeSNaresh Kumar Inna struct csio_evt_msg *evt_msg; 3857a3667aaeSNaresh Kumar Inna struct cpl_fw6_msg *msg; 3858a3667aaeSNaresh Kumar Inna struct csio_rnode *rn; 3859a3667aaeSNaresh Kumar Inna int rv = 0; 3860a3667aaeSNaresh Kumar Inna uint8_t evtq_stop = 0; 3861a3667aaeSNaresh Kumar Inna 3862a3667aaeSNaresh Kumar Inna csio_dbg(hw, "event worker thread active evts#%d\n", 3863a3667aaeSNaresh Kumar Inna hw->stats.n_evt_activeq); 3864a3667aaeSNaresh Kumar Inna 3865a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 3866a3667aaeSNaresh Kumar Inna while (!list_empty(&hw->evt_active_q)) { 3867a3667aaeSNaresh Kumar Inna list_splice_tail_init(&hw->evt_active_q, &evt_q); 3868a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 3869a3667aaeSNaresh Kumar Inna 3870a3667aaeSNaresh Kumar Inna list_for_each_safe(evt_entry, next_entry, &evt_q) { 3871a3667aaeSNaresh Kumar Inna evt_msg = (struct csio_evt_msg *) evt_entry; 3872a3667aaeSNaresh Kumar Inna 3873a3667aaeSNaresh Kumar Inna /* Drop events if queue is STOPPED */ 3874a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 3875a3667aaeSNaresh Kumar Inna if (hw->flags & CSIO_HWF_FWEVT_STOP) 3876a3667aaeSNaresh Kumar Inna evtq_stop = 1; 3877a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 3878a3667aaeSNaresh Kumar Inna if (evtq_stop) { 3879a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_drop); 3880a3667aaeSNaresh Kumar Inna goto free_evt; 3881a3667aaeSNaresh Kumar Inna } 3882a3667aaeSNaresh Kumar Inna 3883a3667aaeSNaresh Kumar Inna switch (evt_msg->type) { 3884a3667aaeSNaresh Kumar Inna case CSIO_EVT_FW: 3885a3667aaeSNaresh Kumar Inna msg = (struct cpl_fw6_msg *)(evt_msg->data); 3886a3667aaeSNaresh Kumar Inna 3887a3667aaeSNaresh Kumar Inna if ((msg->opcode == CPL_FW6_MSG || 3888a3667aaeSNaresh Kumar Inna msg->opcode == CPL_FW4_MSG) && 3889a3667aaeSNaresh Kumar Inna !msg->type) { 3890a3667aaeSNaresh Kumar Inna rv = csio_mb_fwevt_handler(hw, 3891a3667aaeSNaresh Kumar Inna msg->data); 3892a3667aaeSNaresh Kumar Inna if (!rv) 3893a3667aaeSNaresh Kumar Inna break; 3894a3667aaeSNaresh Kumar Inna /* Handle any remaining fw events */ 3895a3667aaeSNaresh Kumar Inna csio_fcoe_fwevt_handler(hw, 3896a3667aaeSNaresh Kumar Inna msg->opcode, msg->data); 3897a3667aaeSNaresh Kumar Inna } else if (msg->opcode == CPL_FW6_PLD) { 3898a3667aaeSNaresh Kumar Inna 3899a3667aaeSNaresh Kumar Inna csio_fcoe_fwevt_handler(hw, 3900a3667aaeSNaresh Kumar Inna msg->opcode, msg->data); 3901a3667aaeSNaresh Kumar Inna } else { 3902a3667aaeSNaresh Kumar Inna csio_warn(hw, 3903a3667aaeSNaresh Kumar Inna "Unhandled FW msg op %x type %x\n", 3904a3667aaeSNaresh Kumar Inna msg->opcode, msg->type); 3905a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_drop); 3906a3667aaeSNaresh Kumar Inna } 3907a3667aaeSNaresh Kumar Inna break; 3908a3667aaeSNaresh Kumar Inna 3909a3667aaeSNaresh Kumar Inna case CSIO_EVT_MBX: 3910a3667aaeSNaresh Kumar Inna csio_mberr_worker(hw); 3911a3667aaeSNaresh Kumar Inna break; 3912a3667aaeSNaresh Kumar Inna 3913a3667aaeSNaresh Kumar Inna case CSIO_EVT_DEV_LOSS: 3914a3667aaeSNaresh Kumar Inna memcpy(&rn, evt_msg->data, sizeof(rn)); 3915a3667aaeSNaresh Kumar Inna csio_rnode_devloss_handler(rn); 3916a3667aaeSNaresh Kumar Inna break; 3917a3667aaeSNaresh Kumar Inna 3918a3667aaeSNaresh Kumar Inna default: 3919a3667aaeSNaresh Kumar Inna csio_warn(hw, "Unhandled event %x on evtq\n", 3920a3667aaeSNaresh Kumar Inna evt_msg->type); 3921a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_unexp); 3922a3667aaeSNaresh Kumar Inna break; 3923a3667aaeSNaresh Kumar Inna } 3924a3667aaeSNaresh Kumar Inna free_evt: 3925a3667aaeSNaresh Kumar Inna csio_free_evt(hw, evt_msg); 3926a3667aaeSNaresh Kumar Inna } 3927a3667aaeSNaresh Kumar Inna 3928a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 3929a3667aaeSNaresh Kumar Inna } 3930a3667aaeSNaresh Kumar Inna hw->flags &= ~CSIO_HWF_FWEVT_PENDING; 3931a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 3932a3667aaeSNaresh Kumar Inna } 3933a3667aaeSNaresh Kumar Inna 3934a3667aaeSNaresh Kumar Inna int 3935a3667aaeSNaresh Kumar Inna csio_fwevtq_handler(struct csio_hw *hw) 3936a3667aaeSNaresh Kumar Inna { 3937a3667aaeSNaresh Kumar Inna int rv; 3938a3667aaeSNaresh Kumar Inna 3939a3667aaeSNaresh Kumar Inna if (csio_q_iqid(hw, hw->fwevt_iq_idx) == CSIO_MAX_QID) { 3940a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_int_stray); 3941a3667aaeSNaresh Kumar Inna return -EINVAL; 3942a3667aaeSNaresh Kumar Inna } 3943a3667aaeSNaresh Kumar Inna 3944a3667aaeSNaresh Kumar Inna rv = csio_wr_process_iq_idx(hw, hw->fwevt_iq_idx, 3945a3667aaeSNaresh Kumar Inna csio_process_fwevtq_entry, NULL); 3946a3667aaeSNaresh Kumar Inna return rv; 3947a3667aaeSNaresh Kumar Inna } 3948a3667aaeSNaresh Kumar Inna 3949a3667aaeSNaresh Kumar Inna /**************************************************************************** 3950a3667aaeSNaresh Kumar Inna * Entry points 3951a3667aaeSNaresh Kumar Inna ****************************************************************************/ 3952a3667aaeSNaresh Kumar Inna 3953a3667aaeSNaresh Kumar Inna /* Management module */ 3954a3667aaeSNaresh Kumar Inna /* 3955a3667aaeSNaresh Kumar Inna * csio_mgmt_req_lookup - Lookup the given IO req exist in Active Q. 3956a3667aaeSNaresh Kumar Inna * mgmt - mgmt module 3957a3667aaeSNaresh Kumar Inna * @io_req - io request 3958a3667aaeSNaresh Kumar Inna * 3959a3667aaeSNaresh Kumar Inna * Return - 0:if given IO Req exists in active Q. 3960a3667aaeSNaresh Kumar Inna * -EINVAL :if lookup fails. 3961a3667aaeSNaresh Kumar Inna */ 3962a3667aaeSNaresh Kumar Inna int 3963a3667aaeSNaresh Kumar Inna csio_mgmt_req_lookup(struct csio_mgmtm *mgmtm, struct csio_ioreq *io_req) 3964a3667aaeSNaresh Kumar Inna { 3965a3667aaeSNaresh Kumar Inna struct list_head *tmp; 3966a3667aaeSNaresh Kumar Inna 3967a3667aaeSNaresh Kumar Inna /* Lookup ioreq in the ACTIVEQ */ 3968a3667aaeSNaresh Kumar Inna list_for_each(tmp, &mgmtm->active_q) { 3969a3667aaeSNaresh Kumar Inna if (io_req == (struct csio_ioreq *)tmp) 3970a3667aaeSNaresh Kumar Inna return 0; 3971a3667aaeSNaresh Kumar Inna } 3972a3667aaeSNaresh Kumar Inna return -EINVAL; 3973a3667aaeSNaresh Kumar Inna } 3974a3667aaeSNaresh Kumar Inna 3975a3667aaeSNaresh Kumar Inna #define ECM_MIN_TMO 1000 /* Minimum timeout value for req */ 3976a3667aaeSNaresh Kumar Inna 3977a3667aaeSNaresh Kumar Inna /* 3978a3667aaeSNaresh Kumar Inna * csio_mgmts_tmo_handler - MGMT IO Timeout handler. 3979a3667aaeSNaresh Kumar Inna * @data - Event data. 3980a3667aaeSNaresh Kumar Inna * 3981a3667aaeSNaresh Kumar Inna * Return - none. 3982a3667aaeSNaresh Kumar Inna */ 3983a3667aaeSNaresh Kumar Inna static void 3984fa60a31bSKees Cook csio_mgmt_tmo_handler(struct timer_list *t) 3985a3667aaeSNaresh Kumar Inna { 3986fa60a31bSKees Cook struct csio_mgmtm *mgmtm = from_timer(mgmtm, t, mgmt_timer); 3987a3667aaeSNaresh Kumar Inna struct list_head *tmp; 3988a3667aaeSNaresh Kumar Inna struct csio_ioreq *io_req; 3989a3667aaeSNaresh Kumar Inna 3990a3667aaeSNaresh Kumar Inna csio_dbg(mgmtm->hw, "Mgmt timer invoked!\n"); 3991a3667aaeSNaresh Kumar Inna 3992a3667aaeSNaresh Kumar Inna spin_lock_irq(&mgmtm->hw->lock); 3993a3667aaeSNaresh Kumar Inna 3994a3667aaeSNaresh Kumar Inna list_for_each(tmp, &mgmtm->active_q) { 3995a3667aaeSNaresh Kumar Inna io_req = (struct csio_ioreq *) tmp; 3996a3667aaeSNaresh Kumar Inna io_req->tmo -= min_t(uint32_t, io_req->tmo, ECM_MIN_TMO); 3997a3667aaeSNaresh Kumar Inna 3998a3667aaeSNaresh Kumar Inna if (!io_req->tmo) { 3999a3667aaeSNaresh Kumar Inna /* Dequeue the request from retry Q. */ 4000a3667aaeSNaresh Kumar Inna tmp = csio_list_prev(tmp); 4001a3667aaeSNaresh Kumar Inna list_del_init(&io_req->sm.sm_list); 4002a3667aaeSNaresh Kumar Inna if (io_req->io_cbfn) { 4003a3667aaeSNaresh Kumar Inna /* io_req will be freed by completion handler */ 4004a3667aaeSNaresh Kumar Inna io_req->wr_status = -ETIMEDOUT; 4005a3667aaeSNaresh Kumar Inna io_req->io_cbfn(mgmtm->hw, io_req); 4006a3667aaeSNaresh Kumar Inna } else { 4007a3667aaeSNaresh Kumar Inna CSIO_DB_ASSERT(0); 4008a3667aaeSNaresh Kumar Inna } 4009a3667aaeSNaresh Kumar Inna } 4010a3667aaeSNaresh Kumar Inna } 4011a3667aaeSNaresh Kumar Inna 4012a3667aaeSNaresh Kumar Inna /* If retry queue is not empty, re-arm timer */ 4013a3667aaeSNaresh Kumar Inna if (!list_empty(&mgmtm->active_q)) 4014a3667aaeSNaresh Kumar Inna mod_timer(&mgmtm->mgmt_timer, 4015a3667aaeSNaresh Kumar Inna jiffies + msecs_to_jiffies(ECM_MIN_TMO)); 4016a3667aaeSNaresh Kumar Inna spin_unlock_irq(&mgmtm->hw->lock); 4017a3667aaeSNaresh Kumar Inna } 4018a3667aaeSNaresh Kumar Inna 4019a3667aaeSNaresh Kumar Inna static void 4020a3667aaeSNaresh Kumar Inna csio_mgmtm_cleanup(struct csio_mgmtm *mgmtm) 4021a3667aaeSNaresh Kumar Inna { 4022a3667aaeSNaresh Kumar Inna struct csio_hw *hw = mgmtm->hw; 4023a3667aaeSNaresh Kumar Inna struct csio_ioreq *io_req; 4024a3667aaeSNaresh Kumar Inna struct list_head *tmp; 4025a3667aaeSNaresh Kumar Inna uint32_t count; 4026a3667aaeSNaresh Kumar Inna 4027a3667aaeSNaresh Kumar Inna count = 30; 4028a3667aaeSNaresh Kumar Inna /* Wait for all outstanding req to complete gracefully */ 4029a3667aaeSNaresh Kumar Inna while ((!list_empty(&mgmtm->active_q)) && count--) { 4030a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 4031a3667aaeSNaresh Kumar Inna msleep(2000); 4032a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 4033a3667aaeSNaresh Kumar Inna } 4034a3667aaeSNaresh Kumar Inna 4035a3667aaeSNaresh Kumar Inna /* release outstanding req from ACTIVEQ */ 4036a3667aaeSNaresh Kumar Inna list_for_each(tmp, &mgmtm->active_q) { 4037a3667aaeSNaresh Kumar Inna io_req = (struct csio_ioreq *) tmp; 4038a3667aaeSNaresh Kumar Inna tmp = csio_list_prev(tmp); 4039a3667aaeSNaresh Kumar Inna list_del_init(&io_req->sm.sm_list); 4040a3667aaeSNaresh Kumar Inna mgmtm->stats.n_active--; 4041a3667aaeSNaresh Kumar Inna if (io_req->io_cbfn) { 4042a3667aaeSNaresh Kumar Inna /* io_req will be freed by completion handler */ 4043a3667aaeSNaresh Kumar Inna io_req->wr_status = -ETIMEDOUT; 4044a3667aaeSNaresh Kumar Inna io_req->io_cbfn(mgmtm->hw, io_req); 4045a3667aaeSNaresh Kumar Inna } 4046a3667aaeSNaresh Kumar Inna } 4047a3667aaeSNaresh Kumar Inna } 4048a3667aaeSNaresh Kumar Inna 4049a3667aaeSNaresh Kumar Inna /* 4050a3667aaeSNaresh Kumar Inna * csio_mgmt_init - Mgmt module init entry point 4051a3667aaeSNaresh Kumar Inna * @mgmtsm - mgmt module 4052a3667aaeSNaresh Kumar Inna * @hw - HW module 4053a3667aaeSNaresh Kumar Inna * 4054a3667aaeSNaresh Kumar Inna * Initialize mgmt timer, resource wait queue, active queue, 4055a3667aaeSNaresh Kumar Inna * completion q. Allocate Egress and Ingress 4056a3667aaeSNaresh Kumar Inna * WR queues and save off the queue index returned by the WR 4057a3667aaeSNaresh Kumar Inna * module for future use. Allocate and save off mgmt reqs in the 4058a3667aaeSNaresh Kumar Inna * mgmt_req_freelist for future use. Make sure their SM is initialized 4059a3667aaeSNaresh Kumar Inna * to uninit state. 4060a3667aaeSNaresh Kumar Inna * Returns: 0 - on success 4061a3667aaeSNaresh Kumar Inna * -ENOMEM - on error. 4062a3667aaeSNaresh Kumar Inna */ 4063a3667aaeSNaresh Kumar Inna static int 4064a3667aaeSNaresh Kumar Inna csio_mgmtm_init(struct csio_mgmtm *mgmtm, struct csio_hw *hw) 4065a3667aaeSNaresh Kumar Inna { 4066fa60a31bSKees Cook timer_setup(&mgmtm->mgmt_timer, csio_mgmt_tmo_handler, 0); 4067a3667aaeSNaresh Kumar Inna 4068a3667aaeSNaresh Kumar Inna INIT_LIST_HEAD(&mgmtm->active_q); 4069a3667aaeSNaresh Kumar Inna INIT_LIST_HEAD(&mgmtm->cbfn_q); 4070a3667aaeSNaresh Kumar Inna 4071a3667aaeSNaresh Kumar Inna mgmtm->hw = hw; 4072a3667aaeSNaresh Kumar Inna /*mgmtm->iq_idx = hw->fwevt_iq_idx;*/ 4073a3667aaeSNaresh Kumar Inna 4074a3667aaeSNaresh Kumar Inna return 0; 4075a3667aaeSNaresh Kumar Inna } 4076a3667aaeSNaresh Kumar Inna 4077a3667aaeSNaresh Kumar Inna /* 4078a3667aaeSNaresh Kumar Inna * csio_mgmtm_exit - MGMT module exit entry point 4079a3667aaeSNaresh Kumar Inna * @mgmtsm - mgmt module 4080a3667aaeSNaresh Kumar Inna * 4081a3667aaeSNaresh Kumar Inna * This function called during MGMT module uninit. 4082a3667aaeSNaresh Kumar Inna * Stop timers, free ioreqs allocated. 4083a3667aaeSNaresh Kumar Inna * Returns: None 4084a3667aaeSNaresh Kumar Inna * 4085a3667aaeSNaresh Kumar Inna */ 4086a3667aaeSNaresh Kumar Inna static void 4087a3667aaeSNaresh Kumar Inna csio_mgmtm_exit(struct csio_mgmtm *mgmtm) 4088a3667aaeSNaresh Kumar Inna { 4089a3667aaeSNaresh Kumar Inna del_timer_sync(&mgmtm->mgmt_timer); 4090a3667aaeSNaresh Kumar Inna } 4091a3667aaeSNaresh Kumar Inna 4092a3667aaeSNaresh Kumar Inna 4093a3667aaeSNaresh Kumar Inna /** 4094a3667aaeSNaresh Kumar Inna * csio_hw_start - Kicks off the HW State machine 4095a3667aaeSNaresh Kumar Inna * @hw: Pointer to HW module. 4096a3667aaeSNaresh Kumar Inna * 4097a3667aaeSNaresh Kumar Inna * It is assumed that the initialization is a synchronous operation. 4098a3667aaeSNaresh Kumar Inna * So when we return afer posting the event, the HW SM should be in 4099a3667aaeSNaresh Kumar Inna * the ready state, if there were no errors during init. 4100a3667aaeSNaresh Kumar Inna */ 4101a3667aaeSNaresh Kumar Inna int 4102a3667aaeSNaresh Kumar Inna csio_hw_start(struct csio_hw *hw) 4103a3667aaeSNaresh Kumar Inna { 4104a3667aaeSNaresh Kumar Inna spin_lock_irq(&hw->lock); 4105a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_CFG); 4106a3667aaeSNaresh Kumar Inna spin_unlock_irq(&hw->lock); 4107a3667aaeSNaresh Kumar Inna 4108a3667aaeSNaresh Kumar Inna if (csio_is_hw_ready(hw)) 4109a3667aaeSNaresh Kumar Inna return 0; 411082f0fd06SVarun Prakash else if (csio_match_state(hw, csio_hws_uninit)) 4111a3667aaeSNaresh Kumar Inna return -EINVAL; 411282f0fd06SVarun Prakash else 411382f0fd06SVarun Prakash return -ENODEV; 4114a3667aaeSNaresh Kumar Inna } 4115a3667aaeSNaresh Kumar Inna 4116a3667aaeSNaresh Kumar Inna int 4117a3667aaeSNaresh Kumar Inna csio_hw_stop(struct csio_hw *hw) 4118a3667aaeSNaresh Kumar Inna { 4119a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_PCI_REMOVE); 4120a3667aaeSNaresh Kumar Inna 4121a3667aaeSNaresh Kumar Inna if (csio_is_hw_removing(hw)) 4122a3667aaeSNaresh Kumar Inna return 0; 4123a3667aaeSNaresh Kumar Inna else 4124a3667aaeSNaresh Kumar Inna return -EINVAL; 4125a3667aaeSNaresh Kumar Inna } 4126a3667aaeSNaresh Kumar Inna 4127a3667aaeSNaresh Kumar Inna /* Max reset retries */ 4128a3667aaeSNaresh Kumar Inna #define CSIO_MAX_RESET_RETRIES 3 4129a3667aaeSNaresh Kumar Inna 4130a3667aaeSNaresh Kumar Inna /** 4131a3667aaeSNaresh Kumar Inna * csio_hw_reset - Reset the hardware 4132a3667aaeSNaresh Kumar Inna * @hw: HW module. 4133a3667aaeSNaresh Kumar Inna * 4134a3667aaeSNaresh Kumar Inna * Caller should hold lock across this function. 4135a3667aaeSNaresh Kumar Inna */ 4136a3667aaeSNaresh Kumar Inna int 4137a3667aaeSNaresh Kumar Inna csio_hw_reset(struct csio_hw *hw) 4138a3667aaeSNaresh Kumar Inna { 4139a3667aaeSNaresh Kumar Inna if (!csio_is_hw_master(hw)) 4140a3667aaeSNaresh Kumar Inna return -EPERM; 4141a3667aaeSNaresh Kumar Inna 4142a3667aaeSNaresh Kumar Inna if (hw->rst_retries >= CSIO_MAX_RESET_RETRIES) { 4143a3667aaeSNaresh Kumar Inna csio_dbg(hw, "Max hw reset attempts reached.."); 4144a3667aaeSNaresh Kumar Inna return -EINVAL; 4145a3667aaeSNaresh Kumar Inna } 4146a3667aaeSNaresh Kumar Inna 4147a3667aaeSNaresh Kumar Inna hw->rst_retries++; 4148a3667aaeSNaresh Kumar Inna csio_post_event(&hw->sm, CSIO_HWE_HBA_RESET); 4149a3667aaeSNaresh Kumar Inna 4150a3667aaeSNaresh Kumar Inna if (csio_is_hw_ready(hw)) { 4151a3667aaeSNaresh Kumar Inna hw->rst_retries = 0; 4152a3667aaeSNaresh Kumar Inna hw->stats.n_reset_start = jiffies_to_msecs(jiffies); 4153a3667aaeSNaresh Kumar Inna return 0; 4154a3667aaeSNaresh Kumar Inna } else 4155a3667aaeSNaresh Kumar Inna return -EINVAL; 4156a3667aaeSNaresh Kumar Inna } 4157a3667aaeSNaresh Kumar Inna 4158a3667aaeSNaresh Kumar Inna /* 4159a3667aaeSNaresh Kumar Inna * csio_hw_get_device_id - Caches the Adapter's vendor & device id. 4160a3667aaeSNaresh Kumar Inna * @hw: HW module. 4161a3667aaeSNaresh Kumar Inna */ 4162a3667aaeSNaresh Kumar Inna static void 4163a3667aaeSNaresh Kumar Inna csio_hw_get_device_id(struct csio_hw *hw) 4164a3667aaeSNaresh Kumar Inna { 4165a3667aaeSNaresh Kumar Inna /* Is the adapter device id cached already ?*/ 4166a3667aaeSNaresh Kumar Inna if (csio_is_dev_id_cached(hw)) 4167a3667aaeSNaresh Kumar Inna return; 4168a3667aaeSNaresh Kumar Inna 4169a3667aaeSNaresh Kumar Inna /* Get the PCI vendor & device id */ 4170a3667aaeSNaresh Kumar Inna pci_read_config_word(hw->pdev, PCI_VENDOR_ID, 4171a3667aaeSNaresh Kumar Inna &hw->params.pci.vendor_id); 4172a3667aaeSNaresh Kumar Inna pci_read_config_word(hw->pdev, PCI_DEVICE_ID, 4173a3667aaeSNaresh Kumar Inna &hw->params.pci.device_id); 4174a3667aaeSNaresh Kumar Inna 4175a3667aaeSNaresh Kumar Inna csio_dev_id_cached(hw); 41767cc16380SArvind Bhushan hw->chip_id = (hw->params.pci.device_id & CSIO_HW_CHIP_MASK); 4177a3667aaeSNaresh Kumar Inna 4178a3667aaeSNaresh Kumar Inna } /* csio_hw_get_device_id */ 4179a3667aaeSNaresh Kumar Inna 4180a3667aaeSNaresh Kumar Inna /* 4181a3667aaeSNaresh Kumar Inna * csio_hw_set_description - Set the model, description of the hw. 4182a3667aaeSNaresh Kumar Inna * @hw: HW module. 4183a3667aaeSNaresh Kumar Inna * @ven_id: PCI Vendor ID 4184a3667aaeSNaresh Kumar Inna * @dev_id: PCI Device ID 4185a3667aaeSNaresh Kumar Inna */ 4186a3667aaeSNaresh Kumar Inna static void 4187a3667aaeSNaresh Kumar Inna csio_hw_set_description(struct csio_hw *hw, uint16_t ven_id, uint16_t dev_id) 4188a3667aaeSNaresh Kumar Inna { 4189a3667aaeSNaresh Kumar Inna uint32_t adap_type, prot_type; 4190a3667aaeSNaresh Kumar Inna 4191a3667aaeSNaresh Kumar Inna if (ven_id == CSIO_VENDOR_ID) { 4192a3667aaeSNaresh Kumar Inna prot_type = (dev_id & CSIO_ASIC_DEVID_PROTO_MASK); 4193a3667aaeSNaresh Kumar Inna adap_type = (dev_id & CSIO_ASIC_DEVID_TYPE_MASK); 4194a3667aaeSNaresh Kumar Inna 41953fb4c22eSPraveen Madhavan if (prot_type == CSIO_T5_FCOE_ASIC) { 41967cc16380SArvind Bhushan memcpy(hw->hw_ver, 41977cc16380SArvind Bhushan csio_t5_fcoe_adapters[adap_type].model_no, 16); 41987cc16380SArvind Bhushan memcpy(hw->model_desc, 41997cc16380SArvind Bhushan csio_t5_fcoe_adapters[adap_type].description, 42007cc16380SArvind Bhushan 32); 4201a3667aaeSNaresh Kumar Inna } else { 4202a3667aaeSNaresh Kumar Inna char tempName[32] = "Chelsio FCoE Controller"; 4203a3667aaeSNaresh Kumar Inna memcpy(hw->model_desc, tempName, 32); 4204a3667aaeSNaresh Kumar Inna } 4205a3667aaeSNaresh Kumar Inna } 4206a3667aaeSNaresh Kumar Inna } /* csio_hw_set_description */ 4207a3667aaeSNaresh Kumar Inna 4208a3667aaeSNaresh Kumar Inna /** 4209a3667aaeSNaresh Kumar Inna * csio_hw_init - Initialize HW module. 4210a3667aaeSNaresh Kumar Inna * @hw: Pointer to HW module. 4211a3667aaeSNaresh Kumar Inna * 4212a3667aaeSNaresh Kumar Inna * Initialize the members of the HW module. 4213a3667aaeSNaresh Kumar Inna */ 4214a3667aaeSNaresh Kumar Inna int 4215a3667aaeSNaresh Kumar Inna csio_hw_init(struct csio_hw *hw) 4216a3667aaeSNaresh Kumar Inna { 4217a3667aaeSNaresh Kumar Inna int rv = -EINVAL; 4218a3667aaeSNaresh Kumar Inna uint32_t i; 4219a3667aaeSNaresh Kumar Inna uint16_t ven_id, dev_id; 4220a3667aaeSNaresh Kumar Inna struct csio_evt_msg *evt_entry; 4221a3667aaeSNaresh Kumar Inna 4222a3667aaeSNaresh Kumar Inna INIT_LIST_HEAD(&hw->sm.sm_list); 4223a3667aaeSNaresh Kumar Inna csio_init_state(&hw->sm, csio_hws_uninit); 4224a3667aaeSNaresh Kumar Inna spin_lock_init(&hw->lock); 4225a3667aaeSNaresh Kumar Inna INIT_LIST_HEAD(&hw->sln_head); 4226a3667aaeSNaresh Kumar Inna 4227a3667aaeSNaresh Kumar Inna /* Get the PCI vendor & device id */ 4228a3667aaeSNaresh Kumar Inna csio_hw_get_device_id(hw); 4229a3667aaeSNaresh Kumar Inna 4230a3667aaeSNaresh Kumar Inna strcpy(hw->name, CSIO_HW_NAME); 4231a3667aaeSNaresh Kumar Inna 42323fb4c22eSPraveen Madhavan /* Initialize the HW chip ops T5 specific ops */ 42333fb4c22eSPraveen Madhavan hw->chip_ops = &t5_ops; 42347cc16380SArvind Bhushan 4235a3667aaeSNaresh Kumar Inna /* Set the model & its description */ 4236a3667aaeSNaresh Kumar Inna 4237a3667aaeSNaresh Kumar Inna ven_id = hw->params.pci.vendor_id; 4238a3667aaeSNaresh Kumar Inna dev_id = hw->params.pci.device_id; 4239a3667aaeSNaresh Kumar Inna 4240a3667aaeSNaresh Kumar Inna csio_hw_set_description(hw, ven_id, dev_id); 4241a3667aaeSNaresh Kumar Inna 4242a3667aaeSNaresh Kumar Inna /* Initialize default log level */ 4243a3667aaeSNaresh Kumar Inna hw->params.log_level = (uint32_t) csio_dbg_level; 4244a3667aaeSNaresh Kumar Inna 4245a3667aaeSNaresh Kumar Inna csio_set_fwevt_intr_idx(hw, -1); 4246a3667aaeSNaresh Kumar Inna csio_set_nondata_intr_idx(hw, -1); 4247a3667aaeSNaresh Kumar Inna 4248a3667aaeSNaresh Kumar Inna /* Init all the modules: Mailbox, WorkRequest and Transport */ 4249a3667aaeSNaresh Kumar Inna if (csio_mbm_init(csio_hw_to_mbm(hw), hw, csio_hw_mb_timer)) 4250a3667aaeSNaresh Kumar Inna goto err; 4251a3667aaeSNaresh Kumar Inna 4252a3667aaeSNaresh Kumar Inna rv = csio_wrm_init(csio_hw_to_wrm(hw), hw); 4253a3667aaeSNaresh Kumar Inna if (rv) 4254a3667aaeSNaresh Kumar Inna goto err_mbm_exit; 4255a3667aaeSNaresh Kumar Inna 4256a3667aaeSNaresh Kumar Inna rv = csio_scsim_init(csio_hw_to_scsim(hw), hw); 4257a3667aaeSNaresh Kumar Inna if (rv) 4258a3667aaeSNaresh Kumar Inna goto err_wrm_exit; 4259a3667aaeSNaresh Kumar Inna 4260a3667aaeSNaresh Kumar Inna rv = csio_mgmtm_init(csio_hw_to_mgmtm(hw), hw); 4261a3667aaeSNaresh Kumar Inna if (rv) 4262a3667aaeSNaresh Kumar Inna goto err_scsim_exit; 4263a3667aaeSNaresh Kumar Inna /* Pre-allocate evtq and initialize them */ 4264a3667aaeSNaresh Kumar Inna INIT_LIST_HEAD(&hw->evt_active_q); 4265a3667aaeSNaresh Kumar Inna INIT_LIST_HEAD(&hw->evt_free_q); 4266a3667aaeSNaresh Kumar Inna for (i = 0; i < csio_evtq_sz; i++) { 4267a3667aaeSNaresh Kumar Inna 4268a3667aaeSNaresh Kumar Inna evt_entry = kzalloc(sizeof(struct csio_evt_msg), GFP_KERNEL); 4269a3667aaeSNaresh Kumar Inna if (!evt_entry) { 4270ea47ebf1SDan Carpenter rv = -ENOMEM; 4271a3667aaeSNaresh Kumar Inna csio_err(hw, "Failed to initialize eventq"); 4272a3667aaeSNaresh Kumar Inna goto err_evtq_cleanup; 4273a3667aaeSNaresh Kumar Inna } 4274a3667aaeSNaresh Kumar Inna 4275a3667aaeSNaresh Kumar Inna list_add_tail(&evt_entry->list, &hw->evt_free_q); 4276a3667aaeSNaresh Kumar Inna CSIO_INC_STATS(hw, n_evt_freeq); 4277a3667aaeSNaresh Kumar Inna } 4278a3667aaeSNaresh Kumar Inna 4279a3667aaeSNaresh Kumar Inna hw->dev_num = dev_num; 4280a3667aaeSNaresh Kumar Inna dev_num++; 4281a3667aaeSNaresh Kumar Inna 4282a3667aaeSNaresh Kumar Inna return 0; 4283a3667aaeSNaresh Kumar Inna 4284a3667aaeSNaresh Kumar Inna err_evtq_cleanup: 4285a3667aaeSNaresh Kumar Inna csio_evtq_cleanup(hw); 4286a3667aaeSNaresh Kumar Inna csio_mgmtm_exit(csio_hw_to_mgmtm(hw)); 4287a3667aaeSNaresh Kumar Inna err_scsim_exit: 4288a3667aaeSNaresh Kumar Inna csio_scsim_exit(csio_hw_to_scsim(hw)); 4289a3667aaeSNaresh Kumar Inna err_wrm_exit: 4290a3667aaeSNaresh Kumar Inna csio_wrm_exit(csio_hw_to_wrm(hw), hw); 4291a3667aaeSNaresh Kumar Inna err_mbm_exit: 4292a3667aaeSNaresh Kumar Inna csio_mbm_exit(csio_hw_to_mbm(hw)); 4293a3667aaeSNaresh Kumar Inna err: 4294a3667aaeSNaresh Kumar Inna return rv; 4295a3667aaeSNaresh Kumar Inna } 4296a3667aaeSNaresh Kumar Inna 4297a3667aaeSNaresh Kumar Inna /** 4298a3667aaeSNaresh Kumar Inna * csio_hw_exit - Un-initialize HW module. 4299a3667aaeSNaresh Kumar Inna * @hw: Pointer to HW module. 4300a3667aaeSNaresh Kumar Inna * 4301a3667aaeSNaresh Kumar Inna */ 4302a3667aaeSNaresh Kumar Inna void 4303a3667aaeSNaresh Kumar Inna csio_hw_exit(struct csio_hw *hw) 4304a3667aaeSNaresh Kumar Inna { 4305a3667aaeSNaresh Kumar Inna csio_evtq_cleanup(hw); 4306a3667aaeSNaresh Kumar Inna csio_mgmtm_exit(csio_hw_to_mgmtm(hw)); 4307a3667aaeSNaresh Kumar Inna csio_scsim_exit(csio_hw_to_scsim(hw)); 4308a3667aaeSNaresh Kumar Inna csio_wrm_exit(csio_hw_to_wrm(hw), hw); 4309a3667aaeSNaresh Kumar Inna csio_mbm_exit(csio_hw_to_mbm(hw)); 4310a3667aaeSNaresh Kumar Inna } 4311