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