1218792Snp/*- 2237436Snp * Copyright (c) 2012 Chelsio Communications, Inc. 3218792Snp * All rights reserved. 4218792Snp * 5218792Snp * Redistribution and use in source and binary forms, with or without 6218792Snp * modification, are permitted provided that the following conditions 7218792Snp * are met: 8218792Snp * 1. Redistributions of source code must retain the above copyright 9218792Snp * notice, this list of conditions and the following disclaimer. 10218792Snp * 2. Redistributions in binary form must reproduce the above copyright 11218792Snp * notice, this list of conditions and the following disclaimer in the 12218792Snp * documentation and/or other materials provided with the distribution. 13218792Snp * 14218792Snp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15218792Snp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16218792Snp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17218792Snp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18218792Snp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19218792Snp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20218792Snp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21218792Snp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22218792Snp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23218792Snp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24218792Snp * SUCH DAMAGE. 25218792Snp */ 26218792Snp 27218792Snp#include <sys/cdefs.h> 28218792Snp__FBSDID("$FreeBSD: releng/10.3/sys/dev/cxgbe/common/t4_hw.c 286897 2015-08-18 19:04:55Z np $"); 29218792Snp 30237263Snp#include "opt_inet.h" 31237263Snp 32218792Snp#include "common.h" 33218792Snp#include "t4_regs.h" 34218792Snp#include "t4_regs_values.h" 35228561Snp#include "firmware/t4fw_interface.h" 36218792Snp 37220649Snp#undef msleep 38246385Snp#define msleep(x) do { \ 39246385Snp if (cold) \ 40246385Snp DELAY((x) * 1000); \ 41246385Snp else \ 42246385Snp pause("t4hw", (x) * hz / 1000); \ 43246385Snp} while (0) 44218792Snp 45218792Snp/** 46218792Snp * t4_wait_op_done_val - wait until an operation is completed 47218792Snp * @adapter: the adapter performing the operation 48218792Snp * @reg: the register to check for completion 49218792Snp * @mask: a single-bit field within @reg that indicates completion 50218792Snp * @polarity: the value of the field when the operation is completed 51218792Snp * @attempts: number of check iterations 52218792Snp * @delay: delay in usecs between iterations 53218792Snp * @valp: where to store the value of the register at completion time 54218792Snp * 55218792Snp * Wait until an operation is completed by checking a bit in a register 56218792Snp * up to @attempts times. If @valp is not NULL the value of the register 57218792Snp * at the time it indicated completion is stored there. Returns 0 if the 58218792Snp * operation completes and -EAGAIN otherwise. 59218792Snp */ 60218792Snpint t4_wait_op_done_val(struct adapter *adapter, int reg, u32 mask, 61218792Snp int polarity, int attempts, int delay, u32 *valp) 62218792Snp{ 63218792Snp while (1) { 64218792Snp u32 val = t4_read_reg(adapter, reg); 65218792Snp 66218792Snp if (!!(val & mask) == polarity) { 67218792Snp if (valp) 68218792Snp *valp = val; 69218792Snp return 0; 70218792Snp } 71218792Snp if (--attempts == 0) 72218792Snp return -EAGAIN; 73218792Snp if (delay) 74218792Snp udelay(delay); 75218792Snp } 76218792Snp} 77218792Snp 78218792Snp/** 79218792Snp * t4_set_reg_field - set a register field to a value 80218792Snp * @adapter: the adapter to program 81218792Snp * @addr: the register address 82218792Snp * @mask: specifies the portion of the register to modify 83218792Snp * @val: the new value for the register field 84218792Snp * 85218792Snp * Sets a register field specified by the supplied mask to the 86218792Snp * given value. 87218792Snp */ 88218792Snpvoid t4_set_reg_field(struct adapter *adapter, unsigned int addr, u32 mask, 89218792Snp u32 val) 90218792Snp{ 91218792Snp u32 v = t4_read_reg(adapter, addr) & ~mask; 92218792Snp 93218792Snp t4_write_reg(adapter, addr, v | val); 94218792Snp (void) t4_read_reg(adapter, addr); /* flush */ 95218792Snp} 96218792Snp 97218792Snp/** 98218792Snp * t4_read_indirect - read indirectly addressed registers 99218792Snp * @adap: the adapter 100218792Snp * @addr_reg: register holding the indirect address 101218792Snp * @data_reg: register holding the value of the indirect register 102218792Snp * @vals: where the read register values are stored 103218792Snp * @nregs: how many indirect registers to read 104218792Snp * @start_idx: index of first indirect register to read 105218792Snp * 106218792Snp * Reads registers that are accessed indirectly through an address/data 107218792Snp * register pair. 108218792Snp */ 109218792Snpvoid t4_read_indirect(struct adapter *adap, unsigned int addr_reg, 110218792Snp unsigned int data_reg, u32 *vals, unsigned int nregs, 111218792Snp unsigned int start_idx) 112218792Snp{ 113218792Snp while (nregs--) { 114218792Snp t4_write_reg(adap, addr_reg, start_idx); 115218792Snp *vals++ = t4_read_reg(adap, data_reg); 116218792Snp start_idx++; 117218792Snp } 118218792Snp} 119218792Snp 120218792Snp/** 121218792Snp * t4_write_indirect - write indirectly addressed registers 122218792Snp * @adap: the adapter 123218792Snp * @addr_reg: register holding the indirect addresses 124218792Snp * @data_reg: register holding the value for the indirect registers 125218792Snp * @vals: values to write 126218792Snp * @nregs: how many indirect registers to write 127218792Snp * @start_idx: address of first indirect register to write 128218792Snp * 129218792Snp * Writes a sequential block of registers that are accessed indirectly 130218792Snp * through an address/data register pair. 131218792Snp */ 132218792Snpvoid t4_write_indirect(struct adapter *adap, unsigned int addr_reg, 133218792Snp unsigned int data_reg, const u32 *vals, 134218792Snp unsigned int nregs, unsigned int start_idx) 135218792Snp{ 136218792Snp while (nregs--) { 137218792Snp t4_write_reg(adap, addr_reg, start_idx++); 138218792Snp t4_write_reg(adap, data_reg, *vals++); 139218792Snp } 140218792Snp} 141218792Snp 142218792Snp/* 143237436Snp * Read a 32-bit PCI Configuration Space register via the PCI-E backdoor 144237436Snp * mechanism. This guarantees that we get the real value even if we're 145237436Snp * operating within a Virtual Machine and the Hypervisor is trapping our 146237436Snp * Configuration Space accesses. 147237436Snp */ 148237436Snpu32 t4_hw_pci_read_cfg4(adapter_t *adap, int reg) 149237436Snp{ 150237436Snp t4_write_reg(adap, A_PCIE_CFG_SPACE_REQ, 151237436Snp F_ENABLE | F_LOCALCFG | V_FUNCTION(adap->pf) | 152237436Snp V_REGISTER(reg)); 153237436Snp return t4_read_reg(adap, A_PCIE_CFG_SPACE_DATA); 154237436Snp} 155237436Snp 156237436Snp/* 157247355Snp * t4_report_fw_error - report firmware error 158247355Snp * @adap: the adapter 159247355Snp * 160247355Snp * The adapter firmware can indicate error conditions to the host. 161247355Snp * This routine prints out the reason for the firmware error (as 162247355Snp * reported by the firmware). 163247355Snp */ 164247355Snpstatic void t4_report_fw_error(struct adapter *adap) 165247355Snp{ 166247355Snp static const char *reason[] = { 167247355Snp "Crash", /* PCIE_FW_EVAL_CRASH */ 168247355Snp "During Device Preparation", /* PCIE_FW_EVAL_PREP */ 169247355Snp "During Device Configuration", /* PCIE_FW_EVAL_CONF */ 170247355Snp "During Device Initialization", /* PCIE_FW_EVAL_INIT */ 171247355Snp "Unexpected Event", /* PCIE_FW_EVAL_UNEXPECTEDEVENT */ 172247355Snp "Insufficient Airflow", /* PCIE_FW_EVAL_OVERHEAT */ 173247355Snp "Device Shutdown", /* PCIE_FW_EVAL_DEVICESHUTDOWN */ 174247355Snp "Reserved", /* reserved */ 175247355Snp }; 176247355Snp u32 pcie_fw; 177247355Snp 178247355Snp pcie_fw = t4_read_reg(adap, A_PCIE_FW); 179250090Snp if (pcie_fw & F_PCIE_FW_ERR) 180247355Snp CH_ERR(adap, "Firmware reports adapter error: %s\n", 181247355Snp reason[G_PCIE_FW_EVAL(pcie_fw)]); 182247355Snp} 183247355Snp 184247355Snp/* 185218792Snp * Get the reply to a mailbox command and store it in @rpl in big-endian order. 186218792Snp */ 187218792Snpstatic void get_mbox_rpl(struct adapter *adap, __be64 *rpl, int nflit, 188218792Snp u32 mbox_addr) 189218792Snp{ 190218792Snp for ( ; nflit; nflit--, mbox_addr += 8) 191218792Snp *rpl++ = cpu_to_be64(t4_read_reg64(adap, mbox_addr)); 192218792Snp} 193218792Snp 194218792Snp/* 195218792Snp * Handle a FW assertion reported in a mailbox. 196218792Snp */ 197218792Snpstatic void fw_asrt(struct adapter *adap, u32 mbox_addr) 198218792Snp{ 199218792Snp struct fw_debug_cmd asrt; 200218792Snp 201218792Snp get_mbox_rpl(adap, (__be64 *)&asrt, sizeof(asrt) / 8, mbox_addr); 202218792Snp CH_ALERT(adap, "FW assertion at %.16s:%u, val0 %#x, val1 %#x\n", 203218792Snp asrt.u.assert.filename_0_7, ntohl(asrt.u.assert.line), 204218792Snp ntohl(asrt.u.assert.x), ntohl(asrt.u.assert.y)); 205218792Snp} 206218792Snp 207218792Snp#define X_CIM_PF_NOACCESS 0xeeeeeeee 208218792Snp/** 209218792Snp * t4_wr_mbox_meat - send a command to FW through the given mailbox 210218792Snp * @adap: the adapter 211218792Snp * @mbox: index of the mailbox to use 212218792Snp * @cmd: the command to write 213218792Snp * @size: command length in bytes 214218792Snp * @rpl: where to optionally store the reply 215218792Snp * @sleep_ok: if true we may sleep while awaiting command completion 216218792Snp * 217218792Snp * Sends the given command to FW through the selected mailbox and waits 218218792Snp * for the FW to execute the command. If @rpl is not %NULL it is used to 219218792Snp * store the FW's reply to the command. The command and its optional 220218792Snp * reply are of the same length. Some FW commands like RESET and 221218792Snp * INITIALIZE can take a considerable amount of time to execute. 222218792Snp * @sleep_ok determines whether we may sleep while awaiting the response. 223218792Snp * If sleeping is allowed we use progressive backoff otherwise we spin. 224218792Snp * 225218792Snp * The return value is 0 on success or a negative errno on failure. A 226218792Snp * failure can happen either because we are not able to execute the 227218792Snp * command or FW executes it but signals an error. In the latter case 228218792Snp * the return value is the error code indicated by FW (negated). 229218792Snp */ 230218792Snpint t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size, 231218792Snp void *rpl, bool sleep_ok) 232218792Snp{ 233218792Snp /* 234218792Snp * We delay in small increments at first in an effort to maintain 235218792Snp * responsiveness for simple, fast executing commands but then back 236218792Snp * off to larger delays to a maximum retry delay. 237218792Snp */ 238218792Snp static const int delay[] = { 239228561Snp 1, 1, 3, 5, 10, 10, 20, 50, 100 240218792Snp }; 241218792Snp 242218792Snp u32 v; 243218792Snp u64 res; 244218792Snp int i, ms, delay_idx; 245218792Snp const __be64 *p = cmd; 246218792Snp u32 data_reg = PF_REG(mbox, A_CIM_PF_MAILBOX_DATA); 247218792Snp u32 ctl_reg = PF_REG(mbox, A_CIM_PF_MAILBOX_CTRL); 248218792Snp 249218792Snp if ((size & 15) || size > MBOX_LEN) 250218792Snp return -EINVAL; 251218792Snp 252218792Snp v = G_MBOWNER(t4_read_reg(adap, ctl_reg)); 253218792Snp for (i = 0; v == X_MBOWNER_NONE && i < 3; i++) 254218792Snp v = G_MBOWNER(t4_read_reg(adap, ctl_reg)); 255218792Snp 256218792Snp if (v != X_MBOWNER_PL) 257218792Snp return v ? -EBUSY : -ETIMEDOUT; 258218792Snp 259218792Snp for (i = 0; i < size; i += 8, p++) 260218792Snp t4_write_reg64(adap, data_reg + i, be64_to_cpu(*p)); 261218792Snp 262286271Snp CH_DUMP_MBOX(adap, mbox, data_reg); 263286271Snp 264218792Snp t4_write_reg(adap, ctl_reg, F_MBMSGVALID | V_MBOWNER(X_MBOWNER_FW)); 265218792Snp t4_read_reg(adap, ctl_reg); /* flush write */ 266218792Snp 267218792Snp delay_idx = 0; 268218792Snp ms = delay[0]; 269218792Snp 270218792Snp for (i = 0; i < FW_CMD_MAX_TIMEOUT; i += ms) { 271218792Snp if (sleep_ok) { 272218792Snp ms = delay[delay_idx]; /* last element may repeat */ 273218792Snp if (delay_idx < ARRAY_SIZE(delay) - 1) 274218792Snp delay_idx++; 275218792Snp msleep(ms); 276218792Snp } else 277218792Snp mdelay(ms); 278218792Snp 279218792Snp v = t4_read_reg(adap, ctl_reg); 280218792Snp if (v == X_CIM_PF_NOACCESS) 281218792Snp continue; 282218792Snp if (G_MBOWNER(v) == X_MBOWNER_PL) { 283218792Snp if (!(v & F_MBMSGVALID)) { 284218792Snp t4_write_reg(adap, ctl_reg, 285218792Snp V_MBOWNER(X_MBOWNER_NONE)); 286218792Snp continue; 287218792Snp } 288218792Snp 289286271Snp CH_DUMP_MBOX(adap, mbox, data_reg); 290286271Snp 291218792Snp res = t4_read_reg64(adap, data_reg); 292218792Snp if (G_FW_CMD_OP(res >> 32) == FW_DEBUG_CMD) { 293218792Snp fw_asrt(adap, data_reg); 294218792Snp res = V_FW_CMD_RETVAL(EIO); 295218792Snp } else if (rpl) 296218792Snp get_mbox_rpl(adap, rpl, size / 8, data_reg); 297218792Snp t4_write_reg(adap, ctl_reg, V_MBOWNER(X_MBOWNER_NONE)); 298218792Snp return -G_FW_CMD_RETVAL((int)res); 299218792Snp } 300218792Snp } 301218792Snp 302247355Snp /* 303247355Snp * We timed out waiting for a reply to our mailbox command. Report 304247355Snp * the error and also check to see if the firmware reported any 305247355Snp * errors ... 306247355Snp */ 307218792Snp CH_ERR(adap, "command %#x in mailbox %d timed out\n", 308218792Snp *(const u8 *)cmd, mbox); 309247355Snp if (t4_read_reg(adap, A_PCIE_FW) & F_PCIE_FW_ERR) 310247355Snp t4_report_fw_error(adap); 311218792Snp return -ETIMEDOUT; 312218792Snp} 313218792Snp 314218792Snp/** 315218792Snp * t4_mc_read - read from MC through backdoor accesses 316218792Snp * @adap: the adapter 317248925Snp * @idx: which MC to access 318218792Snp * @addr: address of first byte requested 319218792Snp * @data: 64 bytes of data containing the requested address 320218792Snp * @ecc: where to store the corresponding 64-bit ECC word 321218792Snp * 322218792Snp * Read 64 bytes of data from MC starting at a 64-byte-aligned address 323218792Snp * that covers the requested address @addr. If @parity is not %NULL it 324218792Snp * is assigned the 64-bit ECC word for the read data. 325218792Snp */ 326248925Snpint t4_mc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *ecc) 327218792Snp{ 328218792Snp int i; 329248925Snp u32 mc_bist_cmd_reg, mc_bist_cmd_addr_reg, mc_bist_cmd_len_reg; 330248925Snp u32 mc_bist_status_rdata_reg, mc_bist_data_pattern_reg; 331218792Snp 332248925Snp if (is_t4(adap)) { 333248925Snp mc_bist_cmd_reg = A_MC_BIST_CMD; 334248925Snp mc_bist_cmd_addr_reg = A_MC_BIST_CMD_ADDR; 335248925Snp mc_bist_cmd_len_reg = A_MC_BIST_CMD_LEN; 336248925Snp mc_bist_status_rdata_reg = A_MC_BIST_STATUS_RDATA; 337248925Snp mc_bist_data_pattern_reg = A_MC_BIST_DATA_PATTERN; 338248925Snp } else { 339248925Snp mc_bist_cmd_reg = MC_REG(A_MC_P_BIST_CMD, idx); 340248925Snp mc_bist_cmd_addr_reg = MC_REG(A_MC_P_BIST_CMD_ADDR, idx); 341248925Snp mc_bist_cmd_len_reg = MC_REG(A_MC_P_BIST_CMD_LEN, idx); 342248925Snp mc_bist_status_rdata_reg = MC_REG(A_MC_P_BIST_STATUS_RDATA, 343248925Snp idx); 344248925Snp mc_bist_data_pattern_reg = MC_REG(A_MC_P_BIST_DATA_PATTERN, 345248925Snp idx); 346248925Snp } 347248925Snp 348248925Snp if (t4_read_reg(adap, mc_bist_cmd_reg) & F_START_BIST) 349218792Snp return -EBUSY; 350248925Snp t4_write_reg(adap, mc_bist_cmd_addr_reg, addr & ~0x3fU); 351248925Snp t4_write_reg(adap, mc_bist_cmd_len_reg, 64); 352248925Snp t4_write_reg(adap, mc_bist_data_pattern_reg, 0xc); 353248925Snp t4_write_reg(adap, mc_bist_cmd_reg, V_BIST_OPCODE(1) | 354248925Snp F_START_BIST | V_BIST_CMD_GAP(1)); 355248925Snp i = t4_wait_op_done(adap, mc_bist_cmd_reg, F_START_BIST, 0, 10, 1); 356218792Snp if (i) 357218792Snp return i; 358218792Snp 359248925Snp#define MC_DATA(i) MC_BIST_STATUS_REG(mc_bist_status_rdata_reg, i) 360218792Snp 361218792Snp for (i = 15; i >= 0; i--) 362237436Snp *data++ = ntohl(t4_read_reg(adap, MC_DATA(i))); 363218792Snp if (ecc) 364218792Snp *ecc = t4_read_reg64(adap, MC_DATA(16)); 365218792Snp#undef MC_DATA 366218792Snp return 0; 367218792Snp} 368218792Snp 369218792Snp/** 370218792Snp * t4_edc_read - read from EDC through backdoor accesses 371218792Snp * @adap: the adapter 372218792Snp * @idx: which EDC to access 373218792Snp * @addr: address of first byte requested 374218792Snp * @data: 64 bytes of data containing the requested address 375218792Snp * @ecc: where to store the corresponding 64-bit ECC word 376218792Snp * 377218792Snp * Read 64 bytes of data from EDC starting at a 64-byte-aligned address 378218792Snp * that covers the requested address @addr. If @parity is not %NULL it 379218792Snp * is assigned the 64-bit ECC word for the read data. 380218792Snp */ 381218792Snpint t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *ecc) 382218792Snp{ 383218792Snp int i; 384248925Snp u32 edc_bist_cmd_reg, edc_bist_cmd_addr_reg, edc_bist_cmd_len_reg; 385248925Snp u32 edc_bist_cmd_data_pattern, edc_bist_status_rdata_reg; 386218792Snp 387248925Snp if (is_t4(adap)) { 388248925Snp edc_bist_cmd_reg = EDC_REG(A_EDC_BIST_CMD, idx); 389248925Snp edc_bist_cmd_addr_reg = EDC_REG(A_EDC_BIST_CMD_ADDR, idx); 390248925Snp edc_bist_cmd_len_reg = EDC_REG(A_EDC_BIST_CMD_LEN, idx); 391248925Snp edc_bist_cmd_data_pattern = EDC_REG(A_EDC_BIST_DATA_PATTERN, 392248925Snp idx); 393248925Snp edc_bist_status_rdata_reg = EDC_REG(A_EDC_BIST_STATUS_RDATA, 394248925Snp idx); 395248925Snp } else { 396248925Snp/* 397248925Snp * These macro are missing in t4_regs.h file. 398248925Snp * Added temporarily for testing. 399248925Snp */ 400248925Snp#define EDC_STRIDE_T5 (EDC_T51_BASE_ADDR - EDC_T50_BASE_ADDR) 401248925Snp#define EDC_REG_T5(reg, idx) (reg + EDC_STRIDE_T5 * idx) 402248925Snp edc_bist_cmd_reg = EDC_REG_T5(A_EDC_H_BIST_CMD, idx); 403248925Snp edc_bist_cmd_addr_reg = EDC_REG_T5(A_EDC_H_BIST_CMD_ADDR, idx); 404248925Snp edc_bist_cmd_len_reg = EDC_REG_T5(A_EDC_H_BIST_CMD_LEN, idx); 405248925Snp edc_bist_cmd_data_pattern = EDC_REG_T5(A_EDC_H_BIST_DATA_PATTERN, 406248925Snp idx); 407248925Snp edc_bist_status_rdata_reg = EDC_REG_T5(A_EDC_H_BIST_STATUS_RDATA, 408248925Snp idx); 409248925Snp#undef EDC_REG_T5 410248925Snp#undef EDC_STRIDE_T5 411248925Snp } 412248925Snp 413248925Snp if (t4_read_reg(adap, edc_bist_cmd_reg) & F_START_BIST) 414218792Snp return -EBUSY; 415248925Snp t4_write_reg(adap, edc_bist_cmd_addr_reg, addr & ~0x3fU); 416248925Snp t4_write_reg(adap, edc_bist_cmd_len_reg, 64); 417248925Snp t4_write_reg(adap, edc_bist_cmd_data_pattern, 0xc); 418248925Snp t4_write_reg(adap, edc_bist_cmd_reg, 419218792Snp V_BIST_OPCODE(1) | V_BIST_CMD_GAP(1) | F_START_BIST); 420248925Snp i = t4_wait_op_done(adap, edc_bist_cmd_reg, F_START_BIST, 0, 10, 1); 421218792Snp if (i) 422218792Snp return i; 423218792Snp 424248925Snp#define EDC_DATA(i) EDC_BIST_STATUS_REG(edc_bist_status_rdata_reg, i) 425218792Snp 426218792Snp for (i = 15; i >= 0; i--) 427237436Snp *data++ = ntohl(t4_read_reg(adap, EDC_DATA(i))); 428218792Snp if (ecc) 429218792Snp *ecc = t4_read_reg64(adap, EDC_DATA(16)); 430218792Snp#undef EDC_DATA 431218792Snp return 0; 432218792Snp} 433218792Snp 434218792Snp/** 435218792Snp * t4_mem_read - read EDC 0, EDC 1 or MC into buffer 436218792Snp * @adap: the adapter 437218792Snp * @mtype: memory type: MEM_EDC0, MEM_EDC1 or MEM_MC 438218792Snp * @addr: address within indicated memory type 439218792Snp * @len: amount of memory to read 440218792Snp * @buf: host memory buffer 441218792Snp * 442218792Snp * Reads an [almost] arbitrary memory region in the firmware: the 443218792Snp * firmware memory address, length and host buffer must be aligned on 444218792Snp * 32-bit boudaries. The memory is returned as a raw byte sequence from 445218792Snp * the firmware's memory. If this memory contains data structures which 446218792Snp * contain multi-byte integers, it's the callers responsibility to 447218792Snp * perform appropriate byte order conversions. 448218792Snp */ 449218792Snpint t4_mem_read(struct adapter *adap, int mtype, u32 addr, u32 len, 450218792Snp __be32 *buf) 451218792Snp{ 452218792Snp u32 pos, start, end, offset; 453218792Snp int ret; 454218792Snp 455218792Snp /* 456218792Snp * Argument sanity checks ... 457218792Snp */ 458218792Snp if ((addr & 0x3) || (len & 0x3)) 459218792Snp return -EINVAL; 460218792Snp 461218792Snp /* 462218792Snp * The underlaying EDC/MC read routines read 64 bytes at a time so we 463218792Snp * need to round down the start and round up the end. We'll start 464218792Snp * copying out of the first line at (addr - start) a word at a time. 465218792Snp */ 466218792Snp start = addr & ~(64-1); 467218792Snp end = (addr + len + 64-1) & ~(64-1); 468218792Snp offset = (addr - start)/sizeof(__be32); 469218792Snp 470218792Snp for (pos = start; pos < end; pos += 64, offset = 0) { 471218792Snp __be32 data[16]; 472218792Snp 473218792Snp /* 474218792Snp * Read the chip's memory block and bail if there's an error. 475218792Snp */ 476248925Snp if ((mtype == MEM_MC) || (mtype == MEM_MC1)) 477248925Snp ret = t4_mc_read(adap, mtype - MEM_MC, pos, data, NULL); 478218792Snp else 479218792Snp ret = t4_edc_read(adap, mtype, pos, data, NULL); 480218792Snp if (ret) 481218792Snp return ret; 482218792Snp 483218792Snp /* 484218792Snp * Copy the data into the caller's memory buffer. 485218792Snp */ 486218792Snp while (offset < 16 && len > 0) { 487218792Snp *buf++ = data[offset++]; 488218792Snp len -= sizeof(__be32); 489218792Snp } 490218792Snp } 491218792Snp 492218792Snp return 0; 493218792Snp} 494218792Snp 495218792Snp/* 496218792Snp * Partial EEPROM Vital Product Data structure. Includes only the ID and 497218792Snp * VPD-R header. 498218792Snp */ 499218792Snpstruct t4_vpd_hdr { 500218792Snp u8 id_tag; 501218792Snp u8 id_len[2]; 502218792Snp u8 id_data[ID_LEN]; 503218792Snp u8 vpdr_tag; 504218792Snp u8 vpdr_len[2]; 505218792Snp}; 506218792Snp 507218792Snp/* 508218792Snp * EEPROM reads take a few tens of us while writes can take a bit over 5 ms. 509218792Snp */ 510218792Snp#define EEPROM_MAX_RD_POLL 40 511218792Snp#define EEPROM_MAX_WR_POLL 6 512218792Snp#define EEPROM_STAT_ADDR 0x7bfc 513218792Snp#define VPD_BASE 0x400 514218792Snp#define VPD_BASE_OLD 0 515248925Snp#define VPD_LEN 1024 516218792Snp#define VPD_INFO_FLD_HDR_SIZE 3 517250090Snp#define CHELSIO_VPD_UNIQUE_ID 0x82 518218792Snp 519218792Snp/** 520218792Snp * t4_seeprom_read - read a serial EEPROM location 521218792Snp * @adapter: adapter to read 522218792Snp * @addr: EEPROM virtual address 523218792Snp * @data: where to store the read data 524218792Snp * 525218792Snp * Read a 32-bit word from a location in serial EEPROM using the card's PCI 526218792Snp * VPD capability. Note that this function must be called with a virtual 527218792Snp * address. 528218792Snp */ 529218792Snpint t4_seeprom_read(struct adapter *adapter, u32 addr, u32 *data) 530218792Snp{ 531218792Snp u16 val; 532218792Snp int attempts = EEPROM_MAX_RD_POLL; 533218792Snp unsigned int base = adapter->params.pci.vpd_cap_addr; 534218792Snp 535218792Snp if (addr >= EEPROMVSIZE || (addr & 3)) 536218792Snp return -EINVAL; 537218792Snp 538218792Snp t4_os_pci_write_cfg2(adapter, base + PCI_VPD_ADDR, (u16)addr); 539218792Snp do { 540218792Snp udelay(10); 541218792Snp t4_os_pci_read_cfg2(adapter, base + PCI_VPD_ADDR, &val); 542218792Snp } while (!(val & PCI_VPD_ADDR_F) && --attempts); 543218792Snp 544218792Snp if (!(val & PCI_VPD_ADDR_F)) { 545218792Snp CH_ERR(adapter, "reading EEPROM address 0x%x failed\n", addr); 546218792Snp return -EIO; 547218792Snp } 548218792Snp t4_os_pci_read_cfg4(adapter, base + PCI_VPD_DATA, data); 549218792Snp *data = le32_to_cpu(*data); 550218792Snp return 0; 551218792Snp} 552218792Snp 553218792Snp/** 554218792Snp * t4_seeprom_write - write a serial EEPROM location 555218792Snp * @adapter: adapter to write 556218792Snp * @addr: virtual EEPROM address 557218792Snp * @data: value to write 558218792Snp * 559218792Snp * Write a 32-bit word to a location in serial EEPROM using the card's PCI 560218792Snp * VPD capability. Note that this function must be called with a virtual 561218792Snp * address. 562218792Snp */ 563218792Snpint t4_seeprom_write(struct adapter *adapter, u32 addr, u32 data) 564218792Snp{ 565218792Snp u16 val; 566218792Snp int attempts = EEPROM_MAX_WR_POLL; 567218792Snp unsigned int base = adapter->params.pci.vpd_cap_addr; 568218792Snp 569218792Snp if (addr >= EEPROMVSIZE || (addr & 3)) 570218792Snp return -EINVAL; 571218792Snp 572218792Snp t4_os_pci_write_cfg4(adapter, base + PCI_VPD_DATA, 573218792Snp cpu_to_le32(data)); 574218792Snp t4_os_pci_write_cfg2(adapter, base + PCI_VPD_ADDR, 575218792Snp (u16)addr | PCI_VPD_ADDR_F); 576218792Snp do { 577218792Snp msleep(1); 578218792Snp t4_os_pci_read_cfg2(adapter, base + PCI_VPD_ADDR, &val); 579218792Snp } while ((val & PCI_VPD_ADDR_F) && --attempts); 580218792Snp 581218792Snp if (val & PCI_VPD_ADDR_F) { 582218792Snp CH_ERR(adapter, "write to EEPROM address 0x%x failed\n", addr); 583218792Snp return -EIO; 584218792Snp } 585218792Snp return 0; 586218792Snp} 587218792Snp 588218792Snp/** 589218792Snp * t4_eeprom_ptov - translate a physical EEPROM address to virtual 590218792Snp * @phys_addr: the physical EEPROM address 591218792Snp * @fn: the PCI function number 592218792Snp * @sz: size of function-specific area 593218792Snp * 594218792Snp * Translate a physical EEPROM address to virtual. The first 1K is 595218792Snp * accessed through virtual addresses starting at 31K, the rest is 596218792Snp * accessed through virtual addresses starting at 0. 597218792Snp * 598218792Snp * The mapping is as follows: 599218792Snp * [0..1K) -> [31K..32K) 600218792Snp * [1K..1K+A) -> [ES-A..ES) 601218792Snp * [1K+A..ES) -> [0..ES-A-1K) 602218792Snp * 603218792Snp * where A = @fn * @sz, and ES = EEPROM size. 604218792Snp */ 605218792Snpint t4_eeprom_ptov(unsigned int phys_addr, unsigned int fn, unsigned int sz) 606218792Snp{ 607218792Snp fn *= sz; 608218792Snp if (phys_addr < 1024) 609218792Snp return phys_addr + (31 << 10); 610218792Snp if (phys_addr < 1024 + fn) 611218792Snp return EEPROMSIZE - fn + phys_addr - 1024; 612218792Snp if (phys_addr < EEPROMSIZE) 613218792Snp return phys_addr - 1024 - fn; 614218792Snp return -EINVAL; 615218792Snp} 616218792Snp 617218792Snp/** 618218792Snp * t4_seeprom_wp - enable/disable EEPROM write protection 619218792Snp * @adapter: the adapter 620218792Snp * @enable: whether to enable or disable write protection 621218792Snp * 622218792Snp * Enables or disables write protection on the serial EEPROM. 623218792Snp */ 624218792Snpint t4_seeprom_wp(struct adapter *adapter, int enable) 625218792Snp{ 626218792Snp return t4_seeprom_write(adapter, EEPROM_STAT_ADDR, enable ? 0xc : 0); 627218792Snp} 628218792Snp 629218792Snp/** 630218792Snp * get_vpd_keyword_val - Locates an information field keyword in the VPD 631218792Snp * @v: Pointer to buffered vpd data structure 632218792Snp * @kw: The keyword to search for 633218792Snp * 634218792Snp * Returns the value of the information field keyword or 635218792Snp * -ENOENT otherwise. 636218792Snp */ 637218792Snpstatic int get_vpd_keyword_val(const struct t4_vpd_hdr *v, const char *kw) 638218792Snp{ 639218792Snp int i; 640218792Snp unsigned int offset , len; 641218792Snp const u8 *buf = &v->id_tag; 642218792Snp const u8 *vpdr_len = &v->vpdr_tag; 643218792Snp offset = sizeof(struct t4_vpd_hdr); 644218792Snp len = (u16)vpdr_len[1] + ((u16)vpdr_len[2] << 8); 645218792Snp 646218792Snp if (len + sizeof(struct t4_vpd_hdr) > VPD_LEN) { 647218792Snp return -ENOENT; 648218792Snp } 649218792Snp 650218792Snp for (i = offset; i + VPD_INFO_FLD_HDR_SIZE <= offset + len;) { 651218792Snp if(memcmp(buf + i , kw , 2) == 0){ 652218792Snp i += VPD_INFO_FLD_HDR_SIZE; 653218792Snp return i; 654218792Snp } 655218792Snp 656218792Snp i += VPD_INFO_FLD_HDR_SIZE + buf[i+2]; 657218792Snp } 658218792Snp 659218792Snp return -ENOENT; 660218792Snp} 661218792Snp 662218792Snp 663218792Snp/** 664218792Snp * get_vpd_params - read VPD parameters from VPD EEPROM 665218792Snp * @adapter: adapter to read 666218792Snp * @p: where to store the parameters 667218792Snp * 668218792Snp * Reads card parameters stored in VPD EEPROM. 669218792Snp */ 670218792Snpstatic int get_vpd_params(struct adapter *adapter, struct vpd_params *p) 671218792Snp{ 672218792Snp int i, ret, addr; 673237436Snp int ec, sn, pn, na; 674218792Snp u8 vpd[VPD_LEN], csum; 675218792Snp const struct t4_vpd_hdr *v; 676218792Snp 677218792Snp /* 678218792Snp * Card information normally starts at VPD_BASE but early cards had 679218792Snp * it at 0. 680218792Snp */ 681218792Snp ret = t4_seeprom_read(adapter, VPD_BASE, (u32 *)(vpd)); 682250090Snp addr = *vpd == CHELSIO_VPD_UNIQUE_ID ? VPD_BASE : VPD_BASE_OLD; 683218792Snp 684218792Snp for (i = 0; i < sizeof(vpd); i += 4) { 685218792Snp ret = t4_seeprom_read(adapter, addr + i, (u32 *)(vpd + i)); 686218792Snp if (ret) 687218792Snp return ret; 688218792Snp } 689218792Snp v = (const struct t4_vpd_hdr *)vpd; 690218792Snp 691218792Snp#define FIND_VPD_KW(var,name) do { \ 692218792Snp var = get_vpd_keyword_val(v , name); \ 693218792Snp if (var < 0) { \ 694218792Snp CH_ERR(adapter, "missing VPD keyword " name "\n"); \ 695218792Snp return -EINVAL; \ 696218792Snp } \ 697218792Snp} while (0) 698218792Snp 699218792Snp FIND_VPD_KW(i, "RV"); 700218792Snp for (csum = 0; i >= 0; i--) 701218792Snp csum += vpd[i]; 702218792Snp 703218792Snp if (csum) { 704218792Snp CH_ERR(adapter, "corrupted VPD EEPROM, actual csum %u\n", csum); 705218792Snp return -EINVAL; 706218792Snp } 707218792Snp FIND_VPD_KW(ec, "EC"); 708218792Snp FIND_VPD_KW(sn, "SN"); 709237436Snp FIND_VPD_KW(pn, "PN"); 710237436Snp FIND_VPD_KW(na, "NA"); 711218792Snp#undef FIND_VPD_KW 712218792Snp 713218792Snp memcpy(p->id, v->id_data, ID_LEN); 714218792Snp strstrip(p->id); 715218792Snp memcpy(p->ec, vpd + ec, EC_LEN); 716218792Snp strstrip(p->ec); 717218792Snp i = vpd[sn - VPD_INFO_FLD_HDR_SIZE + 2]; 718218792Snp memcpy(p->sn, vpd + sn, min(i, SERNUM_LEN)); 719218792Snp strstrip(p->sn); 720250090Snp i = vpd[pn - VPD_INFO_FLD_HDR_SIZE + 2]; 721237436Snp memcpy(p->pn, vpd + pn, min(i, PN_LEN)); 722237436Snp strstrip((char *)p->pn); 723250090Snp i = vpd[na - VPD_INFO_FLD_HDR_SIZE + 2]; 724237436Snp memcpy(p->na, vpd + na, min(i, MACADDR_LEN)); 725237436Snp strstrip((char *)p->na); 726218792Snp 727218792Snp return 0; 728218792Snp} 729218792Snp 730218792Snp/* serial flash and firmware constants and flash config file constants */ 731218792Snpenum { 732218792Snp SF_ATTEMPTS = 10, /* max retries for SF operations */ 733218792Snp 734218792Snp /* flash command opcodes */ 735218792Snp SF_PROG_PAGE = 2, /* program page */ 736218792Snp SF_WR_DISABLE = 4, /* disable writes */ 737218792Snp SF_RD_STATUS = 5, /* read status register */ 738218792Snp SF_WR_ENABLE = 6, /* enable writes */ 739218792Snp SF_RD_DATA_FAST = 0xb, /* read flash */ 740218792Snp SF_RD_ID = 0x9f, /* read ID */ 741218792Snp SF_ERASE_SECTOR = 0xd8, /* erase sector */ 742218792Snp}; 743218792Snp 744218792Snp/** 745218792Snp * sf1_read - read data from the serial flash 746218792Snp * @adapter: the adapter 747218792Snp * @byte_cnt: number of bytes to read 748218792Snp * @cont: whether another operation will be chained 749218792Snp * @lock: whether to lock SF for PL access only 750218792Snp * @valp: where to store the read data 751218792Snp * 752218792Snp * Reads up to 4 bytes of data from the serial flash. The location of 753218792Snp * the read needs to be specified prior to calling this by issuing the 754218792Snp * appropriate commands to the serial flash. 755218792Snp */ 756218792Snpstatic int sf1_read(struct adapter *adapter, unsigned int byte_cnt, int cont, 757218792Snp int lock, u32 *valp) 758218792Snp{ 759218792Snp int ret; 760218792Snp 761218792Snp if (!byte_cnt || byte_cnt > 4) 762218792Snp return -EINVAL; 763218792Snp if (t4_read_reg(adapter, A_SF_OP) & F_BUSY) 764218792Snp return -EBUSY; 765218792Snp t4_write_reg(adapter, A_SF_OP, 766218792Snp V_SF_LOCK(lock) | V_CONT(cont) | V_BYTECNT(byte_cnt - 1)); 767218792Snp ret = t4_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 5); 768218792Snp if (!ret) 769218792Snp *valp = t4_read_reg(adapter, A_SF_DATA); 770218792Snp return ret; 771218792Snp} 772218792Snp 773218792Snp/** 774218792Snp * sf1_write - write data to the serial flash 775218792Snp * @adapter: the adapter 776218792Snp * @byte_cnt: number of bytes to write 777218792Snp * @cont: whether another operation will be chained 778218792Snp * @lock: whether to lock SF for PL access only 779218792Snp * @val: value to write 780218792Snp * 781218792Snp * Writes up to 4 bytes of data to the serial flash. The location of 782218792Snp * the write needs to be specified prior to calling this by issuing the 783218792Snp * appropriate commands to the serial flash. 784218792Snp */ 785218792Snpstatic int sf1_write(struct adapter *adapter, unsigned int byte_cnt, int cont, 786218792Snp int lock, u32 val) 787218792Snp{ 788218792Snp if (!byte_cnt || byte_cnt > 4) 789218792Snp return -EINVAL; 790218792Snp if (t4_read_reg(adapter, A_SF_OP) & F_BUSY) 791218792Snp return -EBUSY; 792218792Snp t4_write_reg(adapter, A_SF_DATA, val); 793218792Snp t4_write_reg(adapter, A_SF_OP, V_SF_LOCK(lock) | 794218792Snp V_CONT(cont) | V_BYTECNT(byte_cnt - 1) | V_OP(1)); 795218792Snp return t4_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 5); 796218792Snp} 797218792Snp 798218792Snp/** 799218792Snp * flash_wait_op - wait for a flash operation to complete 800218792Snp * @adapter: the adapter 801218792Snp * @attempts: max number of polls of the status register 802218792Snp * @delay: delay between polls in ms 803218792Snp * 804218792Snp * Wait for a flash operation to complete by polling the status register. 805218792Snp */ 806218792Snpstatic int flash_wait_op(struct adapter *adapter, int attempts, int delay) 807218792Snp{ 808218792Snp int ret; 809218792Snp u32 status; 810218792Snp 811218792Snp while (1) { 812218792Snp if ((ret = sf1_write(adapter, 1, 1, 1, SF_RD_STATUS)) != 0 || 813218792Snp (ret = sf1_read(adapter, 1, 0, 1, &status)) != 0) 814218792Snp return ret; 815218792Snp if (!(status & 1)) 816218792Snp return 0; 817218792Snp if (--attempts == 0) 818218792Snp return -EAGAIN; 819218792Snp if (delay) 820218792Snp msleep(delay); 821218792Snp } 822218792Snp} 823218792Snp 824218792Snp/** 825218792Snp * t4_read_flash - read words from serial flash 826218792Snp * @adapter: the adapter 827218792Snp * @addr: the start address for the read 828218792Snp * @nwords: how many 32-bit words to read 829218792Snp * @data: where to store the read data 830218792Snp * @byte_oriented: whether to store data as bytes or as words 831218792Snp * 832218792Snp * Read the specified number of 32-bit words from the serial flash. 833218792Snp * If @byte_oriented is set the read data is stored as a byte array 834218792Snp * (i.e., big-endian), otherwise as 32-bit words in the platform's 835218792Snp * natural endianess. 836218792Snp */ 837218792Snpint t4_read_flash(struct adapter *adapter, unsigned int addr, 838218792Snp unsigned int nwords, u32 *data, int byte_oriented) 839218792Snp{ 840218792Snp int ret; 841218792Snp 842218792Snp if (addr + nwords * sizeof(u32) > adapter->params.sf_size || (addr & 3)) 843218792Snp return -EINVAL; 844218792Snp 845218792Snp addr = swab32(addr) | SF_RD_DATA_FAST; 846218792Snp 847218792Snp if ((ret = sf1_write(adapter, 4, 1, 0, addr)) != 0 || 848218792Snp (ret = sf1_read(adapter, 1, 1, 0, data)) != 0) 849218792Snp return ret; 850218792Snp 851218792Snp for ( ; nwords; nwords--, data++) { 852218792Snp ret = sf1_read(adapter, 4, nwords > 1, nwords == 1, data); 853218792Snp if (nwords == 1) 854218792Snp t4_write_reg(adapter, A_SF_OP, 0); /* unlock SF */ 855218792Snp if (ret) 856218792Snp return ret; 857218792Snp if (byte_oriented) 858218792Snp *data = htonl(*data); 859218792Snp } 860218792Snp return 0; 861218792Snp} 862218792Snp 863218792Snp/** 864218792Snp * t4_write_flash - write up to a page of data to the serial flash 865218792Snp * @adapter: the adapter 866218792Snp * @addr: the start address to write 867218792Snp * @n: length of data to write in bytes 868218792Snp * @data: the data to write 869228561Snp * @byte_oriented: whether to store data as bytes or as words 870218792Snp * 871218792Snp * Writes up to a page of data (256 bytes) to the serial flash starting 872218792Snp * at the given address. All the data must be written to the same page. 873228561Snp * If @byte_oriented is set the write data is stored as byte stream 874228561Snp * (i.e. matches what on disk), otherwise in big-endian. 875218792Snp */ 876218792Snpstatic int t4_write_flash(struct adapter *adapter, unsigned int addr, 877228561Snp unsigned int n, const u8 *data, int byte_oriented) 878218792Snp{ 879218792Snp int ret; 880218792Snp u32 buf[SF_PAGE_SIZE / 4]; 881218792Snp unsigned int i, c, left, val, offset = addr & 0xff; 882218792Snp 883218792Snp if (addr >= adapter->params.sf_size || offset + n > SF_PAGE_SIZE) 884218792Snp return -EINVAL; 885218792Snp 886218792Snp val = swab32(addr) | SF_PROG_PAGE; 887218792Snp 888218792Snp if ((ret = sf1_write(adapter, 1, 0, 1, SF_WR_ENABLE)) != 0 || 889218792Snp (ret = sf1_write(adapter, 4, 1, 1, val)) != 0) 890218792Snp goto unlock; 891218792Snp 892218792Snp for (left = n; left; left -= c) { 893218792Snp c = min(left, 4U); 894218792Snp for (val = 0, i = 0; i < c; ++i) 895218792Snp val = (val << 8) + *data++; 896218792Snp 897228561Snp if (!byte_oriented) 898228561Snp val = htonl(val); 899228561Snp 900218792Snp ret = sf1_write(adapter, c, c != left, 1, val); 901218792Snp if (ret) 902218792Snp goto unlock; 903218792Snp } 904218792Snp ret = flash_wait_op(adapter, 8, 1); 905218792Snp if (ret) 906218792Snp goto unlock; 907218792Snp 908218792Snp t4_write_reg(adapter, A_SF_OP, 0); /* unlock SF */ 909218792Snp 910218792Snp /* Read the page to verify the write succeeded */ 911228561Snp ret = t4_read_flash(adapter, addr & ~0xff, ARRAY_SIZE(buf), buf, 912228561Snp byte_oriented); 913218792Snp if (ret) 914218792Snp return ret; 915218792Snp 916218792Snp if (memcmp(data - n, (u8 *)buf + offset, n)) { 917218792Snp CH_ERR(adapter, "failed to correctly write the flash page " 918218792Snp "at %#x\n", addr); 919218792Snp return -EIO; 920218792Snp } 921218792Snp return 0; 922218792Snp 923218792Snpunlock: 924218792Snp t4_write_reg(adapter, A_SF_OP, 0); /* unlock SF */ 925218792Snp return ret; 926218792Snp} 927218792Snp 928218792Snp/** 929218792Snp * t4_get_fw_version - read the firmware version 930218792Snp * @adapter: the adapter 931218792Snp * @vers: where to place the version 932218792Snp * 933218792Snp * Reads the FW version from flash. 934218792Snp */ 935218792Snpint t4_get_fw_version(struct adapter *adapter, u32 *vers) 936218792Snp{ 937218792Snp return t4_read_flash(adapter, 938228561Snp FLASH_FW_START + offsetof(struct fw_hdr, fw_ver), 1, 939218792Snp vers, 0); 940218792Snp} 941218792Snp 942218792Snp/** 943218792Snp * t4_get_tp_version - read the TP microcode version 944218792Snp * @adapter: the adapter 945218792Snp * @vers: where to place the version 946218792Snp * 947218792Snp * Reads the TP microcode version from flash. 948218792Snp */ 949218792Snpint t4_get_tp_version(struct adapter *adapter, u32 *vers) 950218792Snp{ 951228561Snp return t4_read_flash(adapter, FLASH_FW_START + offsetof(struct fw_hdr, 952218792Snp tp_microcode_ver), 953218792Snp 1, vers, 0); 954218792Snp} 955218792Snp 956218792Snp/** 957218792Snp * t4_check_fw_version - check if the FW is compatible with this driver 958218792Snp * @adapter: the adapter 959218792Snp * 960218792Snp * Checks if an adapter's FW is compatible with the driver. Returns 0 961218792Snp * if there's exact match, a negative error if the version could not be 962218792Snp * read or there's a major version mismatch, and a positive value if the 963218792Snp * expected major version is found but there's a minor version mismatch. 964218792Snp */ 965218792Snpint t4_check_fw_version(struct adapter *adapter) 966218792Snp{ 967218792Snp int ret, major, minor, micro; 968248925Snp int exp_major, exp_minor, exp_micro; 969218792Snp 970218792Snp ret = t4_get_fw_version(adapter, &adapter->params.fw_vers); 971218792Snp if (!ret) 972218792Snp ret = t4_get_tp_version(adapter, &adapter->params.tp_vers); 973218792Snp if (ret) 974218792Snp return ret; 975218792Snp 976218792Snp major = G_FW_HDR_FW_VER_MAJOR(adapter->params.fw_vers); 977218792Snp minor = G_FW_HDR_FW_VER_MINOR(adapter->params.fw_vers); 978218792Snp micro = G_FW_HDR_FW_VER_MICRO(adapter->params.fw_vers); 979218792Snp 980248925Snp switch (chip_id(adapter)) { 981248925Snp case CHELSIO_T4: 982252661Snp exp_major = T4FW_VERSION_MAJOR; 983252661Snp exp_minor = T4FW_VERSION_MINOR; 984252661Snp exp_micro = T4FW_VERSION_MICRO; 985248925Snp break; 986248925Snp case CHELSIO_T5: 987252661Snp exp_major = T5FW_VERSION_MAJOR; 988252661Snp exp_minor = T5FW_VERSION_MINOR; 989252661Snp exp_micro = T5FW_VERSION_MICRO; 990248925Snp break; 991248925Snp default: 992248925Snp CH_ERR(adapter, "Unsupported chip type, %x\n", 993248925Snp chip_id(adapter)); 994248925Snp return -EINVAL; 995248925Snp } 996248925Snp 997248925Snp if (major != exp_major) { /* major mismatch - fail */ 998218792Snp CH_ERR(adapter, "card FW has major version %u, driver wants " 999248925Snp "%u\n", major, exp_major); 1000218792Snp return -EINVAL; 1001218792Snp } 1002218792Snp 1003248925Snp if (minor == exp_minor && micro == exp_micro) 1004218792Snp return 0; /* perfect match */ 1005218792Snp 1006218792Snp /* Minor/micro version mismatch. Report it but often it's OK. */ 1007218792Snp return 1; 1008218792Snp} 1009218792Snp 1010218792Snp/** 1011218792Snp * t4_flash_erase_sectors - erase a range of flash sectors 1012218792Snp * @adapter: the adapter 1013218792Snp * @start: the first sector to erase 1014218792Snp * @end: the last sector to erase 1015218792Snp * 1016218792Snp * Erases the sectors in the given inclusive range. 1017218792Snp */ 1018218792Snpstatic int t4_flash_erase_sectors(struct adapter *adapter, int start, int end) 1019218792Snp{ 1020218792Snp int ret = 0; 1021218792Snp 1022218792Snp while (start <= end) { 1023218792Snp if ((ret = sf1_write(adapter, 1, 0, 1, SF_WR_ENABLE)) != 0 || 1024218792Snp (ret = sf1_write(adapter, 4, 0, 1, 1025218792Snp SF_ERASE_SECTOR | (start << 8))) != 0 || 1026218792Snp (ret = flash_wait_op(adapter, 14, 500)) != 0) { 1027218792Snp CH_ERR(adapter, "erase of flash sector %d failed, " 1028218792Snp "error %d\n", start, ret); 1029218792Snp break; 1030218792Snp } 1031218792Snp start++; 1032218792Snp } 1033218792Snp t4_write_reg(adapter, A_SF_OP, 0); /* unlock SF */ 1034218792Snp return ret; 1035218792Snp} 1036218792Snp 1037218792Snp/** 1038228561Snp * t4_flash_cfg_addr - return the address of the flash configuration file 1039228561Snp * @adapter: the adapter 1040228561Snp * 1041228561Snp * Return the address within the flash where the Firmware Configuration 1042250090Snp * File is stored, or an error if the device FLASH is too small to contain 1043250090Snp * a Firmware Configuration File. 1044228561Snp */ 1045250090Snpint t4_flash_cfg_addr(struct adapter *adapter) 1046228561Snp{ 1047250090Snp /* 1048250090Snp * If the device FLASH isn't large enough to hold a Firmware 1049250090Snp * Configuration File, return an error. 1050250090Snp */ 1051250090Snp if (adapter->params.sf_size < FLASH_CFG_START + FLASH_CFG_MAX_SIZE) 1052250090Snp return -ENOSPC; 1053250090Snp 1054250090Snp return FLASH_CFG_START; 1055228561Snp} 1056228561Snp 1057228561Snp/** 1058218792Snp * t4_load_cfg - download config file 1059218792Snp * @adap: the adapter 1060218792Snp * @cfg_data: the cfg text file to write 1061218792Snp * @size: text file size 1062218792Snp * 1063218792Snp * Write the supplied config text file to the card's serial flash. 1064218792Snp */ 1065218792Snpint t4_load_cfg(struct adapter *adap, const u8 *cfg_data, unsigned int size) 1066218792Snp{ 1067250090Snp int ret, i, n, cfg_addr; 1068218792Snp unsigned int addr; 1069218792Snp unsigned int flash_cfg_start_sec; 1070218792Snp unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec; 1071218792Snp 1072250090Snp cfg_addr = t4_flash_cfg_addr(adap); 1073250090Snp if (cfg_addr < 0) 1074250090Snp return cfg_addr; 1075250090Snp 1076250090Snp addr = cfg_addr; 1077228561Snp flash_cfg_start_sec = addr / SF_SEC_SIZE; 1078218792Snp 1079218792Snp if (size > FLASH_CFG_MAX_SIZE) { 1080218792Snp CH_ERR(adap, "cfg file too large, max is %u bytes\n", 1081218792Snp FLASH_CFG_MAX_SIZE); 1082218792Snp return -EFBIG; 1083218792Snp } 1084218792Snp 1085218792Snp i = DIV_ROUND_UP(FLASH_CFG_MAX_SIZE, /* # of sectors spanned */ 1086218792Snp sf_sec_size); 1087218792Snp ret = t4_flash_erase_sectors(adap, flash_cfg_start_sec, 1088218792Snp flash_cfg_start_sec + i - 1); 1089228561Snp /* 1090228561Snp * If size == 0 then we're simply erasing the FLASH sectors associated 1091228561Snp * with the on-adapter Firmware Configuration File. 1092228561Snp */ 1093228561Snp if (ret || size == 0) 1094218792Snp goto out; 1095218792Snp 1096237436Snp /* this will write to the flash up to SF_PAGE_SIZE at a time */ 1097218792Snp for (i = 0; i< size; i+= SF_PAGE_SIZE) { 1098218792Snp if ( (size - i) < SF_PAGE_SIZE) 1099218792Snp n = size - i; 1100218792Snp else 1101218792Snp n = SF_PAGE_SIZE; 1102228561Snp ret = t4_write_flash(adap, addr, n, cfg_data, 1); 1103218792Snp if (ret) 1104218792Snp goto out; 1105218792Snp 1106218792Snp addr += SF_PAGE_SIZE; 1107218792Snp cfg_data += SF_PAGE_SIZE; 1108218792Snp } 1109218792Snp 1110218792Snpout: 1111218792Snp if (ret) 1112228561Snp CH_ERR(adap, "config file %s failed %d\n", 1113228561Snp (size == 0 ? "clear" : "download"), ret); 1114218792Snp return ret; 1115218792Snp} 1116218792Snp 1117218792Snp 1118218792Snp/** 1119218792Snp * t4_load_fw - download firmware 1120218792Snp * @adap: the adapter 1121218792Snp * @fw_data: the firmware image to write 1122218792Snp * @size: image size 1123218792Snp * 1124218792Snp * Write the supplied firmware image to the card's serial flash. 1125218792Snp */ 1126218792Snpint t4_load_fw(struct adapter *adap, const u8 *fw_data, unsigned int size) 1127218792Snp{ 1128218792Snp u32 csum; 1129218792Snp int ret, addr; 1130218792Snp unsigned int i; 1131218792Snp u8 first_page[SF_PAGE_SIZE]; 1132218792Snp const u32 *p = (const u32 *)fw_data; 1133218792Snp const struct fw_hdr *hdr = (const struct fw_hdr *)fw_data; 1134218792Snp unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec; 1135252661Snp unsigned int fw_start_sec; 1136252661Snp unsigned int fw_start; 1137252661Snp unsigned int fw_size; 1138218792Snp 1139252661Snp if (ntohl(hdr->magic) == FW_HDR_MAGIC_BOOTSTRAP) { 1140252661Snp fw_start_sec = FLASH_FWBOOTSTRAP_START_SEC; 1141252661Snp fw_start = FLASH_FWBOOTSTRAP_START; 1142252661Snp fw_size = FLASH_FWBOOTSTRAP_MAX_SIZE; 1143252661Snp } else { 1144252661Snp fw_start_sec = FLASH_FW_START_SEC; 1145252661Snp fw_start = FLASH_FW_START; 1146252661Snp fw_size = FLASH_FW_MAX_SIZE; 1147252661Snp } 1148218792Snp if (!size) { 1149218792Snp CH_ERR(adap, "FW image has no data\n"); 1150218792Snp return -EINVAL; 1151218792Snp } 1152218792Snp if (size & 511) { 1153218792Snp CH_ERR(adap, "FW image size not multiple of 512 bytes\n"); 1154218792Snp return -EINVAL; 1155218792Snp } 1156218792Snp if (ntohs(hdr->len512) * 512 != size) { 1157218792Snp CH_ERR(adap, "FW image size differs from size in FW header\n"); 1158218792Snp return -EINVAL; 1159218792Snp } 1160252661Snp if (size > fw_size) { 1161252661Snp CH_ERR(adap, "FW image too large, max is %u bytes\n", fw_size); 1162218792Snp return -EFBIG; 1163218792Snp } 1164249629Snp if ((is_t4(adap) && hdr->chip != FW_HDR_CHIP_T4) || 1165249629Snp (is_t5(adap) && hdr->chip != FW_HDR_CHIP_T5)) { 1166249629Snp CH_ERR(adap, 1167249629Snp "FW image (%d) is not suitable for this adapter (%d)\n", 1168249629Snp hdr->chip, chip_id(adap)); 1169249629Snp return -EINVAL; 1170249629Snp } 1171218792Snp 1172218792Snp for (csum = 0, i = 0; i < size / sizeof(csum); i++) 1173218792Snp csum += ntohl(p[i]); 1174218792Snp 1175218792Snp if (csum != 0xffffffff) { 1176218792Snp CH_ERR(adap, "corrupted firmware image, checksum %#x\n", 1177218792Snp csum); 1178218792Snp return -EINVAL; 1179218792Snp } 1180218792Snp 1181218792Snp i = DIV_ROUND_UP(size, sf_sec_size); /* # of sectors spanned */ 1182252661Snp ret = t4_flash_erase_sectors(adap, fw_start_sec, fw_start_sec + i - 1); 1183218792Snp if (ret) 1184218792Snp goto out; 1185218792Snp 1186218792Snp /* 1187218792Snp * We write the correct version at the end so the driver can see a bad 1188218792Snp * version if the FW write fails. Start by writing a copy of the 1189218792Snp * first page with a bad version. 1190218792Snp */ 1191218792Snp memcpy(first_page, fw_data, SF_PAGE_SIZE); 1192218792Snp ((struct fw_hdr *)first_page)->fw_ver = htonl(0xffffffff); 1193252661Snp ret = t4_write_flash(adap, fw_start, SF_PAGE_SIZE, first_page, 1); 1194218792Snp if (ret) 1195218792Snp goto out; 1196218792Snp 1197252661Snp addr = fw_start; 1198218792Snp for (size -= SF_PAGE_SIZE; size; size -= SF_PAGE_SIZE) { 1199218792Snp addr += SF_PAGE_SIZE; 1200218792Snp fw_data += SF_PAGE_SIZE; 1201228561Snp ret = t4_write_flash(adap, addr, SF_PAGE_SIZE, fw_data, 1); 1202218792Snp if (ret) 1203218792Snp goto out; 1204218792Snp } 1205218792Snp 1206218792Snp ret = t4_write_flash(adap, 1207252661Snp fw_start + offsetof(struct fw_hdr, fw_ver), 1208228561Snp sizeof(hdr->fw_ver), (const u8 *)&hdr->fw_ver, 1); 1209218792Snpout: 1210218792Snp if (ret) 1211218792Snp CH_ERR(adap, "firmware download failed, error %d\n", ret); 1212218792Snp return ret; 1213218792Snp} 1214218792Snp 1215237436Snp/* BIOS boot headers */ 1216237436Snptypedef struct pci_expansion_rom_header { 1217237436Snp u8 signature[2]; /* ROM Signature. Should be 0xaa55 */ 1218237436Snp u8 reserved[22]; /* Reserved per processor Architecture data */ 1219237436Snp u8 pcir_offset[2]; /* Offset to PCI Data Structure */ 1220237436Snp} pci_exp_rom_header_t; /* PCI_EXPANSION_ROM_HEADER */ 1221228561Snp 1222237436Snp/* Legacy PCI Expansion ROM Header */ 1223237436Snptypedef struct legacy_pci_expansion_rom_header { 1224237436Snp u8 signature[2]; /* ROM Signature. Should be 0xaa55 */ 1225237436Snp u8 size512; /* Current Image Size in units of 512 bytes */ 1226237436Snp u8 initentry_point[4]; 1227237436Snp u8 cksum; /* Checksum computed on the entire Image */ 1228237436Snp u8 reserved[16]; /* Reserved */ 1229237436Snp u8 pcir_offset[2]; /* Offset to PCI Data Struture */ 1230237436Snp} legacy_pci_exp_rom_header_t; /* LEGACY_PCI_EXPANSION_ROM_HEADER */ 1231237436Snp 1232237436Snp/* EFI PCI Expansion ROM Header */ 1233237436Snptypedef struct efi_pci_expansion_rom_header { 1234237436Snp u8 signature[2]; // ROM signature. The value 0xaa55 1235237436Snp u8 initialization_size[2]; /* Units 512. Includes this header */ 1236237436Snp u8 efi_signature[4]; /* Signature from EFI image header. 0x0EF1 */ 1237237436Snp u8 efi_subsystem[2]; /* Subsystem value for EFI image header */ 1238237436Snp u8 efi_machine_type[2]; /* Machine type from EFI image header */ 1239237436Snp u8 compression_type[2]; /* Compression type. */ 1240237436Snp /* 1241237436Snp * Compression type definition 1242237436Snp * 0x0: uncompressed 1243237436Snp * 0x1: Compressed 1244237436Snp * 0x2-0xFFFF: Reserved 1245237436Snp */ 1246237436Snp u8 reserved[8]; /* Reserved */ 1247237436Snp u8 efi_image_header_offset[2]; /* Offset to EFI Image */ 1248237436Snp u8 pcir_offset[2]; /* Offset to PCI Data Structure */ 1249237436Snp} efi_pci_exp_rom_header_t; /* EFI PCI Expansion ROM Header */ 1250237436Snp 1251237436Snp/* PCI Data Structure Format */ 1252237436Snptypedef struct pcir_data_structure { /* PCI Data Structure */ 1253237436Snp u8 signature[4]; /* Signature. The string "PCIR" */ 1254237436Snp u8 vendor_id[2]; /* Vendor Identification */ 1255237436Snp u8 device_id[2]; /* Device Identification */ 1256237436Snp u8 vital_product[2]; /* Pointer to Vital Product Data */ 1257237436Snp u8 length[2]; /* PCIR Data Structure Length */ 1258237436Snp u8 revision; /* PCIR Data Structure Revision */ 1259237436Snp u8 class_code[3]; /* Class Code */ 1260237436Snp u8 image_length[2]; /* Image Length. Multiple of 512B */ 1261237436Snp u8 code_revision[2]; /* Revision Level of Code/Data */ 1262237436Snp u8 code_type; /* Code Type. */ 1263237436Snp /* 1264237436Snp * PCI Expansion ROM Code Types 1265237436Snp * 0x00: Intel IA-32, PC-AT compatible. Legacy 1266237436Snp * 0x01: Open Firmware standard for PCI. FCODE 1267237436Snp * 0x02: Hewlett-Packard PA RISC. HP reserved 1268237436Snp * 0x03: EFI Image. EFI 1269237436Snp * 0x04-0xFF: Reserved. 1270237436Snp */ 1271237436Snp u8 indicator; /* Indicator. Identifies the last image in the ROM */ 1272237436Snp u8 reserved[2]; /* Reserved */ 1273237436Snp} pcir_data_t; /* PCI__DATA_STRUCTURE */ 1274237436Snp 1275237436Snp/* BOOT constants */ 1276228561Snpenum { 1277228561Snp BOOT_FLASH_BOOT_ADDR = 0x0,/* start address of boot image in flash */ 1278228561Snp BOOT_SIGNATURE = 0xaa55, /* signature of BIOS boot ROM */ 1279228561Snp BOOT_SIZE_INC = 512, /* image size measured in 512B chunks */ 1280237436Snp BOOT_MIN_SIZE = sizeof(pci_exp_rom_header_t), /* basic header */ 1281237436Snp BOOT_MAX_SIZE = 1024*BOOT_SIZE_INC, /* 1 byte * length increment */ 1282237436Snp VENDOR_ID = 0x1425, /* Vendor ID */ 1283237436Snp PCIR_SIGNATURE = 0x52494350 /* PCIR signature */ 1284228561Snp}; 1285228561Snp 1286228561Snp/* 1287237436Snp * modify_device_id - Modifies the device ID of the Boot BIOS image 1288237436Snp * @adatper: the device ID to write. 1289237436Snp * @boot_data: the boot image to modify. 1290237436Snp * 1291237436Snp * Write the supplied device ID to the boot BIOS image. 1292237436Snp */ 1293237436Snpstatic void modify_device_id(int device_id, u8 *boot_data) 1294237436Snp{ 1295237436Snp legacy_pci_exp_rom_header_t *header; 1296237436Snp pcir_data_t *pcir_header; 1297237436Snp u32 cur_header = 0; 1298237436Snp 1299237436Snp /* 1300237436Snp * Loop through all chained images and change the device ID's 1301237436Snp */ 1302237436Snp while (1) { 1303237436Snp header = (legacy_pci_exp_rom_header_t *) &boot_data[cur_header]; 1304237436Snp pcir_header = (pcir_data_t *) &boot_data[cur_header + 1305237436Snp le16_to_cpu(*(u16*)header->pcir_offset)]; 1306237436Snp 1307237436Snp /* 1308237436Snp * Only modify the Device ID if code type is Legacy or HP. 1309237436Snp * 0x00: Okay to modify 1310237436Snp * 0x01: FCODE. Do not be modify 1311237436Snp * 0x03: Okay to modify 1312237436Snp * 0x04-0xFF: Do not modify 1313237436Snp */ 1314237436Snp if (pcir_header->code_type == 0x00) { 1315237436Snp u8 csum = 0; 1316237436Snp int i; 1317237436Snp 1318237436Snp /* 1319237436Snp * Modify Device ID to match current adatper 1320237436Snp */ 1321237436Snp *(u16*) pcir_header->device_id = device_id; 1322237436Snp 1323237436Snp /* 1324237436Snp * Set checksum temporarily to 0. 1325237436Snp * We will recalculate it later. 1326237436Snp */ 1327237436Snp header->cksum = 0x0; 1328237436Snp 1329237436Snp /* 1330237436Snp * Calculate and update checksum 1331237436Snp */ 1332237436Snp for (i = 0; i < (header->size512 * 512); i++) 1333237436Snp csum += (u8)boot_data[cur_header + i]; 1334237436Snp 1335237436Snp /* 1336237436Snp * Invert summed value to create the checksum 1337237436Snp * Writing new checksum value directly to the boot data 1338237436Snp */ 1339237436Snp boot_data[cur_header + 7] = -csum; 1340237436Snp 1341237436Snp } else if (pcir_header->code_type == 0x03) { 1342237436Snp 1343237436Snp /* 1344237436Snp * Modify Device ID to match current adatper 1345237436Snp */ 1346237436Snp *(u16*) pcir_header->device_id = device_id; 1347237436Snp 1348237436Snp } 1349237436Snp 1350237436Snp 1351237436Snp /* 1352237436Snp * Check indicator element to identify if this is the last 1353237436Snp * image in the ROM. 1354237436Snp */ 1355237436Snp if (pcir_header->indicator & 0x80) 1356237436Snp break; 1357237436Snp 1358237436Snp /* 1359237436Snp * Move header pointer up to the next image in the ROM. 1360237436Snp */ 1361237436Snp cur_header += header->size512 * 512; 1362237436Snp } 1363237436Snp} 1364237436Snp 1365237436Snp/* 1366228561Snp * t4_load_boot - download boot flash 1367228561Snp * @adapter: the adapter 1368228561Snp * @boot_data: the boot image to write 1369237436Snp * @boot_addr: offset in flash to write boot_data 1370228561Snp * @size: image size 1371228561Snp * 1372228561Snp * Write the supplied boot image to the card's serial flash. 1373228561Snp * The boot image has the following sections: a 28-byte header and the 1374228561Snp * boot image. 1375228561Snp */ 1376237436Snpint t4_load_boot(struct adapter *adap, u8 *boot_data, 1377228561Snp unsigned int boot_addr, unsigned int size) 1378228561Snp{ 1379237436Snp pci_exp_rom_header_t *header; 1380237436Snp int pcir_offset ; 1381237436Snp pcir_data_t *pcir_header; 1382228561Snp int ret, addr; 1383237436Snp uint16_t device_id; 1384228561Snp unsigned int i; 1385228561Snp unsigned int boot_sector = boot_addr * 1024; 1386228561Snp unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec; 1387228561Snp 1388228561Snp /* 1389237436Snp * Make sure the boot image does not encroach on the firmware region 1390237436Snp */ 1391237436Snp if ((boot_sector + size) >> 16 > FLASH_FW_START_SEC) { 1392237436Snp CH_ERR(adap, "boot image encroaching on firmware region\n"); 1393237436Snp return -EFBIG; 1394237436Snp } 1395237436Snp 1396237436Snp /* 1397237436Snp * Number of sectors spanned 1398237436Snp */ 1399237436Snp i = DIV_ROUND_UP(size ? size : FLASH_BOOTCFG_MAX_SIZE, 1400237436Snp sf_sec_size); 1401237436Snp ret = t4_flash_erase_sectors(adap, boot_sector >> 16, 1402237436Snp (boot_sector >> 16) + i - 1); 1403237436Snp 1404237436Snp /* 1405237436Snp * If size == 0 then we're simply erasing the FLASH sectors associated 1406237436Snp * with the on-adapter option ROM file 1407237436Snp */ 1408237436Snp if (ret || (size == 0)) 1409237436Snp goto out; 1410237436Snp 1411237436Snp /* Get boot header */ 1412237436Snp header = (pci_exp_rom_header_t *)boot_data; 1413237436Snp pcir_offset = le16_to_cpu(*(u16 *)header->pcir_offset); 1414237436Snp /* PCIR Data Structure */ 1415237436Snp pcir_header = (pcir_data_t *) &boot_data[pcir_offset]; 1416237436Snp 1417237436Snp /* 1418228561Snp * Perform some primitive sanity testing to avoid accidentally 1419228561Snp * writing garbage over the boot sectors. We ought to check for 1420228561Snp * more but it's not worth it for now ... 1421228561Snp */ 1422228561Snp if (size < BOOT_MIN_SIZE || size > BOOT_MAX_SIZE) { 1423228561Snp CH_ERR(adap, "boot image too small/large\n"); 1424228561Snp return -EFBIG; 1425228561Snp } 1426228561Snp 1427228561Snp /* 1428237436Snp * Check BOOT ROM header signature 1429228561Snp */ 1430237436Snp if (le16_to_cpu(*(u16*)header->signature) != BOOT_SIGNATURE ) { 1431237436Snp CH_ERR(adap, "Boot image missing signature\n"); 1432237436Snp return -EINVAL; 1433228561Snp } 1434228561Snp 1435237436Snp /* 1436237436Snp * Check PCI header signature 1437237436Snp */ 1438237436Snp if (le32_to_cpu(*(u32*)pcir_header->signature) != PCIR_SIGNATURE) { 1439237436Snp CH_ERR(adap, "PCI header missing signature\n"); 1440237436Snp return -EINVAL; 1441237436Snp } 1442228561Snp 1443228561Snp /* 1444237436Snp * Check Vendor ID matches Chelsio ID 1445237436Snp */ 1446237436Snp if (le16_to_cpu(*(u16*)pcir_header->vendor_id) != VENDOR_ID) { 1447237436Snp CH_ERR(adap, "Vendor ID missing signature\n"); 1448237436Snp return -EINVAL; 1449237436Snp } 1450237436Snp 1451237436Snp /* 1452237436Snp * Retrieve adapter's device ID 1453237436Snp */ 1454237436Snp t4_os_pci_read_cfg2(adap, PCI_DEVICE_ID, &device_id); 1455237436Snp /* Want to deal with PF 0 so I strip off PF 4 indicator */ 1456237436Snp device_id = (device_id & 0xff) | 0x4000; 1457237436Snp 1458237436Snp /* 1459237436Snp * Check PCIE Device ID 1460237436Snp */ 1461237436Snp if (le16_to_cpu(*(u16*)pcir_header->device_id) != device_id) { 1462237436Snp /* 1463237436Snp * Change the device ID in the Boot BIOS image to match 1464237436Snp * the Device ID of the current adapter. 1465237436Snp */ 1466237436Snp modify_device_id(device_id, boot_data); 1467237436Snp } 1468237436Snp 1469237436Snp /* 1470228561Snp * Skip over the first SF_PAGE_SIZE worth of data and write it after 1471228561Snp * we finish copying the rest of the boot image. This will ensure 1472228561Snp * that the BIOS boot header will only be written if the boot image 1473228561Snp * was written in full. 1474228561Snp */ 1475228561Snp addr = boot_sector; 1476228561Snp for (size -= SF_PAGE_SIZE; size; size -= SF_PAGE_SIZE) { 1477228561Snp addr += SF_PAGE_SIZE; 1478228561Snp boot_data += SF_PAGE_SIZE; 1479228561Snp ret = t4_write_flash(adap, addr, SF_PAGE_SIZE, boot_data, 0); 1480228561Snp if (ret) 1481228561Snp goto out; 1482228561Snp } 1483228561Snp 1484228561Snp ret = t4_write_flash(adap, boot_sector, SF_PAGE_SIZE, boot_data, 0); 1485228561Snp 1486228561Snpout: 1487228561Snp if (ret) 1488228561Snp CH_ERR(adap, "boot image download failed, error %d\n", ret); 1489228561Snp return ret; 1490228561Snp} 1491228561Snp 1492218792Snp/** 1493218792Snp * t4_read_cimq_cfg - read CIM queue configuration 1494218792Snp * @adap: the adapter 1495218792Snp * @base: holds the queue base addresses in bytes 1496218792Snp * @size: holds the queue sizes in bytes 1497218792Snp * @thres: holds the queue full thresholds in bytes 1498218792Snp * 1499218792Snp * Returns the current configuration of the CIM queues, starting with 1500218792Snp * the IBQs, then the OBQs. 1501218792Snp */ 1502218792Snpvoid t4_read_cimq_cfg(struct adapter *adap, u16 *base, u16 *size, u16 *thres) 1503218792Snp{ 1504218792Snp unsigned int i, v; 1505248925Snp int cim_num_obq = is_t4(adap) ? CIM_NUM_OBQ : CIM_NUM_OBQ_T5; 1506218792Snp 1507218792Snp for (i = 0; i < CIM_NUM_IBQ; i++) { 1508218792Snp t4_write_reg(adap, A_CIM_QUEUE_CONFIG_REF, F_IBQSELECT | 1509218792Snp V_QUENUMSELECT(i)); 1510218792Snp v = t4_read_reg(adap, A_CIM_QUEUE_CONFIG_CTRL); 1511218792Snp *base++ = G_CIMQBASE(v) * 256; /* value is in 256-byte units */ 1512218792Snp *size++ = G_CIMQSIZE(v) * 256; /* value is in 256-byte units */ 1513218792Snp *thres++ = G_QUEFULLTHRSH(v) * 8; /* 8-byte unit */ 1514218792Snp } 1515248925Snp for (i = 0; i < cim_num_obq; i++) { 1516218792Snp t4_write_reg(adap, A_CIM_QUEUE_CONFIG_REF, F_OBQSELECT | 1517218792Snp V_QUENUMSELECT(i)); 1518218792Snp v = t4_read_reg(adap, A_CIM_QUEUE_CONFIG_CTRL); 1519218792Snp *base++ = G_CIMQBASE(v) * 256; /* value is in 256-byte units */ 1520218792Snp *size++ = G_CIMQSIZE(v) * 256; /* value is in 256-byte units */ 1521218792Snp } 1522218792Snp} 1523218792Snp 1524218792Snp/** 1525218792Snp * t4_read_cim_ibq - read the contents of a CIM inbound queue 1526218792Snp * @adap: the adapter 1527218792Snp * @qid: the queue index 1528218792Snp * @data: where to store the queue contents 1529218792Snp * @n: capacity of @data in 32-bit words 1530218792Snp * 1531218792Snp * Reads the contents of the selected CIM queue starting at address 0 up 1532218792Snp * to the capacity of @data. @n must be a multiple of 4. Returns < 0 on 1533218792Snp * error and the number of 32-bit words actually read on success. 1534218792Snp */ 1535218792Snpint t4_read_cim_ibq(struct adapter *adap, unsigned int qid, u32 *data, size_t n) 1536218792Snp{ 1537218792Snp int i, err; 1538218792Snp unsigned int addr; 1539218792Snp const unsigned int nwords = CIM_IBQ_SIZE * 4; 1540218792Snp 1541218792Snp if (qid > 5 || (n & 3)) 1542218792Snp return -EINVAL; 1543218792Snp 1544218792Snp addr = qid * nwords; 1545218792Snp if (n > nwords) 1546218792Snp n = nwords; 1547218792Snp 1548218792Snp for (i = 0; i < n; i++, addr++) { 1549218792Snp t4_write_reg(adap, A_CIM_IBQ_DBG_CFG, V_IBQDBGADDR(addr) | 1550218792Snp F_IBQDBGEN); 1551248925Snp /* 1552248925Snp * It might take 3-10ms before the IBQ debug read access is 1553248925Snp * allowed. Wait for 1 Sec with a delay of 1 usec. 1554248925Snp */ 1555218792Snp err = t4_wait_op_done(adap, A_CIM_IBQ_DBG_CFG, F_IBQDBGBUSY, 0, 1556248925Snp 1000000, 1); 1557218792Snp if (err) 1558218792Snp return err; 1559218792Snp *data++ = t4_read_reg(adap, A_CIM_IBQ_DBG_DATA); 1560218792Snp } 1561218792Snp t4_write_reg(adap, A_CIM_IBQ_DBG_CFG, 0); 1562218792Snp return i; 1563218792Snp} 1564218792Snp 1565218792Snp/** 1566218792Snp * t4_read_cim_obq - read the contents of a CIM outbound queue 1567218792Snp * @adap: the adapter 1568218792Snp * @qid: the queue index 1569218792Snp * @data: where to store the queue contents 1570218792Snp * @n: capacity of @data in 32-bit words 1571218792Snp * 1572218792Snp * Reads the contents of the selected CIM queue starting at address 0 up 1573218792Snp * to the capacity of @data. @n must be a multiple of 4. Returns < 0 on 1574218792Snp * error and the number of 32-bit words actually read on success. 1575218792Snp */ 1576218792Snpint t4_read_cim_obq(struct adapter *adap, unsigned int qid, u32 *data, size_t n) 1577218792Snp{ 1578218792Snp int i, err; 1579218792Snp unsigned int addr, v, nwords; 1580248925Snp int cim_num_obq = is_t4(adap) ? CIM_NUM_OBQ : CIM_NUM_OBQ_T5; 1581218792Snp 1582248925Snp if (qid >= cim_num_obq || (n & 3)) 1583218792Snp return -EINVAL; 1584218792Snp 1585218792Snp t4_write_reg(adap, A_CIM_QUEUE_CONFIG_REF, F_OBQSELECT | 1586218792Snp V_QUENUMSELECT(qid)); 1587218792Snp v = t4_read_reg(adap, A_CIM_QUEUE_CONFIG_CTRL); 1588218792Snp 1589218792Snp addr = G_CIMQBASE(v) * 64; /* muliple of 256 -> muliple of 4 */ 1590218792Snp nwords = G_CIMQSIZE(v) * 64; /* same */ 1591218792Snp if (n > nwords) 1592218792Snp n = nwords; 1593218792Snp 1594218792Snp for (i = 0; i < n; i++, addr++) { 1595218792Snp t4_write_reg(adap, A_CIM_OBQ_DBG_CFG, V_OBQDBGADDR(addr) | 1596218792Snp F_OBQDBGEN); 1597218792Snp err = t4_wait_op_done(adap, A_CIM_OBQ_DBG_CFG, F_OBQDBGBUSY, 0, 1598218792Snp 2, 1); 1599218792Snp if (err) 1600218792Snp return err; 1601218792Snp *data++ = t4_read_reg(adap, A_CIM_OBQ_DBG_DATA); 1602218792Snp } 1603218792Snp t4_write_reg(adap, A_CIM_OBQ_DBG_CFG, 0); 1604218792Snp return i; 1605218792Snp} 1606218792Snp 1607218792Snpenum { 1608218792Snp CIM_QCTL_BASE = 0, 1609218792Snp CIM_CTL_BASE = 0x2000, 1610218792Snp CIM_PBT_ADDR_BASE = 0x2800, 1611218792Snp CIM_PBT_LRF_BASE = 0x3000, 1612218792Snp CIM_PBT_DATA_BASE = 0x3800 1613218792Snp}; 1614218792Snp 1615218792Snp/** 1616218792Snp * t4_cim_read - read a block from CIM internal address space 1617218792Snp * @adap: the adapter 1618218792Snp * @addr: the start address within the CIM address space 1619218792Snp * @n: number of words to read 1620218792Snp * @valp: where to store the result 1621218792Snp * 1622218792Snp * Reads a block of 4-byte words from the CIM intenal address space. 1623218792Snp */ 1624218792Snpint t4_cim_read(struct adapter *adap, unsigned int addr, unsigned int n, 1625218792Snp unsigned int *valp) 1626218792Snp{ 1627218792Snp int ret = 0; 1628218792Snp 1629218792Snp if (t4_read_reg(adap, A_CIM_HOST_ACC_CTRL) & F_HOSTBUSY) 1630218792Snp return -EBUSY; 1631218792Snp 1632218792Snp for ( ; !ret && n--; addr += 4) { 1633218792Snp t4_write_reg(adap, A_CIM_HOST_ACC_CTRL, addr); 1634218792Snp ret = t4_wait_op_done(adap, A_CIM_HOST_ACC_CTRL, F_HOSTBUSY, 1635218792Snp 0, 5, 2); 1636218792Snp if (!ret) 1637218792Snp *valp++ = t4_read_reg(adap, A_CIM_HOST_ACC_DATA); 1638218792Snp } 1639218792Snp return ret; 1640218792Snp} 1641218792Snp 1642218792Snp/** 1643218792Snp * t4_cim_write - write a block into CIM internal address space 1644218792Snp * @adap: the adapter 1645218792Snp * @addr: the start address within the CIM address space 1646218792Snp * @n: number of words to write 1647218792Snp * @valp: set of values to write 1648218792Snp * 1649218792Snp * Writes a block of 4-byte words into the CIM intenal address space. 1650218792Snp */ 1651218792Snpint t4_cim_write(struct adapter *adap, unsigned int addr, unsigned int n, 1652218792Snp const unsigned int *valp) 1653218792Snp{ 1654218792Snp int ret = 0; 1655218792Snp 1656218792Snp if (t4_read_reg(adap, A_CIM_HOST_ACC_CTRL) & F_HOSTBUSY) 1657218792Snp return -EBUSY; 1658218792Snp 1659218792Snp for ( ; !ret && n--; addr += 4) { 1660218792Snp t4_write_reg(adap, A_CIM_HOST_ACC_DATA, *valp++); 1661218792Snp t4_write_reg(adap, A_CIM_HOST_ACC_CTRL, addr | F_HOSTWRITE); 1662218792Snp ret = t4_wait_op_done(adap, A_CIM_HOST_ACC_CTRL, F_HOSTBUSY, 1663218792Snp 0, 5, 2); 1664218792Snp } 1665218792Snp return ret; 1666218792Snp} 1667218792Snp 1668218792Snpstatic int t4_cim_write1(struct adapter *adap, unsigned int addr, unsigned int val) 1669218792Snp{ 1670218792Snp return t4_cim_write(adap, addr, 1, &val); 1671218792Snp} 1672218792Snp 1673218792Snp/** 1674218792Snp * t4_cim_ctl_read - read a block from CIM control region 1675218792Snp * @adap: the adapter 1676218792Snp * @addr: the start address within the CIM control region 1677218792Snp * @n: number of words to read 1678218792Snp * @valp: where to store the result 1679218792Snp * 1680218792Snp * Reads a block of 4-byte words from the CIM control region. 1681218792Snp */ 1682218792Snpint t4_cim_ctl_read(struct adapter *adap, unsigned int addr, unsigned int n, 1683218792Snp unsigned int *valp) 1684218792Snp{ 1685218792Snp return t4_cim_read(adap, addr + CIM_CTL_BASE, n, valp); 1686218792Snp} 1687218792Snp 1688218792Snp/** 1689218792Snp * t4_cim_read_la - read CIM LA capture buffer 1690218792Snp * @adap: the adapter 1691218792Snp * @la_buf: where to store the LA data 1692218792Snp * @wrptr: the HW write pointer within the capture buffer 1693218792Snp * 1694218792Snp * Reads the contents of the CIM LA buffer with the most recent entry at 1695218792Snp * the end of the returned data and with the entry at @wrptr first. 1696218792Snp * We try to leave the LA in the running state we find it in. 1697218792Snp */ 1698218792Snpint t4_cim_read_la(struct adapter *adap, u32 *la_buf, unsigned int *wrptr) 1699218792Snp{ 1700218792Snp int i, ret; 1701218792Snp unsigned int cfg, val, idx; 1702218792Snp 1703218792Snp ret = t4_cim_read(adap, A_UP_UP_DBG_LA_CFG, 1, &cfg); 1704218792Snp if (ret) 1705218792Snp return ret; 1706218792Snp 1707218792Snp if (cfg & F_UPDBGLAEN) { /* LA is running, freeze it */ 1708218792Snp ret = t4_cim_write1(adap, A_UP_UP_DBG_LA_CFG, 0); 1709218792Snp if (ret) 1710218792Snp return ret; 1711218792Snp } 1712218792Snp 1713218792Snp ret = t4_cim_read(adap, A_UP_UP_DBG_LA_CFG, 1, &val); 1714218792Snp if (ret) 1715218792Snp goto restart; 1716218792Snp 1717218792Snp idx = G_UPDBGLAWRPTR(val); 1718218792Snp if (wrptr) 1719218792Snp *wrptr = idx; 1720218792Snp 1721218792Snp for (i = 0; i < adap->params.cim_la_size; i++) { 1722218792Snp ret = t4_cim_write1(adap, A_UP_UP_DBG_LA_CFG, 1723218792Snp V_UPDBGLARDPTR(idx) | F_UPDBGLARDEN); 1724218792Snp if (ret) 1725218792Snp break; 1726218792Snp ret = t4_cim_read(adap, A_UP_UP_DBG_LA_CFG, 1, &val); 1727218792Snp if (ret) 1728218792Snp break; 1729218792Snp if (val & F_UPDBGLARDEN) { 1730218792Snp ret = -ETIMEDOUT; 1731218792Snp break; 1732218792Snp } 1733218792Snp ret = t4_cim_read(adap, A_UP_UP_DBG_LA_DATA, 1, &la_buf[i]); 1734218792Snp if (ret) 1735218792Snp break; 1736218792Snp idx = (idx + 1) & M_UPDBGLARDPTR; 1737218792Snp } 1738218792Snprestart: 1739218792Snp if (cfg & F_UPDBGLAEN) { 1740218792Snp int r = t4_cim_write1(adap, A_UP_UP_DBG_LA_CFG, 1741218792Snp cfg & ~F_UPDBGLARDEN); 1742218792Snp if (!ret) 1743218792Snp ret = r; 1744218792Snp } 1745218792Snp return ret; 1746218792Snp} 1747218792Snp 1748218792Snpvoid t4_cim_read_pif_la(struct adapter *adap, u32 *pif_req, u32 *pif_rsp, 1749218792Snp unsigned int *pif_req_wrptr, 1750218792Snp unsigned int *pif_rsp_wrptr) 1751218792Snp{ 1752218792Snp int i, j; 1753218792Snp u32 cfg, val, req, rsp; 1754218792Snp 1755218792Snp cfg = t4_read_reg(adap, A_CIM_DEBUGCFG); 1756218792Snp if (cfg & F_LADBGEN) 1757218792Snp t4_write_reg(adap, A_CIM_DEBUGCFG, cfg ^ F_LADBGEN); 1758218792Snp 1759218792Snp val = t4_read_reg(adap, A_CIM_DEBUGSTS); 1760218792Snp req = G_POLADBGWRPTR(val); 1761218792Snp rsp = G_PILADBGWRPTR(val); 1762218792Snp if (pif_req_wrptr) 1763218792Snp *pif_req_wrptr = req; 1764218792Snp if (pif_rsp_wrptr) 1765218792Snp *pif_rsp_wrptr = rsp; 1766218792Snp 1767218792Snp for (i = 0; i < CIM_PIFLA_SIZE; i++) { 1768218792Snp for (j = 0; j < 6; j++) { 1769218792Snp t4_write_reg(adap, A_CIM_DEBUGCFG, V_POLADBGRDPTR(req) | 1770218792Snp V_PILADBGRDPTR(rsp)); 1771218792Snp *pif_req++ = t4_read_reg(adap, A_CIM_PO_LA_DEBUGDATA); 1772218792Snp *pif_rsp++ = t4_read_reg(adap, A_CIM_PI_LA_DEBUGDATA); 1773218792Snp req++; 1774218792Snp rsp++; 1775218792Snp } 1776218792Snp req = (req + 2) & M_POLADBGRDPTR; 1777218792Snp rsp = (rsp + 2) & M_PILADBGRDPTR; 1778218792Snp } 1779218792Snp t4_write_reg(adap, A_CIM_DEBUGCFG, cfg); 1780218792Snp} 1781218792Snp 1782218792Snpvoid t4_cim_read_ma_la(struct adapter *adap, u32 *ma_req, u32 *ma_rsp) 1783218792Snp{ 1784218792Snp u32 cfg; 1785218792Snp int i, j, idx; 1786218792Snp 1787218792Snp cfg = t4_read_reg(adap, A_CIM_DEBUGCFG); 1788218792Snp if (cfg & F_LADBGEN) 1789218792Snp t4_write_reg(adap, A_CIM_DEBUGCFG, cfg ^ F_LADBGEN); 1790218792Snp 1791218792Snp for (i = 0; i < CIM_MALA_SIZE; i++) { 1792218792Snp for (j = 0; j < 5; j++) { 1793218792Snp idx = 8 * i + j; 1794218792Snp t4_write_reg(adap, A_CIM_DEBUGCFG, V_POLADBGRDPTR(idx) | 1795218792Snp V_PILADBGRDPTR(idx)); 1796218792Snp *ma_req++ = t4_read_reg(adap, A_CIM_PO_LA_MADEBUGDATA); 1797218792Snp *ma_rsp++ = t4_read_reg(adap, A_CIM_PI_LA_MADEBUGDATA); 1798218792Snp } 1799218792Snp } 1800218792Snp t4_write_reg(adap, A_CIM_DEBUGCFG, cfg); 1801218792Snp} 1802218792Snp 1803218792Snp/** 1804218792Snp * t4_tp_read_la - read TP LA capture buffer 1805218792Snp * @adap: the adapter 1806218792Snp * @la_buf: where to store the LA data 1807218792Snp * @wrptr: the HW write pointer within the capture buffer 1808218792Snp * 1809218792Snp * Reads the contents of the TP LA buffer with the most recent entry at 1810218792Snp * the end of the returned data and with the entry at @wrptr first. 1811218792Snp * We leave the LA in the running state we find it in. 1812218792Snp */ 1813218792Snpvoid t4_tp_read_la(struct adapter *adap, u64 *la_buf, unsigned int *wrptr) 1814218792Snp{ 1815218792Snp bool last_incomplete; 1816218792Snp unsigned int i, cfg, val, idx; 1817218792Snp 1818218792Snp cfg = t4_read_reg(adap, A_TP_DBG_LA_CONFIG) & 0xffff; 1819218792Snp if (cfg & F_DBGLAENABLE) /* freeze LA */ 1820218792Snp t4_write_reg(adap, A_TP_DBG_LA_CONFIG, 1821218792Snp adap->params.tp.la_mask | (cfg ^ F_DBGLAENABLE)); 1822218792Snp 1823218792Snp val = t4_read_reg(adap, A_TP_DBG_LA_CONFIG); 1824218792Snp idx = G_DBGLAWPTR(val); 1825218792Snp last_incomplete = G_DBGLAMODE(val) >= 2 && (val & F_DBGLAWHLF) == 0; 1826218792Snp if (last_incomplete) 1827218792Snp idx = (idx + 1) & M_DBGLARPTR; 1828218792Snp if (wrptr) 1829218792Snp *wrptr = idx; 1830218792Snp 1831218792Snp val &= 0xffff; 1832218792Snp val &= ~V_DBGLARPTR(M_DBGLARPTR); 1833218792Snp val |= adap->params.tp.la_mask; 1834218792Snp 1835218792Snp for (i = 0; i < TPLA_SIZE; i++) { 1836218792Snp t4_write_reg(adap, A_TP_DBG_LA_CONFIG, V_DBGLARPTR(idx) | val); 1837218792Snp la_buf[i] = t4_read_reg64(adap, A_TP_DBG_LA_DATAL); 1838218792Snp idx = (idx + 1) & M_DBGLARPTR; 1839218792Snp } 1840218792Snp 1841218792Snp /* Wipe out last entry if it isn't valid */ 1842218792Snp if (last_incomplete) 1843218792Snp la_buf[TPLA_SIZE - 1] = ~0ULL; 1844218792Snp 1845218792Snp if (cfg & F_DBGLAENABLE) /* restore running state */ 1846218792Snp t4_write_reg(adap, A_TP_DBG_LA_CONFIG, 1847218792Snp cfg | adap->params.tp.la_mask); 1848218792Snp} 1849218792Snp 1850218792Snpvoid t4_ulprx_read_la(struct adapter *adap, u32 *la_buf) 1851218792Snp{ 1852218792Snp unsigned int i, j; 1853218792Snp 1854218792Snp for (i = 0; i < 8; i++) { 1855218792Snp u32 *p = la_buf + i; 1856218792Snp 1857218792Snp t4_write_reg(adap, A_ULP_RX_LA_CTL, i); 1858218792Snp j = t4_read_reg(adap, A_ULP_RX_LA_WRPTR); 1859218792Snp t4_write_reg(adap, A_ULP_RX_LA_RDPTR, j); 1860218792Snp for (j = 0; j < ULPRX_LA_SIZE; j++, p += 8) 1861218792Snp *p = t4_read_reg(adap, A_ULP_RX_LA_RDDATA); 1862218792Snp } 1863218792Snp} 1864218792Snp 1865218792Snp#define ADVERT_MASK (FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G |\ 1866250090Snp FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_SPEED_40G | \ 1867250090Snp FW_PORT_CAP_SPEED_100G | FW_PORT_CAP_ANEG) 1868218792Snp 1869218792Snp/** 1870218792Snp * t4_link_start - apply link configuration to MAC/PHY 1871218792Snp * @phy: the PHY to setup 1872218792Snp * @mac: the MAC to setup 1873218792Snp * @lc: the requested link configuration 1874218792Snp * 1875218792Snp * Set up a port's MAC and PHY according to a desired link configuration. 1876218792Snp * - If the PHY can auto-negotiate first decide what to advertise, then 1877218792Snp * enable/disable auto-negotiation as desired, and reset. 1878218792Snp * - If the PHY does not auto-negotiate just reset it. 1879218792Snp * - If auto-negotiation is off set the MAC to the proper speed/duplex/FC, 1880218792Snp * otherwise do it later based on the outcome of auto-negotiation. 1881218792Snp */ 1882218792Snpint t4_link_start(struct adapter *adap, unsigned int mbox, unsigned int port, 1883218792Snp struct link_config *lc) 1884218792Snp{ 1885218792Snp struct fw_port_cmd c; 1886218792Snp unsigned int fc = 0, mdi = V_FW_PORT_CAP_MDI(FW_PORT_CAP_MDI_AUTO); 1887218792Snp 1888218792Snp lc->link_ok = 0; 1889218792Snp if (lc->requested_fc & PAUSE_RX) 1890218792Snp fc |= FW_PORT_CAP_FC_RX; 1891218792Snp if (lc->requested_fc & PAUSE_TX) 1892218792Snp fc |= FW_PORT_CAP_FC_TX; 1893218792Snp 1894218792Snp memset(&c, 0, sizeof(c)); 1895218792Snp c.op_to_portid = htonl(V_FW_CMD_OP(FW_PORT_CMD) | F_FW_CMD_REQUEST | 1896218792Snp F_FW_CMD_EXEC | V_FW_PORT_CMD_PORTID(port)); 1897218792Snp c.action_to_len16 = htonl(V_FW_PORT_CMD_ACTION(FW_PORT_ACTION_L1_CFG) | 1898218792Snp FW_LEN16(c)); 1899218792Snp 1900218792Snp if (!(lc->supported & FW_PORT_CAP_ANEG)) { 1901218792Snp c.u.l1cfg.rcap = htonl((lc->supported & ADVERT_MASK) | fc); 1902218792Snp lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); 1903218792Snp } else if (lc->autoneg == AUTONEG_DISABLE) { 1904218792Snp c.u.l1cfg.rcap = htonl(lc->requested_speed | fc | mdi); 1905218792Snp lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); 1906218792Snp } else 1907218792Snp c.u.l1cfg.rcap = htonl(lc->advertising | fc | mdi); 1908218792Snp 1909218792Snp return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); 1910218792Snp} 1911218792Snp 1912218792Snp/** 1913218792Snp * t4_restart_aneg - restart autonegotiation 1914218792Snp * @adap: the adapter 1915218792Snp * @mbox: mbox to use for the FW command 1916218792Snp * @port: the port id 1917218792Snp * 1918218792Snp * Restarts autonegotiation for the selected port. 1919218792Snp */ 1920218792Snpint t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port) 1921218792Snp{ 1922218792Snp struct fw_port_cmd c; 1923218792Snp 1924218792Snp memset(&c, 0, sizeof(c)); 1925218792Snp c.op_to_portid = htonl(V_FW_CMD_OP(FW_PORT_CMD) | F_FW_CMD_REQUEST | 1926218792Snp F_FW_CMD_EXEC | V_FW_PORT_CMD_PORTID(port)); 1927218792Snp c.action_to_len16 = htonl(V_FW_PORT_CMD_ACTION(FW_PORT_ACTION_L1_CFG) | 1928218792Snp FW_LEN16(c)); 1929218792Snp c.u.l1cfg.rcap = htonl(FW_PORT_CAP_ANEG); 1930218792Snp return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); 1931218792Snp} 1932218792Snp 1933218792Snpstruct intr_info { 1934218792Snp unsigned int mask; /* bits to check in interrupt status */ 1935218792Snp const char *msg; /* message to print or NULL */ 1936218792Snp short stat_idx; /* stat counter to increment or -1 */ 1937218792Snp unsigned short fatal; /* whether the condition reported is fatal */ 1938218792Snp}; 1939218792Snp 1940218792Snp/** 1941218792Snp * t4_handle_intr_status - table driven interrupt handler 1942218792Snp * @adapter: the adapter that generated the interrupt 1943218792Snp * @reg: the interrupt status register to process 1944218792Snp * @acts: table of interrupt actions 1945218792Snp * 1946218792Snp * A table driven interrupt handler that applies a set of masks to an 1947218792Snp * interrupt status word and performs the corresponding actions if the 1948218792Snp * interrupts described by the mask have occured. The actions include 1949218792Snp * optionally emitting a warning or alert message. The table is terminated 1950218792Snp * by an entry specifying mask 0. Returns the number of fatal interrupt 1951218792Snp * conditions. 1952218792Snp */ 1953218792Snpstatic int t4_handle_intr_status(struct adapter *adapter, unsigned int reg, 1954218792Snp const struct intr_info *acts) 1955218792Snp{ 1956218792Snp int fatal = 0; 1957218792Snp unsigned int mask = 0; 1958218792Snp unsigned int status = t4_read_reg(adapter, reg); 1959218792Snp 1960218792Snp for ( ; acts->mask; ++acts) { 1961218792Snp if (!(status & acts->mask)) 1962218792Snp continue; 1963218792Snp if (acts->fatal) { 1964218792Snp fatal++; 1965218792Snp CH_ALERT(adapter, "%s (0x%x)\n", 1966218792Snp acts->msg, status & acts->mask); 1967218792Snp } else if (acts->msg) 1968218792Snp CH_WARN_RATELIMIT(adapter, "%s (0x%x)\n", 1969218792Snp acts->msg, status & acts->mask); 1970218792Snp mask |= acts->mask; 1971218792Snp } 1972218792Snp status &= mask; 1973218792Snp if (status) /* clear processed interrupts */ 1974218792Snp t4_write_reg(adapter, reg, status); 1975218792Snp return fatal; 1976218792Snp} 1977218792Snp 1978218792Snp/* 1979218792Snp * Interrupt handler for the PCIE module. 1980218792Snp */ 1981218792Snpstatic void pcie_intr_handler(struct adapter *adapter) 1982218792Snp{ 1983218792Snp static struct intr_info sysbus_intr_info[] = { 1984218792Snp { F_RNPP, "RXNP array parity error", -1, 1 }, 1985218792Snp { F_RPCP, "RXPC array parity error", -1, 1 }, 1986218792Snp { F_RCIP, "RXCIF array parity error", -1, 1 }, 1987218792Snp { F_RCCP, "Rx completions control array parity error", -1, 1 }, 1988218792Snp { F_RFTP, "RXFT array parity error", -1, 1 }, 1989218792Snp { 0 } 1990218792Snp }; 1991218792Snp static struct intr_info pcie_port_intr_info[] = { 1992218792Snp { F_TPCP, "TXPC array parity error", -1, 1 }, 1993218792Snp { F_TNPP, "TXNP array parity error", -1, 1 }, 1994218792Snp { F_TFTP, "TXFT array parity error", -1, 1 }, 1995218792Snp { F_TCAP, "TXCA array parity error", -1, 1 }, 1996218792Snp { F_TCIP, "TXCIF array parity error", -1, 1 }, 1997218792Snp { F_RCAP, "RXCA array parity error", -1, 1 }, 1998218792Snp { F_OTDD, "outbound request TLP discarded", -1, 1 }, 1999218792Snp { F_RDPE, "Rx data parity error", -1, 1 }, 2000218792Snp { F_TDUE, "Tx uncorrectable data error", -1, 1 }, 2001218792Snp { 0 } 2002218792Snp }; 2003218792Snp static struct intr_info pcie_intr_info[] = { 2004218792Snp { F_MSIADDRLPERR, "MSI AddrL parity error", -1, 1 }, 2005218792Snp { F_MSIADDRHPERR, "MSI AddrH parity error", -1, 1 }, 2006218792Snp { F_MSIDATAPERR, "MSI data parity error", -1, 1 }, 2007218792Snp { F_MSIXADDRLPERR, "MSI-X AddrL parity error", -1, 1 }, 2008218792Snp { F_MSIXADDRHPERR, "MSI-X AddrH parity error", -1, 1 }, 2009218792Snp { F_MSIXDATAPERR, "MSI-X data parity error", -1, 1 }, 2010218792Snp { F_MSIXDIPERR, "MSI-X DI parity error", -1, 1 }, 2011218792Snp { F_PIOCPLPERR, "PCI PIO completion FIFO parity error", -1, 1 }, 2012218792Snp { F_PIOREQPERR, "PCI PIO request FIFO parity error", -1, 1 }, 2013218792Snp { F_TARTAGPERR, "PCI PCI target tag FIFO parity error", -1, 1 }, 2014218792Snp { F_CCNTPERR, "PCI CMD channel count parity error", -1, 1 }, 2015218792Snp { F_CREQPERR, "PCI CMD channel request parity error", -1, 1 }, 2016218792Snp { F_CRSPPERR, "PCI CMD channel response parity error", -1, 1 }, 2017218792Snp { F_DCNTPERR, "PCI DMA channel count parity error", -1, 1 }, 2018218792Snp { F_DREQPERR, "PCI DMA channel request parity error", -1, 1 }, 2019218792Snp { F_DRSPPERR, "PCI DMA channel response parity error", -1, 1 }, 2020218792Snp { F_HCNTPERR, "PCI HMA channel count parity error", -1, 1 }, 2021218792Snp { F_HREQPERR, "PCI HMA channel request parity error", -1, 1 }, 2022218792Snp { F_HRSPPERR, "PCI HMA channel response parity error", -1, 1 }, 2023218792Snp { F_CFGSNPPERR, "PCI config snoop FIFO parity error", -1, 1 }, 2024218792Snp { F_FIDPERR, "PCI FID parity error", -1, 1 }, 2025218792Snp { F_INTXCLRPERR, "PCI INTx clear parity error", -1, 1 }, 2026218792Snp { F_MATAGPERR, "PCI MA tag parity error", -1, 1 }, 2027218792Snp { F_PIOTAGPERR, "PCI PIO tag parity error", -1, 1 }, 2028218792Snp { F_RXCPLPERR, "PCI Rx completion parity error", -1, 1 }, 2029218792Snp { F_RXWRPERR, "PCI Rx write parity error", -1, 1 }, 2030218792Snp { F_RPLPERR, "PCI replay buffer parity error", -1, 1 }, 2031218792Snp { F_PCIESINT, "PCI core secondary fault", -1, 1 }, 2032218792Snp { F_PCIEPINT, "PCI core primary fault", -1, 1 }, 2033218792Snp { F_UNXSPLCPLERR, "PCI unexpected split completion error", -1, 2034218792Snp 0 }, 2035218792Snp { 0 } 2036218792Snp }; 2037218792Snp 2038248925Snp static struct intr_info t5_pcie_intr_info[] = { 2039248925Snp { F_MSTGRPPERR, "Master Response Read Queue parity error", 2040248925Snp -1, 1 }, 2041248925Snp { F_MSTTIMEOUTPERR, "Master Timeout FIFO parity error", -1, 1 }, 2042248925Snp { F_MSIXSTIPERR, "MSI-X STI SRAM parity error", -1, 1 }, 2043248925Snp { F_MSIXADDRLPERR, "MSI-X AddrL parity error", -1, 1 }, 2044248925Snp { F_MSIXADDRHPERR, "MSI-X AddrH parity error", -1, 1 }, 2045248925Snp { F_MSIXDATAPERR, "MSI-X data parity error", -1, 1 }, 2046248925Snp { F_MSIXDIPERR, "MSI-X DI parity error", -1, 1 }, 2047248925Snp { F_PIOCPLGRPPERR, "PCI PIO completion Group FIFO parity error", 2048248925Snp -1, 1 }, 2049248925Snp { F_PIOREQGRPPERR, "PCI PIO request Group FIFO parity error", 2050248925Snp -1, 1 }, 2051248925Snp { F_TARTAGPERR, "PCI PCI target tag FIFO parity error", -1, 1 }, 2052248925Snp { F_MSTTAGQPERR, "PCI master tag queue parity error", -1, 1 }, 2053248925Snp { F_CREQPERR, "PCI CMD channel request parity error", -1, 1 }, 2054248925Snp { F_CRSPPERR, "PCI CMD channel response parity error", -1, 1 }, 2055248925Snp { F_DREQWRPERR, "PCI DMA channel write request parity error", 2056248925Snp -1, 1 }, 2057248925Snp { F_DREQPERR, "PCI DMA channel request parity error", -1, 1 }, 2058248925Snp { F_DRSPPERR, "PCI DMA channel response parity error", -1, 1 }, 2059248925Snp { F_HREQWRPERR, "PCI HMA channel count parity error", -1, 1 }, 2060248925Snp { F_HREQPERR, "PCI HMA channel request parity error", -1, 1 }, 2061248925Snp { F_HRSPPERR, "PCI HMA channel response parity error", -1, 1 }, 2062248925Snp { F_CFGSNPPERR, "PCI config snoop FIFO parity error", -1, 1 }, 2063248925Snp { F_FIDPERR, "PCI FID parity error", -1, 1 }, 2064248925Snp { F_VFIDPERR, "PCI INTx clear parity error", -1, 1 }, 2065248925Snp { F_MAGRPPERR, "PCI MA group FIFO parity error", -1, 1 }, 2066248925Snp { F_PIOTAGPERR, "PCI PIO tag parity error", -1, 1 }, 2067248925Snp { F_IPRXHDRGRPPERR, "PCI IP Rx header group parity error", 2068248925Snp -1, 1 }, 2069248925Snp { F_IPRXDATAGRPPERR, "PCI IP Rx data group parity error", 2070248925Snp -1, 1 }, 2071248925Snp { F_RPLPERR, "PCI IP replay buffer parity error", -1, 1 }, 2072248925Snp { F_IPSOTPERR, "PCI IP SOT buffer parity error", -1, 1 }, 2073248925Snp { F_TRGT1GRPPERR, "PCI TRGT1 group FIFOs parity error", -1, 1 }, 2074248925Snp { F_READRSPERR, "Outbound read error", -1, 2075248925Snp 0 }, 2076248925Snp { 0 } 2077248925Snp }; 2078248925Snp 2079218792Snp int fat; 2080218792Snp 2081270297Snp if (is_t4(adapter)) 2082270297Snp fat = t4_handle_intr_status(adapter, 2083270297Snp A_PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS, 2084270297Snp sysbus_intr_info) + 2085270297Snp t4_handle_intr_status(adapter, 2086270297Snp A_PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS, 2087270297Snp pcie_port_intr_info) + 2088270297Snp t4_handle_intr_status(adapter, A_PCIE_INT_CAUSE, 2089270297Snp pcie_intr_info); 2090270297Snp else 2091270297Snp fat = t4_handle_intr_status(adapter, A_PCIE_INT_CAUSE, 2092270297Snp t5_pcie_intr_info); 2093218792Snp if (fat) 2094218792Snp t4_fatal_err(adapter); 2095218792Snp} 2096218792Snp 2097218792Snp/* 2098218792Snp * TP interrupt handler. 2099218792Snp */ 2100218792Snpstatic void tp_intr_handler(struct adapter *adapter) 2101218792Snp{ 2102218792Snp static struct intr_info tp_intr_info[] = { 2103218792Snp { 0x3fffffff, "TP parity error", -1, 1 }, 2104218792Snp { F_FLMTXFLSTEMPTY, "TP out of Tx pages", -1, 1 }, 2105218792Snp { 0 } 2106218792Snp }; 2107218792Snp 2108218792Snp if (t4_handle_intr_status(adapter, A_TP_INT_CAUSE, tp_intr_info)) 2109218792Snp t4_fatal_err(adapter); 2110218792Snp} 2111218792Snp 2112218792Snp/* 2113218792Snp * SGE interrupt handler. 2114218792Snp */ 2115218792Snpstatic void sge_intr_handler(struct adapter *adapter) 2116218792Snp{ 2117218792Snp u64 v; 2118218792Snp u32 err; 2119218792Snp 2120218792Snp static struct intr_info sge_intr_info[] = { 2121218792Snp { F_ERR_CPL_EXCEED_IQE_SIZE, 2122218792Snp "SGE received CPL exceeding IQE size", -1, 1 }, 2123218792Snp { F_ERR_INVALID_CIDX_INC, 2124218792Snp "SGE GTS CIDX increment too large", -1, 0 }, 2125218792Snp { F_ERR_CPL_OPCODE_0, "SGE received 0-length CPL", -1, 0 }, 2126218792Snp { F_ERR_DROPPED_DB, "SGE doorbell dropped", -1, 0 }, 2127218792Snp { F_ERR_DATA_CPL_ON_HIGH_QID1 | F_ERR_DATA_CPL_ON_HIGH_QID0, 2128218792Snp "SGE IQID > 1023 received CPL for FL", -1, 0 }, 2129218792Snp { F_ERR_BAD_DB_PIDX3, "SGE DBP 3 pidx increment too large", -1, 2130218792Snp 0 }, 2131218792Snp { F_ERR_BAD_DB_PIDX2, "SGE DBP 2 pidx increment too large", -1, 2132218792Snp 0 }, 2133218792Snp { F_ERR_BAD_DB_PIDX1, "SGE DBP 1 pidx increment too large", -1, 2134218792Snp 0 }, 2135218792Snp { F_ERR_BAD_DB_PIDX0, "SGE DBP 0 pidx increment too large", -1, 2136218792Snp 0 }, 2137218792Snp { F_ERR_ING_CTXT_PRIO, 2138218792Snp "SGE too many priority ingress contexts", -1, 0 }, 2139218792Snp { F_ERR_EGR_CTXT_PRIO, 2140218792Snp "SGE too many priority egress contexts", -1, 0 }, 2141218792Snp { F_INGRESS_SIZE_ERR, "SGE illegal ingress QID", -1, 0 }, 2142218792Snp { F_EGRESS_SIZE_ERR, "SGE illegal egress QID", -1, 0 }, 2143218792Snp { 0 } 2144218792Snp }; 2145218792Snp 2146218792Snp v = (u64)t4_read_reg(adapter, A_SGE_INT_CAUSE1) | 2147218792Snp ((u64)t4_read_reg(adapter, A_SGE_INT_CAUSE2) << 32); 2148218792Snp if (v) { 2149218792Snp CH_ALERT(adapter, "SGE parity error (%#llx)\n", 2150218792Snp (unsigned long long)v); 2151218792Snp t4_write_reg(adapter, A_SGE_INT_CAUSE1, v); 2152218792Snp t4_write_reg(adapter, A_SGE_INT_CAUSE2, v >> 32); 2153218792Snp } 2154218792Snp 2155218792Snp v |= t4_handle_intr_status(adapter, A_SGE_INT_CAUSE3, sge_intr_info); 2156218792Snp 2157218792Snp err = t4_read_reg(adapter, A_SGE_ERROR_STATS); 2158218792Snp if (err & F_ERROR_QID_VALID) { 2159218792Snp CH_ERR(adapter, "SGE error for queue %u\n", G_ERROR_QID(err)); 2160228561Snp if (err & F_UNCAPTURED_ERROR) 2161228561Snp CH_ERR(adapter, "SGE UNCAPTURED_ERROR set (clearing)\n"); 2162228561Snp t4_write_reg(adapter, A_SGE_ERROR_STATS, F_ERROR_QID_VALID | 2163228561Snp F_UNCAPTURED_ERROR); 2164218792Snp } 2165218792Snp 2166218792Snp if (v != 0) 2167218792Snp t4_fatal_err(adapter); 2168218792Snp} 2169218792Snp 2170218792Snp#define CIM_OBQ_INTR (F_OBQULP0PARERR | F_OBQULP1PARERR | F_OBQULP2PARERR |\ 2171218792Snp F_OBQULP3PARERR | F_OBQSGEPARERR | F_OBQNCSIPARERR) 2172218792Snp#define CIM_IBQ_INTR (F_IBQTP0PARERR | F_IBQTP1PARERR | F_IBQULPPARERR |\ 2173218792Snp F_IBQSGEHIPARERR | F_IBQSGELOPARERR | F_IBQNCSIPARERR) 2174218792Snp 2175218792Snp/* 2176218792Snp * CIM interrupt handler. 2177218792Snp */ 2178218792Snpstatic void cim_intr_handler(struct adapter *adapter) 2179218792Snp{ 2180218792Snp static struct intr_info cim_intr_info[] = { 2181218792Snp { F_PREFDROPINT, "CIM control register prefetch drop", -1, 1 }, 2182218792Snp { CIM_OBQ_INTR, "CIM OBQ parity error", -1, 1 }, 2183218792Snp { CIM_IBQ_INTR, "CIM IBQ parity error", -1, 1 }, 2184218792Snp { F_MBUPPARERR, "CIM mailbox uP parity error", -1, 1 }, 2185218792Snp { F_MBHOSTPARERR, "CIM mailbox host parity error", -1, 1 }, 2186218792Snp { F_TIEQINPARERRINT, "CIM TIEQ outgoing parity error", -1, 1 }, 2187218792Snp { F_TIEQOUTPARERRINT, "CIM TIEQ incoming parity error", -1, 1 }, 2188218792Snp { 0 } 2189218792Snp }; 2190218792Snp static struct intr_info cim_upintr_info[] = { 2191218792Snp { F_RSVDSPACEINT, "CIM reserved space access", -1, 1 }, 2192218792Snp { F_ILLTRANSINT, "CIM illegal transaction", -1, 1 }, 2193218792Snp { F_ILLWRINT, "CIM illegal write", -1, 1 }, 2194218792Snp { F_ILLRDINT, "CIM illegal read", -1, 1 }, 2195218792Snp { F_ILLRDBEINT, "CIM illegal read BE", -1, 1 }, 2196218792Snp { F_ILLWRBEINT, "CIM illegal write BE", -1, 1 }, 2197218792Snp { F_SGLRDBOOTINT, "CIM single read from boot space", -1, 1 }, 2198218792Snp { F_SGLWRBOOTINT, "CIM single write to boot space", -1, 1 }, 2199218792Snp { F_BLKWRBOOTINT, "CIM block write to boot space", -1, 1 }, 2200218792Snp { F_SGLRDFLASHINT, "CIM single read from flash space", -1, 1 }, 2201218792Snp { F_SGLWRFLASHINT, "CIM single write to flash space", -1, 1 }, 2202218792Snp { F_BLKWRFLASHINT, "CIM block write to flash space", -1, 1 }, 2203218792Snp { F_SGLRDEEPROMINT, "CIM single EEPROM read", -1, 1 }, 2204218792Snp { F_SGLWREEPROMINT, "CIM single EEPROM write", -1, 1 }, 2205218792Snp { F_BLKRDEEPROMINT, "CIM block EEPROM read", -1, 1 }, 2206218792Snp { F_BLKWREEPROMINT, "CIM block EEPROM write", -1, 1 }, 2207218792Snp { F_SGLRDCTLINT , "CIM single read from CTL space", -1, 1 }, 2208218792Snp { F_SGLWRCTLINT , "CIM single write to CTL space", -1, 1 }, 2209218792Snp { F_BLKRDCTLINT , "CIM block read from CTL space", -1, 1 }, 2210218792Snp { F_BLKWRCTLINT , "CIM block write to CTL space", -1, 1 }, 2211218792Snp { F_SGLRDPLINT , "CIM single read from PL space", -1, 1 }, 2212218792Snp { F_SGLWRPLINT , "CIM single write to PL space", -1, 1 }, 2213218792Snp { F_BLKRDPLINT , "CIM block read from PL space", -1, 1 }, 2214218792Snp { F_BLKWRPLINT , "CIM block write to PL space", -1, 1 }, 2215218792Snp { F_REQOVRLOOKUPINT , "CIM request FIFO overwrite", -1, 1 }, 2216218792Snp { F_RSPOVRLOOKUPINT , "CIM response FIFO overwrite", -1, 1 }, 2217218792Snp { F_TIMEOUTINT , "CIM PIF timeout", -1, 1 }, 2218218792Snp { F_TIMEOUTMAINT , "CIM PIF MA timeout", -1, 1 }, 2219218792Snp { 0 } 2220218792Snp }; 2221218792Snp int fat; 2222218792Snp 2223247355Snp if (t4_read_reg(adapter, A_PCIE_FW) & F_PCIE_FW_ERR) 2224247355Snp t4_report_fw_error(adapter); 2225247355Snp 2226218792Snp fat = t4_handle_intr_status(adapter, A_CIM_HOST_INT_CAUSE, 2227218792Snp cim_intr_info) + 2228218792Snp t4_handle_intr_status(adapter, A_CIM_HOST_UPACC_INT_CAUSE, 2229218792Snp cim_upintr_info); 2230218792Snp if (fat) 2231218792Snp t4_fatal_err(adapter); 2232218792Snp} 2233218792Snp 2234218792Snp/* 2235218792Snp * ULP RX interrupt handler. 2236218792Snp */ 2237218792Snpstatic void ulprx_intr_handler(struct adapter *adapter) 2238218792Snp{ 2239218792Snp static struct intr_info ulprx_intr_info[] = { 2240218792Snp { F_CAUSE_CTX_1, "ULPRX channel 1 context error", -1, 1 }, 2241218792Snp { F_CAUSE_CTX_0, "ULPRX channel 0 context error", -1, 1 }, 2242218792Snp { 0x7fffff, "ULPRX parity error", -1, 1 }, 2243218792Snp { 0 } 2244218792Snp }; 2245218792Snp 2246218792Snp if (t4_handle_intr_status(adapter, A_ULP_RX_INT_CAUSE, ulprx_intr_info)) 2247218792Snp t4_fatal_err(adapter); 2248218792Snp} 2249218792Snp 2250218792Snp/* 2251218792Snp * ULP TX interrupt handler. 2252218792Snp */ 2253218792Snpstatic void ulptx_intr_handler(struct adapter *adapter) 2254218792Snp{ 2255218792Snp static struct intr_info ulptx_intr_info[] = { 2256218792Snp { F_PBL_BOUND_ERR_CH3, "ULPTX channel 3 PBL out of bounds", -1, 2257218792Snp 0 }, 2258218792Snp { F_PBL_BOUND_ERR_CH2, "ULPTX channel 2 PBL out of bounds", -1, 2259218792Snp 0 }, 2260218792Snp { F_PBL_BOUND_ERR_CH1, "ULPTX channel 1 PBL out of bounds", -1, 2261218792Snp 0 }, 2262218792Snp { F_PBL_BOUND_ERR_CH0, "ULPTX channel 0 PBL out of bounds", -1, 2263218792Snp 0 }, 2264218792Snp { 0xfffffff, "ULPTX parity error", -1, 1 }, 2265218792Snp { 0 } 2266218792Snp }; 2267218792Snp 2268218792Snp if (t4_handle_intr_status(adapter, A_ULP_TX_INT_CAUSE, ulptx_intr_info)) 2269218792Snp t4_fatal_err(adapter); 2270218792Snp} 2271218792Snp 2272218792Snp/* 2273218792Snp * PM TX interrupt handler. 2274218792Snp */ 2275218792Snpstatic void pmtx_intr_handler(struct adapter *adapter) 2276218792Snp{ 2277218792Snp static struct intr_info pmtx_intr_info[] = { 2278218792Snp { F_PCMD_LEN_OVFL0, "PMTX channel 0 pcmd too large", -1, 1 }, 2279218792Snp { F_PCMD_LEN_OVFL1, "PMTX channel 1 pcmd too large", -1, 1 }, 2280218792Snp { F_PCMD_LEN_OVFL2, "PMTX channel 2 pcmd too large", -1, 1 }, 2281218792Snp { F_ZERO_C_CMD_ERROR, "PMTX 0-length pcmd", -1, 1 }, 2282218792Snp { 0xffffff0, "PMTX framing error", -1, 1 }, 2283218792Snp { F_OESPI_PAR_ERROR, "PMTX oespi parity error", -1, 1 }, 2284218792Snp { F_DB_OPTIONS_PAR_ERROR, "PMTX db_options parity error", -1, 2285218792Snp 1 }, 2286218792Snp { F_ICSPI_PAR_ERROR, "PMTX icspi parity error", -1, 1 }, 2287218792Snp { F_C_PCMD_PAR_ERROR, "PMTX c_pcmd parity error", -1, 1}, 2288218792Snp { 0 } 2289218792Snp }; 2290218792Snp 2291218792Snp if (t4_handle_intr_status(adapter, A_PM_TX_INT_CAUSE, pmtx_intr_info)) 2292218792Snp t4_fatal_err(adapter); 2293218792Snp} 2294218792Snp 2295218792Snp/* 2296218792Snp * PM RX interrupt handler. 2297218792Snp */ 2298218792Snpstatic void pmrx_intr_handler(struct adapter *adapter) 2299218792Snp{ 2300218792Snp static struct intr_info pmrx_intr_info[] = { 2301218792Snp { F_ZERO_E_CMD_ERROR, "PMRX 0-length pcmd", -1, 1 }, 2302218792Snp { 0x3ffff0, "PMRX framing error", -1, 1 }, 2303218792Snp { F_OCSPI_PAR_ERROR, "PMRX ocspi parity error", -1, 1 }, 2304218792Snp { F_DB_OPTIONS_PAR_ERROR, "PMRX db_options parity error", -1, 2305218792Snp 1 }, 2306218792Snp { F_IESPI_PAR_ERROR, "PMRX iespi parity error", -1, 1 }, 2307218792Snp { F_E_PCMD_PAR_ERROR, "PMRX e_pcmd parity error", -1, 1}, 2308218792Snp { 0 } 2309218792Snp }; 2310218792Snp 2311218792Snp if (t4_handle_intr_status(adapter, A_PM_RX_INT_CAUSE, pmrx_intr_info)) 2312218792Snp t4_fatal_err(adapter); 2313218792Snp} 2314218792Snp 2315218792Snp/* 2316218792Snp * CPL switch interrupt handler. 2317218792Snp */ 2318218792Snpstatic void cplsw_intr_handler(struct adapter *adapter) 2319218792Snp{ 2320218792Snp static struct intr_info cplsw_intr_info[] = { 2321218792Snp { F_CIM_OP_MAP_PERR, "CPLSW CIM op_map parity error", -1, 1 }, 2322218792Snp { F_CIM_OVFL_ERROR, "CPLSW CIM overflow", -1, 1 }, 2323218792Snp { F_TP_FRAMING_ERROR, "CPLSW TP framing error", -1, 1 }, 2324218792Snp { F_SGE_FRAMING_ERROR, "CPLSW SGE framing error", -1, 1 }, 2325218792Snp { F_CIM_FRAMING_ERROR, "CPLSW CIM framing error", -1, 1 }, 2326218792Snp { F_ZERO_SWITCH_ERROR, "CPLSW no-switch error", -1, 1 }, 2327218792Snp { 0 } 2328218792Snp }; 2329218792Snp 2330218792Snp if (t4_handle_intr_status(adapter, A_CPL_INTR_CAUSE, cplsw_intr_info)) 2331218792Snp t4_fatal_err(adapter); 2332218792Snp} 2333218792Snp 2334218792Snp/* 2335218792Snp * LE interrupt handler. 2336218792Snp */ 2337218792Snpstatic void le_intr_handler(struct adapter *adap) 2338218792Snp{ 2339218792Snp static struct intr_info le_intr_info[] = { 2340218792Snp { F_LIPMISS, "LE LIP miss", -1, 0 }, 2341218792Snp { F_LIP0, "LE 0 LIP error", -1, 0 }, 2342218792Snp { F_PARITYERR, "LE parity error", -1, 1 }, 2343218792Snp { F_UNKNOWNCMD, "LE unknown command", -1, 1 }, 2344218792Snp { F_REQQPARERR, "LE request queue parity error", -1, 1 }, 2345218792Snp { 0 } 2346218792Snp }; 2347218792Snp 2348218792Snp if (t4_handle_intr_status(adap, A_LE_DB_INT_CAUSE, le_intr_info)) 2349218792Snp t4_fatal_err(adap); 2350218792Snp} 2351218792Snp 2352218792Snp/* 2353218792Snp * MPS interrupt handler. 2354218792Snp */ 2355218792Snpstatic void mps_intr_handler(struct adapter *adapter) 2356218792Snp{ 2357218792Snp static struct intr_info mps_rx_intr_info[] = { 2358218792Snp { 0xffffff, "MPS Rx parity error", -1, 1 }, 2359218792Snp { 0 } 2360218792Snp }; 2361218792Snp static struct intr_info mps_tx_intr_info[] = { 2362218792Snp { V_TPFIFO(M_TPFIFO), "MPS Tx TP FIFO parity error", -1, 1 }, 2363218792Snp { F_NCSIFIFO, "MPS Tx NC-SI FIFO parity error", -1, 1 }, 2364218792Snp { V_TXDATAFIFO(M_TXDATAFIFO), "MPS Tx data FIFO parity error", 2365218792Snp -1, 1 }, 2366218792Snp { V_TXDESCFIFO(M_TXDESCFIFO), "MPS Tx desc FIFO parity error", 2367218792Snp -1, 1 }, 2368218792Snp { F_BUBBLE, "MPS Tx underflow", -1, 1 }, 2369218792Snp { F_SECNTERR, "MPS Tx SOP/EOP error", -1, 1 }, 2370218792Snp { F_FRMERR, "MPS Tx framing error", -1, 1 }, 2371218792Snp { 0 } 2372218792Snp }; 2373218792Snp static struct intr_info mps_trc_intr_info[] = { 2374218792Snp { V_FILTMEM(M_FILTMEM), "MPS TRC filter parity error", -1, 1 }, 2375218792Snp { V_PKTFIFO(M_PKTFIFO), "MPS TRC packet FIFO parity error", -1, 2376218792Snp 1 }, 2377218792Snp { F_MISCPERR, "MPS TRC misc parity error", -1, 1 }, 2378218792Snp { 0 } 2379218792Snp }; 2380218792Snp static struct intr_info mps_stat_sram_intr_info[] = { 2381218792Snp { 0x1fffff, "MPS statistics SRAM parity error", -1, 1 }, 2382218792Snp { 0 } 2383218792Snp }; 2384218792Snp static struct intr_info mps_stat_tx_intr_info[] = { 2385218792Snp { 0xfffff, "MPS statistics Tx FIFO parity error", -1, 1 }, 2386218792Snp { 0 } 2387218792Snp }; 2388218792Snp static struct intr_info mps_stat_rx_intr_info[] = { 2389218792Snp { 0xffffff, "MPS statistics Rx FIFO parity error", -1, 1 }, 2390218792Snp { 0 } 2391218792Snp }; 2392218792Snp static struct intr_info mps_cls_intr_info[] = { 2393218792Snp { F_MATCHSRAM, "MPS match SRAM parity error", -1, 1 }, 2394218792Snp { F_MATCHTCAM, "MPS match TCAM parity error", -1, 1 }, 2395218792Snp { F_HASHSRAM, "MPS hash SRAM parity error", -1, 1 }, 2396218792Snp { 0 } 2397218792Snp }; 2398218792Snp 2399218792Snp int fat; 2400218792Snp 2401218792Snp fat = t4_handle_intr_status(adapter, A_MPS_RX_PERR_INT_CAUSE, 2402218792Snp mps_rx_intr_info) + 2403218792Snp t4_handle_intr_status(adapter, A_MPS_TX_INT_CAUSE, 2404218792Snp mps_tx_intr_info) + 2405218792Snp t4_handle_intr_status(adapter, A_MPS_TRC_INT_CAUSE, 2406218792Snp mps_trc_intr_info) + 2407218792Snp t4_handle_intr_status(adapter, A_MPS_STAT_PERR_INT_CAUSE_SRAM, 2408218792Snp mps_stat_sram_intr_info) + 2409218792Snp t4_handle_intr_status(adapter, A_MPS_STAT_PERR_INT_CAUSE_TX_FIFO, 2410218792Snp mps_stat_tx_intr_info) + 2411218792Snp t4_handle_intr_status(adapter, A_MPS_STAT_PERR_INT_CAUSE_RX_FIFO, 2412218792Snp mps_stat_rx_intr_info) + 2413218792Snp t4_handle_intr_status(adapter, A_MPS_CLS_INT_CAUSE, 2414218792Snp mps_cls_intr_info); 2415218792Snp 2416218792Snp t4_write_reg(adapter, A_MPS_INT_CAUSE, 0); 2417218792Snp t4_read_reg(adapter, A_MPS_INT_CAUSE); /* flush */ 2418218792Snp if (fat) 2419218792Snp t4_fatal_err(adapter); 2420218792Snp} 2421218792Snp 2422218792Snp#define MEM_INT_MASK (F_PERR_INT_CAUSE | F_ECC_CE_INT_CAUSE | F_ECC_UE_INT_CAUSE) 2423218792Snp 2424218792Snp/* 2425218792Snp * EDC/MC interrupt handler. 2426218792Snp */ 2427218792Snpstatic void mem_intr_handler(struct adapter *adapter, int idx) 2428218792Snp{ 2429218792Snp static const char name[3][5] = { "EDC0", "EDC1", "MC" }; 2430218792Snp 2431218792Snp unsigned int addr, cnt_addr, v; 2432218792Snp 2433218792Snp if (idx <= MEM_EDC1) { 2434218792Snp addr = EDC_REG(A_EDC_INT_CAUSE, idx); 2435218792Snp cnt_addr = EDC_REG(A_EDC_ECC_STATUS, idx); 2436218792Snp } else { 2437250090Snp if (is_t4(adapter)) { 2438250090Snp addr = A_MC_INT_CAUSE; 2439250090Snp cnt_addr = A_MC_ECC_STATUS; 2440250090Snp } else { 2441250090Snp addr = A_MC_P_INT_CAUSE; 2442250090Snp cnt_addr = A_MC_P_ECC_STATUS; 2443250090Snp } 2444218792Snp } 2445218792Snp 2446218792Snp v = t4_read_reg(adapter, addr) & MEM_INT_MASK; 2447218792Snp if (v & F_PERR_INT_CAUSE) 2448218792Snp CH_ALERT(adapter, "%s FIFO parity error\n", name[idx]); 2449218792Snp if (v & F_ECC_CE_INT_CAUSE) { 2450218792Snp u32 cnt = G_ECC_CECNT(t4_read_reg(adapter, cnt_addr)); 2451218792Snp 2452218792Snp t4_write_reg(adapter, cnt_addr, V_ECC_CECNT(M_ECC_CECNT)); 2453218792Snp CH_WARN_RATELIMIT(adapter, 2454218792Snp "%u %s correctable ECC data error%s\n", 2455218792Snp cnt, name[idx], cnt > 1 ? "s" : ""); 2456218792Snp } 2457218792Snp if (v & F_ECC_UE_INT_CAUSE) 2458218792Snp CH_ALERT(adapter, "%s uncorrectable ECC data error\n", 2459218792Snp name[idx]); 2460218792Snp 2461218792Snp t4_write_reg(adapter, addr, v); 2462218792Snp if (v & (F_PERR_INT_CAUSE | F_ECC_UE_INT_CAUSE)) 2463218792Snp t4_fatal_err(adapter); 2464218792Snp} 2465218792Snp 2466218792Snp/* 2467218792Snp * MA interrupt handler. 2468218792Snp */ 2469218792Snpstatic void ma_intr_handler(struct adapter *adapter) 2470218792Snp{ 2471218792Snp u32 v, status = t4_read_reg(adapter, A_MA_INT_CAUSE); 2472218792Snp 2473270297Snp if (status & F_MEM_PERR_INT_CAUSE) { 2474218792Snp CH_ALERT(adapter, "MA parity error, parity status %#x\n", 2475270297Snp t4_read_reg(adapter, A_MA_PARITY_ERROR_STATUS1)); 2476270297Snp if (is_t5(adapter)) 2477270297Snp CH_ALERT(adapter, 2478270297Snp "MA parity error, parity status %#x\n", 2479270297Snp t4_read_reg(adapter, 2480270297Snp A_MA_PARITY_ERROR_STATUS2)); 2481270297Snp } 2482218792Snp if (status & F_MEM_WRAP_INT_CAUSE) { 2483218792Snp v = t4_read_reg(adapter, A_MA_INT_WRAP_STATUS); 2484218792Snp CH_ALERT(adapter, "MA address wrap-around error by client %u to" 2485218792Snp " address %#x\n", G_MEM_WRAP_CLIENT_NUM(v), 2486218792Snp G_MEM_WRAP_ADDRESS(v) << 4); 2487218792Snp } 2488218792Snp t4_write_reg(adapter, A_MA_INT_CAUSE, status); 2489218792Snp t4_fatal_err(adapter); 2490218792Snp} 2491218792Snp 2492218792Snp/* 2493218792Snp * SMB interrupt handler. 2494218792Snp */ 2495218792Snpstatic void smb_intr_handler(struct adapter *adap) 2496218792Snp{ 2497218792Snp static struct intr_info smb_intr_info[] = { 2498218792Snp { F_MSTTXFIFOPARINT, "SMB master Tx FIFO parity error", -1, 1 }, 2499218792Snp { F_MSTRXFIFOPARINT, "SMB master Rx FIFO parity error", -1, 1 }, 2500218792Snp { F_SLVFIFOPARINT, "SMB slave FIFO parity error", -1, 1 }, 2501218792Snp { 0 } 2502218792Snp }; 2503218792Snp 2504218792Snp if (t4_handle_intr_status(adap, A_SMB_INT_CAUSE, smb_intr_info)) 2505218792Snp t4_fatal_err(adap); 2506218792Snp} 2507218792Snp 2508218792Snp/* 2509218792Snp * NC-SI interrupt handler. 2510218792Snp */ 2511218792Snpstatic void ncsi_intr_handler(struct adapter *adap) 2512218792Snp{ 2513218792Snp static struct intr_info ncsi_intr_info[] = { 2514218792Snp { F_CIM_DM_PRTY_ERR, "NC-SI CIM parity error", -1, 1 }, 2515218792Snp { F_MPS_DM_PRTY_ERR, "NC-SI MPS parity error", -1, 1 }, 2516218792Snp { F_TXFIFO_PRTY_ERR, "NC-SI Tx FIFO parity error", -1, 1 }, 2517218792Snp { F_RXFIFO_PRTY_ERR, "NC-SI Rx FIFO parity error", -1, 1 }, 2518218792Snp { 0 } 2519218792Snp }; 2520218792Snp 2521218792Snp if (t4_handle_intr_status(adap, A_NCSI_INT_CAUSE, ncsi_intr_info)) 2522218792Snp t4_fatal_err(adap); 2523218792Snp} 2524218792Snp 2525218792Snp/* 2526218792Snp * XGMAC interrupt handler. 2527218792Snp */ 2528218792Snpstatic void xgmac_intr_handler(struct adapter *adap, int port) 2529218792Snp{ 2530248925Snp u32 v, int_cause_reg; 2531218792Snp 2532248925Snp if (is_t4(adap)) 2533248925Snp int_cause_reg = PORT_REG(port, A_XGMAC_PORT_INT_CAUSE); 2534248925Snp else 2535248925Snp int_cause_reg = T5_PORT_REG(port, A_MAC_PORT_INT_CAUSE); 2536248925Snp 2537248925Snp v = t4_read_reg(adap, int_cause_reg); 2538248925Snp v &= (F_TXFIFO_PRTY_ERR | F_RXFIFO_PRTY_ERR); 2539218792Snp if (!v) 2540218792Snp return; 2541218792Snp 2542218792Snp if (v & F_TXFIFO_PRTY_ERR) 2543218792Snp CH_ALERT(adap, "XGMAC %d Tx FIFO parity error\n", port); 2544218792Snp if (v & F_RXFIFO_PRTY_ERR) 2545218792Snp CH_ALERT(adap, "XGMAC %d Rx FIFO parity error\n", port); 2546248925Snp t4_write_reg(adap, int_cause_reg, v); 2547218792Snp t4_fatal_err(adap); 2548218792Snp} 2549218792Snp 2550218792Snp/* 2551218792Snp * PL interrupt handler. 2552218792Snp */ 2553218792Snpstatic void pl_intr_handler(struct adapter *adap) 2554218792Snp{ 2555218792Snp static struct intr_info pl_intr_info[] = { 2556250090Snp { F_FATALPERR, "Fatal parity error", -1, 1 }, 2557218792Snp { F_PERRVFID, "PL VFID_MAP parity error", -1, 1 }, 2558218792Snp { 0 } 2559218792Snp }; 2560218792Snp 2561250090Snp static struct intr_info t5_pl_intr_info[] = { 2562250090Snp { F_PL_BUSPERR, "PL bus parity error", -1, 1 }, 2563250090Snp { F_FATALPERR, "Fatal parity error", -1, 1 }, 2564250090Snp { 0 } 2565250090Snp }; 2566250090Snp 2567250090Snp if (t4_handle_intr_status(adap, A_PL_PL_INT_CAUSE, 2568250090Snp is_t4(adap) ? pl_intr_info : t5_pl_intr_info)) 2569218792Snp t4_fatal_err(adap); 2570218792Snp} 2571218792Snp 2572218792Snp#define PF_INTR_MASK (F_PFSW | F_PFCIM) 2573218792Snp#define GLBL_INTR_MASK (F_CIM | F_MPS | F_PL | F_PCIE | F_MC | F_EDC0 | \ 2574218792Snp F_EDC1 | F_LE | F_TP | F_MA | F_PM_TX | F_PM_RX | F_ULP_RX | \ 2575218792Snp F_CPL_SWITCH | F_SGE | F_ULP_TX) 2576218792Snp 2577218792Snp/** 2578218792Snp * t4_slow_intr_handler - control path interrupt handler 2579218792Snp * @adapter: the adapter 2580218792Snp * 2581218792Snp * T4 interrupt handler for non-data global interrupt events, e.g., errors. 2582218792Snp * The designation 'slow' is because it involves register reads, while 2583218792Snp * data interrupts typically don't involve any MMIOs. 2584218792Snp */ 2585218792Snpint t4_slow_intr_handler(struct adapter *adapter) 2586218792Snp{ 2587218792Snp u32 cause = t4_read_reg(adapter, A_PL_INT_CAUSE); 2588218792Snp 2589218792Snp if (!(cause & GLBL_INTR_MASK)) 2590218792Snp return 0; 2591218792Snp if (cause & F_CIM) 2592218792Snp cim_intr_handler(adapter); 2593218792Snp if (cause & F_MPS) 2594218792Snp mps_intr_handler(adapter); 2595218792Snp if (cause & F_NCSI) 2596218792Snp ncsi_intr_handler(adapter); 2597218792Snp if (cause & F_PL) 2598218792Snp pl_intr_handler(adapter); 2599218792Snp if (cause & F_SMB) 2600218792Snp smb_intr_handler(adapter); 2601218792Snp if (cause & F_XGMAC0) 2602218792Snp xgmac_intr_handler(adapter, 0); 2603218792Snp if (cause & F_XGMAC1) 2604218792Snp xgmac_intr_handler(adapter, 1); 2605218792Snp if (cause & F_XGMAC_KR0) 2606218792Snp xgmac_intr_handler(adapter, 2); 2607218792Snp if (cause & F_XGMAC_KR1) 2608218792Snp xgmac_intr_handler(adapter, 3); 2609218792Snp if (cause & F_PCIE) 2610218792Snp pcie_intr_handler(adapter); 2611218792Snp if (cause & F_MC) 2612218792Snp mem_intr_handler(adapter, MEM_MC); 2613218792Snp if (cause & F_EDC0) 2614218792Snp mem_intr_handler(adapter, MEM_EDC0); 2615218792Snp if (cause & F_EDC1) 2616218792Snp mem_intr_handler(adapter, MEM_EDC1); 2617218792Snp if (cause & F_LE) 2618218792Snp le_intr_handler(adapter); 2619218792Snp if (cause & F_TP) 2620218792Snp tp_intr_handler(adapter); 2621218792Snp if (cause & F_MA) 2622218792Snp ma_intr_handler(adapter); 2623218792Snp if (cause & F_PM_TX) 2624218792Snp pmtx_intr_handler(adapter); 2625218792Snp if (cause & F_PM_RX) 2626218792Snp pmrx_intr_handler(adapter); 2627218792Snp if (cause & F_ULP_RX) 2628218792Snp ulprx_intr_handler(adapter); 2629218792Snp if (cause & F_CPL_SWITCH) 2630218792Snp cplsw_intr_handler(adapter); 2631218792Snp if (cause & F_SGE) 2632218792Snp sge_intr_handler(adapter); 2633218792Snp if (cause & F_ULP_TX) 2634218792Snp ulptx_intr_handler(adapter); 2635218792Snp 2636218792Snp /* Clear the interrupts just processed for which we are the master. */ 2637218792Snp t4_write_reg(adapter, A_PL_INT_CAUSE, cause & GLBL_INTR_MASK); 2638218792Snp (void) t4_read_reg(adapter, A_PL_INT_CAUSE); /* flush */ 2639218792Snp return 1; 2640218792Snp} 2641218792Snp 2642218792Snp/** 2643218792Snp * t4_intr_enable - enable interrupts 2644218792Snp * @adapter: the adapter whose interrupts should be enabled 2645218792Snp * 2646218792Snp * Enable PF-specific interrupts for the calling function and the top-level 2647218792Snp * interrupt concentrator for global interrupts. Interrupts are already 2648218792Snp * enabled at each module, here we just enable the roots of the interrupt 2649218792Snp * hierarchies. 2650218792Snp * 2651218792Snp * Note: this function should be called only when the driver manages 2652218792Snp * non PF-specific interrupts from the various HW modules. Only one PCI 2653218792Snp * function at a time should be doing this. 2654218792Snp */ 2655218792Snpvoid t4_intr_enable(struct adapter *adapter) 2656218792Snp{ 2657218792Snp u32 pf = G_SOURCEPF(t4_read_reg(adapter, A_PL_WHOAMI)); 2658218792Snp 2659218792Snp t4_write_reg(adapter, A_SGE_INT_ENABLE3, F_ERR_CPL_EXCEED_IQE_SIZE | 2660218792Snp F_ERR_INVALID_CIDX_INC | F_ERR_CPL_OPCODE_0 | 2661218792Snp F_ERR_DROPPED_DB | F_ERR_DATA_CPL_ON_HIGH_QID1 | 2662218792Snp F_ERR_DATA_CPL_ON_HIGH_QID0 | F_ERR_BAD_DB_PIDX3 | 2663218792Snp F_ERR_BAD_DB_PIDX2 | F_ERR_BAD_DB_PIDX1 | 2664218792Snp F_ERR_BAD_DB_PIDX0 | F_ERR_ING_CTXT_PRIO | 2665218792Snp F_ERR_EGR_CTXT_PRIO | F_INGRESS_SIZE_ERR | 2666218792Snp F_EGRESS_SIZE_ERR); 2667218792Snp t4_write_reg(adapter, MYPF_REG(A_PL_PF_INT_ENABLE), PF_INTR_MASK); 2668218792Snp t4_set_reg_field(adapter, A_PL_INT_MAP0, 0, 1 << pf); 2669218792Snp} 2670218792Snp 2671218792Snp/** 2672218792Snp * t4_intr_disable - disable interrupts 2673218792Snp * @adapter: the adapter whose interrupts should be disabled 2674218792Snp * 2675218792Snp * Disable interrupts. We only disable the top-level interrupt 2676218792Snp * concentrators. The caller must be a PCI function managing global 2677218792Snp * interrupts. 2678218792Snp */ 2679218792Snpvoid t4_intr_disable(struct adapter *adapter) 2680218792Snp{ 2681218792Snp u32 pf = G_SOURCEPF(t4_read_reg(adapter, A_PL_WHOAMI)); 2682218792Snp 2683218792Snp t4_write_reg(adapter, MYPF_REG(A_PL_PF_INT_ENABLE), 0); 2684218792Snp t4_set_reg_field(adapter, A_PL_INT_MAP0, 1 << pf, 0); 2685218792Snp} 2686218792Snp 2687218792Snp/** 2688218792Snp * t4_intr_clear - clear all interrupts 2689218792Snp * @adapter: the adapter whose interrupts should be cleared 2690218792Snp * 2691218792Snp * Clears all interrupts. The caller must be a PCI function managing 2692218792Snp * global interrupts. 2693218792Snp */ 2694218792Snpvoid t4_intr_clear(struct adapter *adapter) 2695218792Snp{ 2696218792Snp static const unsigned int cause_reg[] = { 2697218792Snp A_SGE_INT_CAUSE1, A_SGE_INT_CAUSE2, A_SGE_INT_CAUSE3, 2698218792Snp A_PCIE_NONFAT_ERR, A_PCIE_INT_CAUSE, 2699270297Snp A_MA_INT_WRAP_STATUS, A_MA_PARITY_ERROR_STATUS1, A_MA_INT_CAUSE, 2700218792Snp A_EDC_INT_CAUSE, EDC_REG(A_EDC_INT_CAUSE, 1), 2701218792Snp A_CIM_HOST_INT_CAUSE, A_CIM_HOST_UPACC_INT_CAUSE, 2702218792Snp MYPF_REG(A_CIM_PF_HOST_INT_CAUSE), 2703218792Snp A_TP_INT_CAUSE, 2704218792Snp A_ULP_RX_INT_CAUSE, A_ULP_TX_INT_CAUSE, 2705218792Snp A_PM_RX_INT_CAUSE, A_PM_TX_INT_CAUSE, 2706218792Snp A_MPS_RX_PERR_INT_CAUSE, 2707218792Snp A_CPL_INTR_CAUSE, 2708218792Snp MYPF_REG(A_PL_PF_INT_CAUSE), 2709218792Snp A_PL_PL_INT_CAUSE, 2710218792Snp A_LE_DB_INT_CAUSE, 2711218792Snp }; 2712218792Snp 2713218792Snp unsigned int i; 2714218792Snp 2715218792Snp for (i = 0; i < ARRAY_SIZE(cause_reg); ++i) 2716218792Snp t4_write_reg(adapter, cause_reg[i], 0xffffffff); 2717218792Snp 2718250090Snp t4_write_reg(adapter, is_t4(adapter) ? A_MC_INT_CAUSE : 2719250090Snp A_MC_P_INT_CAUSE, 0xffffffff); 2720250090Snp 2721270297Snp if (is_t4(adapter)) { 2722270297Snp t4_write_reg(adapter, A_PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS, 2723270297Snp 0xffffffff); 2724270297Snp t4_write_reg(adapter, A_PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS, 2725270297Snp 0xffffffff); 2726270297Snp } else 2727270297Snp t4_write_reg(adapter, A_MA_PARITY_ERROR_STATUS2, 0xffffffff); 2728270297Snp 2729218792Snp t4_write_reg(adapter, A_PL_INT_CAUSE, GLBL_INTR_MASK); 2730218792Snp (void) t4_read_reg(adapter, A_PL_INT_CAUSE); /* flush */ 2731218792Snp} 2732218792Snp 2733218792Snp/** 2734218792Snp * hash_mac_addr - return the hash value of a MAC address 2735218792Snp * @addr: the 48-bit Ethernet MAC address 2736218792Snp * 2737218792Snp * Hashes a MAC address according to the hash function used by HW inexact 2738218792Snp * (hash) address matching. 2739218792Snp */ 2740218792Snpstatic int hash_mac_addr(const u8 *addr) 2741218792Snp{ 2742218792Snp u32 a = ((u32)addr[0] << 16) | ((u32)addr[1] << 8) | addr[2]; 2743218792Snp u32 b = ((u32)addr[3] << 16) | ((u32)addr[4] << 8) | addr[5]; 2744218792Snp a ^= b; 2745218792Snp a ^= (a >> 12); 2746218792Snp a ^= (a >> 6); 2747218792Snp return a & 0x3f; 2748218792Snp} 2749218792Snp 2750218792Snp/** 2751218792Snp * t4_config_rss_range - configure a portion of the RSS mapping table 2752218792Snp * @adapter: the adapter 2753218792Snp * @mbox: mbox to use for the FW command 2754218792Snp * @viid: virtual interface whose RSS subtable is to be written 2755218792Snp * @start: start entry in the table to write 2756218792Snp * @n: how many table entries to write 2757218792Snp * @rspq: values for the "response queue" (Ingress Queue) lookup table 2758218792Snp * @nrspq: number of values in @rspq 2759218792Snp * 2760218792Snp * Programs the selected part of the VI's RSS mapping table with the 2761218792Snp * provided values. If @nrspq < @n the supplied values are used repeatedly 2762218792Snp * until the full table range is populated. 2763218792Snp * 2764218792Snp * The caller must ensure the values in @rspq are in the range allowed for 2765218792Snp * @viid. 2766218792Snp */ 2767218792Snpint t4_config_rss_range(struct adapter *adapter, int mbox, unsigned int viid, 2768218792Snp int start, int n, const u16 *rspq, unsigned int nrspq) 2769218792Snp{ 2770218792Snp int ret; 2771218792Snp const u16 *rsp = rspq; 2772218792Snp const u16 *rsp_end = rspq + nrspq; 2773218792Snp struct fw_rss_ind_tbl_cmd cmd; 2774218792Snp 2775218792Snp memset(&cmd, 0, sizeof(cmd)); 2776218792Snp cmd.op_to_viid = htonl(V_FW_CMD_OP(FW_RSS_IND_TBL_CMD) | 2777218792Snp F_FW_CMD_REQUEST | F_FW_CMD_WRITE | 2778218792Snp V_FW_RSS_IND_TBL_CMD_VIID(viid)); 2779218792Snp cmd.retval_len16 = htonl(FW_LEN16(cmd)); 2780218792Snp 2781218792Snp 2782218792Snp /* 2783218792Snp * Each firmware RSS command can accommodate up to 32 RSS Ingress 2784218792Snp * Queue Identifiers. These Ingress Queue IDs are packed three to 2785218792Snp * a 32-bit word as 10-bit values with the upper remaining 2 bits 2786218792Snp * reserved. 2787218792Snp */ 2788218792Snp while (n > 0) { 2789218792Snp int nq = min(n, 32); 2790228561Snp int nq_packed = 0; 2791218792Snp __be32 *qp = &cmd.iq0_to_iq2; 2792218792Snp 2793218792Snp /* 2794218792Snp * Set up the firmware RSS command header to send the next 2795218792Snp * "nq" Ingress Queue IDs to the firmware. 2796218792Snp */ 2797218792Snp cmd.niqid = htons(nq); 2798218792Snp cmd.startidx = htons(start); 2799218792Snp 2800218792Snp /* 2801218792Snp * "nq" more done for the start of the next loop. 2802218792Snp */ 2803218792Snp start += nq; 2804218792Snp n -= nq; 2805218792Snp 2806218792Snp /* 2807218792Snp * While there are still Ingress Queue IDs to stuff into the 2808218792Snp * current firmware RSS command, retrieve them from the 2809218792Snp * Ingress Queue ID array and insert them into the command. 2810218792Snp */ 2811218792Snp while (nq > 0) { 2812218792Snp /* 2813218792Snp * Grab up to the next 3 Ingress Queue IDs (wrapping 2814218792Snp * around the Ingress Queue ID array if necessary) and 2815218792Snp * insert them into the firmware RSS command at the 2816218792Snp * current 3-tuple position within the commad. 2817218792Snp */ 2818228561Snp u16 qbuf[3]; 2819228561Snp u16 *qbp = qbuf; 2820228561Snp int nqbuf = min(3, nq); 2821218792Snp 2822228561Snp nq -= nqbuf; 2823228561Snp qbuf[0] = qbuf[1] = qbuf[2] = 0; 2824228561Snp while (nqbuf && nq_packed < 32) { 2825228561Snp nqbuf--; 2826228561Snp nq_packed++; 2827228561Snp *qbp++ = *rsp++; 2828228561Snp if (rsp >= rsp_end) 2829228561Snp rsp = rspq; 2830228561Snp } 2831228561Snp *qp++ = cpu_to_be32(V_FW_RSS_IND_TBL_CMD_IQ0(qbuf[0]) | 2832228561Snp V_FW_RSS_IND_TBL_CMD_IQ1(qbuf[1]) | 2833228561Snp V_FW_RSS_IND_TBL_CMD_IQ2(qbuf[2])); 2834218792Snp } 2835218792Snp 2836218792Snp /* 2837218792Snp * Send this portion of the RRS table update to the firmware; 2838218792Snp * bail out on any errors. 2839218792Snp */ 2840218792Snp ret = t4_wr_mbox(adapter, mbox, &cmd, sizeof(cmd), NULL); 2841218792Snp if (ret) 2842218792Snp return ret; 2843218792Snp } 2844218792Snp 2845218792Snp return 0; 2846218792Snp} 2847218792Snp 2848218792Snp/** 2849218792Snp * t4_config_glbl_rss - configure the global RSS mode 2850218792Snp * @adapter: the adapter 2851218792Snp * @mbox: mbox to use for the FW command 2852218792Snp * @mode: global RSS mode 2853218792Snp * @flags: mode-specific flags 2854218792Snp * 2855218792Snp * Sets the global RSS mode. 2856218792Snp */ 2857218792Snpint t4_config_glbl_rss(struct adapter *adapter, int mbox, unsigned int mode, 2858218792Snp unsigned int flags) 2859218792Snp{ 2860218792Snp struct fw_rss_glb_config_cmd c; 2861218792Snp 2862218792Snp memset(&c, 0, sizeof(c)); 2863218792Snp c.op_to_write = htonl(V_FW_CMD_OP(FW_RSS_GLB_CONFIG_CMD) | 2864218792Snp F_FW_CMD_REQUEST | F_FW_CMD_WRITE); 2865218792Snp c.retval_len16 = htonl(FW_LEN16(c)); 2866218792Snp if (mode == FW_RSS_GLB_CONFIG_CMD_MODE_MANUAL) { 2867218792Snp c.u.manual.mode_pkd = htonl(V_FW_RSS_GLB_CONFIG_CMD_MODE(mode)); 2868218792Snp } else if (mode == FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL) { 2869218792Snp c.u.basicvirtual.mode_pkd = 2870218792Snp htonl(V_FW_RSS_GLB_CONFIG_CMD_MODE(mode)); 2871218792Snp c.u.basicvirtual.synmapen_to_hashtoeplitz = htonl(flags); 2872218792Snp } else 2873218792Snp return -EINVAL; 2874218792Snp return t4_wr_mbox(adapter, mbox, &c, sizeof(c), NULL); 2875218792Snp} 2876218792Snp 2877218792Snp/** 2878218792Snp * t4_config_vi_rss - configure per VI RSS settings 2879218792Snp * @adapter: the adapter 2880218792Snp * @mbox: mbox to use for the FW command 2881218792Snp * @viid: the VI id 2882218792Snp * @flags: RSS flags 2883218792Snp * @defq: id of the default RSS queue for the VI. 2884218792Snp * 2885218792Snp * Configures VI-specific RSS properties. 2886218792Snp */ 2887218792Snpint t4_config_vi_rss(struct adapter *adapter, int mbox, unsigned int viid, 2888218792Snp unsigned int flags, unsigned int defq) 2889218792Snp{ 2890218792Snp struct fw_rss_vi_config_cmd c; 2891218792Snp 2892218792Snp memset(&c, 0, sizeof(c)); 2893218792Snp c.op_to_viid = htonl(V_FW_CMD_OP(FW_RSS_VI_CONFIG_CMD) | 2894218792Snp F_FW_CMD_REQUEST | F_FW_CMD_WRITE | 2895218792Snp V_FW_RSS_VI_CONFIG_CMD_VIID(viid)); 2896218792Snp c.retval_len16 = htonl(FW_LEN16(c)); 2897218792Snp c.u.basicvirtual.defaultq_to_udpen = htonl(flags | 2898218792Snp V_FW_RSS_VI_CONFIG_CMD_DEFAULTQ(defq)); 2899218792Snp return t4_wr_mbox(adapter, mbox, &c, sizeof(c), NULL); 2900218792Snp} 2901218792Snp 2902218792Snp/* Read an RSS table row */ 2903218792Snpstatic int rd_rss_row(struct adapter *adap, int row, u32 *val) 2904218792Snp{ 2905218792Snp t4_write_reg(adap, A_TP_RSS_LKP_TABLE, 0xfff00000 | row); 2906218792Snp return t4_wait_op_done_val(adap, A_TP_RSS_LKP_TABLE, F_LKPTBLROWVLD, 1, 2907218792Snp 5, 0, val); 2908218792Snp} 2909218792Snp 2910218792Snp/** 2911218792Snp * t4_read_rss - read the contents of the RSS mapping table 2912218792Snp * @adapter: the adapter 2913218792Snp * @map: holds the contents of the RSS mapping table 2914218792Snp * 2915218792Snp * Reads the contents of the RSS hash->queue mapping table. 2916218792Snp */ 2917218792Snpint t4_read_rss(struct adapter *adapter, u16 *map) 2918218792Snp{ 2919218792Snp u32 val; 2920218792Snp int i, ret; 2921218792Snp 2922218792Snp for (i = 0; i < RSS_NENTRIES / 2; ++i) { 2923218792Snp ret = rd_rss_row(adapter, i, &val); 2924218792Snp if (ret) 2925218792Snp return ret; 2926218792Snp *map++ = G_LKPTBLQUEUE0(val); 2927218792Snp *map++ = G_LKPTBLQUEUE1(val); 2928218792Snp } 2929218792Snp return 0; 2930218792Snp} 2931218792Snp 2932218792Snp/** 2933218792Snp * t4_read_rss_key - read the global RSS key 2934218792Snp * @adap: the adapter 2935218792Snp * @key: 10-entry array holding the 320-bit RSS key 2936218792Snp * 2937218792Snp * Reads the global 320-bit RSS key. 2938218792Snp */ 2939218792Snpvoid t4_read_rss_key(struct adapter *adap, u32 *key) 2940218792Snp{ 2941218792Snp t4_read_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, key, 10, 2942218792Snp A_TP_RSS_SECRET_KEY0); 2943218792Snp} 2944218792Snp 2945218792Snp/** 2946218792Snp * t4_write_rss_key - program one of the RSS keys 2947218792Snp * @adap: the adapter 2948218792Snp * @key: 10-entry array holding the 320-bit RSS key 2949218792Snp * @idx: which RSS key to write 2950218792Snp * 2951218792Snp * Writes one of the RSS keys with the given 320-bit value. If @idx is 2952218792Snp * 0..15 the corresponding entry in the RSS key table is written, 2953218792Snp * otherwise the global RSS key is written. 2954218792Snp */ 2955218792Snpvoid t4_write_rss_key(struct adapter *adap, const u32 *key, int idx) 2956218792Snp{ 2957218792Snp t4_write_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, key, 10, 2958218792Snp A_TP_RSS_SECRET_KEY0); 2959218792Snp if (idx >= 0 && idx < 16) 2960218792Snp t4_write_reg(adap, A_TP_RSS_CONFIG_VRT, 2961218792Snp V_KEYWRADDR(idx) | F_KEYWREN); 2962218792Snp} 2963218792Snp 2964218792Snp/** 2965218792Snp * t4_read_rss_pf_config - read PF RSS Configuration Table 2966218792Snp * @adapter: the adapter 2967218792Snp * @index: the entry in the PF RSS table to read 2968218792Snp * @valp: where to store the returned value 2969218792Snp * 2970218792Snp * Reads the PF RSS Configuration Table at the specified index and returns 2971218792Snp * the value found there. 2972218792Snp */ 2973218792Snpvoid t4_read_rss_pf_config(struct adapter *adapter, unsigned int index, u32 *valp) 2974218792Snp{ 2975218792Snp t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA, 2976218792Snp valp, 1, A_TP_RSS_PF0_CONFIG + index); 2977218792Snp} 2978218792Snp 2979218792Snp/** 2980218792Snp * t4_write_rss_pf_config - write PF RSS Configuration Table 2981218792Snp * @adapter: the adapter 2982218792Snp * @index: the entry in the VF RSS table to read 2983218792Snp * @val: the value to store 2984218792Snp * 2985218792Snp * Writes the PF RSS Configuration Table at the specified index with the 2986218792Snp * specified value. 2987218792Snp */ 2988218792Snpvoid t4_write_rss_pf_config(struct adapter *adapter, unsigned int index, u32 val) 2989218792Snp{ 2990218792Snp t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA, 2991218792Snp &val, 1, A_TP_RSS_PF0_CONFIG + index); 2992218792Snp} 2993218792Snp 2994218792Snp/** 2995218792Snp * t4_read_rss_vf_config - read VF RSS Configuration Table 2996218792Snp * @adapter: the adapter 2997218792Snp * @index: the entry in the VF RSS table to read 2998218792Snp * @vfl: where to store the returned VFL 2999218792Snp * @vfh: where to store the returned VFH 3000218792Snp * 3001218792Snp * Reads the VF RSS Configuration Table at the specified index and returns 3002218792Snp * the (VFL, VFH) values found there. 3003218792Snp */ 3004218792Snpvoid t4_read_rss_vf_config(struct adapter *adapter, unsigned int index, 3005218792Snp u32 *vfl, u32 *vfh) 3006218792Snp{ 3007218792Snp u32 vrt; 3008218792Snp 3009218792Snp /* 3010218792Snp * Request that the index'th VF Table values be read into VFL/VFH. 3011218792Snp */ 3012218792Snp vrt = t4_read_reg(adapter, A_TP_RSS_CONFIG_VRT); 3013218792Snp vrt &= ~(F_VFRDRG | V_VFWRADDR(M_VFWRADDR) | F_VFWREN | F_KEYWREN); 3014218792Snp vrt |= V_VFWRADDR(index) | F_VFRDEN; 3015218792Snp t4_write_reg(adapter, A_TP_RSS_CONFIG_VRT, vrt); 3016218792Snp 3017218792Snp /* 3018218792Snp * Grab the VFL/VFH values ... 3019218792Snp */ 3020218792Snp t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA, 3021218792Snp vfl, 1, A_TP_RSS_VFL_CONFIG); 3022218792Snp t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA, 3023218792Snp vfh, 1, A_TP_RSS_VFH_CONFIG); 3024218792Snp} 3025218792Snp 3026218792Snp/** 3027218792Snp * t4_write_rss_vf_config - write VF RSS Configuration Table 3028218792Snp * 3029218792Snp * @adapter: the adapter 3030218792Snp * @index: the entry in the VF RSS table to write 3031218792Snp * @vfl: the VFL to store 3032218792Snp * @vfh: the VFH to store 3033218792Snp * 3034218792Snp * Writes the VF RSS Configuration Table at the specified index with the 3035218792Snp * specified (VFL, VFH) values. 3036218792Snp */ 3037218792Snpvoid t4_write_rss_vf_config(struct adapter *adapter, unsigned int index, 3038218792Snp u32 vfl, u32 vfh) 3039218792Snp{ 3040218792Snp u32 vrt; 3041218792Snp 3042218792Snp /* 3043218792Snp * Load up VFL/VFH with the values to be written ... 3044218792Snp */ 3045218792Snp t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA, 3046218792Snp &vfl, 1, A_TP_RSS_VFL_CONFIG); 3047218792Snp t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA, 3048218792Snp &vfh, 1, A_TP_RSS_VFH_CONFIG); 3049218792Snp 3050218792Snp /* 3051218792Snp * Write the VFL/VFH into the VF Table at index'th location. 3052218792Snp */ 3053218792Snp vrt = t4_read_reg(adapter, A_TP_RSS_CONFIG_VRT); 3054218792Snp vrt &= ~(F_VFRDRG | F_VFRDEN | V_VFWRADDR(M_VFWRADDR) | F_KEYWREN); 3055218792Snp vrt |= V_VFWRADDR(index) | F_VFWREN; 3056218792Snp t4_write_reg(adapter, A_TP_RSS_CONFIG_VRT, vrt); 3057218792Snp} 3058218792Snp 3059218792Snp/** 3060218792Snp * t4_read_rss_pf_map - read PF RSS Map 3061218792Snp * @adapter: the adapter 3062218792Snp * 3063218792Snp * Reads the PF RSS Map register and returns its value. 3064218792Snp */ 3065218792Snpu32 t4_read_rss_pf_map(struct adapter *adapter) 3066218792Snp{ 3067218792Snp u32 pfmap; 3068218792Snp 3069218792Snp t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA, 3070218792Snp &pfmap, 1, A_TP_RSS_PF_MAP); 3071218792Snp return pfmap; 3072218792Snp} 3073218792Snp 3074218792Snp/** 3075218792Snp * t4_write_rss_pf_map - write PF RSS Map 3076218792Snp * @adapter: the adapter 3077218792Snp * @pfmap: PF RSS Map value 3078218792Snp * 3079218792Snp * Writes the specified value to the PF RSS Map register. 3080218792Snp */ 3081218792Snpvoid t4_write_rss_pf_map(struct adapter *adapter, u32 pfmap) 3082218792Snp{ 3083218792Snp t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA, 3084218792Snp &pfmap, 1, A_TP_RSS_PF_MAP); 3085218792Snp} 3086218792Snp 3087218792Snp/** 3088218792Snp * t4_read_rss_pf_mask - read PF RSS Mask 3089218792Snp * @adapter: the adapter 3090218792Snp * 3091218792Snp * Reads the PF RSS Mask register and returns its value. 3092218792Snp */ 3093218792Snpu32 t4_read_rss_pf_mask(struct adapter *adapter) 3094218792Snp{ 3095218792Snp u32 pfmask; 3096218792Snp 3097218792Snp t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA, 3098218792Snp &pfmask, 1, A_TP_RSS_PF_MSK); 3099218792Snp return pfmask; 3100218792Snp} 3101218792Snp 3102218792Snp/** 3103218792Snp * t4_write_rss_pf_mask - write PF RSS Mask 3104218792Snp * @adapter: the adapter 3105218792Snp * @pfmask: PF RSS Mask value 3106218792Snp * 3107218792Snp * Writes the specified value to the PF RSS Mask register. 3108218792Snp */ 3109218792Snpvoid t4_write_rss_pf_mask(struct adapter *adapter, u32 pfmask) 3110218792Snp{ 3111218792Snp t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA, 3112218792Snp &pfmask, 1, A_TP_RSS_PF_MSK); 3113218792Snp} 3114218792Snp 3115281259Snpstatic void refresh_vlan_pri_map(struct adapter *adap) 3116281259Snp{ 3117281259Snp 3118281259Snp t4_read_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, 3119281259Snp &adap->params.tp.vlan_pri_map, 1, 3120281259Snp A_TP_VLAN_PRI_MAP); 3121281259Snp 3122281259Snp /* 3123281259Snp * Now that we have TP_VLAN_PRI_MAP cached, we can calculate the field 3124281259Snp * shift positions of several elements of the Compressed Filter Tuple 3125281259Snp * for this adapter which we need frequently ... 3126281259Snp */ 3127281259Snp adap->params.tp.vlan_shift = t4_filter_field_shift(adap, F_VLAN); 3128281259Snp adap->params.tp.vnic_shift = t4_filter_field_shift(adap, F_VNIC_ID); 3129281259Snp adap->params.tp.port_shift = t4_filter_field_shift(adap, F_PORT); 3130281259Snp adap->params.tp.protocol_shift = t4_filter_field_shift(adap, F_PROTOCOL); 3131281259Snp 3132281259Snp /* 3133281259Snp * If TP_INGRESS_CONFIG.VNID == 0, then TP_VLAN_PRI_MAP.VNIC_ID 3134281259Snp * represents the presense of an Outer VLAN instead of a VNIC ID. 3135281259Snp */ 3136281259Snp if ((adap->params.tp.ingress_config & F_VNIC) == 0) 3137281259Snp adap->params.tp.vnic_shift = -1; 3138281259Snp} 3139281259Snp 3140218792Snp/** 3141218792Snp * t4_set_filter_mode - configure the optional components of filter tuples 3142218792Snp * @adap: the adapter 3143218792Snp * @mode_map: a bitmap selcting which optional filter components to enable 3144218792Snp * 3145218792Snp * Sets the filter mode by selecting the optional components to enable 3146218792Snp * in filter tuples. Returns 0 on success and a negative error if the 3147218792Snp * requested mode needs more bits than are available for optional 3148218792Snp * components. 3149218792Snp */ 3150218792Snpint t4_set_filter_mode(struct adapter *adap, unsigned int mode_map) 3151218792Snp{ 3152218792Snp static u8 width[] = { 1, 3, 17, 17, 8, 8, 16, 9, 3, 1 }; 3153218792Snp 3154218792Snp int i, nbits = 0; 3155218792Snp 3156218792Snp for (i = S_FCOE; i <= S_FRAGMENTATION; i++) 3157218792Snp if (mode_map & (1 << i)) 3158218792Snp nbits += width[i]; 3159218792Snp if (nbits > FILTER_OPT_LEN) 3160218792Snp return -EINVAL; 3161218792Snp t4_write_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, &mode_map, 1, 3162218792Snp A_TP_VLAN_PRI_MAP); 3163281259Snp refresh_vlan_pri_map(adap); 3164281259Snp 3165218792Snp return 0; 3166218792Snp} 3167218792Snp 3168218792Snp/** 3169218792Snp * t4_tp_get_tcp_stats - read TP's TCP MIB counters 3170218792Snp * @adap: the adapter 3171218792Snp * @v4: holds the TCP/IP counter values 3172218792Snp * @v6: holds the TCP/IPv6 counter values 3173218792Snp * 3174218792Snp * Returns the values of TP's TCP/IP and TCP/IPv6 MIB counters. 3175218792Snp * Either @v4 or @v6 may be %NULL to skip the corresponding stats. 3176218792Snp */ 3177218792Snpvoid t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4, 3178218792Snp struct tp_tcp_stats *v6) 3179218792Snp{ 3180218792Snp u32 val[A_TP_MIB_TCP_RXT_SEG_LO - A_TP_MIB_TCP_OUT_RST + 1]; 3181218792Snp 3182218792Snp#define STAT_IDX(x) ((A_TP_MIB_TCP_##x) - A_TP_MIB_TCP_OUT_RST) 3183218792Snp#define STAT(x) val[STAT_IDX(x)] 3184218792Snp#define STAT64(x) (((u64)STAT(x##_HI) << 32) | STAT(x##_LO)) 3185218792Snp 3186218792Snp if (v4) { 3187218792Snp t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, val, 3188218792Snp ARRAY_SIZE(val), A_TP_MIB_TCP_OUT_RST); 3189218792Snp v4->tcpOutRsts = STAT(OUT_RST); 3190218792Snp v4->tcpInSegs = STAT64(IN_SEG); 3191218792Snp v4->tcpOutSegs = STAT64(OUT_SEG); 3192218792Snp v4->tcpRetransSegs = STAT64(RXT_SEG); 3193218792Snp } 3194218792Snp if (v6) { 3195218792Snp t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, val, 3196218792Snp ARRAY_SIZE(val), A_TP_MIB_TCP_V6OUT_RST); 3197218792Snp v6->tcpOutRsts = STAT(OUT_RST); 3198218792Snp v6->tcpInSegs = STAT64(IN_SEG); 3199218792Snp v6->tcpOutSegs = STAT64(OUT_SEG); 3200218792Snp v6->tcpRetransSegs = STAT64(RXT_SEG); 3201218792Snp } 3202218792Snp#undef STAT64 3203218792Snp#undef STAT 3204218792Snp#undef STAT_IDX 3205218792Snp} 3206218792Snp 3207218792Snp/** 3208218792Snp * t4_tp_get_err_stats - read TP's error MIB counters 3209218792Snp * @adap: the adapter 3210218792Snp * @st: holds the counter values 3211218792Snp * 3212218792Snp * Returns the values of TP's error counters. 3213218792Snp */ 3214218792Snpvoid t4_tp_get_err_stats(struct adapter *adap, struct tp_err_stats *st) 3215218792Snp{ 3216218792Snp t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->macInErrs, 3217218792Snp 12, A_TP_MIB_MAC_IN_ERR_0); 3218218792Snp t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->tnlCongDrops, 3219218792Snp 8, A_TP_MIB_TNL_CNG_DROP_0); 3220218792Snp t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->tnlTxDrops, 3221218792Snp 4, A_TP_MIB_TNL_DROP_0); 3222218792Snp t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->ofldVlanDrops, 3223218792Snp 4, A_TP_MIB_OFD_VLN_DROP_0); 3224218792Snp t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->tcp6InErrs, 3225218792Snp 4, A_TP_MIB_TCP_V6IN_ERR_0); 3226218792Snp t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, &st->ofldNoNeigh, 3227218792Snp 2, A_TP_MIB_OFD_ARP_DROP); 3228218792Snp} 3229218792Snp 3230218792Snp/** 3231218792Snp * t4_tp_get_proxy_stats - read TP's proxy MIB counters 3232218792Snp * @adap: the adapter 3233218792Snp * @st: holds the counter values 3234218792Snp * 3235218792Snp * Returns the values of TP's proxy counters. 3236218792Snp */ 3237218792Snpvoid t4_tp_get_proxy_stats(struct adapter *adap, struct tp_proxy_stats *st) 3238218792Snp{ 3239218792Snp t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->proxy, 3240218792Snp 4, A_TP_MIB_TNL_LPBK_0); 3241218792Snp} 3242218792Snp 3243218792Snp/** 3244218792Snp * t4_tp_get_cpl_stats - read TP's CPL MIB counters 3245218792Snp * @adap: the adapter 3246218792Snp * @st: holds the counter values 3247218792Snp * 3248218792Snp * Returns the values of TP's CPL counters. 3249218792Snp */ 3250218792Snpvoid t4_tp_get_cpl_stats(struct adapter *adap, struct tp_cpl_stats *st) 3251218792Snp{ 3252218792Snp t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->req, 3253218792Snp 8, A_TP_MIB_CPL_IN_REQ_0); 3254218792Snp} 3255218792Snp 3256218792Snp/** 3257218792Snp * t4_tp_get_rdma_stats - read TP's RDMA MIB counters 3258218792Snp * @adap: the adapter 3259218792Snp * @st: holds the counter values 3260218792Snp * 3261218792Snp * Returns the values of TP's RDMA counters. 3262218792Snp */ 3263218792Snpvoid t4_tp_get_rdma_stats(struct adapter *adap, struct tp_rdma_stats *st) 3264218792Snp{ 3265218792Snp t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, &st->rqe_dfr_mod, 3266218792Snp 2, A_TP_MIB_RQE_DFR_MOD); 3267218792Snp} 3268218792Snp 3269218792Snp/** 3270218792Snp * t4_get_fcoe_stats - read TP's FCoE MIB counters for a port 3271218792Snp * @adap: the adapter 3272218792Snp * @idx: the port index 3273218792Snp * @st: holds the counter values 3274218792Snp * 3275218792Snp * Returns the values of TP's FCoE counters for the selected port. 3276218792Snp */ 3277218792Snpvoid t4_get_fcoe_stats(struct adapter *adap, unsigned int idx, 3278218792Snp struct tp_fcoe_stats *st) 3279218792Snp{ 3280218792Snp u32 val[2]; 3281218792Snp 3282218792Snp t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, &st->framesDDP, 3283218792Snp 1, A_TP_MIB_FCOE_DDP_0 + idx); 3284218792Snp t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, &st->framesDrop, 3285218792Snp 1, A_TP_MIB_FCOE_DROP_0 + idx); 3286218792Snp t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, val, 3287218792Snp 2, A_TP_MIB_FCOE_BYTE_0_HI + 2 * idx); 3288218792Snp st->octetsDDP = ((u64)val[0] << 32) | val[1]; 3289218792Snp} 3290218792Snp 3291218792Snp/** 3292218792Snp * t4_get_usm_stats - read TP's non-TCP DDP MIB counters 3293218792Snp * @adap: the adapter 3294218792Snp * @st: holds the counter values 3295218792Snp * 3296218792Snp * Returns the values of TP's counters for non-TCP directly-placed packets. 3297218792Snp */ 3298218792Snpvoid t4_get_usm_stats(struct adapter *adap, struct tp_usm_stats *st) 3299218792Snp{ 3300218792Snp u32 val[4]; 3301218792Snp 3302218792Snp t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, val, 4, 3303218792Snp A_TP_MIB_USM_PKTS); 3304218792Snp st->frames = val[0]; 3305218792Snp st->drops = val[1]; 3306218792Snp st->octets = ((u64)val[2] << 32) | val[3]; 3307218792Snp} 3308218792Snp 3309218792Snp/** 3310218792Snp * t4_read_mtu_tbl - returns the values in the HW path MTU table 3311218792Snp * @adap: the adapter 3312218792Snp * @mtus: where to store the MTU values 3313218792Snp * @mtu_log: where to store the MTU base-2 log (may be %NULL) 3314218792Snp * 3315218792Snp * Reads the HW path MTU table. 3316218792Snp */ 3317218792Snpvoid t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log) 3318218792Snp{ 3319218792Snp u32 v; 3320218792Snp int i; 3321218792Snp 3322218792Snp for (i = 0; i < NMTUS; ++i) { 3323218792Snp t4_write_reg(adap, A_TP_MTU_TABLE, 3324218792Snp V_MTUINDEX(0xff) | V_MTUVALUE(i)); 3325218792Snp v = t4_read_reg(adap, A_TP_MTU_TABLE); 3326218792Snp mtus[i] = G_MTUVALUE(v); 3327218792Snp if (mtu_log) 3328218792Snp mtu_log[i] = G_MTUWIDTH(v); 3329218792Snp } 3330218792Snp} 3331218792Snp 3332218792Snp/** 3333218792Snp * t4_read_cong_tbl - reads the congestion control table 3334218792Snp * @adap: the adapter 3335218792Snp * @incr: where to store the alpha values 3336218792Snp * 3337218792Snp * Reads the additive increments programmed into the HW congestion 3338218792Snp * control table. 3339218792Snp */ 3340218792Snpvoid t4_read_cong_tbl(struct adapter *adap, u16 incr[NMTUS][NCCTRL_WIN]) 3341218792Snp{ 3342218792Snp unsigned int mtu, w; 3343218792Snp 3344218792Snp for (mtu = 0; mtu < NMTUS; ++mtu) 3345218792Snp for (w = 0; w < NCCTRL_WIN; ++w) { 3346218792Snp t4_write_reg(adap, A_TP_CCTRL_TABLE, 3347218792Snp V_ROWINDEX(0xffff) | (mtu << 5) | w); 3348218792Snp incr[mtu][w] = (u16)t4_read_reg(adap, 3349218792Snp A_TP_CCTRL_TABLE) & 0x1fff; 3350218792Snp } 3351218792Snp} 3352218792Snp 3353218792Snp/** 3354218792Snp * t4_read_pace_tbl - read the pace table 3355218792Snp * @adap: the adapter 3356218792Snp * @pace_vals: holds the returned values 3357218792Snp * 3358218792Snp * Returns the values of TP's pace table in microseconds. 3359218792Snp */ 3360218792Snpvoid t4_read_pace_tbl(struct adapter *adap, unsigned int pace_vals[NTX_SCHED]) 3361218792Snp{ 3362218792Snp unsigned int i, v; 3363218792Snp 3364218792Snp for (i = 0; i < NTX_SCHED; i++) { 3365218792Snp t4_write_reg(adap, A_TP_PACE_TABLE, 0xffff0000 + i); 3366218792Snp v = t4_read_reg(adap, A_TP_PACE_TABLE); 3367218792Snp pace_vals[i] = dack_ticks_to_usec(adap, v); 3368218792Snp } 3369218792Snp} 3370218792Snp 3371218792Snp/** 3372218792Snp * t4_tp_wr_bits_indirect - set/clear bits in an indirect TP register 3373218792Snp * @adap: the adapter 3374218792Snp * @addr: the indirect TP register address 3375218792Snp * @mask: specifies the field within the register to modify 3376218792Snp * @val: new value for the field 3377218792Snp * 3378218792Snp * Sets a field of an indirect TP register to the given value. 3379218792Snp */ 3380218792Snpvoid t4_tp_wr_bits_indirect(struct adapter *adap, unsigned int addr, 3381218792Snp unsigned int mask, unsigned int val) 3382218792Snp{ 3383218792Snp t4_write_reg(adap, A_TP_PIO_ADDR, addr); 3384218792Snp val |= t4_read_reg(adap, A_TP_PIO_DATA) & ~mask; 3385218792Snp t4_write_reg(adap, A_TP_PIO_DATA, val); 3386218792Snp} 3387218792Snp 3388218792Snp/** 3389218792Snp * init_cong_ctrl - initialize congestion control parameters 3390218792Snp * @a: the alpha values for congestion control 3391218792Snp * @b: the beta values for congestion control 3392218792Snp * 3393218792Snp * Initialize the congestion control parameters. 3394218792Snp */ 3395218792Snpstatic void __devinit init_cong_ctrl(unsigned short *a, unsigned short *b) 3396218792Snp{ 3397218792Snp a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = a[8] = 1; 3398218792Snp a[9] = 2; 3399218792Snp a[10] = 3; 3400218792Snp a[11] = 4; 3401218792Snp a[12] = 5; 3402218792Snp a[13] = 6; 3403218792Snp a[14] = 7; 3404218792Snp a[15] = 8; 3405218792Snp a[16] = 9; 3406218792Snp a[17] = 10; 3407218792Snp a[18] = 14; 3408218792Snp a[19] = 17; 3409218792Snp a[20] = 21; 3410218792Snp a[21] = 25; 3411218792Snp a[22] = 30; 3412218792Snp a[23] = 35; 3413218792Snp a[24] = 45; 3414218792Snp a[25] = 60; 3415218792Snp a[26] = 80; 3416218792Snp a[27] = 100; 3417218792Snp a[28] = 200; 3418218792Snp a[29] = 300; 3419218792Snp a[30] = 400; 3420218792Snp a[31] = 500; 3421218792Snp 3422218792Snp b[0] = b[1] = b[2] = b[3] = b[4] = b[5] = b[6] = b[7] = b[8] = 0; 3423218792Snp b[9] = b[10] = 1; 3424218792Snp b[11] = b[12] = 2; 3425218792Snp b[13] = b[14] = b[15] = b[16] = 3; 3426218792Snp b[17] = b[18] = b[19] = b[20] = b[21] = 4; 3427218792Snp b[22] = b[23] = b[24] = b[25] = b[26] = b[27] = 5; 3428218792Snp b[28] = b[29] = 6; 3429218792Snp b[30] = b[31] = 7; 3430218792Snp} 3431218792Snp 3432218792Snp/* The minimum additive increment value for the congestion control table */ 3433218792Snp#define CC_MIN_INCR 2U 3434218792Snp 3435218792Snp/** 3436218792Snp * t4_load_mtus - write the MTU and congestion control HW tables 3437218792Snp * @adap: the adapter 3438218792Snp * @mtus: the values for the MTU table 3439218792Snp * @alpha: the values for the congestion control alpha parameter 3440218792Snp * @beta: the values for the congestion control beta parameter 3441218792Snp * 3442218792Snp * Write the HW MTU table with the supplied MTUs and the high-speed 3443218792Snp * congestion control table with the supplied alpha, beta, and MTUs. 3444218792Snp * We write the two tables together because the additive increments 3445218792Snp * depend on the MTUs. 3446218792Snp */ 3447218792Snpvoid t4_load_mtus(struct adapter *adap, const unsigned short *mtus, 3448218792Snp const unsigned short *alpha, const unsigned short *beta) 3449218792Snp{ 3450218792Snp static const unsigned int avg_pkts[NCCTRL_WIN] = { 3451218792Snp 2, 6, 10, 14, 20, 28, 40, 56, 80, 112, 160, 224, 320, 448, 640, 3452218792Snp 896, 1281, 1792, 2560, 3584, 5120, 7168, 10240, 14336, 20480, 3453218792Snp 28672, 40960, 57344, 81920, 114688, 163840, 229376 3454218792Snp }; 3455218792Snp 3456218792Snp unsigned int i, w; 3457218792Snp 3458218792Snp for (i = 0; i < NMTUS; ++i) { 3459218792Snp unsigned int mtu = mtus[i]; 3460218792Snp unsigned int log2 = fls(mtu); 3461218792Snp 3462218792Snp if (!(mtu & ((1 << log2) >> 2))) /* round */ 3463218792Snp log2--; 3464218792Snp t4_write_reg(adap, A_TP_MTU_TABLE, V_MTUINDEX(i) | 3465218792Snp V_MTUWIDTH(log2) | V_MTUVALUE(mtu)); 3466218792Snp 3467218792Snp for (w = 0; w < NCCTRL_WIN; ++w) { 3468218792Snp unsigned int inc; 3469218792Snp 3470218792Snp inc = max(((mtu - 40) * alpha[w]) / avg_pkts[w], 3471218792Snp CC_MIN_INCR); 3472218792Snp 3473218792Snp t4_write_reg(adap, A_TP_CCTRL_TABLE, (i << 21) | 3474218792Snp (w << 16) | (beta[w] << 13) | inc); 3475218792Snp } 3476218792Snp } 3477218792Snp} 3478218792Snp 3479218792Snp/** 3480218792Snp * t4_set_pace_tbl - set the pace table 3481218792Snp * @adap: the adapter 3482218792Snp * @pace_vals: the pace values in microseconds 3483218792Snp * @start: index of the first entry in the HW pace table to set 3484218792Snp * @n: how many entries to set 3485218792Snp * 3486218792Snp * Sets (a subset of the) HW pace table. 3487218792Snp */ 3488218792Snpint t4_set_pace_tbl(struct adapter *adap, const unsigned int *pace_vals, 3489218792Snp unsigned int start, unsigned int n) 3490218792Snp{ 3491218792Snp unsigned int vals[NTX_SCHED], i; 3492218792Snp unsigned int tick_ns = dack_ticks_to_usec(adap, 1000); 3493218792Snp 3494218792Snp if (n > NTX_SCHED) 3495218792Snp return -ERANGE; 3496218792Snp 3497218792Snp /* convert values from us to dack ticks, rounding to closest value */ 3498218792Snp for (i = 0; i < n; i++, pace_vals++) { 3499218792Snp vals[i] = (1000 * *pace_vals + tick_ns / 2) / tick_ns; 3500218792Snp if (vals[i] > 0x7ff) 3501218792Snp return -ERANGE; 3502218792Snp if (*pace_vals && vals[i] == 0) 3503218792Snp return -ERANGE; 3504218792Snp } 3505218792Snp for (i = 0; i < n; i++, start++) 3506218792Snp t4_write_reg(adap, A_TP_PACE_TABLE, (start << 16) | vals[i]); 3507218792Snp return 0; 3508218792Snp} 3509218792Snp 3510218792Snp/** 3511218792Snp * t4_set_sched_bps - set the bit rate for a HW traffic scheduler 3512218792Snp * @adap: the adapter 3513218792Snp * @kbps: target rate in Kbps 3514218792Snp * @sched: the scheduler index 3515218792Snp * 3516218792Snp * Configure a Tx HW scheduler for the target rate. 3517218792Snp */ 3518218792Snpint t4_set_sched_bps(struct adapter *adap, int sched, unsigned int kbps) 3519218792Snp{ 3520218792Snp unsigned int v, tps, cpt, bpt, delta, mindelta = ~0; 3521218792Snp unsigned int clk = adap->params.vpd.cclk * 1000; 3522218792Snp unsigned int selected_cpt = 0, selected_bpt = 0; 3523218792Snp 3524218792Snp if (kbps > 0) { 3525218792Snp kbps *= 125; /* -> bytes */ 3526218792Snp for (cpt = 1; cpt <= 255; cpt++) { 3527218792Snp tps = clk / cpt; 3528218792Snp bpt = (kbps + tps / 2) / tps; 3529218792Snp if (bpt > 0 && bpt <= 255) { 3530218792Snp v = bpt * tps; 3531218792Snp delta = v >= kbps ? v - kbps : kbps - v; 3532218792Snp if (delta < mindelta) { 3533218792Snp mindelta = delta; 3534218792Snp selected_cpt = cpt; 3535218792Snp selected_bpt = bpt; 3536218792Snp } 3537218792Snp } else if (selected_cpt) 3538218792Snp break; 3539218792Snp } 3540218792Snp if (!selected_cpt) 3541218792Snp return -EINVAL; 3542218792Snp } 3543218792Snp t4_write_reg(adap, A_TP_TM_PIO_ADDR, 3544218792Snp A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2); 3545218792Snp v = t4_read_reg(adap, A_TP_TM_PIO_DATA); 3546218792Snp if (sched & 1) 3547218792Snp v = (v & 0xffff) | (selected_cpt << 16) | (selected_bpt << 24); 3548218792Snp else 3549218792Snp v = (v & 0xffff0000) | selected_cpt | (selected_bpt << 8); 3550218792Snp t4_write_reg(adap, A_TP_TM_PIO_DATA, v); 3551218792Snp return 0; 3552218792Snp} 3553218792Snp 3554218792Snp/** 3555218792Snp * t4_set_sched_ipg - set the IPG for a Tx HW packet rate scheduler 3556218792Snp * @adap: the adapter 3557218792Snp * @sched: the scheduler index 3558218792Snp * @ipg: the interpacket delay in tenths of nanoseconds 3559218792Snp * 3560218792Snp * Set the interpacket delay for a HW packet rate scheduler. 3561218792Snp */ 3562218792Snpint t4_set_sched_ipg(struct adapter *adap, int sched, unsigned int ipg) 3563218792Snp{ 3564218792Snp unsigned int v, addr = A_TP_TX_MOD_Q1_Q0_TIMER_SEPARATOR - sched / 2; 3565218792Snp 3566218792Snp /* convert ipg to nearest number of core clocks */ 3567218792Snp ipg *= core_ticks_per_usec(adap); 3568218792Snp ipg = (ipg + 5000) / 10000; 3569218792Snp if (ipg > M_TXTIMERSEPQ0) 3570218792Snp return -EINVAL; 3571218792Snp 3572218792Snp t4_write_reg(adap, A_TP_TM_PIO_ADDR, addr); 3573218792Snp v = t4_read_reg(adap, A_TP_TM_PIO_DATA); 3574218792Snp if (sched & 1) 3575218792Snp v = (v & V_TXTIMERSEPQ0(M_TXTIMERSEPQ0)) | V_TXTIMERSEPQ1(ipg); 3576218792Snp else 3577218792Snp v = (v & V_TXTIMERSEPQ1(M_TXTIMERSEPQ1)) | V_TXTIMERSEPQ0(ipg); 3578218792Snp t4_write_reg(adap, A_TP_TM_PIO_DATA, v); 3579218792Snp t4_read_reg(adap, A_TP_TM_PIO_DATA); 3580218792Snp return 0; 3581218792Snp} 3582218792Snp 3583218792Snp/** 3584218792Snp * t4_get_tx_sched - get the configuration of a Tx HW traffic scheduler 3585218792Snp * @adap: the adapter 3586218792Snp * @sched: the scheduler index 3587218792Snp * @kbps: the byte rate in Kbps 3588218792Snp * @ipg: the interpacket delay in tenths of nanoseconds 3589218792Snp * 3590218792Snp * Return the current configuration of a HW Tx scheduler. 3591218792Snp */ 3592218792Snpvoid t4_get_tx_sched(struct adapter *adap, unsigned int sched, unsigned int *kbps, 3593218792Snp unsigned int *ipg) 3594218792Snp{ 3595218792Snp unsigned int v, addr, bpt, cpt; 3596218792Snp 3597218792Snp if (kbps) { 3598218792Snp addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2; 3599218792Snp t4_write_reg(adap, A_TP_TM_PIO_ADDR, addr); 3600218792Snp v = t4_read_reg(adap, A_TP_TM_PIO_DATA); 3601218792Snp if (sched & 1) 3602218792Snp v >>= 16; 3603218792Snp bpt = (v >> 8) & 0xff; 3604218792Snp cpt = v & 0xff; 3605218792Snp if (!cpt) 3606218792Snp *kbps = 0; /* scheduler disabled */ 3607218792Snp else { 3608218792Snp v = (adap->params.vpd.cclk * 1000) / cpt; /* ticks/s */ 3609218792Snp *kbps = (v * bpt) / 125; 3610218792Snp } 3611218792Snp } 3612218792Snp if (ipg) { 3613218792Snp addr = A_TP_TX_MOD_Q1_Q0_TIMER_SEPARATOR - sched / 2; 3614218792Snp t4_write_reg(adap, A_TP_TM_PIO_ADDR, addr); 3615218792Snp v = t4_read_reg(adap, A_TP_TM_PIO_DATA); 3616218792Snp if (sched & 1) 3617218792Snp v >>= 16; 3618218792Snp v &= 0xffff; 3619218792Snp *ipg = (10000 * v) / core_ticks_per_usec(adap); 3620218792Snp } 3621218792Snp} 3622218792Snp 3623218792Snp/* 3624218792Snp * Calculates a rate in bytes/s given the number of 256-byte units per 4K core 3625218792Snp * clocks. The formula is 3626218792Snp * 3627218792Snp * bytes/s = bytes256 * 256 * ClkFreq / 4096 3628218792Snp * 3629218792Snp * which is equivalent to 3630218792Snp * 3631218792Snp * bytes/s = 62.5 * bytes256 * ClkFreq_ms 3632218792Snp */ 3633218792Snpstatic u64 chan_rate(struct adapter *adap, unsigned int bytes256) 3634218792Snp{ 3635218792Snp u64 v = bytes256 * adap->params.vpd.cclk; 3636218792Snp 3637218792Snp return v * 62 + v / 2; 3638218792Snp} 3639218792Snp 3640218792Snp/** 3641218792Snp * t4_get_chan_txrate - get the current per channel Tx rates 3642218792Snp * @adap: the adapter 3643218792Snp * @nic_rate: rates for NIC traffic 3644218792Snp * @ofld_rate: rates for offloaded traffic 3645218792Snp * 3646218792Snp * Return the current Tx rates in bytes/s for NIC and offloaded traffic 3647218792Snp * for each channel. 3648218792Snp */ 3649218792Snpvoid t4_get_chan_txrate(struct adapter *adap, u64 *nic_rate, u64 *ofld_rate) 3650218792Snp{ 3651218792Snp u32 v; 3652218792Snp 3653218792Snp v = t4_read_reg(adap, A_TP_TX_TRATE); 3654218792Snp nic_rate[0] = chan_rate(adap, G_TNLRATE0(v)); 3655218792Snp nic_rate[1] = chan_rate(adap, G_TNLRATE1(v)); 3656218792Snp nic_rate[2] = chan_rate(adap, G_TNLRATE2(v)); 3657218792Snp nic_rate[3] = chan_rate(adap, G_TNLRATE3(v)); 3658218792Snp 3659218792Snp v = t4_read_reg(adap, A_TP_TX_ORATE); 3660218792Snp ofld_rate[0] = chan_rate(adap, G_OFDRATE0(v)); 3661218792Snp ofld_rate[1] = chan_rate(adap, G_OFDRATE1(v)); 3662218792Snp ofld_rate[2] = chan_rate(adap, G_OFDRATE2(v)); 3663218792Snp ofld_rate[3] = chan_rate(adap, G_OFDRATE3(v)); 3664218792Snp} 3665218792Snp 3666218792Snp/** 3667218792Snp * t4_set_trace_filter - configure one of the tracing filters 3668218792Snp * @adap: the adapter 3669218792Snp * @tp: the desired trace filter parameters 3670218792Snp * @idx: which filter to configure 3671218792Snp * @enable: whether to enable or disable the filter 3672218792Snp * 3673253691Snp * Configures one of the tracing filters available in HW. If @tp is %NULL 3674253691Snp * it indicates that the filter is already written in the register and it 3675253691Snp * just needs to be enabled or disabled. 3676218792Snp */ 3677253691Snpint t4_set_trace_filter(struct adapter *adap, const struct trace_params *tp, 3678253691Snp int idx, int enable) 3679218792Snp{ 3680218792Snp int i, ofst = idx * 4; 3681218792Snp u32 data_reg, mask_reg, cfg; 3682218792Snp u32 multitrc = F_TRCMULTIFILTER; 3683253691Snp u32 en = is_t4(adap) ? F_TFEN : F_T5_TFEN; 3684218792Snp 3685253691Snp if (idx < 0 || idx >= NTRACE) 3686253691Snp return -EINVAL; 3687253691Snp 3688253691Snp if (tp == NULL || !enable) { 3689253691Snp t4_set_reg_field(adap, A_MPS_TRC_FILTER_MATCH_CTL_A + ofst, en, 3690253691Snp enable ? en : 0); 3691237436Snp return 0; 3692218792Snp } 3693218792Snp 3694237436Snp /* 3695237436Snp * TODO - After T4 data book is updated, specify the exact 3696237436Snp * section below. 3697237436Snp * 3698237436Snp * See T4 data book - MPS section for a complete description 3699237436Snp * of the below if..else handling of A_MPS_TRC_CFG register 3700237436Snp * value. 3701237436Snp */ 3702237436Snp cfg = t4_read_reg(adap, A_MPS_TRC_CFG); 3703237436Snp if (cfg & F_TRCMULTIFILTER) { 3704237436Snp /* 3705237436Snp * If multiple tracers are enabled, then maximum 3706237436Snp * capture size is 2.5KB (FIFO size of a single channel) 3707237436Snp * minus 2 flits for CPL_TRACE_PKT header. 3708237436Snp */ 3709237436Snp if (tp->snap_len > ((10 * 1024 / 4) - (2 * 8))) 3710237436Snp return -EINVAL; 3711253691Snp } else { 3712237436Snp /* 3713237436Snp * If multiple tracers are disabled, to avoid deadlocks 3714237436Snp * maximum packet capture size of 9600 bytes is recommended. 3715237436Snp * Also in this mode, only trace0 can be enabled and running. 3716237436Snp */ 3717218792Snp multitrc = 0; 3718237436Snp if (tp->snap_len > 9600 || idx) 3719218792Snp return -EINVAL; 3720218792Snp } 3721218792Snp 3722253691Snp if (tp->port > (is_t4(adap) ? 11 : 19) || tp->invert > 1 || 3723253691Snp tp->skip_len > M_TFLENGTH || tp->skip_ofst > M_TFOFFSET || 3724253691Snp tp->min_len > M_TFMINPKTSIZE) 3725237436Snp return -EINVAL; 3726237436Snp 3727218792Snp /* stop the tracer we'll be changing */ 3728253691Snp t4_set_reg_field(adap, A_MPS_TRC_FILTER_MATCH_CTL_A + ofst, en, 0); 3729218792Snp 3730218792Snp idx *= (A_MPS_TRC_FILTER1_MATCH - A_MPS_TRC_FILTER0_MATCH); 3731218792Snp data_reg = A_MPS_TRC_FILTER0_MATCH + idx; 3732218792Snp mask_reg = A_MPS_TRC_FILTER0_DONT_CARE + idx; 3733218792Snp 3734218792Snp for (i = 0; i < TRACE_LEN / 4; i++, data_reg += 4, mask_reg += 4) { 3735218792Snp t4_write_reg(adap, data_reg, tp->data[i]); 3736218792Snp t4_write_reg(adap, mask_reg, ~tp->mask[i]); 3737218792Snp } 3738218792Snp t4_write_reg(adap, A_MPS_TRC_FILTER_MATCH_CTL_B + ofst, 3739218792Snp V_TFCAPTUREMAX(tp->snap_len) | 3740218792Snp V_TFMINPKTSIZE(tp->min_len)); 3741218792Snp t4_write_reg(adap, A_MPS_TRC_FILTER_MATCH_CTL_A + ofst, 3742253691Snp V_TFOFFSET(tp->skip_ofst) | V_TFLENGTH(tp->skip_len) | en | 3743253691Snp (is_t4(adap) ? 3744253691Snp V_TFPORT(tp->port) | V_TFINVERTMATCH(tp->invert) : 3745253691Snp V_T5_TFPORT(tp->port) | V_T5_TFINVERTMATCH(tp->invert))); 3746218792Snp 3747218792Snp return 0; 3748218792Snp} 3749218792Snp 3750218792Snp/** 3751218792Snp * t4_get_trace_filter - query one of the tracing filters 3752218792Snp * @adap: the adapter 3753218792Snp * @tp: the current trace filter parameters 3754218792Snp * @idx: which trace filter to query 3755218792Snp * @enabled: non-zero if the filter is enabled 3756218792Snp * 3757218792Snp * Returns the current settings of one of the HW tracing filters. 3758218792Snp */ 3759218792Snpvoid t4_get_trace_filter(struct adapter *adap, struct trace_params *tp, int idx, 3760218792Snp int *enabled) 3761218792Snp{ 3762218792Snp u32 ctla, ctlb; 3763218792Snp int i, ofst = idx * 4; 3764218792Snp u32 data_reg, mask_reg; 3765218792Snp 3766218792Snp ctla = t4_read_reg(adap, A_MPS_TRC_FILTER_MATCH_CTL_A + ofst); 3767218792Snp ctlb = t4_read_reg(adap, A_MPS_TRC_FILTER_MATCH_CTL_B + ofst); 3768218792Snp 3769248925Snp if (is_t4(adap)) { 3770248925Snp *enabled = !!(ctla & F_TFEN); 3771248925Snp tp->port = G_TFPORT(ctla); 3772253691Snp tp->invert = !!(ctla & F_TFINVERTMATCH); 3773248925Snp } else { 3774248925Snp *enabled = !!(ctla & F_T5_TFEN); 3775248925Snp tp->port = G_T5_TFPORT(ctla); 3776253691Snp tp->invert = !!(ctla & F_T5_TFINVERTMATCH); 3777248925Snp } 3778218792Snp tp->snap_len = G_TFCAPTUREMAX(ctlb); 3779218792Snp tp->min_len = G_TFMINPKTSIZE(ctlb); 3780218792Snp tp->skip_ofst = G_TFOFFSET(ctla); 3781218792Snp tp->skip_len = G_TFLENGTH(ctla); 3782218792Snp 3783218792Snp ofst = (A_MPS_TRC_FILTER1_MATCH - A_MPS_TRC_FILTER0_MATCH) * idx; 3784218792Snp data_reg = A_MPS_TRC_FILTER0_MATCH + ofst; 3785218792Snp mask_reg = A_MPS_TRC_FILTER0_DONT_CARE + ofst; 3786218792Snp 3787218792Snp for (i = 0; i < TRACE_LEN / 4; i++, data_reg += 4, mask_reg += 4) { 3788218792Snp tp->mask[i] = ~t4_read_reg(adap, mask_reg); 3789218792Snp tp->data[i] = t4_read_reg(adap, data_reg) & tp->mask[i]; 3790218792Snp } 3791218792Snp} 3792218792Snp 3793218792Snp/** 3794218792Snp * t4_pmtx_get_stats - returns the HW stats from PMTX 3795218792Snp * @adap: the adapter 3796218792Snp * @cnt: where to store the count statistics 3797218792Snp * @cycles: where to store the cycle statistics 3798218792Snp * 3799218792Snp * Returns performance statistics from PMTX. 3800218792Snp */ 3801218792Snpvoid t4_pmtx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[]) 3802218792Snp{ 3803218792Snp int i; 3804248925Snp u32 data[2]; 3805218792Snp 3806218792Snp for (i = 0; i < PM_NSTATS; i++) { 3807218792Snp t4_write_reg(adap, A_PM_TX_STAT_CONFIG, i + 1); 3808218792Snp cnt[i] = t4_read_reg(adap, A_PM_TX_STAT_COUNT); 3809248925Snp if (is_t4(adap)) 3810248925Snp cycles[i] = t4_read_reg64(adap, A_PM_TX_STAT_LSB); 3811248925Snp else { 3812248925Snp t4_read_indirect(adap, A_PM_TX_DBG_CTRL, 3813248925Snp A_PM_TX_DBG_DATA, data, 2, 3814248925Snp A_PM_TX_DBG_STAT_MSB); 3815248925Snp cycles[i] = (((u64)data[0] << 32) | data[1]); 3816248925Snp } 3817218792Snp } 3818218792Snp} 3819218792Snp 3820218792Snp/** 3821218792Snp * t4_pmrx_get_stats - returns the HW stats from PMRX 3822218792Snp * @adap: the adapter 3823218792Snp * @cnt: where to store the count statistics 3824218792Snp * @cycles: where to store the cycle statistics 3825218792Snp * 3826218792Snp * Returns performance statistics from PMRX. 3827218792Snp */ 3828218792Snpvoid t4_pmrx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[]) 3829218792Snp{ 3830218792Snp int i; 3831248925Snp u32 data[2]; 3832218792Snp 3833218792Snp for (i = 0; i < PM_NSTATS; i++) { 3834218792Snp t4_write_reg(adap, A_PM_RX_STAT_CONFIG, i + 1); 3835218792Snp cnt[i] = t4_read_reg(adap, A_PM_RX_STAT_COUNT); 3836248925Snp if (is_t4(adap)) 3837248925Snp cycles[i] = t4_read_reg64(adap, A_PM_RX_STAT_LSB); 3838248925Snp else { 3839248925Snp t4_read_indirect(adap, A_PM_RX_DBG_CTRL, 3840248925Snp A_PM_RX_DBG_DATA, data, 2, 3841248925Snp A_PM_RX_DBG_STAT_MSB); 3842248925Snp cycles[i] = (((u64)data[0] << 32) | data[1]); 3843248925Snp } 3844218792Snp } 3845218792Snp} 3846218792Snp 3847218792Snp/** 3848218792Snp * get_mps_bg_map - return the buffer groups associated with a port 3849218792Snp * @adap: the adapter 3850218792Snp * @idx: the port index 3851218792Snp * 3852218792Snp * Returns a bitmap indicating which MPS buffer groups are associated 3853218792Snp * with the given port. Bit i is set if buffer group i is used by the 3854218792Snp * port. 3855218792Snp */ 3856218792Snpstatic unsigned int get_mps_bg_map(struct adapter *adap, int idx) 3857218792Snp{ 3858218792Snp u32 n = G_NUMPORTS(t4_read_reg(adap, A_MPS_CMN_CTL)); 3859218792Snp 3860218792Snp if (n == 0) 3861218792Snp return idx == 0 ? 0xf : 0; 3862218792Snp if (n == 1) 3863218792Snp return idx < 2 ? (3 << (2 * idx)) : 0; 3864218792Snp return 1 << idx; 3865218792Snp} 3866218792Snp 3867218792Snp/** 3868237436Snp * t4_get_port_stats_offset - collect port stats relative to a previous 3869237436Snp * snapshot 3870237436Snp * @adap: The adapter 3871237436Snp * @idx: The port 3872237436Snp * @stats: Current stats to fill 3873237436Snp * @offset: Previous stats snapshot 3874237436Snp */ 3875237436Snpvoid t4_get_port_stats_offset(struct adapter *adap, int idx, 3876237436Snp struct port_stats *stats, 3877237436Snp struct port_stats *offset) 3878237436Snp{ 3879237436Snp u64 *s, *o; 3880237436Snp int i; 3881237436Snp 3882237436Snp t4_get_port_stats(adap, idx, stats); 3883237436Snp for (i = 0, s = (u64 *)stats, o = (u64 *)offset ; 3884237436Snp i < (sizeof(struct port_stats)/sizeof(u64)) ; 3885237436Snp i++, s++, o++) 3886237436Snp *s -= *o; 3887237436Snp} 3888237436Snp 3889237436Snp/** 3890218792Snp * t4_get_port_stats - collect port statistics 3891218792Snp * @adap: the adapter 3892218792Snp * @idx: the port index 3893218792Snp * @p: the stats structure to fill 3894218792Snp * 3895218792Snp * Collect statistics related to the given port from HW. 3896218792Snp */ 3897218792Snpvoid t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p) 3898218792Snp{ 3899218792Snp u32 bgmap = get_mps_bg_map(adap, idx); 3900218792Snp 3901218792Snp#define GET_STAT(name) \ 3902248925Snp t4_read_reg64(adap, \ 3903248925Snp (is_t4(adap) ? PORT_REG(idx, A_MPS_PORT_STAT_##name##_L) : \ 3904248925Snp T5_PORT_REG(idx, A_MPS_PORT_STAT_##name##_L))) 3905218792Snp#define GET_STAT_COM(name) t4_read_reg64(adap, A_MPS_STAT_##name##_L) 3906218792Snp 3907228561Snp p->tx_pause = GET_STAT(TX_PORT_PAUSE); 3908218792Snp p->tx_octets = GET_STAT(TX_PORT_BYTES); 3909218792Snp p->tx_frames = GET_STAT(TX_PORT_FRAMES); 3910218792Snp p->tx_bcast_frames = GET_STAT(TX_PORT_BCAST); 3911218792Snp p->tx_mcast_frames = GET_STAT(TX_PORT_MCAST); 3912218792Snp p->tx_ucast_frames = GET_STAT(TX_PORT_UCAST); 3913218792Snp p->tx_error_frames = GET_STAT(TX_PORT_ERROR); 3914218792Snp p->tx_frames_64 = GET_STAT(TX_PORT_64B); 3915218792Snp p->tx_frames_65_127 = GET_STAT(TX_PORT_65B_127B); 3916218792Snp p->tx_frames_128_255 = GET_STAT(TX_PORT_128B_255B); 3917218792Snp p->tx_frames_256_511 = GET_STAT(TX_PORT_256B_511B); 3918218792Snp p->tx_frames_512_1023 = GET_STAT(TX_PORT_512B_1023B); 3919218792Snp p->tx_frames_1024_1518 = GET_STAT(TX_PORT_1024B_1518B); 3920218792Snp p->tx_frames_1519_max = GET_STAT(TX_PORT_1519B_MAX); 3921218792Snp p->tx_drop = GET_STAT(TX_PORT_DROP); 3922218792Snp p->tx_ppp0 = GET_STAT(TX_PORT_PPP0); 3923218792Snp p->tx_ppp1 = GET_STAT(TX_PORT_PPP1); 3924218792Snp p->tx_ppp2 = GET_STAT(TX_PORT_PPP2); 3925218792Snp p->tx_ppp3 = GET_STAT(TX_PORT_PPP3); 3926218792Snp p->tx_ppp4 = GET_STAT(TX_PORT_PPP4); 3927218792Snp p->tx_ppp5 = GET_STAT(TX_PORT_PPP5); 3928218792Snp p->tx_ppp6 = GET_STAT(TX_PORT_PPP6); 3929218792Snp p->tx_ppp7 = GET_STAT(TX_PORT_PPP7); 3930218792Snp 3931228561Snp p->rx_pause = GET_STAT(RX_PORT_PAUSE); 3932218792Snp p->rx_octets = GET_STAT(RX_PORT_BYTES); 3933218792Snp p->rx_frames = GET_STAT(RX_PORT_FRAMES); 3934218792Snp p->rx_bcast_frames = GET_STAT(RX_PORT_BCAST); 3935218792Snp p->rx_mcast_frames = GET_STAT(RX_PORT_MCAST); 3936218792Snp p->rx_ucast_frames = GET_STAT(RX_PORT_UCAST); 3937218792Snp p->rx_too_long = GET_STAT(RX_PORT_MTU_ERROR); 3938218792Snp p->rx_jabber = GET_STAT(RX_PORT_MTU_CRC_ERROR); 3939218792Snp p->rx_fcs_err = GET_STAT(RX_PORT_CRC_ERROR); 3940218792Snp p->rx_len_err = GET_STAT(RX_PORT_LEN_ERROR); 3941218792Snp p->rx_symbol_err = GET_STAT(RX_PORT_SYM_ERROR); 3942218792Snp p->rx_runt = GET_STAT(RX_PORT_LESS_64B); 3943218792Snp p->rx_frames_64 = GET_STAT(RX_PORT_64B); 3944218792Snp p->rx_frames_65_127 = GET_STAT(RX_PORT_65B_127B); 3945218792Snp p->rx_frames_128_255 = GET_STAT(RX_PORT_128B_255B); 3946218792Snp p->rx_frames_256_511 = GET_STAT(RX_PORT_256B_511B); 3947218792Snp p->rx_frames_512_1023 = GET_STAT(RX_PORT_512B_1023B); 3948218792Snp p->rx_frames_1024_1518 = GET_STAT(RX_PORT_1024B_1518B); 3949218792Snp p->rx_frames_1519_max = GET_STAT(RX_PORT_1519B_MAX); 3950218792Snp p->rx_ppp0 = GET_STAT(RX_PORT_PPP0); 3951218792Snp p->rx_ppp1 = GET_STAT(RX_PORT_PPP1); 3952218792Snp p->rx_ppp2 = GET_STAT(RX_PORT_PPP2); 3953218792Snp p->rx_ppp3 = GET_STAT(RX_PORT_PPP3); 3954218792Snp p->rx_ppp4 = GET_STAT(RX_PORT_PPP4); 3955218792Snp p->rx_ppp5 = GET_STAT(RX_PORT_PPP5); 3956218792Snp p->rx_ppp6 = GET_STAT(RX_PORT_PPP6); 3957218792Snp p->rx_ppp7 = GET_STAT(RX_PORT_PPP7); 3958218792Snp 3959218792Snp p->rx_ovflow0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_MAC_DROP_FRAME) : 0; 3960218792Snp p->rx_ovflow1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_MAC_DROP_FRAME) : 0; 3961218792Snp p->rx_ovflow2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_MAC_DROP_FRAME) : 0; 3962218792Snp p->rx_ovflow3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_MAC_DROP_FRAME) : 0; 3963218792Snp p->rx_trunc0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_MAC_TRUNC_FRAME) : 0; 3964218792Snp p->rx_trunc1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_MAC_TRUNC_FRAME) : 0; 3965218792Snp p->rx_trunc2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_MAC_TRUNC_FRAME) : 0; 3966218792Snp p->rx_trunc3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_MAC_TRUNC_FRAME) : 0; 3967218792Snp 3968218792Snp#undef GET_STAT 3969218792Snp#undef GET_STAT_COM 3970218792Snp} 3971218792Snp 3972218792Snp/** 3973218792Snp * t4_clr_port_stats - clear port statistics 3974218792Snp * @adap: the adapter 3975218792Snp * @idx: the port index 3976218792Snp * 3977218792Snp * Clear HW statistics for the given port. 3978218792Snp */ 3979218792Snpvoid t4_clr_port_stats(struct adapter *adap, int idx) 3980218792Snp{ 3981218792Snp unsigned int i; 3982218792Snp u32 bgmap = get_mps_bg_map(adap, idx); 3983248925Snp u32 port_base_addr; 3984218792Snp 3985248925Snp if (is_t4(adap)) 3986248925Snp port_base_addr = PORT_BASE(idx); 3987248925Snp else 3988248925Snp port_base_addr = T5_PORT_BASE(idx); 3989248925Snp 3990218792Snp for (i = A_MPS_PORT_STAT_TX_PORT_BYTES_L; 3991248925Snp i <= A_MPS_PORT_STAT_TX_PORT_PPP7_H; i += 8) 3992248925Snp t4_write_reg(adap, port_base_addr + i, 0); 3993218792Snp for (i = A_MPS_PORT_STAT_RX_PORT_BYTES_L; 3994248925Snp i <= A_MPS_PORT_STAT_RX_PORT_LESS_64B_H; i += 8) 3995248925Snp t4_write_reg(adap, port_base_addr + i, 0); 3996218792Snp for (i = 0; i < 4; i++) 3997218792Snp if (bgmap & (1 << i)) { 3998218792Snp t4_write_reg(adap, 3999218792Snp A_MPS_STAT_RX_BG_0_MAC_DROP_FRAME_L + i * 8, 0); 4000218792Snp t4_write_reg(adap, 4001218792Snp A_MPS_STAT_RX_BG_0_MAC_TRUNC_FRAME_L + i * 8, 0); 4002218792Snp } 4003218792Snp} 4004218792Snp 4005218792Snp/** 4006218792Snp * t4_get_lb_stats - collect loopback port statistics 4007218792Snp * @adap: the adapter 4008218792Snp * @idx: the loopback port index 4009218792Snp * @p: the stats structure to fill 4010218792Snp * 4011218792Snp * Return HW statistics for the given loopback port. 4012218792Snp */ 4013218792Snpvoid t4_get_lb_stats(struct adapter *adap, int idx, struct lb_port_stats *p) 4014218792Snp{ 4015218792Snp u32 bgmap = get_mps_bg_map(adap, idx); 4016218792Snp 4017218792Snp#define GET_STAT(name) \ 4018248925Snp t4_read_reg64(adap, \ 4019248925Snp (is_t4(adap) ? \ 4020248925Snp PORT_REG(idx, A_MPS_PORT_STAT_LB_PORT_##name##_L) : \ 4021248925Snp T5_PORT_REG(idx, A_MPS_PORT_STAT_LB_PORT_##name##_L))) 4022218792Snp#define GET_STAT_COM(name) t4_read_reg64(adap, A_MPS_STAT_##name##_L) 4023218792Snp 4024218792Snp p->octets = GET_STAT(BYTES); 4025218792Snp p->frames = GET_STAT(FRAMES); 4026218792Snp p->bcast_frames = GET_STAT(BCAST); 4027218792Snp p->mcast_frames = GET_STAT(MCAST); 4028218792Snp p->ucast_frames = GET_STAT(UCAST); 4029218792Snp p->error_frames = GET_STAT(ERROR); 4030218792Snp 4031218792Snp p->frames_64 = GET_STAT(64B); 4032218792Snp p->frames_65_127 = GET_STAT(65B_127B); 4033218792Snp p->frames_128_255 = GET_STAT(128B_255B); 4034218792Snp p->frames_256_511 = GET_STAT(256B_511B); 4035218792Snp p->frames_512_1023 = GET_STAT(512B_1023B); 4036218792Snp p->frames_1024_1518 = GET_STAT(1024B_1518B); 4037218792Snp p->frames_1519_max = GET_STAT(1519B_MAX); 4038248925Snp p->drop = GET_STAT(DROP_FRAMES); 4039218792Snp 4040218792Snp p->ovflow0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_LB_DROP_FRAME) : 0; 4041218792Snp p->ovflow1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_LB_DROP_FRAME) : 0; 4042218792Snp p->ovflow2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_LB_DROP_FRAME) : 0; 4043218792Snp p->ovflow3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_LB_DROP_FRAME) : 0; 4044218792Snp p->trunc0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_LB_TRUNC_FRAME) : 0; 4045218792Snp p->trunc1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_LB_TRUNC_FRAME) : 0; 4046218792Snp p->trunc2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_LB_TRUNC_FRAME) : 0; 4047218792Snp p->trunc3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_LB_TRUNC_FRAME) : 0; 4048218792Snp 4049218792Snp#undef GET_STAT 4050218792Snp#undef GET_STAT_COM 4051218792Snp} 4052218792Snp 4053218792Snp/** 4054218792Snp * t4_wol_magic_enable - enable/disable magic packet WoL 4055218792Snp * @adap: the adapter 4056218792Snp * @port: the physical port index 4057218792Snp * @addr: MAC address expected in magic packets, %NULL to disable 4058218792Snp * 4059218792Snp * Enables/disables magic packet wake-on-LAN for the selected port. 4060218792Snp */ 4061218792Snpvoid t4_wol_magic_enable(struct adapter *adap, unsigned int port, 4062218792Snp const u8 *addr) 4063218792Snp{ 4064248925Snp u32 mag_id_reg_l, mag_id_reg_h, port_cfg_reg; 4065248925Snp 4066248925Snp if (is_t4(adap)) { 4067248925Snp mag_id_reg_l = PORT_REG(port, A_XGMAC_PORT_MAGIC_MACID_LO); 4068248925Snp mag_id_reg_h = PORT_REG(port, A_XGMAC_PORT_MAGIC_MACID_HI); 4069248925Snp port_cfg_reg = PORT_REG(port, A_XGMAC_PORT_CFG2); 4070248925Snp } else { 4071248925Snp mag_id_reg_l = T5_PORT_REG(port, A_MAC_PORT_MAGIC_MACID_LO); 4072248925Snp mag_id_reg_h = T5_PORT_REG(port, A_MAC_PORT_MAGIC_MACID_HI); 4073248925Snp port_cfg_reg = T5_PORT_REG(port, A_MAC_PORT_CFG2); 4074248925Snp } 4075248925Snp 4076218792Snp if (addr) { 4077248925Snp t4_write_reg(adap, mag_id_reg_l, 4078218792Snp (addr[2] << 24) | (addr[3] << 16) | 4079218792Snp (addr[4] << 8) | addr[5]); 4080248925Snp t4_write_reg(adap, mag_id_reg_h, 4081218792Snp (addr[0] << 8) | addr[1]); 4082218792Snp } 4083248925Snp t4_set_reg_field(adap, port_cfg_reg, F_MAGICEN, 4084218792Snp V_MAGICEN(addr != NULL)); 4085218792Snp} 4086218792Snp 4087218792Snp/** 4088218792Snp * t4_wol_pat_enable - enable/disable pattern-based WoL 4089218792Snp * @adap: the adapter 4090218792Snp * @port: the physical port index 4091218792Snp * @map: bitmap of which HW pattern filters to set 4092218792Snp * @mask0: byte mask for bytes 0-63 of a packet 4093218792Snp * @mask1: byte mask for bytes 64-127 of a packet 4094218792Snp * @crc: Ethernet CRC for selected bytes 4095218792Snp * @enable: enable/disable switch 4096218792Snp * 4097218792Snp * Sets the pattern filters indicated in @map to mask out the bytes 4098218792Snp * specified in @mask0/@mask1 in received packets and compare the CRC of 4099218792Snp * the resulting packet against @crc. If @enable is %true pattern-based 4100218792Snp * WoL is enabled, otherwise disabled. 4101218792Snp */ 4102218792Snpint t4_wol_pat_enable(struct adapter *adap, unsigned int port, unsigned int map, 4103218792Snp u64 mask0, u64 mask1, unsigned int crc, bool enable) 4104218792Snp{ 4105218792Snp int i; 4106248925Snp u32 port_cfg_reg; 4107218792Snp 4108248925Snp if (is_t4(adap)) 4109248925Snp port_cfg_reg = PORT_REG(port, A_XGMAC_PORT_CFG2); 4110248925Snp else 4111248925Snp port_cfg_reg = T5_PORT_REG(port, A_MAC_PORT_CFG2); 4112248925Snp 4113218792Snp if (!enable) { 4114248925Snp t4_set_reg_field(adap, port_cfg_reg, F_PATEN, 0); 4115218792Snp return 0; 4116218792Snp } 4117218792Snp if (map > 0xff) 4118218792Snp return -EINVAL; 4119218792Snp 4120248925Snp#define EPIO_REG(name) \ 4121248925Snp (is_t4(adap) ? PORT_REG(port, A_XGMAC_PORT_EPIO_##name) : \ 4122248925Snp T5_PORT_REG(port, A_MAC_PORT_EPIO_##name)) 4123218792Snp 4124218792Snp t4_write_reg(adap, EPIO_REG(DATA1), mask0 >> 32); 4125218792Snp t4_write_reg(adap, EPIO_REG(DATA2), mask1); 4126218792Snp t4_write_reg(adap, EPIO_REG(DATA3), mask1 >> 32); 4127218792Snp 4128218792Snp for (i = 0; i < NWOL_PAT; i++, map >>= 1) { 4129218792Snp if (!(map & 1)) 4130218792Snp continue; 4131218792Snp 4132218792Snp /* write byte masks */ 4133218792Snp t4_write_reg(adap, EPIO_REG(DATA0), mask0); 4134218792Snp t4_write_reg(adap, EPIO_REG(OP), V_ADDRESS(i) | F_EPIOWR); 4135218792Snp t4_read_reg(adap, EPIO_REG(OP)); /* flush */ 4136218792Snp if (t4_read_reg(adap, EPIO_REG(OP)) & F_BUSY) 4137218792Snp return -ETIMEDOUT; 4138218792Snp 4139218792Snp /* write CRC */ 4140218792Snp t4_write_reg(adap, EPIO_REG(DATA0), crc); 4141218792Snp t4_write_reg(adap, EPIO_REG(OP), V_ADDRESS(i + 32) | F_EPIOWR); 4142218792Snp t4_read_reg(adap, EPIO_REG(OP)); /* flush */ 4143218792Snp if (t4_read_reg(adap, EPIO_REG(OP)) & F_BUSY) 4144218792Snp return -ETIMEDOUT; 4145218792Snp } 4146218792Snp#undef EPIO_REG 4147218792Snp 4148248925Snp t4_set_reg_field(adap, port_cfg_reg, 0, F_PATEN); 4149218792Snp return 0; 4150218792Snp} 4151218792Snp 4152218792Snp/** 4153218792Snp * t4_mk_filtdelwr - create a delete filter WR 4154218792Snp * @ftid: the filter ID 4155218792Snp * @wr: the filter work request to populate 4156218792Snp * @qid: ingress queue to receive the delete notification 4157218792Snp * 4158218792Snp * Creates a filter work request to delete the supplied filter. If @qid is 4159218792Snp * negative the delete notification is suppressed. 4160218792Snp */ 4161218792Snpvoid t4_mk_filtdelwr(unsigned int ftid, struct fw_filter_wr *wr, int qid) 4162218792Snp{ 4163218792Snp memset(wr, 0, sizeof(*wr)); 4164218792Snp wr->op_pkd = htonl(V_FW_WR_OP(FW_FILTER_WR)); 4165218792Snp wr->len16_pkd = htonl(V_FW_WR_LEN16(sizeof(*wr) / 16)); 4166218792Snp wr->tid_to_iq = htonl(V_FW_FILTER_WR_TID(ftid) | 4167218792Snp V_FW_FILTER_WR_NOREPLY(qid < 0)); 4168218792Snp wr->del_filter_to_l2tix = htonl(F_FW_FILTER_WR_DEL_FILTER); 4169218792Snp if (qid >= 0) 4170218792Snp wr->rx_chan_rx_rpl_iq = htons(V_FW_FILTER_WR_RX_RPL_IQ(qid)); 4171218792Snp} 4172218792Snp 4173218792Snp#define INIT_CMD(var, cmd, rd_wr) do { \ 4174218792Snp (var).op_to_write = htonl(V_FW_CMD_OP(FW_##cmd##_CMD) | \ 4175218792Snp F_FW_CMD_REQUEST | F_FW_CMD_##rd_wr); \ 4176218792Snp (var).retval_len16 = htonl(FW_LEN16(var)); \ 4177218792Snp} while (0) 4178218792Snp 4179237436Snpint t4_fwaddrspace_write(struct adapter *adap, unsigned int mbox, u32 addr, u32 val) 4180237436Snp{ 4181237436Snp struct fw_ldst_cmd c; 4182237436Snp 4183237436Snp memset(&c, 0, sizeof(c)); 4184237436Snp c.op_to_addrspace = htonl(V_FW_CMD_OP(FW_LDST_CMD) | F_FW_CMD_REQUEST | 4185237436Snp F_FW_CMD_WRITE | V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_FIRMWARE)); 4186237436Snp c.cycles_to_len16 = htonl(FW_LEN16(c)); 4187237436Snp c.u.addrval.addr = htonl(addr); 4188237436Snp c.u.addrval.val = htonl(val); 4189237436Snp 4190237436Snp return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); 4191237436Snp} 4192237436Snp 4193218792Snp/** 4194218792Snp * t4_mdio_rd - read a PHY register through MDIO 4195218792Snp * @adap: the adapter 4196218792Snp * @mbox: mailbox to use for the FW command 4197218792Snp * @phy_addr: the PHY address 4198218792Snp * @mmd: the PHY MMD to access (0 for clause 22 PHYs) 4199218792Snp * @reg: the register to read 4200218792Snp * @valp: where to store the value 4201218792Snp * 4202218792Snp * Issues a FW command through the given mailbox to read a PHY register. 4203218792Snp */ 4204218792Snpint t4_mdio_rd(struct adapter *adap, unsigned int mbox, unsigned int phy_addr, 4205218792Snp unsigned int mmd, unsigned int reg, unsigned int *valp) 4206218792Snp{ 4207218792Snp int ret; 4208218792Snp struct fw_ldst_cmd c; 4209218792Snp 4210218792Snp memset(&c, 0, sizeof(c)); 4211218792Snp c.op_to_addrspace = htonl(V_FW_CMD_OP(FW_LDST_CMD) | F_FW_CMD_REQUEST | 4212218792Snp F_FW_CMD_READ | V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MDIO)); 4213218792Snp c.cycles_to_len16 = htonl(FW_LEN16(c)); 4214218792Snp c.u.mdio.paddr_mmd = htons(V_FW_LDST_CMD_PADDR(phy_addr) | 4215218792Snp V_FW_LDST_CMD_MMD(mmd)); 4216218792Snp c.u.mdio.raddr = htons(reg); 4217218792Snp 4218218792Snp ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); 4219218792Snp if (ret == 0) 4220218792Snp *valp = ntohs(c.u.mdio.rval); 4221218792Snp return ret; 4222218792Snp} 4223218792Snp 4224218792Snp/** 4225218792Snp * t4_mdio_wr - write a PHY register through MDIO 4226218792Snp * @adap: the adapter 4227218792Snp * @mbox: mailbox to use for the FW command 4228218792Snp * @phy_addr: the PHY address 4229218792Snp * @mmd: the PHY MMD to access (0 for clause 22 PHYs) 4230218792Snp * @reg: the register to write 4231218792Snp * @valp: value to write 4232218792Snp * 4233218792Snp * Issues a FW command through the given mailbox to write a PHY register. 4234218792Snp */ 4235218792Snpint t4_mdio_wr(struct adapter *adap, unsigned int mbox, unsigned int phy_addr, 4236218792Snp unsigned int mmd, unsigned int reg, unsigned int val) 4237218792Snp{ 4238218792Snp struct fw_ldst_cmd c; 4239218792Snp 4240218792Snp memset(&c, 0, sizeof(c)); 4241218792Snp c.op_to_addrspace = htonl(V_FW_CMD_OP(FW_LDST_CMD) | F_FW_CMD_REQUEST | 4242218792Snp F_FW_CMD_WRITE | V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MDIO)); 4243218792Snp c.cycles_to_len16 = htonl(FW_LEN16(c)); 4244218792Snp c.u.mdio.paddr_mmd = htons(V_FW_LDST_CMD_PADDR(phy_addr) | 4245218792Snp V_FW_LDST_CMD_MMD(mmd)); 4246218792Snp c.u.mdio.raddr = htons(reg); 4247218792Snp c.u.mdio.rval = htons(val); 4248218792Snp 4249218792Snp return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); 4250218792Snp} 4251218792Snp 4252218792Snp/** 4253269082Snp * t4_i2c_rd - read I2C data from adapter 4254269082Snp * @adap: the adapter 4255269082Snp * @port: Port number if per-port device; <0 if not 4256269082Snp * @devid: per-port device ID or absolute device ID 4257269082Snp * @offset: byte offset into device I2C space 4258269082Snp * @len: byte length of I2C space data 4259269082Snp * @buf: buffer in which to return I2C data 4260269082Snp * 4261269082Snp * Reads the I2C data from the indicated device and location. 4262269082Snp */ 4263269082Snpint t4_i2c_rd(struct adapter *adap, unsigned int mbox, 4264269082Snp int port, unsigned int devid, 4265269082Snp unsigned int offset, unsigned int len, 4266269082Snp u8 *buf) 4267269082Snp{ 4268269082Snp struct fw_ldst_cmd ldst; 4269269082Snp int ret; 4270269082Snp 4271269082Snp if (port >= 4 || 4272269082Snp devid >= 256 || 4273269082Snp offset >= 256 || 4274269082Snp len > sizeof ldst.u.i2c.data) 4275269082Snp return -EINVAL; 4276269082Snp 4277269082Snp memset(&ldst, 0, sizeof ldst); 4278269082Snp ldst.op_to_addrspace = 4279269082Snp cpu_to_be32(V_FW_CMD_OP(FW_LDST_CMD) | 4280269082Snp F_FW_CMD_REQUEST | 4281269082Snp F_FW_CMD_READ | 4282269082Snp V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_I2C)); 4283269082Snp ldst.cycles_to_len16 = cpu_to_be32(FW_LEN16(ldst)); 4284269082Snp ldst.u.i2c.pid = (port < 0 ? 0xff : port); 4285269082Snp ldst.u.i2c.did = devid; 4286269082Snp ldst.u.i2c.boffset = offset; 4287269082Snp ldst.u.i2c.blen = len; 4288269082Snp ret = t4_wr_mbox(adap, mbox, &ldst, sizeof ldst, &ldst); 4289269082Snp if (!ret) 4290269082Snp memcpy(buf, ldst.u.i2c.data, len); 4291269082Snp return ret; 4292269082Snp} 4293269082Snp 4294269082Snp/** 4295269082Snp * t4_i2c_wr - write I2C data to adapter 4296269082Snp * @adap: the adapter 4297269082Snp * @port: Port number if per-port device; <0 if not 4298269082Snp * @devid: per-port device ID or absolute device ID 4299269082Snp * @offset: byte offset into device I2C space 4300269082Snp * @len: byte length of I2C space data 4301269082Snp * @buf: buffer containing new I2C data 4302269082Snp * 4303269082Snp * Write the I2C data to the indicated device and location. 4304269082Snp */ 4305269082Snpint t4_i2c_wr(struct adapter *adap, unsigned int mbox, 4306269082Snp int port, unsigned int devid, 4307269082Snp unsigned int offset, unsigned int len, 4308269082Snp u8 *buf) 4309269082Snp{ 4310269082Snp struct fw_ldst_cmd ldst; 4311269082Snp 4312269082Snp if (port >= 4 || 4313269082Snp devid >= 256 || 4314269082Snp offset >= 256 || 4315269082Snp len > sizeof ldst.u.i2c.data) 4316269082Snp return -EINVAL; 4317269082Snp 4318269082Snp memset(&ldst, 0, sizeof ldst); 4319269082Snp ldst.op_to_addrspace = 4320269082Snp cpu_to_be32(V_FW_CMD_OP(FW_LDST_CMD) | 4321269082Snp F_FW_CMD_REQUEST | 4322269082Snp F_FW_CMD_WRITE | 4323269082Snp V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_I2C)); 4324269082Snp ldst.cycles_to_len16 = cpu_to_be32(FW_LEN16(ldst)); 4325269082Snp ldst.u.i2c.pid = (port < 0 ? 0xff : port); 4326269082Snp ldst.u.i2c.did = devid; 4327269082Snp ldst.u.i2c.boffset = offset; 4328269082Snp ldst.u.i2c.blen = len; 4329269082Snp memcpy(ldst.u.i2c.data, buf, len); 4330269082Snp return t4_wr_mbox(adap, mbox, &ldst, sizeof ldst, &ldst); 4331269082Snp} 4332269082Snp 4333269082Snp/** 4334237436Snp * t4_sge_ctxt_flush - flush the SGE context cache 4335237436Snp * @adap: the adapter 4336237436Snp * @mbox: mailbox to use for the FW command 4337237436Snp * 4338237436Snp * Issues a FW command through the given mailbox to flush the 4339237436Snp * SGE context cache. 4340237436Snp */ 4341237436Snpint t4_sge_ctxt_flush(struct adapter *adap, unsigned int mbox) 4342237436Snp{ 4343237436Snp int ret; 4344237436Snp struct fw_ldst_cmd c; 4345237436Snp 4346237436Snp memset(&c, 0, sizeof(c)); 4347237436Snp c.op_to_addrspace = htonl(V_FW_CMD_OP(FW_LDST_CMD) | F_FW_CMD_REQUEST | 4348237436Snp F_FW_CMD_READ | 4349237436Snp V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_SGE_EGRC)); 4350237436Snp c.cycles_to_len16 = htonl(FW_LEN16(c)); 4351237436Snp c.u.idctxt.msg_ctxtflush = htonl(F_FW_LDST_CMD_CTXTFLUSH); 4352237436Snp 4353237436Snp ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); 4354237436Snp return ret; 4355237436Snp} 4356237436Snp 4357237436Snp/** 4358218792Snp * t4_sge_ctxt_rd - read an SGE context through FW 4359218792Snp * @adap: the adapter 4360218792Snp * @mbox: mailbox to use for the FW command 4361218792Snp * @cid: the context id 4362218792Snp * @ctype: the context type 4363218792Snp * @data: where to store the context data 4364218792Snp * 4365218792Snp * Issues a FW command through the given mailbox to read an SGE context. 4366218792Snp */ 4367218792Snpint t4_sge_ctxt_rd(struct adapter *adap, unsigned int mbox, unsigned int cid, 4368218792Snp enum ctxt_type ctype, u32 *data) 4369218792Snp{ 4370218792Snp int ret; 4371218792Snp struct fw_ldst_cmd c; 4372218792Snp 4373218792Snp if (ctype == CTXT_EGRESS) 4374218792Snp ret = FW_LDST_ADDRSPC_SGE_EGRC; 4375218792Snp else if (ctype == CTXT_INGRESS) 4376218792Snp ret = FW_LDST_ADDRSPC_SGE_INGC; 4377218792Snp else if (ctype == CTXT_FLM) 4378218792Snp ret = FW_LDST_ADDRSPC_SGE_FLMC; 4379218792Snp else 4380218792Snp ret = FW_LDST_ADDRSPC_SGE_CONMC; 4381218792Snp 4382218792Snp memset(&c, 0, sizeof(c)); 4383218792Snp c.op_to_addrspace = htonl(V_FW_CMD_OP(FW_LDST_CMD) | F_FW_CMD_REQUEST | 4384218792Snp F_FW_CMD_READ | V_FW_LDST_CMD_ADDRSPACE(ret)); 4385218792Snp c.cycles_to_len16 = htonl(FW_LEN16(c)); 4386218792Snp c.u.idctxt.physid = htonl(cid); 4387218792Snp 4388218792Snp ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); 4389218792Snp if (ret == 0) { 4390218792Snp data[0] = ntohl(c.u.idctxt.ctxt_data0); 4391218792Snp data[1] = ntohl(c.u.idctxt.ctxt_data1); 4392218792Snp data[2] = ntohl(c.u.idctxt.ctxt_data2); 4393218792Snp data[3] = ntohl(c.u.idctxt.ctxt_data3); 4394218792Snp data[4] = ntohl(c.u.idctxt.ctxt_data4); 4395218792Snp data[5] = ntohl(c.u.idctxt.ctxt_data5); 4396218792Snp } 4397218792Snp return ret; 4398218792Snp} 4399218792Snp 4400218792Snp/** 4401218792Snp * t4_sge_ctxt_rd_bd - read an SGE context bypassing FW 4402218792Snp * @adap: the adapter 4403218792Snp * @cid: the context id 4404218792Snp * @ctype: the context type 4405218792Snp * @data: where to store the context data 4406218792Snp * 4407218792Snp * Reads an SGE context directly, bypassing FW. This is only for 4408218792Snp * debugging when FW is unavailable. 4409218792Snp */ 4410218792Snpint t4_sge_ctxt_rd_bd(struct adapter *adap, unsigned int cid, enum ctxt_type ctype, 4411218792Snp u32 *data) 4412218792Snp{ 4413218792Snp int i, ret; 4414218792Snp 4415218792Snp t4_write_reg(adap, A_SGE_CTXT_CMD, V_CTXTQID(cid) | V_CTXTTYPE(ctype)); 4416218792Snp ret = t4_wait_op_done(adap, A_SGE_CTXT_CMD, F_BUSY, 0, 3, 1); 4417218792Snp if (!ret) 4418218792Snp for (i = A_SGE_CTXT_DATA0; i <= A_SGE_CTXT_DATA5; i += 4) 4419218792Snp *data++ = t4_read_reg(adap, i); 4420218792Snp return ret; 4421218792Snp} 4422218792Snp 4423218792Snp/** 4424218792Snp * t4_fw_hello - establish communication with FW 4425218792Snp * @adap: the adapter 4426218792Snp * @mbox: mailbox to use for the FW command 4427218792Snp * @evt_mbox: mailbox to receive async FW events 4428218792Snp * @master: specifies the caller's willingness to be the device master 4429237436Snp * @state: returns the current device state (if non-NULL) 4430218792Snp * 4431237436Snp * Issues a command to establish communication with FW. Returns either 4432237436Snp * an error (negative integer) or the mailbox of the Master PF. 4433218792Snp */ 4434218792Snpint t4_fw_hello(struct adapter *adap, unsigned int mbox, unsigned int evt_mbox, 4435218792Snp enum dev_master master, enum dev_state *state) 4436218792Snp{ 4437218792Snp int ret; 4438218792Snp struct fw_hello_cmd c; 4439228561Snp u32 v; 4440228561Snp unsigned int master_mbox; 4441228561Snp int retries = FW_CMD_HELLO_RETRIES; 4442218792Snp 4443228561Snpretry: 4444218792Snp memset(&c, 0, sizeof(c)); 4445218792Snp INIT_CMD(c, HELLO, WRITE); 4446228561Snp c.err_to_clearinit = htonl( 4447218792Snp V_FW_HELLO_CMD_MASTERDIS(master == MASTER_CANT) | 4448218792Snp V_FW_HELLO_CMD_MASTERFORCE(master == MASTER_MUST) | 4449218792Snp V_FW_HELLO_CMD_MBMASTER(master == MASTER_MUST ? mbox : 4450218792Snp M_FW_HELLO_CMD_MBMASTER) | 4451228561Snp V_FW_HELLO_CMD_MBASYNCNOT(evt_mbox) | 4452228561Snp V_FW_HELLO_CMD_STAGE(FW_HELLO_CMD_STAGE_OS) | 4453228561Snp F_FW_HELLO_CMD_CLEARINIT); 4454218792Snp 4455228561Snp /* 4456228561Snp * Issue the HELLO command to the firmware. If it's not successful 4457228561Snp * but indicates that we got a "busy" or "timeout" condition, retry 4458247355Snp * the HELLO until we exhaust our retry limit. If we do exceed our 4459247355Snp * retry limit, check to see if the firmware left us any error 4460247355Snp * information and report that if so ... 4461228561Snp */ 4462218792Snp ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); 4463228561Snp if (ret != FW_SUCCESS) { 4464228561Snp if ((ret == -EBUSY || ret == -ETIMEDOUT) && retries-- > 0) 4465228561Snp goto retry; 4466247355Snp if (t4_read_reg(adap, A_PCIE_FW) & F_PCIE_FW_ERR) 4467247355Snp t4_report_fw_error(adap); 4468228561Snp return ret; 4469228561Snp } 4470228561Snp 4471228561Snp v = ntohl(c.err_to_clearinit); 4472228561Snp master_mbox = G_FW_HELLO_CMD_MBMASTER(v); 4473228561Snp if (state) { 4474228561Snp if (v & F_FW_HELLO_CMD_ERR) 4475228561Snp *state = DEV_STATE_ERR; 4476228561Snp else if (v & F_FW_HELLO_CMD_INIT) 4477218792Snp *state = DEV_STATE_INIT; 4478218792Snp else 4479218792Snp *state = DEV_STATE_UNINIT; 4480218792Snp } 4481228561Snp 4482228561Snp /* 4483228561Snp * If we're not the Master PF then we need to wait around for the 4484228561Snp * Master PF Driver to finish setting up the adapter. 4485228561Snp * 4486228561Snp * Note that we also do this wait if we're a non-Master-capable PF and 4487228561Snp * there is no current Master PF; a Master PF may show up momentarily 4488228561Snp * and we wouldn't want to fail pointlessly. (This can happen when an 4489228561Snp * OS loads lots of different drivers rapidly at the same time). In 4490228561Snp * this case, the Master PF returned by the firmware will be 4491228561Snp * M_PCIE_FW_MASTER so the test below will work ... 4492228561Snp */ 4493228561Snp if ((v & (F_FW_HELLO_CMD_ERR|F_FW_HELLO_CMD_INIT)) == 0 && 4494228561Snp master_mbox != mbox) { 4495228561Snp int waiting = FW_CMD_HELLO_TIMEOUT; 4496228561Snp 4497228561Snp /* 4498228561Snp * Wait for the firmware to either indicate an error or 4499228561Snp * initialized state. If we see either of these we bail out 4500228561Snp * and report the issue to the caller. If we exhaust the 4501228561Snp * "hello timeout" and we haven't exhausted our retries, try 4502228561Snp * again. Otherwise bail with a timeout error. 4503228561Snp */ 4504228561Snp for (;;) { 4505228561Snp u32 pcie_fw; 4506228561Snp 4507228561Snp msleep(50); 4508228561Snp waiting -= 50; 4509228561Snp 4510228561Snp /* 4511228561Snp * If neither Error nor Initialialized are indicated 4512228561Snp * by the firmware keep waiting till we exhaust our 4513228561Snp * timeout ... and then retry if we haven't exhausted 4514228561Snp * our retries ... 4515228561Snp */ 4516228561Snp pcie_fw = t4_read_reg(adap, A_PCIE_FW); 4517228561Snp if (!(pcie_fw & (F_PCIE_FW_ERR|F_PCIE_FW_INIT))) { 4518228561Snp if (waiting <= 0) { 4519228561Snp if (retries-- > 0) 4520228561Snp goto retry; 4521228561Snp 4522228561Snp return -ETIMEDOUT; 4523228561Snp } 4524228561Snp continue; 4525228561Snp } 4526228561Snp 4527228561Snp /* 4528228561Snp * We either have an Error or Initialized condition 4529228561Snp * report errors preferentially. 4530228561Snp */ 4531228561Snp if (state) { 4532228561Snp if (pcie_fw & F_PCIE_FW_ERR) 4533228561Snp *state = DEV_STATE_ERR; 4534228561Snp else if (pcie_fw & F_PCIE_FW_INIT) 4535228561Snp *state = DEV_STATE_INIT; 4536228561Snp } 4537228561Snp 4538228561Snp /* 4539228561Snp * If we arrived before a Master PF was selected and 4540228561Snp * there's not a valid Master PF, grab its identity 4541228561Snp * for our caller. 4542228561Snp */ 4543228561Snp if (master_mbox == M_PCIE_FW_MASTER && 4544228561Snp (pcie_fw & F_PCIE_FW_MASTER_VLD)) 4545228561Snp master_mbox = G_PCIE_FW_MASTER(pcie_fw); 4546228561Snp break; 4547228561Snp } 4548228561Snp } 4549228561Snp 4550228561Snp return master_mbox; 4551218792Snp} 4552218792Snp 4553218792Snp/** 4554218792Snp * t4_fw_bye - end communication with FW 4555218792Snp * @adap: the adapter 4556218792Snp * @mbox: mailbox to use for the FW command 4557218792Snp * 4558218792Snp * Issues a command to terminate communication with FW. 4559218792Snp */ 4560218792Snpint t4_fw_bye(struct adapter *adap, unsigned int mbox) 4561218792Snp{ 4562218792Snp struct fw_bye_cmd c; 4563218792Snp 4564218792Snp memset(&c, 0, sizeof(c)); 4565218792Snp INIT_CMD(c, BYE, WRITE); 4566218792Snp return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); 4567218792Snp} 4568218792Snp 4569218792Snp/** 4570228561Snp * t4_fw_reset - issue a reset to FW 4571218792Snp * @adap: the adapter 4572218792Snp * @mbox: mailbox to use for the FW command 4573228561Snp * @reset: specifies the type of reset to perform 4574218792Snp * 4575228561Snp * Issues a reset command of the specified type to FW. 4576218792Snp */ 4577228561Snpint t4_fw_reset(struct adapter *adap, unsigned int mbox, int reset) 4578218792Snp{ 4579228561Snp struct fw_reset_cmd c; 4580218792Snp 4581218792Snp memset(&c, 0, sizeof(c)); 4582228561Snp INIT_CMD(c, RESET, WRITE); 4583228561Snp c.val = htonl(reset); 4584218792Snp return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); 4585218792Snp} 4586218792Snp 4587218792Snp/** 4588237436Snp * t4_fw_halt - issue a reset/halt to FW and put uP into RESET 4589237436Snp * @adap: the adapter 4590237436Snp * @mbox: mailbox to use for the FW RESET command (if desired) 4591237436Snp * @force: force uP into RESET even if FW RESET command fails 4592237436Snp * 4593237436Snp * Issues a RESET command to firmware (if desired) with a HALT indication 4594237436Snp * and then puts the microprocessor into RESET state. The RESET command 4595237436Snp * will only be issued if a legitimate mailbox is provided (mbox <= 4596237436Snp * M_PCIE_FW_MASTER). 4597237436Snp * 4598237436Snp * This is generally used in order for the host to safely manipulate the 4599237436Snp * adapter without fear of conflicting with whatever the firmware might 4600237436Snp * be doing. The only way out of this state is to RESTART the firmware 4601237436Snp * ... 4602237436Snp */ 4603237436Snpint t4_fw_halt(struct adapter *adap, unsigned int mbox, int force) 4604237436Snp{ 4605237436Snp int ret = 0; 4606237436Snp 4607237436Snp /* 4608237436Snp * If a legitimate mailbox is provided, issue a RESET command 4609237436Snp * with a HALT indication. 4610237436Snp */ 4611237436Snp if (mbox <= M_PCIE_FW_MASTER) { 4612237436Snp struct fw_reset_cmd c; 4613237436Snp 4614237436Snp memset(&c, 0, sizeof(c)); 4615237436Snp INIT_CMD(c, RESET, WRITE); 4616237436Snp c.val = htonl(F_PIORST | F_PIORSTMODE); 4617237436Snp c.halt_pkd = htonl(F_FW_RESET_CMD_HALT); 4618237436Snp ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); 4619237436Snp } 4620237436Snp 4621237436Snp /* 4622237436Snp * Normally we won't complete the operation if the firmware RESET 4623237436Snp * command fails but if our caller insists we'll go ahead and put the 4624237436Snp * uP into RESET. This can be useful if the firmware is hung or even 4625237436Snp * missing ... We'll have to take the risk of putting the uP into 4626237436Snp * RESET without the cooperation of firmware in that case. 4627237436Snp * 4628237436Snp * We also force the firmware's HALT flag to be on in case we bypassed 4629237436Snp * the firmware RESET command above or we're dealing with old firmware 4630237436Snp * which doesn't have the HALT capability. This will serve as a flag 4631237436Snp * for the incoming firmware to know that it's coming out of a HALT 4632237436Snp * rather than a RESET ... if it's new enough to understand that ... 4633237436Snp */ 4634237436Snp if (ret == 0 || force) { 4635237436Snp t4_set_reg_field(adap, A_CIM_BOOT_CFG, F_UPCRST, F_UPCRST); 4636237436Snp t4_set_reg_field(adap, A_PCIE_FW, F_PCIE_FW_HALT, F_PCIE_FW_HALT); 4637237436Snp } 4638237436Snp 4639237436Snp /* 4640237436Snp * And we always return the result of the firmware RESET command 4641237436Snp * even when we force the uP into RESET ... 4642237436Snp */ 4643237436Snp return ret; 4644237436Snp} 4645237436Snp 4646237436Snp/** 4647237436Snp * t4_fw_restart - restart the firmware by taking the uP out of RESET 4648237436Snp * @adap: the adapter 4649237436Snp * @reset: if we want to do a RESET to restart things 4650237436Snp * 4651237436Snp * Restart firmware previously halted by t4_fw_halt(). On successful 4652237436Snp * return the previous PF Master remains as the new PF Master and there 4653237436Snp * is no need to issue a new HELLO command, etc. 4654237436Snp * 4655237436Snp * We do this in two ways: 4656237436Snp * 4657237436Snp * 1. If we're dealing with newer firmware we'll simply want to take 4658237436Snp * the chip's microprocessor out of RESET. This will cause the 4659237436Snp * firmware to start up from its start vector. And then we'll loop 4660237436Snp * until the firmware indicates it's started again (PCIE_FW.HALT 4661237436Snp * reset to 0) or we timeout. 4662237436Snp * 4663237436Snp * 2. If we're dealing with older firmware then we'll need to RESET 4664237436Snp * the chip since older firmware won't recognize the PCIE_FW.HALT 4665237436Snp * flag and automatically RESET itself on startup. 4666237436Snp */ 4667237436Snpint t4_fw_restart(struct adapter *adap, unsigned int mbox, int reset) 4668237436Snp{ 4669237436Snp if (reset) { 4670237436Snp /* 4671237436Snp * Since we're directing the RESET instead of the firmware 4672237436Snp * doing it automatically, we need to clear the PCIE_FW.HALT 4673237436Snp * bit. 4674237436Snp */ 4675237436Snp t4_set_reg_field(adap, A_PCIE_FW, F_PCIE_FW_HALT, 0); 4676237436Snp 4677237436Snp /* 4678237436Snp * If we've been given a valid mailbox, first try to get the 4679237436Snp * firmware to do the RESET. If that works, great and we can 4680237436Snp * return success. Otherwise, if we haven't been given a 4681237436Snp * valid mailbox or the RESET command failed, fall back to 4682237436Snp * hitting the chip with a hammer. 4683237436Snp */ 4684237436Snp if (mbox <= M_PCIE_FW_MASTER) { 4685237436Snp t4_set_reg_field(adap, A_CIM_BOOT_CFG, F_UPCRST, 0); 4686237436Snp msleep(100); 4687237436Snp if (t4_fw_reset(adap, mbox, 4688237436Snp F_PIORST | F_PIORSTMODE) == 0) 4689237436Snp return 0; 4690237436Snp } 4691237436Snp 4692237436Snp t4_write_reg(adap, A_PL_RST, F_PIORST | F_PIORSTMODE); 4693237436Snp msleep(2000); 4694237436Snp } else { 4695237436Snp int ms; 4696237436Snp 4697237436Snp t4_set_reg_field(adap, A_CIM_BOOT_CFG, F_UPCRST, 0); 4698237436Snp for (ms = 0; ms < FW_CMD_MAX_TIMEOUT; ) { 4699237436Snp if (!(t4_read_reg(adap, A_PCIE_FW) & F_PCIE_FW_HALT)) 4700237436Snp return FW_SUCCESS; 4701237436Snp msleep(100); 4702237436Snp ms += 100; 4703237436Snp } 4704237436Snp return -ETIMEDOUT; 4705237436Snp } 4706237436Snp return 0; 4707237436Snp} 4708237436Snp 4709237436Snp/** 4710237436Snp * t4_fw_upgrade - perform all of the steps necessary to upgrade FW 4711237436Snp * @adap: the adapter 4712237436Snp * @mbox: mailbox to use for the FW RESET command (if desired) 4713237436Snp * @fw_data: the firmware image to write 4714237436Snp * @size: image size 4715237436Snp * @force: force upgrade even if firmware doesn't cooperate 4716237436Snp * 4717237436Snp * Perform all of the steps necessary for upgrading an adapter's 4718237436Snp * firmware image. Normally this requires the cooperation of the 4719237436Snp * existing firmware in order to halt all existing activities 4720237436Snp * but if an invalid mailbox token is passed in we skip that step 4721237436Snp * (though we'll still put the adapter microprocessor into RESET in 4722237436Snp * that case). 4723237436Snp * 4724237436Snp * On successful return the new firmware will have been loaded and 4725237436Snp * the adapter will have been fully RESET losing all previous setup 4726237436Snp * state. On unsuccessful return the adapter may be completely hosed ... 4727237436Snp * positive errno indicates that the adapter is ~probably~ intact, a 4728237436Snp * negative errno indicates that things are looking bad ... 4729237436Snp */ 4730237436Snpint t4_fw_upgrade(struct adapter *adap, unsigned int mbox, 4731237436Snp const u8 *fw_data, unsigned int size, int force) 4732237436Snp{ 4733237436Snp const struct fw_hdr *fw_hdr = (const struct fw_hdr *)fw_data; 4734252661Snp unsigned int bootstrap = ntohl(fw_hdr->magic) == FW_HDR_MAGIC_BOOTSTRAP; 4735237436Snp int reset, ret; 4736237436Snp 4737252661Snp if (!bootstrap) { 4738252661Snp ret = t4_fw_halt(adap, mbox, force); 4739252661Snp if (ret < 0 && !force) 4740252661Snp return ret; 4741252661Snp } 4742237436Snp 4743237436Snp ret = t4_load_fw(adap, fw_data, size); 4744252661Snp if (ret < 0 || bootstrap) 4745237436Snp return ret; 4746237436Snp 4747237436Snp /* 4748237436Snp * Older versions of the firmware don't understand the new 4749237436Snp * PCIE_FW.HALT flag and so won't know to perform a RESET when they 4750237436Snp * restart. So for newly loaded older firmware we'll have to do the 4751237436Snp * RESET for it so it starts up on a clean slate. We can tell if 4752237436Snp * the newly loaded firmware will handle this right by checking 4753237436Snp * its header flags to see if it advertises the capability. 4754237436Snp */ 4755237436Snp reset = ((ntohl(fw_hdr->flags) & FW_HDR_FLAGS_RESET_HALT) == 0); 4756237436Snp return t4_fw_restart(adap, mbox, reset); 4757237436Snp} 4758237436Snp 4759237436Snp/** 4760228561Snp * t4_fw_initialize - ask FW to initialize the device 4761218792Snp * @adap: the adapter 4762218792Snp * @mbox: mailbox to use for the FW command 4763218792Snp * 4764228561Snp * Issues a command to FW to partially initialize the device. This 4765228561Snp * performs initialization that generally doesn't depend on user input. 4766218792Snp */ 4767228561Snpint t4_fw_initialize(struct adapter *adap, unsigned int mbox) 4768218792Snp{ 4769228561Snp struct fw_initialize_cmd c; 4770218792Snp 4771218792Snp memset(&c, 0, sizeof(c)); 4772228561Snp INIT_CMD(c, INITIALIZE, WRITE); 4773218792Snp return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); 4774218792Snp} 4775218792Snp 4776218792Snp/** 4777218792Snp * t4_query_params - query FW or device parameters 4778218792Snp * @adap: the adapter 4779218792Snp * @mbox: mailbox to use for the FW command 4780218792Snp * @pf: the PF 4781218792Snp * @vf: the VF 4782218792Snp * @nparams: the number of parameters 4783218792Snp * @params: the parameter names 4784218792Snp * @val: the parameter values 4785218792Snp * 4786218792Snp * Reads the value of FW or device parameters. Up to 7 parameters can be 4787218792Snp * queried at once. 4788218792Snp */ 4789218792Snpint t4_query_params(struct adapter *adap, unsigned int mbox, unsigned int pf, 4790218792Snp unsigned int vf, unsigned int nparams, const u32 *params, 4791218792Snp u32 *val) 4792218792Snp{ 4793218792Snp int i, ret; 4794218792Snp struct fw_params_cmd c; 4795218792Snp __be32 *p = &c.param[0].mnem; 4796218792Snp 4797218792Snp if (nparams > 7) 4798218792Snp return -EINVAL; 4799218792Snp 4800218792Snp memset(&c, 0, sizeof(c)); 4801218792Snp c.op_to_vfn = htonl(V_FW_CMD_OP(FW_PARAMS_CMD) | F_FW_CMD_REQUEST | 4802218792Snp F_FW_CMD_READ | V_FW_PARAMS_CMD_PFN(pf) | 4803218792Snp V_FW_PARAMS_CMD_VFN(vf)); 4804218792Snp c.retval_len16 = htonl(FW_LEN16(c)); 4805218792Snp 4806250090Snp for (i = 0; i < nparams; i++, p += 2, params++) 4807250090Snp *p = htonl(*params); 4808218792Snp 4809218792Snp ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); 4810218792Snp if (ret == 0) 4811218792Snp for (i = 0, p = &c.param[0].val; i < nparams; i++, p += 2) 4812218792Snp *val++ = ntohl(*p); 4813218792Snp return ret; 4814218792Snp} 4815218792Snp 4816218792Snp/** 4817218792Snp * t4_set_params - sets FW or device parameters 4818218792Snp * @adap: the adapter 4819218792Snp * @mbox: mailbox to use for the FW command 4820218792Snp * @pf: the PF 4821218792Snp * @vf: the VF 4822218792Snp * @nparams: the number of parameters 4823218792Snp * @params: the parameter names 4824218792Snp * @val: the parameter values 4825218792Snp * 4826218792Snp * Sets the value of FW or device parameters. Up to 7 parameters can be 4827218792Snp * specified at once. 4828218792Snp */ 4829218792Snpint t4_set_params(struct adapter *adap, unsigned int mbox, unsigned int pf, 4830218792Snp unsigned int vf, unsigned int nparams, const u32 *params, 4831218792Snp const u32 *val) 4832218792Snp{ 4833218792Snp struct fw_params_cmd c; 4834218792Snp __be32 *p = &c.param[0].mnem; 4835218792Snp 4836218792Snp if (nparams > 7) 4837218792Snp return -EINVAL; 4838218792Snp 4839218792Snp memset(&c, 0, sizeof(c)); 4840218792Snp c.op_to_vfn = htonl(V_FW_CMD_OP(FW_PARAMS_CMD) | F_FW_CMD_REQUEST | 4841218792Snp F_FW_CMD_WRITE | V_FW_PARAMS_CMD_PFN(pf) | 4842218792Snp V_FW_PARAMS_CMD_VFN(vf)); 4843218792Snp c.retval_len16 = htonl(FW_LEN16(c)); 4844218792Snp 4845218792Snp while (nparams--) { 4846250090Snp *p++ = htonl(*params); 4847250090Snp params++; 4848250090Snp *p++ = htonl(*val); 4849250090Snp val++; 4850218792Snp } 4851218792Snp 4852218792Snp return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); 4853218792Snp} 4854218792Snp 4855218792Snp/** 4856218792Snp * t4_cfg_pfvf - configure PF/VF resource limits 4857218792Snp * @adap: the adapter 4858218792Snp * @mbox: mailbox to use for the FW command 4859218792Snp * @pf: the PF being configured 4860218792Snp * @vf: the VF being configured 4861218792Snp * @txq: the max number of egress queues 4862218792Snp * @txq_eth_ctrl: the max number of egress Ethernet or control queues 4863218792Snp * @rxqi: the max number of interrupt-capable ingress queues 4864218792Snp * @rxq: the max number of interruptless ingress queues 4865218792Snp * @tc: the PCI traffic class 4866218792Snp * @vi: the max number of virtual interfaces 4867218792Snp * @cmask: the channel access rights mask for the PF/VF 4868218792Snp * @pmask: the port access rights mask for the PF/VF 4869218792Snp * @nexact: the maximum number of exact MPS filters 4870218792Snp * @rcaps: read capabilities 4871218792Snp * @wxcaps: write/execute capabilities 4872218792Snp * 4873218792Snp * Configures resource limits and capabilities for a physical or virtual 4874218792Snp * function. 4875218792Snp */ 4876218792Snpint t4_cfg_pfvf(struct adapter *adap, unsigned int mbox, unsigned int pf, 4877218792Snp unsigned int vf, unsigned int txq, unsigned int txq_eth_ctrl, 4878218792Snp unsigned int rxqi, unsigned int rxq, unsigned int tc, 4879218792Snp unsigned int vi, unsigned int cmask, unsigned int pmask, 4880218792Snp unsigned int nexact, unsigned int rcaps, unsigned int wxcaps) 4881218792Snp{ 4882218792Snp struct fw_pfvf_cmd c; 4883218792Snp 4884218792Snp memset(&c, 0, sizeof(c)); 4885218792Snp c.op_to_vfn = htonl(V_FW_CMD_OP(FW_PFVF_CMD) | F_FW_CMD_REQUEST | 4886218792Snp F_FW_CMD_WRITE | V_FW_PFVF_CMD_PFN(pf) | 4887218792Snp V_FW_PFVF_CMD_VFN(vf)); 4888218792Snp c.retval_len16 = htonl(FW_LEN16(c)); 4889218792Snp c.niqflint_niq = htonl(V_FW_PFVF_CMD_NIQFLINT(rxqi) | 4890218792Snp V_FW_PFVF_CMD_NIQ(rxq)); 4891218792Snp c.type_to_neq = htonl(V_FW_PFVF_CMD_CMASK(cmask) | 4892218792Snp V_FW_PFVF_CMD_PMASK(pmask) | 4893218792Snp V_FW_PFVF_CMD_NEQ(txq)); 4894218792Snp c.tc_to_nexactf = htonl(V_FW_PFVF_CMD_TC(tc) | V_FW_PFVF_CMD_NVI(vi) | 4895218792Snp V_FW_PFVF_CMD_NEXACTF(nexact)); 4896218792Snp c.r_caps_to_nethctrl = htonl(V_FW_PFVF_CMD_R_CAPS(rcaps) | 4897218792Snp V_FW_PFVF_CMD_WX_CAPS(wxcaps) | 4898218792Snp V_FW_PFVF_CMD_NETHCTRL(txq_eth_ctrl)); 4899218792Snp return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); 4900218792Snp} 4901218792Snp 4902218792Snp/** 4903237436Snp * t4_alloc_vi_func - allocate a virtual interface 4904218792Snp * @adap: the adapter 4905218792Snp * @mbox: mailbox to use for the FW command 4906218792Snp * @port: physical port associated with the VI 4907218792Snp * @pf: the PF owning the VI 4908218792Snp * @vf: the VF owning the VI 4909218792Snp * @nmac: number of MAC addresses needed (1 to 5) 4910218792Snp * @mac: the MAC addresses of the VI 4911218792Snp * @rss_size: size of RSS table slice associated with this VI 4912237436Snp * @portfunc: which Port Application Function MAC Address is desired 4913237436Snp * @idstype: Intrusion Detection Type 4914218792Snp * 4915218792Snp * Allocates a virtual interface for the given physical port. If @mac is 4916218792Snp * not %NULL it contains the MAC addresses of the VI as assigned by FW. 4917218792Snp * @mac should be large enough to hold @nmac Ethernet addresses, they are 4918218792Snp * stored consecutively so the space needed is @nmac * 6 bytes. 4919218792Snp * Returns a negative error number or the non-negative VI id. 4920218792Snp */ 4921237436Snpint t4_alloc_vi_func(struct adapter *adap, unsigned int mbox, 4922237436Snp unsigned int port, unsigned int pf, unsigned int vf, 4923270297Snp unsigned int nmac, u8 *mac, u16 *rss_size, 4924237436Snp unsigned int portfunc, unsigned int idstype) 4925218792Snp{ 4926218792Snp int ret; 4927218792Snp struct fw_vi_cmd c; 4928218792Snp 4929218792Snp memset(&c, 0, sizeof(c)); 4930218792Snp c.op_to_vfn = htonl(V_FW_CMD_OP(FW_VI_CMD) | F_FW_CMD_REQUEST | 4931218792Snp F_FW_CMD_WRITE | F_FW_CMD_EXEC | 4932218792Snp V_FW_VI_CMD_PFN(pf) | V_FW_VI_CMD_VFN(vf)); 4933218792Snp c.alloc_to_len16 = htonl(F_FW_VI_CMD_ALLOC | FW_LEN16(c)); 4934237436Snp c.type_to_viid = htons(V_FW_VI_CMD_TYPE(idstype) | 4935237436Snp V_FW_VI_CMD_FUNC(portfunc)); 4936218792Snp c.portid_pkd = V_FW_VI_CMD_PORTID(port); 4937218792Snp c.nmac = nmac - 1; 4938218792Snp 4939218792Snp ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); 4940218792Snp if (ret) 4941218792Snp return ret; 4942218792Snp 4943218792Snp if (mac) { 4944218792Snp memcpy(mac, c.mac, sizeof(c.mac)); 4945218792Snp switch (nmac) { 4946218792Snp case 5: 4947218792Snp memcpy(mac + 24, c.nmac3, sizeof(c.nmac3)); 4948218792Snp case 4: 4949218792Snp memcpy(mac + 18, c.nmac2, sizeof(c.nmac2)); 4950218792Snp case 3: 4951218792Snp memcpy(mac + 12, c.nmac1, sizeof(c.nmac1)); 4952218792Snp case 2: 4953218792Snp memcpy(mac + 6, c.nmac0, sizeof(c.nmac0)); 4954218792Snp } 4955218792Snp } 4956218792Snp if (rss_size) 4957247289Snp *rss_size = G_FW_VI_CMD_RSSSIZE(ntohs(c.norss_rsssize)); 4958237436Snp return G_FW_VI_CMD_VIID(htons(c.type_to_viid)); 4959218792Snp} 4960218792Snp 4961218792Snp/** 4962237436Snp * t4_alloc_vi - allocate an [Ethernet Function] virtual interface 4963237436Snp * @adap: the adapter 4964237436Snp * @mbox: mailbox to use for the FW command 4965237436Snp * @port: physical port associated with the VI 4966237436Snp * @pf: the PF owning the VI 4967237436Snp * @vf: the VF owning the VI 4968237436Snp * @nmac: number of MAC addresses needed (1 to 5) 4969237436Snp * @mac: the MAC addresses of the VI 4970237436Snp * @rss_size: size of RSS table slice associated with this VI 4971237436Snp * 4972237436Snp * backwards compatible and convieniance routine to allocate a Virtual 4973237436Snp * Interface with a Ethernet Port Application Function and Intrustion 4974237436Snp * Detection System disabled. 4975237436Snp */ 4976237436Snpint t4_alloc_vi(struct adapter *adap, unsigned int mbox, unsigned int port, 4977237436Snp unsigned int pf, unsigned int vf, unsigned int nmac, u8 *mac, 4978270297Snp u16 *rss_size) 4979237436Snp{ 4980237436Snp return t4_alloc_vi_func(adap, mbox, port, pf, vf, nmac, mac, rss_size, 4981237436Snp FW_VI_FUNC_ETH, 0); 4982237436Snp} 4983237436Snp 4984237436Snp/** 4985218792Snp * t4_free_vi - free a virtual interface 4986218792Snp * @adap: the adapter 4987218792Snp * @mbox: mailbox to use for the FW command 4988218792Snp * @pf: the PF owning the VI 4989218792Snp * @vf: the VF owning the VI 4990218792Snp * @viid: virtual interface identifiler 4991218792Snp * 4992218792Snp * Free a previously allocated virtual interface. 4993218792Snp */ 4994218792Snpint t4_free_vi(struct adapter *adap, unsigned int mbox, unsigned int pf, 4995218792Snp unsigned int vf, unsigned int viid) 4996218792Snp{ 4997218792Snp struct fw_vi_cmd c; 4998218792Snp 4999218792Snp memset(&c, 0, sizeof(c)); 5000218792Snp c.op_to_vfn = htonl(V_FW_CMD_OP(FW_VI_CMD) | 5001218792Snp F_FW_CMD_REQUEST | 5002218792Snp F_FW_CMD_EXEC | 5003218792Snp V_FW_VI_CMD_PFN(pf) | 5004218792Snp V_FW_VI_CMD_VFN(vf)); 5005218792Snp c.alloc_to_len16 = htonl(F_FW_VI_CMD_FREE | FW_LEN16(c)); 5006218792Snp c.type_to_viid = htons(V_FW_VI_CMD_VIID(viid)); 5007218792Snp 5008218792Snp return t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); 5009218792Snp} 5010218792Snp 5011218792Snp/** 5012218792Snp * t4_set_rxmode - set Rx properties of a virtual interface 5013218792Snp * @adap: the adapter 5014218792Snp * @mbox: mailbox to use for the FW command 5015218792Snp * @viid: the VI id 5016218792Snp * @mtu: the new MTU or -1 5017218792Snp * @promisc: 1 to enable promiscuous mode, 0 to disable it, -1 no change 5018218792Snp * @all_multi: 1 to enable all-multi mode, 0 to disable it, -1 no change 5019218792Snp * @bcast: 1 to enable broadcast Rx, 0 to disable it, -1 no change 5020218792Snp * @vlanex: 1 to enable HVLAN extraction, 0 to disable it, -1 no change 5021218792Snp * @sleep_ok: if true we may sleep while awaiting command completion 5022218792Snp * 5023218792Snp * Sets Rx properties of a virtual interface. 5024218792Snp */ 5025218792Snpint t4_set_rxmode(struct adapter *adap, unsigned int mbox, unsigned int viid, 5026218792Snp int mtu, int promisc, int all_multi, int bcast, int vlanex, 5027218792Snp bool sleep_ok) 5028218792Snp{ 5029218792Snp struct fw_vi_rxmode_cmd c; 5030218792Snp 5031218792Snp /* convert to FW values */ 5032218792Snp if (mtu < 0) 5033218792Snp mtu = M_FW_VI_RXMODE_CMD_MTU; 5034218792Snp if (promisc < 0) 5035218792Snp promisc = M_FW_VI_RXMODE_CMD_PROMISCEN; 5036218792Snp if (all_multi < 0) 5037218792Snp all_multi = M_FW_VI_RXMODE_CMD_ALLMULTIEN; 5038218792Snp if (bcast < 0) 5039218792Snp bcast = M_FW_VI_RXMODE_CMD_BROADCASTEN; 5040218792Snp if (vlanex < 0) 5041218792Snp vlanex = M_FW_VI_RXMODE_CMD_VLANEXEN; 5042218792Snp 5043218792Snp memset(&c, 0, sizeof(c)); 5044218792Snp c.op_to_viid = htonl(V_FW_CMD_OP(FW_VI_RXMODE_CMD) | F_FW_CMD_REQUEST | 5045218792Snp F_FW_CMD_WRITE | V_FW_VI_RXMODE_CMD_VIID(viid)); 5046218792Snp c.retval_len16 = htonl(FW_LEN16(c)); 5047218792Snp c.mtu_to_vlanexen = htonl(V_FW_VI_RXMODE_CMD_MTU(mtu) | 5048218792Snp V_FW_VI_RXMODE_CMD_PROMISCEN(promisc) | 5049218792Snp V_FW_VI_RXMODE_CMD_ALLMULTIEN(all_multi) | 5050218792Snp V_FW_VI_RXMODE_CMD_BROADCASTEN(bcast) | 5051218792Snp V_FW_VI_RXMODE_CMD_VLANEXEN(vlanex)); 5052218792Snp return t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), NULL, sleep_ok); 5053218792Snp} 5054218792Snp 5055218792Snp/** 5056218792Snp * t4_alloc_mac_filt - allocates exact-match filters for MAC addresses 5057218792Snp * @adap: the adapter 5058218792Snp * @mbox: mailbox to use for the FW command 5059218792Snp * @viid: the VI id 5060218792Snp * @free: if true any existing filters for this VI id are first removed 5061218792Snp * @naddr: the number of MAC addresses to allocate filters for (up to 7) 5062218792Snp * @addr: the MAC address(es) 5063218792Snp * @idx: where to store the index of each allocated filter 5064218792Snp * @hash: pointer to hash address filter bitmap 5065218792Snp * @sleep_ok: call is allowed to sleep 5066218792Snp * 5067218792Snp * Allocates an exact-match filter for each of the supplied addresses and 5068218792Snp * sets it to the corresponding address. If @idx is not %NULL it should 5069218792Snp * have at least @naddr entries, each of which will be set to the index of 5070218792Snp * the filter allocated for the corresponding MAC address. If a filter 5071218792Snp * could not be allocated for an address its index is set to 0xffff. 5072218792Snp * If @hash is not %NULL addresses that fail to allocate an exact filter 5073218792Snp * are hashed and update the hash filter bitmap pointed at by @hash. 5074218792Snp * 5075218792Snp * Returns a negative error number or the number of filters allocated. 5076218792Snp */ 5077218792Snpint t4_alloc_mac_filt(struct adapter *adap, unsigned int mbox, 5078218792Snp unsigned int viid, bool free, unsigned int naddr, 5079218792Snp const u8 **addr, u16 *idx, u64 *hash, bool sleep_ok) 5080218792Snp{ 5081218792Snp int offset, ret = 0; 5082218792Snp struct fw_vi_mac_cmd c; 5083218792Snp unsigned int nfilters = 0; 5084248925Snp unsigned int max_naddr = is_t4(adap) ? 5085248925Snp NUM_MPS_CLS_SRAM_L_INSTANCES : 5086248925Snp NUM_MPS_T5_CLS_SRAM_L_INSTANCES; 5087218792Snp unsigned int rem = naddr; 5088218792Snp 5089248925Snp if (naddr > max_naddr) 5090218792Snp return -EINVAL; 5091218792Snp 5092218792Snp for (offset = 0; offset < naddr ; /**/) { 5093218792Snp unsigned int fw_naddr = (rem < ARRAY_SIZE(c.u.exact) 5094218792Snp ? rem 5095218792Snp : ARRAY_SIZE(c.u.exact)); 5096218792Snp size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd, 5097218792Snp u.exact[fw_naddr]), 16); 5098218792Snp struct fw_vi_mac_exact *p; 5099218792Snp int i; 5100218792Snp 5101218792Snp memset(&c, 0, sizeof(c)); 5102218792Snp c.op_to_viid = htonl(V_FW_CMD_OP(FW_VI_MAC_CMD) | 5103218792Snp F_FW_CMD_REQUEST | 5104218792Snp F_FW_CMD_WRITE | 5105218792Snp V_FW_CMD_EXEC(free) | 5106218792Snp V_FW_VI_MAC_CMD_VIID(viid)); 5107218792Snp c.freemacs_to_len16 = htonl(V_FW_VI_MAC_CMD_FREEMACS(free) | 5108218792Snp V_FW_CMD_LEN16(len16)); 5109218792Snp 5110218792Snp for (i = 0, p = c.u.exact; i < fw_naddr; i++, p++) { 5111218792Snp p->valid_to_idx = htons( 5112218792Snp F_FW_VI_MAC_CMD_VALID | 5113218792Snp V_FW_VI_MAC_CMD_IDX(FW_VI_MAC_ADD_MAC)); 5114218792Snp memcpy(p->macaddr, addr[offset+i], sizeof(p->macaddr)); 5115218792Snp } 5116218792Snp 5117218792Snp /* 5118218792Snp * It's okay if we run out of space in our MAC address arena. 5119218792Snp * Some of the addresses we submit may get stored so we need 5120218792Snp * to run through the reply to see what the results were ... 5121218792Snp */ 5122218792Snp ret = t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), &c, sleep_ok); 5123218792Snp if (ret && ret != -FW_ENOMEM) 5124218792Snp break; 5125218792Snp 5126218792Snp for (i = 0, p = c.u.exact; i < fw_naddr; i++, p++) { 5127218792Snp u16 index = G_FW_VI_MAC_CMD_IDX(ntohs(p->valid_to_idx)); 5128218792Snp 5129218792Snp if (idx) 5130248925Snp idx[offset+i] = (index >= max_naddr 5131218792Snp ? 0xffff 5132218792Snp : index); 5133248925Snp if (index < max_naddr) 5134218792Snp nfilters++; 5135218792Snp else if (hash) 5136218792Snp *hash |= (1ULL << hash_mac_addr(addr[offset+i])); 5137218792Snp } 5138218792Snp 5139218792Snp free = false; 5140218792Snp offset += fw_naddr; 5141218792Snp rem -= fw_naddr; 5142218792Snp } 5143218792Snp 5144218792Snp if (ret == 0 || ret == -FW_ENOMEM) 5145218792Snp ret = nfilters; 5146218792Snp return ret; 5147218792Snp} 5148218792Snp 5149218792Snp/** 5150218792Snp * t4_change_mac - modifies the exact-match filter for a MAC address 5151218792Snp * @adap: the adapter 5152218792Snp * @mbox: mailbox to use for the FW command 5153218792Snp * @viid: the VI id 5154218792Snp * @idx: index of existing filter for old value of MAC address, or -1 5155218792Snp * @addr: the new MAC address value 5156218792Snp * @persist: whether a new MAC allocation should be persistent 5157218792Snp * @add_smt: if true also add the address to the HW SMT 5158218792Snp * 5159218792Snp * Modifies an exact-match filter and sets it to the new MAC address if 5160218792Snp * @idx >= 0, or adds the MAC address to a new filter if @idx < 0. In the 5161218792Snp * latter case the address is added persistently if @persist is %true. 5162218792Snp * 5163218792Snp * Note that in general it is not possible to modify the value of a given 5164218792Snp * filter so the generic way to modify an address filter is to free the one 5165218792Snp * being used by the old address value and allocate a new filter for the 5166218792Snp * new address value. 5167218792Snp * 5168218792Snp * Returns a negative error number or the index of the filter with the new 5169218792Snp * MAC value. Note that this index may differ from @idx. 5170218792Snp */ 5171218792Snpint t4_change_mac(struct adapter *adap, unsigned int mbox, unsigned int viid, 5172218792Snp int idx, const u8 *addr, bool persist, bool add_smt) 5173218792Snp{ 5174218792Snp int ret, mode; 5175218792Snp struct fw_vi_mac_cmd c; 5176218792Snp struct fw_vi_mac_exact *p = c.u.exact; 5177248925Snp unsigned int max_mac_addr = is_t4(adap) ? 5178248925Snp NUM_MPS_CLS_SRAM_L_INSTANCES : 5179248925Snp NUM_MPS_T5_CLS_SRAM_L_INSTANCES; 5180218792Snp 5181218792Snp if (idx < 0) /* new allocation */ 5182218792Snp idx = persist ? FW_VI_MAC_ADD_PERSIST_MAC : FW_VI_MAC_ADD_MAC; 5183218792Snp mode = add_smt ? FW_VI_MAC_SMT_AND_MPSTCAM : FW_VI_MAC_MPS_TCAM_ENTRY; 5184218792Snp 5185218792Snp memset(&c, 0, sizeof(c)); 5186218792Snp c.op_to_viid = htonl(V_FW_CMD_OP(FW_VI_MAC_CMD) | F_FW_CMD_REQUEST | 5187218792Snp F_FW_CMD_WRITE | V_FW_VI_MAC_CMD_VIID(viid)); 5188218792Snp c.freemacs_to_len16 = htonl(V_FW_CMD_LEN16(1)); 5189218792Snp p->valid_to_idx = htons(F_FW_VI_MAC_CMD_VALID | 5190218792Snp V_FW_VI_MAC_CMD_SMAC_RESULT(mode) | 5191218792Snp V_FW_VI_MAC_CMD_IDX(idx)); 5192218792Snp memcpy(p->macaddr, addr, sizeof(p->macaddr)); 5193218792Snp 5194248925Snp ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); 5195218792Snp if (ret == 0) { 5196218792Snp ret = G_FW_VI_MAC_CMD_IDX(ntohs(p->valid_to_idx)); 5197248925Snp if (ret >= max_mac_addr) 5198218792Snp ret = -ENOMEM; 5199218792Snp } 5200218792Snp return ret; 5201218792Snp} 5202218792Snp 5203218792Snp/** 5204218792Snp * t4_set_addr_hash - program the MAC inexact-match hash filter 5205218792Snp * @adap: the adapter 5206218792Snp * @mbox: mailbox to use for the FW command 5207218792Snp * @viid: the VI id 5208218792Snp * @ucast: whether the hash filter should also match unicast addresses 5209218792Snp * @vec: the value to be written to the hash filter 5210218792Snp * @sleep_ok: call is allowed to sleep 5211218792Snp * 5212218792Snp * Sets the 64-bit inexact-match hash filter for a virtual interface. 5213218792Snp */ 5214218792Snpint t4_set_addr_hash(struct adapter *adap, unsigned int mbox, unsigned int viid, 5215218792Snp bool ucast, u64 vec, bool sleep_ok) 5216218792Snp{ 5217218792Snp struct fw_vi_mac_cmd c; 5218218792Snp 5219218792Snp memset(&c, 0, sizeof(c)); 5220218792Snp c.op_to_viid = htonl(V_FW_CMD_OP(FW_VI_MAC_CMD) | F_FW_CMD_REQUEST | 5221218792Snp F_FW_CMD_WRITE | V_FW_VI_ENABLE_CMD_VIID(viid)); 5222218792Snp c.freemacs_to_len16 = htonl(F_FW_VI_MAC_CMD_HASHVECEN | 5223218792Snp V_FW_VI_MAC_CMD_HASHUNIEN(ucast) | 5224218792Snp V_FW_CMD_LEN16(1)); 5225218792Snp c.u.hash.hashvec = cpu_to_be64(vec); 5226218792Snp return t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), NULL, sleep_ok); 5227218792Snp} 5228218792Snp 5229218792Snp/** 5230218792Snp * t4_enable_vi - enable/disable a virtual interface 5231218792Snp * @adap: the adapter 5232218792Snp * @mbox: mailbox to use for the FW command 5233218792Snp * @viid: the VI id 5234218792Snp * @rx_en: 1=enable Rx, 0=disable Rx 5235218792Snp * @tx_en: 1=enable Tx, 0=disable Tx 5236218792Snp * 5237218792Snp * Enables/disables a virtual interface. 5238218792Snp */ 5239218792Snpint t4_enable_vi(struct adapter *adap, unsigned int mbox, unsigned int viid, 5240218792Snp bool rx_en, bool tx_en) 5241218792Snp{ 5242218792Snp struct fw_vi_enable_cmd c; 5243218792Snp 5244218792Snp memset(&c, 0, sizeof(c)); 5245218792Snp c.op_to_viid = htonl(V_FW_CMD_OP(FW_VI_ENABLE_CMD) | F_FW_CMD_REQUEST | 5246218792Snp F_FW_CMD_EXEC | V_FW_VI_ENABLE_CMD_VIID(viid)); 5247218792Snp c.ien_to_len16 = htonl(V_FW_VI_ENABLE_CMD_IEN(rx_en) | 5248218792Snp V_FW_VI_ENABLE_CMD_EEN(tx_en) | FW_LEN16(c)); 5249218792Snp return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); 5250218792Snp} 5251218792Snp 5252218792Snp/** 5253218792Snp * t4_identify_port - identify a VI's port by blinking its LED 5254218792Snp * @adap: the adapter 5255218792Snp * @mbox: mailbox to use for the FW command 5256218792Snp * @viid: the VI id 5257218792Snp * @nblinks: how many times to blink LED at 2.5 Hz 5258218792Snp * 5259218792Snp * Identifies a VI's port by blinking its LED. 5260218792Snp */ 5261218792Snpint t4_identify_port(struct adapter *adap, unsigned int mbox, unsigned int viid, 5262218792Snp unsigned int nblinks) 5263218792Snp{ 5264218792Snp struct fw_vi_enable_cmd c; 5265218792Snp 5266218792Snp memset(&c, 0, sizeof(c)); 5267218792Snp c.op_to_viid = htonl(V_FW_CMD_OP(FW_VI_ENABLE_CMD) | F_FW_CMD_REQUEST | 5268218792Snp F_FW_CMD_EXEC | V_FW_VI_ENABLE_CMD_VIID(viid)); 5269218792Snp c.ien_to_len16 = htonl(F_FW_VI_ENABLE_CMD_LED | FW_LEN16(c)); 5270218792Snp c.blinkdur = htons(nblinks); 5271218792Snp return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); 5272218792Snp} 5273218792Snp 5274218792Snp/** 5275218792Snp * t4_iq_start_stop - enable/disable an ingress queue and its FLs 5276218792Snp * @adap: the adapter 5277218792Snp * @mbox: mailbox to use for the FW command 5278218792Snp * @start: %true to enable the queues, %false to disable them 5279218792Snp * @pf: the PF owning the queues 5280218792Snp * @vf: the VF owning the queues 5281218792Snp * @iqid: ingress queue id 5282218792Snp * @fl0id: FL0 queue id or 0xffff if no attached FL0 5283218792Snp * @fl1id: FL1 queue id or 0xffff if no attached FL1 5284218792Snp * 5285218792Snp * Starts or stops an ingress queue and its associated FLs, if any. 5286218792Snp */ 5287218792Snpint t4_iq_start_stop(struct adapter *adap, unsigned int mbox, bool start, 5288218792Snp unsigned int pf, unsigned int vf, unsigned int iqid, 5289218792Snp unsigned int fl0id, unsigned int fl1id) 5290218792Snp{ 5291218792Snp struct fw_iq_cmd c; 5292218792Snp 5293218792Snp memset(&c, 0, sizeof(c)); 5294218792Snp c.op_to_vfn = htonl(V_FW_CMD_OP(FW_IQ_CMD) | F_FW_CMD_REQUEST | 5295218792Snp F_FW_CMD_EXEC | V_FW_IQ_CMD_PFN(pf) | 5296218792Snp V_FW_IQ_CMD_VFN(vf)); 5297218792Snp c.alloc_to_len16 = htonl(V_FW_IQ_CMD_IQSTART(start) | 5298218792Snp V_FW_IQ_CMD_IQSTOP(!start) | FW_LEN16(c)); 5299218792Snp c.iqid = htons(iqid); 5300218792Snp c.fl0id = htons(fl0id); 5301218792Snp c.fl1id = htons(fl1id); 5302218792Snp return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); 5303218792Snp} 5304218792Snp 5305218792Snp/** 5306218792Snp * t4_iq_free - free an ingress queue and its FLs 5307218792Snp * @adap: the adapter 5308218792Snp * @mbox: mailbox to use for the FW command 5309218792Snp * @pf: the PF owning the queues 5310218792Snp * @vf: the VF owning the queues 5311218792Snp * @iqtype: the ingress queue type (FW_IQ_TYPE_FL_INT_CAP, etc.) 5312218792Snp * @iqid: ingress queue id 5313218792Snp * @fl0id: FL0 queue id or 0xffff if no attached FL0 5314218792Snp * @fl1id: FL1 queue id or 0xffff if no attached FL1 5315218792Snp * 5316218792Snp * Frees an ingress queue and its associated FLs, if any. 5317218792Snp */ 5318218792Snpint t4_iq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, 5319218792Snp unsigned int vf, unsigned int iqtype, unsigned int iqid, 5320218792Snp unsigned int fl0id, unsigned int fl1id) 5321218792Snp{ 5322218792Snp struct fw_iq_cmd c; 5323218792Snp 5324218792Snp memset(&c, 0, sizeof(c)); 5325218792Snp c.op_to_vfn = htonl(V_FW_CMD_OP(FW_IQ_CMD) | F_FW_CMD_REQUEST | 5326218792Snp F_FW_CMD_EXEC | V_FW_IQ_CMD_PFN(pf) | 5327218792Snp V_FW_IQ_CMD_VFN(vf)); 5328218792Snp c.alloc_to_len16 = htonl(F_FW_IQ_CMD_FREE | FW_LEN16(c)); 5329218792Snp c.type_to_iqandstindex = htonl(V_FW_IQ_CMD_TYPE(iqtype)); 5330218792Snp c.iqid = htons(iqid); 5331218792Snp c.fl0id = htons(fl0id); 5332218792Snp c.fl1id = htons(fl1id); 5333218792Snp return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); 5334218792Snp} 5335218792Snp 5336218792Snp/** 5337218792Snp * t4_eth_eq_free - free an Ethernet egress queue 5338218792Snp * @adap: the adapter 5339218792Snp * @mbox: mailbox to use for the FW command 5340218792Snp * @pf: the PF owning the queue 5341218792Snp * @vf: the VF owning the queue 5342218792Snp * @eqid: egress queue id 5343218792Snp * 5344218792Snp * Frees an Ethernet egress queue. 5345218792Snp */ 5346218792Snpint t4_eth_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, 5347218792Snp unsigned int vf, unsigned int eqid) 5348218792Snp{ 5349218792Snp struct fw_eq_eth_cmd c; 5350218792Snp 5351218792Snp memset(&c, 0, sizeof(c)); 5352218792Snp c.op_to_vfn = htonl(V_FW_CMD_OP(FW_EQ_ETH_CMD) | F_FW_CMD_REQUEST | 5353218792Snp F_FW_CMD_EXEC | V_FW_EQ_ETH_CMD_PFN(pf) | 5354218792Snp V_FW_EQ_ETH_CMD_VFN(vf)); 5355218792Snp c.alloc_to_len16 = htonl(F_FW_EQ_ETH_CMD_FREE | FW_LEN16(c)); 5356218792Snp c.eqid_pkd = htonl(V_FW_EQ_ETH_CMD_EQID(eqid)); 5357218792Snp return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); 5358218792Snp} 5359218792Snp 5360218792Snp/** 5361218792Snp * t4_ctrl_eq_free - free a control egress queue 5362218792Snp * @adap: the adapter 5363218792Snp * @mbox: mailbox to use for the FW command 5364218792Snp * @pf: the PF owning the queue 5365218792Snp * @vf: the VF owning the queue 5366218792Snp * @eqid: egress queue id 5367218792Snp * 5368218792Snp * Frees a control egress queue. 5369218792Snp */ 5370218792Snpint t4_ctrl_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, 5371218792Snp unsigned int vf, unsigned int eqid) 5372218792Snp{ 5373218792Snp struct fw_eq_ctrl_cmd c; 5374218792Snp 5375218792Snp memset(&c, 0, sizeof(c)); 5376218792Snp c.op_to_vfn = htonl(V_FW_CMD_OP(FW_EQ_CTRL_CMD) | F_FW_CMD_REQUEST | 5377218792Snp F_FW_CMD_EXEC | V_FW_EQ_CTRL_CMD_PFN(pf) | 5378218792Snp V_FW_EQ_CTRL_CMD_VFN(vf)); 5379218792Snp c.alloc_to_len16 = htonl(F_FW_EQ_CTRL_CMD_FREE | FW_LEN16(c)); 5380218792Snp c.cmpliqid_eqid = htonl(V_FW_EQ_CTRL_CMD_EQID(eqid)); 5381218792Snp return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); 5382218792Snp} 5383218792Snp 5384218792Snp/** 5385218792Snp * t4_ofld_eq_free - free an offload egress queue 5386218792Snp * @adap: the adapter 5387218792Snp * @mbox: mailbox to use for the FW command 5388218792Snp * @pf: the PF owning the queue 5389218792Snp * @vf: the VF owning the queue 5390218792Snp * @eqid: egress queue id 5391218792Snp * 5392218792Snp * Frees a control egress queue. 5393218792Snp */ 5394218792Snpint t4_ofld_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, 5395218792Snp unsigned int vf, unsigned int eqid) 5396218792Snp{ 5397218792Snp struct fw_eq_ofld_cmd c; 5398218792Snp 5399218792Snp memset(&c, 0, sizeof(c)); 5400218792Snp c.op_to_vfn = htonl(V_FW_CMD_OP(FW_EQ_OFLD_CMD) | F_FW_CMD_REQUEST | 5401218792Snp F_FW_CMD_EXEC | V_FW_EQ_OFLD_CMD_PFN(pf) | 5402218792Snp V_FW_EQ_OFLD_CMD_VFN(vf)); 5403218792Snp c.alloc_to_len16 = htonl(F_FW_EQ_OFLD_CMD_FREE | FW_LEN16(c)); 5404218792Snp c.eqid_pkd = htonl(V_FW_EQ_OFLD_CMD_EQID(eqid)); 5405218792Snp return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); 5406218792Snp} 5407218792Snp 5408218792Snp/** 5409218792Snp * t4_handle_fw_rpl - process a FW reply message 5410218792Snp * @adap: the adapter 5411218792Snp * @rpl: start of the FW message 5412218792Snp * 5413218792Snp * Processes a FW message, such as link state change messages. 5414218792Snp */ 5415218792Snpint t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl) 5416218792Snp{ 5417218792Snp u8 opcode = *(const u8 *)rpl; 5418237436Snp const struct fw_port_cmd *p = (const void *)rpl; 5419237436Snp unsigned int action = G_FW_PORT_CMD_ACTION(ntohl(p->action_to_len16)); 5420218792Snp 5421237436Snp if (opcode == FW_PORT_CMD && action == FW_PORT_ACTION_GET_PORT_INFO) { 5422237436Snp /* link/module state change message */ 5423218792Snp int speed = 0, fc = 0, i; 5424218792Snp int chan = G_FW_PORT_CMD_PORTID(ntohl(p->op_to_portid)); 5425218792Snp struct port_info *pi = NULL; 5426218792Snp struct link_config *lc; 5427218792Snp u32 stat = ntohl(p->u.info.lstatus_to_modtype); 5428218792Snp int link_ok = (stat & F_FW_PORT_CMD_LSTATUS) != 0; 5429218792Snp u32 mod = G_FW_PORT_CMD_MODTYPE(stat); 5430218792Snp 5431218792Snp if (stat & F_FW_PORT_CMD_RXPAUSE) 5432218792Snp fc |= PAUSE_RX; 5433218792Snp if (stat & F_FW_PORT_CMD_TXPAUSE) 5434218792Snp fc |= PAUSE_TX; 5435218792Snp if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_100M)) 5436218792Snp speed = SPEED_100; 5437218792Snp else if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_1G)) 5438218792Snp speed = SPEED_1000; 5439218792Snp else if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_10G)) 5440218792Snp speed = SPEED_10000; 5441250090Snp else if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_40G)) 5442250090Snp speed = SPEED_40000; 5443218792Snp 5444218792Snp for_each_port(adap, i) { 5445218792Snp pi = adap2pinfo(adap, i); 5446218792Snp if (pi->tx_chan == chan) 5447218792Snp break; 5448218792Snp } 5449218792Snp lc = &pi->link_cfg; 5450218792Snp 5451281207Snp if (mod != pi->mod_type) { 5452281207Snp pi->mod_type = mod; 5453281207Snp t4_os_portmod_changed(adap, i); 5454281207Snp } 5455218792Snp if (link_ok != lc->link_ok || speed != lc->speed || 5456218792Snp fc != lc->fc) { /* something changed */ 5457252747Snp int reason; 5458252747Snp 5459252747Snp if (!link_ok && lc->link_ok) 5460252747Snp reason = G_FW_PORT_CMD_LINKDNRC(stat); 5461252747Snp else 5462252747Snp reason = -1; 5463252747Snp 5464218792Snp lc->link_ok = link_ok; 5465218792Snp lc->speed = speed; 5466218792Snp lc->fc = fc; 5467250090Snp lc->supported = ntohs(p->u.info.pcap); 5468252747Snp t4_os_link_changed(adap, i, link_ok, reason); 5469218792Snp } 5470237436Snp } else { 5471237436Snp CH_WARN_RATELIMIT(adap, 5472237436Snp "Unknown firmware reply 0x%x (0x%x)\n", opcode, action); 5473237436Snp return -EINVAL; 5474218792Snp } 5475218792Snp return 0; 5476218792Snp} 5477218792Snp 5478218792Snp/** 5479218792Snp * get_pci_mode - determine a card's PCI mode 5480218792Snp * @adapter: the adapter 5481218792Snp * @p: where to store the PCI settings 5482218792Snp * 5483218792Snp * Determines a card's PCI mode and associated parameters, such as speed 5484218792Snp * and width. 5485218792Snp */ 5486218792Snpstatic void __devinit get_pci_mode(struct adapter *adapter, 5487218792Snp struct pci_params *p) 5488218792Snp{ 5489218792Snp u16 val; 5490218792Snp u32 pcie_cap; 5491218792Snp 5492218792Snp pcie_cap = t4_os_find_pci_capability(adapter, PCI_CAP_ID_EXP); 5493218792Snp if (pcie_cap) { 5494218792Snp t4_os_pci_read_cfg2(adapter, pcie_cap + PCI_EXP_LNKSTA, &val); 5495218792Snp p->speed = val & PCI_EXP_LNKSTA_CLS; 5496218792Snp p->width = (val & PCI_EXP_LNKSTA_NLW) >> 4; 5497218792Snp } 5498218792Snp} 5499218792Snp 5500218792Snp/** 5501218792Snp * init_link_config - initialize a link's SW state 5502218792Snp * @lc: structure holding the link state 5503218792Snp * @caps: link capabilities 5504218792Snp * 5505218792Snp * Initializes the SW state maintained for each link, including the link's 5506218792Snp * capabilities and default speed/flow-control/autonegotiation settings. 5507218792Snp */ 5508218792Snpstatic void __devinit init_link_config(struct link_config *lc, 5509218792Snp unsigned int caps) 5510218792Snp{ 5511218792Snp lc->supported = caps; 5512218792Snp lc->requested_speed = 0; 5513218792Snp lc->speed = 0; 5514218792Snp lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX; 5515218792Snp if (lc->supported & FW_PORT_CAP_ANEG) { 5516218792Snp lc->advertising = lc->supported & ADVERT_MASK; 5517218792Snp lc->autoneg = AUTONEG_ENABLE; 5518218792Snp lc->requested_fc |= PAUSE_AUTONEG; 5519218792Snp } else { 5520218792Snp lc->advertising = 0; 5521218792Snp lc->autoneg = AUTONEG_DISABLE; 5522218792Snp } 5523218792Snp} 5524218792Snp 5525218792Snpstatic int __devinit get_flash_params(struct adapter *adapter) 5526218792Snp{ 5527218792Snp int ret; 5528218792Snp u32 info = 0; 5529218792Snp 5530218792Snp ret = sf1_write(adapter, 1, 1, 0, SF_RD_ID); 5531218792Snp if (!ret) 5532218792Snp ret = sf1_read(adapter, 3, 0, 1, &info); 5533218792Snp t4_write_reg(adapter, A_SF_OP, 0); /* unlock SF */ 5534218792Snp if (ret < 0) 5535218792Snp return ret; 5536218792Snp 5537218792Snp if ((info & 0xff) != 0x20) /* not a Numonix flash */ 5538218792Snp return -EINVAL; 5539218792Snp info >>= 16; /* log2 of size */ 5540218792Snp if (info >= 0x14 && info < 0x18) 5541218792Snp adapter->params.sf_nsec = 1 << (info - 16); 5542218792Snp else if (info == 0x18) 5543218792Snp adapter->params.sf_nsec = 64; 5544218792Snp else 5545218792Snp return -EINVAL; 5546218792Snp adapter->params.sf_size = 1 << info; 5547218792Snp return 0; 5548218792Snp} 5549218792Snp 5550228561Snpstatic void __devinit set_pcie_completion_timeout(struct adapter *adapter, 5551228561Snp u8 range) 5552228561Snp{ 5553228561Snp u16 val; 5554228561Snp u32 pcie_cap; 5555228561Snp 5556228561Snp pcie_cap = t4_os_find_pci_capability(adapter, PCI_CAP_ID_EXP); 5557228561Snp if (pcie_cap) { 5558228561Snp t4_os_pci_read_cfg2(adapter, pcie_cap + PCI_EXP_DEVCTL2, &val); 5559228561Snp val &= 0xfff0; 5560228561Snp val |= range ; 5561228561Snp t4_os_pci_write_cfg2(adapter, pcie_cap + PCI_EXP_DEVCTL2, val); 5562228561Snp } 5563228561Snp} 5564228561Snp 5565218792Snp/** 5566218792Snp * t4_prep_adapter - prepare SW and HW for operation 5567218792Snp * @adapter: the adapter 5568218792Snp * @reset: if true perform a HW reset 5569218792Snp * 5570218792Snp * Initialize adapter SW state for the various HW modules, set initial 5571218792Snp * values for some adapter tunables, take PHYs out of reset, and 5572218792Snp * initialize the MDIO interface. 5573218792Snp */ 5574218792Snpint __devinit t4_prep_adapter(struct adapter *adapter) 5575218792Snp{ 5576218792Snp int ret; 5577248925Snp uint16_t device_id; 5578248925Snp uint32_t pl_rev; 5579218792Snp 5580218792Snp get_pci_mode(adapter, &adapter->params.pci); 5581218792Snp 5582248925Snp pl_rev = t4_read_reg(adapter, A_PL_REV); 5583248925Snp adapter->params.chipid = G_CHIPID(pl_rev); 5584248925Snp adapter->params.rev = G_REV(pl_rev); 5585248925Snp if (adapter->params.chipid == 0) { 5586248925Snp /* T4 did not have chipid in PL_REV (T5 onwards do) */ 5587248925Snp adapter->params.chipid = CHELSIO_T4; 5588248925Snp 5589248925Snp /* T4A1 chip is not supported */ 5590248925Snp if (adapter->params.rev == 1) { 5591248925Snp CH_ALERT(adapter, "T4 rev 1 chip is not supported.\n"); 5592248925Snp return -EINVAL; 5593248925Snp } 5594237436Snp } 5595218792Snp adapter->params.pci.vpd_cap_addr = 5596248925Snp t4_os_find_pci_capability(adapter, PCI_CAP_ID_VPD); 5597218792Snp 5598218792Snp ret = get_flash_params(adapter); 5599218792Snp if (ret < 0) 5600218792Snp return ret; 5601218792Snp 5602218792Snp ret = get_vpd_params(adapter, &adapter->params.vpd); 5603218792Snp if (ret < 0) 5604218792Snp return ret; 5605218792Snp 5606248925Snp /* Cards with real ASICs have the chipid in the PCIe device id */ 5607248925Snp t4_os_pci_read_cfg2(adapter, PCI_DEVICE_ID, &device_id); 5608248925Snp if (device_id >> 12 == adapter->params.chipid) 5609248925Snp adapter->params.cim_la_size = CIMLA_SIZE; 5610248925Snp else { 5611237436Snp /* FPGA */ 5612248925Snp adapter->params.fpga = 1; 5613218792Snp adapter->params.cim_la_size = 2 * CIMLA_SIZE; 5614218792Snp } 5615218792Snp 5616218792Snp init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd); 5617218792Snp 5618218792Snp /* 5619218792Snp * Default port and clock for debugging in case we can't reach FW. 5620218792Snp */ 5621218792Snp adapter->params.nports = 1; 5622218792Snp adapter->params.portvec = 1; 5623218792Snp adapter->params.vpd.cclk = 50000; 5624218792Snp 5625228561Snp /* Set pci completion timeout value to 4 seconds. */ 5626228561Snp set_pcie_completion_timeout(adapter, 0xd); 5627218792Snp return 0; 5628218792Snp} 5629218792Snp 5630252705Snp/** 5631252705Snp * t4_init_tp_params - initialize adap->params.tp 5632252705Snp * @adap: the adapter 5633252705Snp * 5634252705Snp * Initialize various fields of the adapter's TP Parameters structure. 5635252705Snp */ 5636252705Snpint __devinit t4_init_tp_params(struct adapter *adap) 5637252705Snp{ 5638252705Snp int chan; 5639252705Snp u32 v; 5640252705Snp 5641252705Snp v = t4_read_reg(adap, A_TP_TIMER_RESOLUTION); 5642252705Snp adap->params.tp.tre = G_TIMERRESOLUTION(v); 5643252705Snp adap->params.tp.dack_re = G_DELAYEDACKRESOLUTION(v); 5644252705Snp 5645252705Snp /* MODQ_REQ_MAP defaults to setting queues 0-3 to chan 0-3 */ 5646252705Snp for (chan = 0; chan < NCHAN; chan++) 5647252705Snp adap->params.tp.tx_modq[chan] = chan; 5648252705Snp 5649252705Snp t4_read_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, 5650252705Snp &adap->params.tp.ingress_config, 1, 5651252705Snp A_TP_INGRESS_CONFIG); 5652281259Snp refresh_vlan_pri_map(adap); 5653252705Snp 5654252705Snp return 0; 5655252705Snp} 5656252705Snp 5657252705Snp/** 5658252705Snp * t4_filter_field_shift - calculate filter field shift 5659252705Snp * @adap: the adapter 5660252705Snp * @filter_sel: the desired field (from TP_VLAN_PRI_MAP bits) 5661252705Snp * 5662252705Snp * Return the shift position of a filter field within the Compressed 5663252705Snp * Filter Tuple. The filter field is specified via its selection bit 5664252705Snp * within TP_VLAN_PRI_MAL (filter mode). E.g. F_VLAN. 5665252705Snp */ 5666252705Snpint t4_filter_field_shift(const struct adapter *adap, int filter_sel) 5667252705Snp{ 5668252705Snp unsigned int filter_mode = adap->params.tp.vlan_pri_map; 5669252705Snp unsigned int sel; 5670252705Snp int field_shift; 5671252705Snp 5672252705Snp if ((filter_mode & filter_sel) == 0) 5673252705Snp return -1; 5674252705Snp 5675252705Snp for (sel = 1, field_shift = 0; sel < filter_sel; sel <<= 1) { 5676252705Snp switch (filter_mode & sel) { 5677252705Snp case F_FCOE: field_shift += W_FT_FCOE; break; 5678252705Snp case F_PORT: field_shift += W_FT_PORT; break; 5679252705Snp case F_VNIC_ID: field_shift += W_FT_VNIC_ID; break; 5680252705Snp case F_VLAN: field_shift += W_FT_VLAN; break; 5681252705Snp case F_TOS: field_shift += W_FT_TOS; break; 5682252705Snp case F_PROTOCOL: field_shift += W_FT_PROTOCOL; break; 5683252705Snp case F_ETHERTYPE: field_shift += W_FT_ETHERTYPE; break; 5684252705Snp case F_MACMATCH: field_shift += W_FT_MACMATCH; break; 5685252705Snp case F_MPSHITTYPE: field_shift += W_FT_MPSHITTYPE; break; 5686252705Snp case F_FRAGMENTATION: field_shift += W_FT_FRAGMENTATION; break; 5687252705Snp } 5688252705Snp } 5689252705Snp return field_shift; 5690252705Snp} 5691252705Snp 5692218792Snpint __devinit t4_port_init(struct port_info *p, int mbox, int pf, int vf) 5693218792Snp{ 5694218792Snp u8 addr[6]; 5695218792Snp int ret, i, j; 5696218792Snp struct fw_port_cmd c; 5697270297Snp u16 rss_size; 5698218792Snp adapter_t *adap = p->adapter; 5699286897Snp u32 param, val; 5700218792Snp 5701218792Snp memset(&c, 0, sizeof(c)); 5702218792Snp 5703218792Snp for (i = 0, j = -1; i <= p->port_id; i++) { 5704218792Snp do { 5705218792Snp j++; 5706218792Snp } while ((adap->params.portvec & (1 << j)) == 0); 5707218792Snp } 5708218792Snp 5709218792Snp c.op_to_portid = htonl(V_FW_CMD_OP(FW_PORT_CMD) | 5710218792Snp F_FW_CMD_REQUEST | F_FW_CMD_READ | 5711218792Snp V_FW_PORT_CMD_PORTID(j)); 5712218792Snp c.action_to_len16 = htonl( 5713218792Snp V_FW_PORT_CMD_ACTION(FW_PORT_ACTION_GET_PORT_INFO) | 5714218792Snp FW_LEN16(c)); 5715218792Snp ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); 5716218792Snp if (ret) 5717218792Snp return ret; 5718218792Snp 5719218792Snp ret = t4_alloc_vi(adap, mbox, j, pf, vf, 1, addr, &rss_size); 5720218792Snp if (ret < 0) 5721218792Snp return ret; 5722218792Snp 5723218792Snp p->viid = ret; 5724218792Snp p->tx_chan = j; 5725265410Snp p->rx_chan_map = get_mps_bg_map(adap, j); 5726218792Snp p->lport = j; 5727218792Snp p->rss_size = rss_size; 5728218792Snp t4_os_set_hw_addr(adap, p->port_id, addr); 5729218792Snp 5730218792Snp ret = ntohl(c.u.info.lstatus_to_modtype); 5731218792Snp p->mdio_addr = (ret & F_FW_PORT_CMD_MDIOCAP) ? 5732218792Snp G_FW_PORT_CMD_MDIOADDR(ret) : -1; 5733218792Snp p->port_type = G_FW_PORT_CMD_PTYPE(ret); 5734218792Snp p->mod_type = G_FW_PORT_CMD_MODTYPE(ret); 5735218792Snp 5736218792Snp init_link_config(&p->link_cfg, ntohs(c.u.info.pcap)); 5737218792Snp 5738286897Snp param = V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | 5739286897Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_RSSINFO) | 5740286897Snp V_FW_PARAMS_PARAM_YZ(p->viid); 5741286897Snp ret = t4_query_params(adap, mbox, pf, vf, 1, ¶m, &val); 5742286897Snp if (ret) 5743286897Snp p->rss_base = 0xffff; 5744286897Snp else { 5745286897Snp /* MPASS((val >> 16) == rss_size); */ 5746286897Snp p->rss_base = val & 0xffff; 5747286897Snp } 5748286897Snp 5749218792Snp return 0; 5750218792Snp} 5751259142Snp 5752270297Snpint t4_sched_config(struct adapter *adapter, int type, int minmaxen, 5753270297Snp int sleep_ok) 5754259142Snp{ 5755259142Snp struct fw_sched_cmd cmd; 5756259142Snp 5757259142Snp memset(&cmd, 0, sizeof(cmd)); 5758259142Snp cmd.op_to_write = cpu_to_be32(V_FW_CMD_OP(FW_SCHED_CMD) | 5759259142Snp F_FW_CMD_REQUEST | 5760259142Snp F_FW_CMD_WRITE); 5761259142Snp cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd)); 5762259142Snp 5763259142Snp cmd.u.config.sc = FW_SCHED_SC_CONFIG; 5764259142Snp cmd.u.config.type = type; 5765259142Snp cmd.u.config.minmaxen = minmaxen; 5766259142Snp 5767259142Snp return t4_wr_mbox_meat(adapter,adapter->mbox, &cmd, sizeof(cmd), 5768270297Snp NULL, sleep_ok); 5769259142Snp} 5770259142Snp 5771259142Snpint t4_sched_params(struct adapter *adapter, int type, int level, int mode, 5772259142Snp int rateunit, int ratemode, int channel, int cl, 5773270297Snp int minrate, int maxrate, int weight, int pktsize, 5774270297Snp int sleep_ok) 5775259142Snp{ 5776259142Snp struct fw_sched_cmd cmd; 5777259142Snp 5778259142Snp memset(&cmd, 0, sizeof(cmd)); 5779259142Snp cmd.op_to_write = cpu_to_be32(V_FW_CMD_OP(FW_SCHED_CMD) | 5780259142Snp F_FW_CMD_REQUEST | 5781259142Snp F_FW_CMD_WRITE); 5782259142Snp cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd)); 5783259142Snp 5784259142Snp cmd.u.params.sc = FW_SCHED_SC_PARAMS; 5785259142Snp cmd.u.params.type = type; 5786259142Snp cmd.u.params.level = level; 5787259142Snp cmd.u.params.mode = mode; 5788259142Snp cmd.u.params.ch = channel; 5789259142Snp cmd.u.params.cl = cl; 5790259142Snp cmd.u.params.unit = rateunit; 5791259142Snp cmd.u.params.rate = ratemode; 5792259142Snp cmd.u.params.min = cpu_to_be32(minrate); 5793259142Snp cmd.u.params.max = cpu_to_be32(maxrate); 5794259142Snp cmd.u.params.weight = cpu_to_be16(weight); 5795259142Snp cmd.u.params.pktsize = cpu_to_be16(pktsize); 5796259142Snp 5797259142Snp return t4_wr_mbox_meat(adapter,adapter->mbox, &cmd, sizeof(cmd), 5798270297Snp NULL, sleep_ok); 5799259142Snp} 5800