/* * This file is part of the Chelsio T4 Ethernet driver for Linux. * * Copyright (c) 2003-2016 Chelsio Communications, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * OpenIB.org BSD license below: * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE.
*/
/** * t4_wait_op_done_val - wait until an operation is completed * @adapter: the adapter performing the operation * @reg: the register to check for completion * @mask: a single-bit field within @reg that indicates completion * @polarity: the value of the field when the operation is completed * @attempts: number of check iterations * @delay: delay in usecs between iterations * @valp: where to store the value of the register at completion time * * Wait until an operation is completed by checking a bit in a register * up to @attempts times. If @valp is not NULL the value of the register * at the time it indicated completion is stored there. Returns 0 if the * operation completes and -EAGAIN otherwise.
*/ staticint t4_wait_op_done_val(struct adapter *adapter, int reg, u32 mask, int polarity, int attempts, int delay, u32 *valp)
{ while (1) {
u32 val = t4_read_reg(adapter, reg);
if (!!(val & mask) == polarity) { if (valp)
*valp = val; return0;
} if (--attempts == 0) return -EAGAIN; if (delay)
udelay(delay);
}
}
staticinlineint t4_wait_op_done(struct adapter *adapter, int reg, u32 mask, int polarity, int attempts, int delay)
{ return t4_wait_op_done_val(adapter, reg, mask, polarity, attempts,
delay, NULL);
}
/** * t4_set_reg_field - set a register field to a value * @adapter: the adapter to program * @addr: the register address * @mask: specifies the portion of the register to modify * @val: the new value for the register field * * Sets a register field specified by the supplied mask to the * given value.
*/ void t4_set_reg_field(struct adapter *adapter, unsignedint addr, u32 mask,
u32 val)
{
u32 v = t4_read_reg(adapter, addr) & ~mask;
/** * t4_read_indirect - read indirectly addressed registers * @adap: the adapter * @addr_reg: register holding the indirect address * @data_reg: register holding the value of the indirect register * @vals: where the read register values are stored * @nregs: how many indirect registers to read * @start_idx: index of first indirect register to read * * Reads registers that are accessed indirectly through an address/data * register pair.
*/ void t4_read_indirect(struct adapter *adap, unsignedint addr_reg, unsignedint data_reg, u32 *vals, unsignedint nregs, unsignedint start_idx)
{ while (nregs--) {
t4_write_reg(adap, addr_reg, start_idx);
*vals++ = t4_read_reg(adap, data_reg);
start_idx++;
}
}
/** * t4_write_indirect - write indirectly addressed registers * @adap: the adapter * @addr_reg: register holding the indirect addresses * @data_reg: register holding the value for the indirect registers * @vals: values to write * @nregs: how many indirect registers to write * @start_idx: address of first indirect register to write * * Writes a sequential block of registers that are accessed indirectly * through an address/data register pair.
*/ void t4_write_indirect(struct adapter *adap, unsignedint addr_reg, unsignedint data_reg, const u32 *vals, unsignedint nregs, unsignedint start_idx)
{ while (nregs--) {
t4_write_reg(adap, addr_reg, start_idx++);
t4_write_reg(adap, data_reg, *vals++);
}
}
/* * Read a 32-bit PCI Configuration Space register via the PCI-E backdoor * mechanism. This guarantees that we get the real value even if we're * operating within a Virtual Machine and the Hypervisor is trapping our * Configuration Space accesses.
*/ void t4_hw_pci_read_cfg4(struct adapter *adap, int reg, u32 *val)
{
u32 req = FUNCTION_V(adap->pf) | REGISTER_V(reg);
/* Reset ENABLE to 0 so reads of PCIE_CFG_SPACE_DATA won't cause a * Configuration Space read. (None of the other fields matter when * ENABLE is 0 so a simple register write is easier than a * read-modify-write via t4_set_reg_field().)
*/
t4_write_reg(adap, PCIE_CFG_SPACE_REQ_A, 0);
}
/* * t4_report_fw_error - report firmware error * @adap: the adapter * * The adapter firmware can indicate error conditions to the host. * If the firmware has indicated an error, print out the reason for * the firmware error.
*/ staticvoid t4_report_fw_error(struct adapter *adap)
{ staticconstchar *const reason[] = { "Crash", /* PCIE_FW_EVAL_CRASH */ "During Device Preparation", /* PCIE_FW_EVAL_PREP */ "During Device Configuration", /* PCIE_FW_EVAL_CONF */ "During Device Initialization", /* PCIE_FW_EVAL_INIT */ "Unexpected Event", /* PCIE_FW_EVAL_UNEXPECTEDEVENT */ "Insufficient Airflow", /* PCIE_FW_EVAL_OVERHEAT */ "Device Shutdown", /* PCIE_FW_EVAL_DEVICESHUTDOWN */ "Reserved", /* reserved */
};
u32 pcie_fw;
/* * Get the reply to a mailbox command and store it in @rpl in big-endian order.
*/ staticvoid get_mbox_rpl(struct adapter *adap, __be64 *rpl, int nflit,
u32 mbox_addr)
{ for ( ; nflit; nflit--, mbox_addr += 8)
*rpl++ = cpu_to_be64(t4_read_reg64(adap, mbox_addr));
}
/* * Handle a FW assertion reported in a mailbox.
*/ staticvoid fw_asrt(struct adapter *adap, u32 mbox_addr)
{ struct fw_debug_cmd asrt;
/** * t4_record_mbox - record a Firmware Mailbox Command/Reply in the log * @adapter: the adapter * @cmd: the Firmware Mailbox Command or Reply * @size: command length in bytes * @access: the time (ms) needed to access the Firmware Mailbox * @execute: the time (ms) the command spent being executed
*/ staticvoid t4_record_mbox(struct adapter *adapter, const __be64 *cmd, unsignedint size, int access, int execute)
{ struct mbox_cmd_log *log = adapter->mbox_log; struct mbox_cmd *entry; int i;
for (i = 0; i < size / 8; i++)
entry->cmd[i] = be64_to_cpu(cmd[i]); while (i < MBOX_LEN / 8)
entry->cmd[i++] = 0;
entry->timestamp = jiffies;
entry->seqno = log->seqno++;
entry->access = access;
entry->execute = execute;
}
/** * t4_wr_mbox_meat_timeout - send a command to FW through the given mailbox * @adap: the adapter * @mbox: index of the mailbox to use * @cmd: the command to write * @size: command length in bytes * @rpl: where to optionally store the reply * @sleep_ok: if true we may sleep while awaiting command completion * @timeout: time to wait for command to finish before timing out * * Sends the given command to FW through the selected mailbox and waits * for the FW to execute the command. If @rpl is not %NULL it is used to * store the FW's reply to the command. The command and its optional * reply are of the same length. FW can take up to %FW_CMD_MAX_TIMEOUT ms * to respond. @sleep_ok determines whether we may sleep while awaiting * the response. If sleeping is allowed we use progressive backoff * otherwise we spin. * * The return value is 0 on success or a negative errno on failure. A * failure can happen either because we are not able to execute the * command or FW executes it but signals an error. In the latter case * the return value is the error code indicated by FW (negated).
*/ int t4_wr_mbox_meat_timeout(struct adapter *adap, int mbox, constvoid *cmd, int size, void *rpl, bool sleep_ok, int timeout)
{ staticconstint delay[] = { 1, 1, 3, 5, 10, 10, 20, 50, 100, 200
};
if ((size & 15) || size > MBOX_LEN) return -EINVAL;
/* * If the device is off-line, as in EEH, commands will time out. * Fail them early so we don't waste time waiting.
*/ if (adap->pdev->error_state != pci_channel_io_normal) return -EIO;
/* If we have a negative timeout, that implies that we can't sleep. */ if (timeout < 0) {
sleep_ok = false;
timeout = -timeout;
}
/* Queue ourselves onto the mailbox access list. When our entry is at * the front of the list, we have rights to access the mailbox. So we * wait [for a while] till we're at the front [or bail out with an * EBUSY] ...
*/
spin_lock_bh(&adap->mbox_lock);
list_add_tail(&entry.list, &adap->mlist.list);
spin_unlock_bh(&adap->mbox_lock);
delay_idx = 0;
ms = delay[0];
for (i = 0; ; i += ms) { /* If we've waited too long, return a busy indication. This * really ought to be based on our initial position in the * mailbox access list but this is a start. We very rarely * contend on access to the mailbox ...
*/
pcie_fw = t4_read_reg(adap, PCIE_FW_A); if (i > FW_CMD_MAX_TIMEOUT || (pcie_fw & PCIE_FW_ERR_F)) {
spin_lock_bh(&adap->mbox_lock);
list_del(&entry.list);
spin_unlock_bh(&adap->mbox_lock);
ret = (pcie_fw & PCIE_FW_ERR_F) ? -ENXIO : -EBUSY;
t4_record_mbox(adap, cmd, size, access, ret); return ret;
}
/* If we're at the head, break out and start the mailbox * protocol.
*/ if (list_first_entry(&adap->mlist.list, struct mbox_list,
list) == &entry) break;
/* Delay for a bit before checking again ... */ if (sleep_ok) {
ms = delay[delay_idx]; /* last element may repeat */ if (delay_idx < ARRAY_SIZE(delay) - 1)
delay_idx++;
msleep(ms);
} else {
mdelay(ms);
}
}
/* Loop trying to get ownership of the mailbox. Return an error * if we can't gain ownership.
*/
v = MBOWNER_G(t4_read_reg(adap, ctl_reg)); for (i = 0; v == MBOX_OWNER_NONE && i < 3; i++)
v = MBOWNER_G(t4_read_reg(adap, ctl_reg)); if (v != MBOX_OWNER_DRV) {
spin_lock_bh(&adap->mbox_lock);
list_del(&entry.list);
spin_unlock_bh(&adap->mbox_lock);
ret = (v == MBOX_OWNER_FW) ? -EBUSY : -ETIMEDOUT;
t4_record_mbox(adap, cmd, size, access, ret); return ret;
}
/* Copy in the new mailbox command and send it on its way ... */
t4_record_mbox(adap, cmd, size, access, 0); for (i = 0; i < size; i += 8)
t4_write_reg64(adap, data_reg + i, be64_to_cpu(*p++));
for (i = 0;
!((pcie_fw = t4_read_reg(adap, PCIE_FW_A)) & PCIE_FW_ERR_F) &&
i < timeout;
i += ms) { if (sleep_ok) {
ms = delay[delay_idx]; /* last element may repeat */ if (delay_idx < ARRAY_SIZE(delay) - 1)
delay_idx++;
msleep(ms);
} else
mdelay(ms);
v = t4_read_reg(adap, ctl_reg); if (MBOWNER_G(v) == MBOX_OWNER_DRV) { if (!(v & MBMSGVALID_F)) {
t4_write_reg(adap, ctl_reg, 0); continue;
}
get_mbox_rpl(adap, cmd_rpl, MBOX_LEN / 8, data_reg);
res = be64_to_cpu(cmd_rpl[0]);
if (FW_CMD_OP_G(res >> 32) == FW_DEBUG_CMD) {
fw_asrt(adap, data_reg);
res = FW_CMD_RETVAL_V(EIO);
} elseif (rpl) {
memcpy(rpl, cmd_rpl, size);
}
/** * t4_memory_rw_init - Get memory window relative offset, base, and size. * @adap: the adapter * @win: PCI-E Memory Window to use * @mtype: memory type: MEM_EDC0, MEM_EDC1, MEM_HMA or MEM_MC * @mem_off: memory relative offset with respect to @mtype. * @mem_base: configured memory base address. * @mem_aperture: configured memory window aperture. * * Get the configured memory window's relative offset, base, and size.
*/ int t4_memory_rw_init(struct adapter *adap, int win, int mtype, u32 *mem_off,
u32 *mem_base, u32 *mem_aperture)
{
u32 edc_size, mc_size, mem_reg;
/* Offset into the region of memory which is being accessed * MEM_EDC0 = 0 * MEM_EDC1 = 1 * MEM_MC = 2 -- MEM_MC for chips with only 1 memory controller * MEM_MC1 = 3 -- for chips with 2 memory controllers (e.g. T5) * MEM_HMA = 4
*/
edc_size = EDRAM0_SIZE_G(t4_read_reg(adap, MA_EDRAM0_BAR_A)); if (mtype == MEM_HMA) {
*mem_off = 2 * (edc_size * 1024 * 1024);
} elseif (mtype != MEM_MC1) {
*mem_off = (mtype * (edc_size * 1024 * 1024));
} else {
mc_size = EXT_MEM0_SIZE_G(t4_read_reg(adap,
MA_EXT_MEMORY0_BAR_A));
*mem_off = (MEM_MC0 * edc_size + mc_size) * 1024 * 1024;
}
/* Each PCI-E Memory Window is programmed with a window size -- or * "aperture" -- which controls the granularity of its mapping onto * adapter memory. We need to grab that aperture in order to know * how to use the specified window. The window is also programmed * with the base address of the Memory Window in BAR0's address * space. For T4 this is an absolute PCI-E Bus Address. For T5 * the address is relative to BAR0.
*/
mem_reg = t4_read_reg(adap,
PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A,
win)); /* a dead adapter will return 0xffffffff for PIO reads */ if (mem_reg == 0xffffffff) return -ENXIO;
/** * t4_memory_update_win - Move memory window to specified address. * @adap: the adapter * @win: PCI-E Memory Window to use * @addr: location to move. * * Move memory window to specified address.
*/ void t4_memory_update_win(struct adapter *adap, int win, u32 addr)
{
t4_write_reg(adap,
PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A, win),
addr); /* Read it back to ensure that changes propagate before we * attempt to use the new value.
*/
t4_read_reg(adap,
PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A, win));
}
/** * t4_memory_rw_residual - Read/Write residual data. * @adap: the adapter * @off: relative offset within residual to start read/write. * @addr: address within indicated memory type. * @buf: host memory buffer * @dir: direction of transfer T4_MEMORY_READ (1) or T4_MEMORY_WRITE (0) * * Read/Write residual data less than 32-bits.
*/ void t4_memory_rw_residual(struct adapter *adap, u32 off, u32 addr, u8 *buf, int dir)
{ union {
u32 word; char byte[4];
} last; unsignedchar *bp; int i;
if (dir == T4_MEMORY_READ) {
last.word = le32_to_cpu((__force __le32)
t4_read_reg(adap, addr)); for (bp = (unsignedchar *)buf, i = off; i < 4; i++)
bp[i] = last.byte[i];
} else {
last.word = *buf; for (i = off; i < 4; i++)
last.byte[i] = 0;
t4_write_reg(adap, addr,
(__force u32)cpu_to_le32(last.word));
}
}
/** * t4_memory_rw - read/write EDC 0, EDC 1 or MC via PCIE memory window * @adap: the adapter * @win: PCI-E Memory Window to use * @mtype: memory type: MEM_EDC0, MEM_EDC1 or MEM_MC * @addr: address within indicated memory type * @len: amount of memory to transfer * @hbuf: host memory buffer * @dir: direction of transfer T4_MEMORY_READ (1) or T4_MEMORY_WRITE (0) * * Reads/writes an [almost] arbitrary memory region in the firmware: the * firmware memory address and host buffer must be aligned on 32-bit * boundaries; the length may be arbitrary. The memory is transferred as * a raw byte sequence from/to the firmware's memory. If this memory * contains data structures which contain multi-byte integers, it's the * caller's responsibility to perform appropriate byte order conversions.
*/ int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr,
u32 len, void *hbuf, int dir)
{
u32 pos, offset, resid, memoffset;
u32 win_pf, mem_aperture, mem_base;
u32 *buf; int ret;
/* It's convenient to be able to handle lengths which aren't a * multiple of 32-bits because we often end up transferring files to * the firmware. So we'll handle that by normalizing the length here * and then handling any residual transfer at the end.
*/
resid = len & 0x3;
len -= resid;
ret = t4_memory_rw_init(adap, win, mtype, &memoffset, &mem_base,
&mem_aperture); if (ret) return ret;
/* Determine the PCIE_MEM_ACCESS_OFFSET */
addr = addr + memoffset;
/* Calculate our initial PCI-E Memory Window Position and Offset into * that Window.
*/
pos = addr & ~(mem_aperture - 1);
offset = addr - pos;
/* Set up initial PCI-E Memory Window to cover the start of our * transfer.
*/
t4_memory_update_win(adap, win, pos | win_pf);
/* Transfer data to/from the adapter as long as there's an integral * number of 32-bit transfers to complete. * * A note on Endianness issues: * * The "register" reads and writes below from/to the PCI-E Memory * Window invoke the standard adapter Big-Endian to PCI-E Link * Little-Endian "swizzel." As a result, if we have the following * data in adapter memory: * * Memory: ... | b0 | b1 | b2 | b3 | ... * Address: i+0 i+1 i+2 i+3 * * Then a read of the adapter memory via the PCI-E Memory Window * will yield: * * x = readl(i) * 31 0 * [ b3 | b2 | b1 | b0 ] * * If this value is stored into local memory on a Little-Endian system * it will show up correctly in local memory as: * * ( ..., b0, b1, b2, b3, ... ) * * But on a Big-Endian system, the store will show up in memory * incorrectly swizzled as: * * ( ..., b3, b2, b1, b0, ... ) * * So we need to account for this in the reads and writes to the * PCI-E Memory Window below by undoing the register read/write * swizzels.
*/ while (len > 0) { if (dir == T4_MEMORY_READ)
*buf++ = le32_to_cpu((__force __le32)t4_read_reg(adap,
mem_base + offset)); else
t4_write_reg(adap, mem_base + offset,
(__force u32)cpu_to_le32(*buf++));
offset += sizeof(__be32);
len -= sizeof(__be32);
/* If we've reached the end of our current window aperture, * move the PCI-E Memory Window on to the next. Note that * doing this here after "len" may be 0 allows us to set up * the PCI-E Memory Window for a possible final residual * transfer below ...
*/ if (offset == mem_aperture) {
pos += mem_aperture;
offset = 0;
t4_memory_update_win(adap, win, pos | win_pf);
}
}
/* If the original transfer had a length which wasn't a multiple of * 32-bits, now's where we need to finish off the transfer of the * residual amount. The PCI-E Memory Window has already been moved * above (if necessary) to cover this final transfer.
*/ if (resid)
t4_memory_rw_residual(adap, resid, mem_base + offset,
(u8 *)buf, dir);
return0;
}
/* Return the specified PCI-E Configuration Space register from our Physical * Function. We try first via a Firmware LDST Command since we prefer to let * the firmware own all of these registers, but if that fails we go for it * directly ourselves.
*/
u32 t4_read_pcie_cfg4(struct adapter *adap, int reg)
{
u32 val, ldst_addrspace;
/* If fw_attach != 0, construct and send the Firmware LDST Command to * retrieve the specified PCI-E Configuration Space register.
*/ struct fw_ldst_cmd ldst_cmd; int ret;
/* If the LDST Command succeeds, return the result, otherwise * fall through to reading it directly ourselves ...
*/
ret = t4_wr_mbox(adap, adap->mbox, &ldst_cmd, sizeof(ldst_cmd),
&ldst_cmd); if (ret == 0)
val = be32_to_cpu(ldst_cmd.u.pcie.data[0]); else /* Read the desired Configuration Space register via the PCI-E * Backdoor mechanism.
*/
t4_hw_pci_read_cfg4(adap, reg, &val); return val;
}
/* Get the window based on base passed to it. * Window aperture is currently unhandled, but there is no use case for it * right now
*/ static u32 t4_get_window(struct adapter *adap, u32 pci_base, u64 pci_mask,
u32 memwin_base)
{
u32 ret;
if (is_t4(adap->params.chip)) {
u32 bar0;
/* Truncation intentional: we only read the bottom 32-bits of * the 64-bit BAR0/BAR1 ... We use the hardware backdoor * mechanism to read BAR0 instead of using * pci_resource_start() because we could be operating from * within a Virtual Machine which is trapping our accesses to * our Configuration Space and we need to set up the PCI-E * Memory Window decoders with the actual addresses which will * be coming across the PCI-E link.
*/
bar0 = t4_read_pcie_cfg4(adap, pci_base);
bar0 &= pci_mask;
adap->t4_bar0 = bar0;
ret = bar0 + memwin_base;
} else { /* For T5, only relative offset inside the PCIe BAR is passed */
ret = memwin_base;
} return ret;
}
/* Get the default utility window (win0) used by everyone */
u32 t4_get_util_window(struct adapter *adap)
{ return t4_get_window(adap, PCI_BASE_ADDRESS_0,
PCI_BASE_ADDRESS_MEM_MASK, MEMWIN0_BASE);
}
/* Set up memory window for accessing adapter memory ranges. (Read * back MA register to ensure that changes propagate before we attempt * to use the new values.)
*/ void t4_setup_memwin(struct adapter *adap, u32 memwin_base, u32 window)
{
t4_write_reg(adap,
PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, window),
memwin_base | BIR_V(0) |
WINDOW_V(ilog2(MEMWIN0_APERTURE) - WINDOW_SHIFT_X));
t4_read_reg(adap,
PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, window));
}
/** * t4_get_regs_len - return the size of the chips register set * @adapter: the adapter * * Returns the size of the chip's BAR0 register space.
*/ unsignedint t4_get_regs_len(struct adapter *adapter)
{ unsignedint chip_version = CHELSIO_CHIP_VERSION(adapter->params.chip);
switch (chip_version) { case CHELSIO_T4: return T4_REGMAP_SIZE;
case CHELSIO_T5: case CHELSIO_T6: return T5_REGMAP_SIZE;
}
dev_err(adapter->pdev_dev, "Unsupported chip version %d\n", chip_version); return0;
}
/* Select the right set of register ranges to dump depending on the * adapter chip type.
*/ switch (chip_version) { case CHELSIO_T4:
reg_ranges = t4_reg_ranges;
reg_ranges_size = ARRAY_SIZE(t4_reg_ranges); break;
case CHELSIO_T5:
reg_ranges = t5_reg_ranges;
reg_ranges_size = ARRAY_SIZE(t5_reg_ranges); break;
case CHELSIO_T6:
reg_ranges = t6_reg_ranges;
reg_ranges_size = ARRAY_SIZE(t6_reg_ranges); break;
default:
dev_err(adap->pdev_dev, "Unsupported chip version %d\n", chip_version); return;
}
/* Clear the register buffer and insert the appropriate register * values selected by the above register ranges.
*/
memset(buf, 0, buf_size); for (range = 0; range < reg_ranges_size; range += 2) { unsignedint reg = reg_ranges[range]; unsignedint last_reg = reg_ranges[range + 1];
u32 *bufp = (u32 *)((char *)buf + reg);
/* Iterate across the register range filling in the register * buffer but don't write past the end of the register buffer.
*/ while (reg <= last_reg && bufp < buf_end) {
*bufp++ = t4_read_reg(adap, reg);
reg += sizeof(u32);
}
}
}
/** * t4_eeprom_ptov - translate a physical EEPROM address to virtual * @phys_addr: the physical EEPROM address * @fn: the PCI function number * @sz: size of function-specific area * * Translate a physical EEPROM address to virtual. The first 1K is * accessed through virtual addresses starting at 31K, the rest is * accessed through virtual addresses starting at 0. * * The mapping is as follows: * [0..1K) -> [31K..32K) * [1K..1K+A) -> [31K-A..31K) * [1K+A..ES) -> [0..ES-A-1K) * * where A = @fn * @sz, and ES = EEPROM size.
*/ int t4_eeprom_ptov(unsignedint phys_addr, unsignedint fn, unsignedint sz)
{
fn *= sz; if (phys_addr < 1024) return phys_addr + (31 << 10); if (phys_addr < 1024 + fn) return31744 - fn + phys_addr - 1024; if (phys_addr < EEPROMSIZE) return phys_addr - 1024 - fn; return -EINVAL;
}
/** * t4_seeprom_wp - enable/disable EEPROM write protection * @adapter: the adapter * @enable: whether to enable or disable write protection * * Enables or disables write protection on the serial EEPROM.
*/ int t4_seeprom_wp(struct adapter *adapter, bool enable)
{ unsignedint v = enable ? 0xc : 0; int ret = pci_write_vpd(adapter->pdev, EEPROM_STAT_ADDR, 4, &v); return ret < 0 ? ret : 0;
}
/** * t4_get_raw_vpd_params - read VPD parameters from VPD EEPROM * @adapter: adapter to read * @p: where to store the parameters * * Reads card parameters stored in VPD EEPROM.
*/ int t4_get_raw_vpd_params(struct adapter *adapter, struct vpd_params *p)
{ unsignedint id_len, pn_len, sn_len, na_len; int id, sn, pn, na, addr, ret = 0;
u8 *vpd, base_val = 0;
vpd = vmalloc(VPD_LEN); if (!vpd) return -ENOMEM;
/* Card information normally starts at VPD_BASE but early cards had * it at 0.
*/
ret = pci_read_vpd(adapter->pdev, VPD_BASE, 1, &base_val); if (ret < 0) goto out;
/** * t4_get_vpd_params - read VPD parameters & retrieve Core Clock * @adapter: adapter to read * @p: where to store the parameters * * Reads card parameters stored in VPD EEPROM and retrieves the Core * Clock. This can only be called after a connection to the firmware * is established.
*/ int t4_get_vpd_params(struct adapter *adapter, struct vpd_params *p)
{
u32 cclk_param, cclk_val; int ret;
/* Grab the raw VPD parameters.
*/
ret = t4_get_raw_vpd_params(adapter, p); if (ret) return ret;
/* Ask firmware for the Core Clock since it knows how to translate the * Reference Clock ('V2') VPD field into a Core Clock value ...
*/
cclk_param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_CCLK));
ret = t4_query_params(adapter, adapter->mbox, adapter->pf, 0, 1, &cclk_param, &cclk_val);
if (ret) return ret;
p->cclk = cclk_val;
return0;
}
/** * t4_get_pfres - retrieve VF resource limits * @adapter: the adapter * * Retrieves configured resource limits and capabilities for a physical * function. The results are stored in @adapter->pfres.
*/ int t4_get_pfres(struct adapter *adapter)
{ struct pf_resources *pfres = &adapter->params.pfres; struct fw_pfvf_cmd cmd, rpl; int v;
u32 word;
/* Execute PFVF Read command to get VF resource limits; bail out early * with error on command failure.
*/
memset(&cmd, 0, sizeof(cmd));
cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_PFVF_CMD) |
FW_CMD_REQUEST_F |
FW_CMD_READ_F |
FW_PFVF_CMD_PFN_V(adapter->pf) |
FW_PFVF_CMD_VFN_V(0));
cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
v = t4_wr_mbox(adapter, adapter->mbox, &cmd, sizeof(cmd), &rpl); if (v != FW_SUCCESS) return v;
/* Extract PF resource limits and return success.
*/
word = be32_to_cpu(rpl.niqflint_niq);
pfres->niqflint = FW_PFVF_CMD_NIQFLINT_G(word);
pfres->niq = FW_PFVF_CMD_NIQ_G(word);
word = be32_to_cpu(rpl.type_to_neq);
pfres->neq = FW_PFVF_CMD_NEQ_G(word);
pfres->pmask = FW_PFVF_CMD_PMASK_G(word);
/** * sf1_read - read data from the serial flash * @adapter: the adapter * @byte_cnt: number of bytes to read * @cont: whether another operation will be chained * @lock: whether to lock SF for PL access only * @valp: where to store the read data * * Reads up to 4 bytes of data from the serial flash. The location of * the read needs to be specified prior to calling this by issuing the * appropriate commands to the serial flash.
*/ staticint sf1_read(struct adapter *adapter, unsignedint byte_cnt, int cont, int lock, u32 *valp)
{ int ret;
/** * sf1_write - write data to the serial flash * @adapter: the adapter * @byte_cnt: number of bytes to write * @cont: whether another operation will be chained * @lock: whether to lock SF for PL access only * @val: value to write * * Writes up to 4 bytes of data to the serial flash. The location of * the write needs to be specified prior to calling this by issuing the * appropriate commands to the serial flash.
*/ staticint sf1_write(struct adapter *adapter, unsignedint byte_cnt, int cont, int lock, u32 val)
{ if (!byte_cnt || byte_cnt > 4) return -EINVAL; if (t4_read_reg(adapter, SF_OP_A) & SF_BUSY_F) return -EBUSY;
t4_write_reg(adapter, SF_DATA_A, val);
t4_write_reg(adapter, SF_OP_A, SF_LOCK_V(lock) |
SF_CONT_V(cont) | BYTECNT_V(byte_cnt - 1) | OP_V(1)); return t4_wait_op_done(adapter, SF_OP_A, SF_BUSY_F, 0, SF_ATTEMPTS, 5);
}
/** * flash_wait_op - wait for a flash operation to complete * @adapter: the adapter * @attempts: max number of polls of the status register * @delay: delay between polls in ms * * Wait for a flash operation to complete by polling the status register.
*/ staticint flash_wait_op(struct adapter *adapter, int attempts, int delay)
{ int ret;
u32 status;
while (1) { if ((ret = sf1_write(adapter, 1, 1, 1, SF_RD_STATUS)) != 0 ||
(ret = sf1_read(adapter, 1, 0, 1, &status)) != 0) return ret; if (!(status & 1)) return0; if (--attempts == 0) return -EAGAIN; if (delay)
msleep(delay);
}
}
/** * t4_read_flash - read words from serial flash * @adapter: the adapter * @addr: the start address for the read * @nwords: how many 32-bit words to read * @data: where to store the read data * @byte_oriented: whether to store data as bytes or as words * * Read the specified number of 32-bit words from the serial flash. * If @byte_oriented is set the read data is stored as a byte array * (i.e., big-endian), otherwise as 32-bit words in the platform's * natural endianness.
*/ int t4_read_flash(struct adapter *adapter, unsignedint addr, unsignedint nwords, u32 *data, int byte_oriented)
{ int ret;
for ( ; nwords; nwords--, data++) {
ret = sf1_read(adapter, 4, nwords > 1, nwords == 1, data); if (nwords == 1)
t4_write_reg(adapter, SF_OP_A, 0); /* unlock SF */ if (ret) return ret; if (byte_oriented)
*data = (__force __u32)(cpu_to_be32(*data));
} return0;
}
/** * t4_write_flash - write up to a page of data to the serial flash * @adapter: the adapter * @addr: the start address to write * @n: length of data to write in bytes * @data: the data to write * @byte_oriented: whether to store data as bytes or as words * * Writes up to a page of data (256 bytes) to the serial flash starting * at the given address. All the data must be written to the same page. * If @byte_oriented is set the write data is stored as byte stream * (i.e. matches what on disk), otherwise in big-endian.
*/ staticint t4_write_flash(struct adapter *adapter, unsignedint addr, unsignedint n, const u8 *data, bool byte_oriented)
{ unsignedint i, c, left, val, offset = addr & 0xff;
u32 buf[64]; int ret;
if (addr >= adapter->params.sf_size || offset + n > SF_PAGE_SIZE) return -EINVAL;
for (left = n; left; left -= c, data += c) {
c = min(left, 4U); for (val = 0, i = 0; i < c; ++i) { if (byte_oriented)
val = (val << 8) + data[i]; else
val = (val << 8) + data[c - i - 1];
}
ret = sf1_write(adapter, c, c != left, 1, val); if (ret) goto unlock;
}
ret = flash_wait_op(adapter, 8, 1); if (ret) goto unlock;
t4_write_reg(adapter, SF_OP_A, 0); /* unlock SF */
/* Read the page to verify the write succeeded */
ret = t4_read_flash(adapter, addr & ~0xff, ARRAY_SIZE(buf), buf,
byte_oriented); if (ret) return ret;
if (memcmp(data - n, (u8 *)buf + offset, n)) {
dev_err(adapter->pdev_dev, "failed to correctly write the flash page at %#x\n",
addr); return -EIO;
} return0;
/** * t4_get_fw_version - read the firmware version * @adapter: the adapter * @vers: where to place the version * * Reads the FW version from flash.
*/ int t4_get_fw_version(struct adapter *adapter, u32 *vers)
{ return t4_read_flash(adapter, FLASH_FW_START +
offsetof(struct fw_hdr, fw_ver), 1,
vers, 0);
}
/** * t4_get_bs_version - read the firmware bootstrap version * @adapter: the adapter * @vers: where to place the version * * Reads the FW Bootstrap version from flash.
*/ int t4_get_bs_version(struct adapter *adapter, u32 *vers)
{ return t4_read_flash(adapter, FLASH_FWBOOTSTRAP_START +
offsetof(struct fw_hdr, fw_ver), 1,
vers, 0);
}
/** * t4_get_tp_version - read the TP microcode version * @adapter: the adapter * @vers: where to place the version * * Reads the TP microcode version from flash.
*/ int t4_get_tp_version(struct adapter *adapter, u32 *vers)
{ return t4_read_flash(adapter, FLASH_FW_START +
offsetof(struct fw_hdr, tp_microcode_ver), 1, vers, 0);
}
/** * t4_get_exprom_version - return the Expansion ROM version (if any) * @adap: the adapter * @vers: where to place the version * * Reads the Expansion ROM header from FLASH and returns the version * number (if present) through the @vers return value pointer. We return * this in the Firmware Version Format since it's convenient. Return * 0 on success, -ENOENT if no Expansion ROM is present.
*/ int t4_get_exprom_version(struct adapter *adap, u32 *vers)
{ struct exprom_header { unsignedchar hdr_arr[16]; /* must start with 0x55aa */ unsignedchar hdr_ver[4]; /* Expansion ROM version */
} *hdr;
u32 exprom_header_buf[DIV_ROUND_UP(sizeof(struct exprom_header), sizeof(u32))]; int ret;
ret = t4_read_flash(adap, FLASH_EXP_ROM_START,
ARRAY_SIZE(exprom_header_buf), exprom_header_buf, 0); if (ret) return ret;
/** * t4_get_vpd_version - return the VPD version * @adapter: the adapter * @vers: where to place the version * * Reads the VPD via the Firmware interface (thus this can only be called * once we're ready to issue Firmware commands). The format of the * VPD version is adapter specific. Returns 0 on success, an error on * failure. * * Note that early versions of the Firmware didn't include the ability * to retrieve the VPD version, so we zero-out the return-value parameter * in that case to avoid leaving it with garbage in it. * * Also note that the Firmware will return its cached copy of the VPD * Revision ID, not the actual Revision ID as written in the Serial * EEPROM. This is only an issue if a new VPD has been written and the * Firmware/Chip haven't yet gone through a RESET sequence. So it's best * to defer calling this routine till after a FW_RESET_CMD has been issued * if the Host Driver will be performing a full adapter initialization.
*/ int t4_get_vpd_version(struct adapter *adapter, u32 *vers)
{
u32 vpdrev_param; int ret;
/** * t4_get_scfg_version - return the Serial Configuration version * @adapter: the adapter * @vers: where to place the version * * Reads the Serial Configuration Version via the Firmware interface * (thus this can only be called once we're ready to issue Firmware * commands). The format of the Serial Configuration version is * adapter specific. Returns 0 on success, an error on failure. * * Note that early versions of the Firmware didn't include the ability * to retrieve the Serial Configuration version, so we zero-out the * return-value parameter in that case to avoid leaving it with * garbage in it. * * Also note that the Firmware will return its cached copy of the Serial * Initialization Revision ID, not the actual Revision ID as written in * the Serial EEPROM. This is only an issue if a new VPD has been written * and the Firmware/Chip haven't yet gone through a RESET sequence. So * it's best to defer calling this routine till after a FW_RESET_CMD has * been issued if the Host Driver will be performing a full adapter * initialization.
*/ int t4_get_scfg_version(struct adapter *adapter, u32 *vers)
{
u32 scfgrev_param; int ret;
/** * t4_get_version_info - extract various chip/firmware version information * @adapter: the adapter * * Reads various chip/firmware version numbers and stores them into the * adapter Adapter Parameters structure. If any of the efforts fails * the first failure will be returned, but all of the version numbers * will be read.
*/ int t4_get_version_info(struct adapter *adapter)
{ int ret = 0;
#define FIRST_RET(__getvinfo) \ do { \ int __ret = __getvinfo; \ if (__ret && !ret) \
ret = __ret; \
} while (0)
/** * t4_dump_version_info - dump all of the adapter configuration IDs * @adapter: the adapter * * Dumps all of the various bits of adapter configuration version/revision * IDs information. This is typically called at some point after * t4_get_version_info() has been called.
*/ void t4_dump_version_info(struct adapter *adapter)
{ /* Device information */
dev_info(adapter->pdev_dev, "Chelsio %s rev %d\n",
adapter->params.vpd.id,
CHELSIO_CHIP_RELEASE(adapter->params.chip));
dev_info(adapter->pdev_dev, "S/N: %s, P/N: %s\n",
adapter->params.vpd.sn, adapter->params.vpd.pn);
/* Firmware Version */ if (!adapter->params.fw_vers)
dev_warn(adapter->pdev_dev, "No firmware loaded\n"); else
dev_info(adapter->pdev_dev, "Firmware version: %u.%u.%u.%u\n",
FW_HDR_FW_VER_MAJOR_G(adapter->params.fw_vers),
FW_HDR_FW_VER_MINOR_G(adapter->params.fw_vers),
FW_HDR_FW_VER_MICRO_G(adapter->params.fw_vers),
FW_HDR_FW_VER_BUILD_G(adapter->params.fw_vers));
/* Bootstrap Firmware Version. (Some adapters don't have Bootstrap * Firmware, so dev_info() is more appropriate here.)
*/ if (!adapter->params.bs_vers)
dev_info(adapter->pdev_dev, "No bootstrap loaded\n"); else
dev_info(adapter->pdev_dev, "Bootstrap version: %u.%u.%u.%u\n",
FW_HDR_FW_VER_MAJOR_G(adapter->params.bs_vers),
FW_HDR_FW_VER_MINOR_G(adapter->params.bs_vers),
FW_HDR_FW_VER_MICRO_G(adapter->params.bs_vers),
FW_HDR_FW_VER_BUILD_G(adapter->params.bs_vers));
/* TP Microcode Version */ if (!adapter->params.tp_vers)
dev_warn(adapter->pdev_dev, "No TP Microcode loaded\n"); else
dev_info(adapter->pdev_dev, "TP Microcode version: %u.%u.%u.%u\n",
FW_HDR_FW_VER_MAJOR_G(adapter->params.tp_vers),
FW_HDR_FW_VER_MINOR_G(adapter->params.tp_vers),
FW_HDR_FW_VER_MICRO_G(adapter->params.tp_vers),
FW_HDR_FW_VER_BUILD_G(adapter->params.tp_vers));
/* Expansion ROM version */ if (!adapter->params.er_vers)
dev_info(adapter->pdev_dev, "No Expansion ROM loaded\n"); else
dev_info(adapter->pdev_dev, "Expansion ROM version: %u.%u.%u.%u\n",
FW_HDR_FW_VER_MAJOR_G(adapter->params.er_vers),
FW_HDR_FW_VER_MINOR_G(adapter->params.er_vers),
FW_HDR_FW_VER_MICRO_G(adapter->params.er_vers),
FW_HDR_FW_VER_BUILD_G(adapter->params.er_vers));
/* Serial Configuration version */
dev_info(adapter->pdev_dev, "Serial Configuration version: %#x\n",
adapter->params.scfg_vers);
/* VPD Version */
dev_info(adapter->pdev_dev, "VPD version: %#x\n",
adapter->params.vpd_vers);
}
/** * t4_check_fw_version - check if the FW is supported with this driver * @adap: the adapter * * Checks if an adapter's FW is compatible with the driver. Returns 0 * if there's exact match, a negative error if the version could not be * read or there's a major version mismatch
*/ int t4_check_fw_version(struct adapter *adap)
{ int i, ret, major, minor, micro; int exp_major, exp_minor, exp_micro; unsignedint chip_version = CHELSIO_CHIP_VERSION(adap->params.chip);
ret = t4_get_fw_version(adap, &adap->params.fw_vers); /* Try multiple times before returning error */ for (i = 0; (ret == -EBUSY || ret == -EAGAIN) && i < 3; i++)
ret = t4_get_fw_version(adap, &adap->params.fw_vers);
if (ret) return ret;
major = FW_HDR_FW_VER_MAJOR_G(adap->params.fw_vers);
minor = FW_HDR_FW_VER_MINOR_G(adap->params.fw_vers);
micro = FW_HDR_FW_VER_MICRO_G(adap->params.fw_vers);
if (major < exp_major || (major == exp_major && minor < exp_minor) ||
(major == exp_major && minor == exp_minor && micro < exp_micro)) {
dev_err(adap->pdev_dev, "Card has firmware version %u.%u.%u, minimum " "supported firmware is %u.%u.%u.\n", major, minor,
micro, exp_major, exp_minor, exp_micro); return -EFAULT;
} return0;
}
/* Is the given firmware API compatible with the one the driver was compiled * with?
*/ staticint fw_compatible(conststruct fw_hdr *hdr1, conststruct fw_hdr *hdr2)
{
/* short circuit if it's the exact same firmware version */ if (hdr1->chip == hdr2->chip && hdr1->fw_ver == hdr2->fw_ver) return1;
/* The firmware in the filesystem is usable, but should it be installed? * This routine explains itself in detail if it indicates the filesystem * firmware should be installed.
*/ staticint should_install_fs_fw(struct adapter *adap, int card_fw_usable, int k, int c)
{ constchar *reason;
if (!card_fw_usable) {
reason = "incompatible or unusable"; goto install;
}
if (k > c) {
reason = "older than the version supported with this driver"; goto install;
}
return0;
install:
dev_err(adap->pdev_dev, "firmware on card (%u.%u.%u.%u) is %s, " "installing firmware %u.%u.%u.%u on card.\n",
FW_HDR_FW_VER_MAJOR_G(c), FW_HDR_FW_VER_MINOR_G(c),
FW_HDR_FW_VER_MICRO_G(c), FW_HDR_FW_VER_BUILD_G(c), reason,
FW_HDR_FW_VER_MAJOR_G(k), FW_HDR_FW_VER_MINOR_G(k),
FW_HDR_FW_VER_MICRO_G(k), FW_HDR_FW_VER_BUILD_G(k));
if (card_fw_usable && card_fw->fw_ver == drv_fw->fw_ver &&
(!fs_fw_usable || fs_fw->fw_ver == drv_fw->fw_ver)) { /* Common case: the firmware on the card is an exact match and * the filesystem one is an exact match too, or the filesystem * one is absent/incompatible.
*/
} elseif (fs_fw_usable && state == DEV_STATE_UNINIT &&
should_install_fs_fw(adap, card_fw_usable,
be32_to_cpu(fs_fw->fw_ver),
be32_to_cpu(card_fw->fw_ver))) {
ret = t4_fw_upgrade(adap, adap->mbox, fw_data,
fw_size, 0); if (ret != 0) {
dev_err(adap->pdev_dev, "failed to install firmware: %d\n", ret); goto bye;
}
/* Installed successfully, update the cached header too. */
*card_fw = *fs_fw;
card_fw_usable = 1;
*reset = 0; /* already reset as part of load_fw */
}
if (!card_fw_usable) {
uint32_t d, c, k;
d = be32_to_cpu(drv_fw->fw_ver);
c = be32_to_cpu(card_fw->fw_ver);
k = fs_fw ? be32_to_cpu(fs_fw->fw_ver) : 0;
dev_err(adap->pdev_dev, "Cannot find a usable firmware: " "chip state %d, " "driver compiled with %d.%d.%d.%d, " "card has %d.%d.%d.%d, filesystem has %d.%d.%d.%d\n",
state,
FW_HDR_FW_VER_MAJOR_G(d), FW_HDR_FW_VER_MINOR_G(d),
FW_HDR_FW_VER_MICRO_G(d), FW_HDR_FW_VER_BUILD_G(d),
FW_HDR_FW_VER_MAJOR_G(c), FW_HDR_FW_VER_MINOR_G(c),
FW_HDR_FW_VER_MICRO_G(c), FW_HDR_FW_VER_BUILD_G(c),
FW_HDR_FW_VER_MAJOR_G(k), FW_HDR_FW_VER_MINOR_G(k),
FW_HDR_FW_VER_MICRO_G(k), FW_HDR_FW_VER_BUILD_G(k));
ret = -EINVAL; goto bye;
}
/* We're using whatever's on the card and it's known to be good. */
adap->params.fw_vers = be32_to_cpu(card_fw->fw_ver);
adap->params.tp_vers = be32_to_cpu(card_fw->tp_microcode_ver);
bye: return ret;
}
/** * t4_flash_erase_sectors - erase a range of flash sectors * @adapter: the adapter * @start: the first sector to erase * @end: the last sector to erase * * Erases the sectors in the given inclusive range.
*/ staticint t4_flash_erase_sectors(struct adapter *adapter, int start, int end)
{ int ret = 0;
if (end >= adapter->params.sf_nsec) return -EINVAL;
/** * t4_flash_cfg_addr - return the address of the flash configuration file * @adapter: the adapter * * Return the address within the flash where the Firmware Configuration * File is stored.
*/ unsignedint t4_flash_cfg_addr(struct adapter *adapter)
{ if (adapter->params.sf_size == 0x100000) return FLASH_FPGA_CFG_START; else return FLASH_CFG_START;
}
/* Return TRUE if the specified firmware matches the adapter. I.e. T4 * firmware for T4 adapters, T5 firmware for T5 adapters, etc. We go ahead * and emit an error message for mismatched firmware to save our caller the * effort ...
*/ staticbool t4_fw_matches_chip(conststruct adapter *adap, conststruct fw_hdr *hdr)
{ /* The expression below will return FALSE for any unsupported adapter * which will keep us "honest" in the future ...
*/ if ((is_t4(adap->params.chip) && hdr->chip == FW_HDR_CHIP_T4) ||
(is_t5(adap->params.chip) && hdr->chip == FW_HDR_CHIP_T5) ||
(is_t6(adap->params.chip) && hdr->chip == FW_HDR_CHIP_T6)) returntrue;
dev_err(adap->pdev_dev, "FW image (%d) is not suitable for this adapter (%d)\n",
hdr->chip, CHELSIO_CHIP_VERSION(adap->params.chip)); returnfalse;
}
/** * t4_load_fw - download firmware * @adap: the adapter * @fw_data: the firmware image to write * @size: image size * * Write the supplied firmware image to the card's serial flash.
*/ int t4_load_fw(struct adapter *adap, const u8 *fw_data, unsignedint size)
{
u32 csum; int ret, addr; unsignedint i;
u8 first_page[SF_PAGE_SIZE]; const __be32 *p = (const __be32 *)fw_data; conststruct fw_hdr *hdr = (conststruct fw_hdr *)fw_data; unsignedint sf_sec_size = adap->params.sf_size / adap->params.sf_nsec; unsignedint fw_start_sec = FLASH_FW_START_SEC; unsignedint fw_size = FLASH_FW_MAX_SIZE; unsignedint fw_start = FLASH_FW_START;
if (!size) {
dev_err(adap->pdev_dev, "FW image has no data\n"); return -EINVAL;
} if (size & 511) {
dev_err(adap->pdev_dev, "FW image size not multiple of 512 bytes\n"); return -EINVAL;
} if ((unsignedint)be16_to_cpu(hdr->len512) * 512 != size) {
dev_err(adap->pdev_dev, "FW image size differs from size in FW header\n"); return -EINVAL;
} if (size > fw_size) {
dev_err(adap->pdev_dev, "FW image too large, max is %u bytes\n",
fw_size); return -EFBIG;
} if (!t4_fw_matches_chip(adap, hdr)) return -EINVAL;
for (csum = 0, i = 0; i < size / sizeof(csum); i++)
csum += be32_to_cpu(p[i]);
i = DIV_ROUND_UP(size, sf_sec_size); /* # of sectors spanned */
ret = t4_flash_erase_sectors(adap, fw_start_sec, fw_start_sec + i - 1); if (ret) goto out;
/* * We write the correct version at the end so the driver can see a bad * version if the FW write fails. Start by writing a copy of the * first page with a bad version.
*/
memcpy(first_page, fw_data, SF_PAGE_SIZE);
((struct fw_hdr *)first_page)->fw_ver = cpu_to_be32(0xffffffff);
ret = t4_write_flash(adap, fw_start, SF_PAGE_SIZE, first_page, true); if (ret) goto out;
addr = fw_start; for (size -= SF_PAGE_SIZE; size; size -= SF_PAGE_SIZE) {
addr += SF_PAGE_SIZE;
fw_data += SF_PAGE_SIZE;
ret = t4_write_flash(adap, addr, SF_PAGE_SIZE, fw_data, true); if (ret) goto out;
}
/** * t4_phy_fw_ver - return current PHY firmware version * @adap: the adapter * @phy_fw_ver: return value buffer for PHY firmware version * * Returns the current version of external PHY firmware on the * adapter.
*/ int t4_phy_fw_ver(struct adapter *adap, int *phy_fw_ver)
{
u32 param, val; int ret;
/** * t4_load_phy_fw - download port PHY firmware * @adap: the adapter * @win: the PCI-E Memory Window index to use for t4_memory_rw() * @phy_fw_version: function to check PHY firmware versions * @phy_fw_data: the PHY firmware image to write * @phy_fw_size: image size * * Transfer the specified PHY firmware to the adapter. If a non-NULL * @phy_fw_version is supplied, then it will be used to determine if * it's necessary to perform the transfer by comparing the version * of any existing adapter PHY firmware with that of the passed in * PHY firmware image. * * A negative error number will be returned if an error occurs. If * version number support is available and there's no need to upgrade * the firmware, 0 will be returned. If firmware is successfully * transferred to the adapter, 1 will be returned. * * NOTE: some adapters only have local RAM to store the PHY firmware. As * a result, a RESET of the adapter would cause that RAM to lose its * contents. Thus, loading PHY firmware on such adapters must happen * after any FW_RESET_CMDs ...
*/ int t4_load_phy_fw(struct adapter *adap, int win, int (*phy_fw_version)(const u8 *, size_t), const u8 *phy_fw_data, size_t phy_fw_size)
{ int cur_phy_fw_ver = 0, new_phy_fw_vers = 0; unsignedlong mtype = 0, maddr = 0;
u32 param, val; int ret;
/* If we have version number support, then check to see if the adapter * already has up-to-date PHY firmware loaded.
*/ if (phy_fw_version) {
new_phy_fw_vers = phy_fw_version(phy_fw_data, phy_fw_size);
ret = t4_phy_fw_ver(adap, &cur_phy_fw_ver); if (ret < 0) return ret;
/* Ask the firmware where it wants us to copy the PHY firmware image. * The size of the file requires a special version of the READ command * which will pass the file size via the values field in PARAMS_CMD and * retrieve the return value from firmware and place it in the same * buffer values
*/
param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_PHYFW) |
FW_PARAMS_PARAM_Y_V(adap->params.portvec) |
FW_PARAMS_PARAM_Z_V(FW_PARAMS_PARAM_DEV_PHYFW_DOWNLOAD));
val = phy_fw_size;
ret = t4_query_params_rw(adap, adap->mbox, adap->pf, 0, 1,
¶m, &val, 1, true); if (ret < 0) return ret;
mtype = val >> 8;
maddr = (val & 0xff) << 16;
/* Copy the supplied PHY Firmware image to the adapter memory location * allocated by the adapter firmware.
*/
spin_lock_bh(&adap->win0_lock);
ret = t4_memory_rw(adap, win, mtype, maddr,
phy_fw_size, (__be32 *)phy_fw_data,
T4_MEMORY_WRITE);
spin_unlock_bh(&adap->win0_lock); if (ret) return ret;
/* Tell the firmware that the PHY firmware image has been written to * RAM and it can now start copying it over to the PHYs. The chip * firmware will RESET the affected PHYs as part of this operation * leaving them running the new PHY firmware image.
*/
param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_PHYFW) |
FW_PARAMS_PARAM_Y_V(adap->params.portvec) |
FW_PARAMS_PARAM_Z_V(FW_PARAMS_PARAM_DEV_PHYFW_DOWNLOAD));
ret = t4_set_params_timeout(adap, adap->mbox, adap->pf, 0, 1,
¶m, &val, 30000); if (ret) return ret;
/* If we have version number support, then check to see that the new * firmware got loaded properly.
*/ if (phy_fw_version) {
ret = t4_phy_fw_ver(adap, &cur_phy_fw_ver); if (ret < 0) return ret;
if (cur_phy_fw_ver != new_phy_fw_vers) {
CH_WARN(adap, "PHY Firmware did not update: " "version on adapter %#x, " "version flashed %#x\n",
cur_phy_fw_ver, new_phy_fw_vers); return -ENXIO;
}
}
return1;
}
/** * t4_fwcache - firmware cache operation * @adap: the adapter * @op : the operation (flush or flush and invalidate)
*/ int t4_fwcache(struct adapter *adap, enum fw_params_param_dev_fwcache op)
{ struct fw_params_cmd c;
/* The ADVERT_MASK is used to mask out all of the Advertised Firmware Port * Capabilities which we control with separate controls -- see, for instance, * Pause Frames and Forward Error Correction. In order to determine what the * full set of Advertised Port Capabilities are, the base Advertised Port * Capabilities (masked by ADVERT_MASK) must be combined with the Advertised * Port Capabilities associated with those other controls. See * t4_link_acaps() for how this is done.
*/ #define ADVERT_MASK (FW_PORT_CAP32_SPEED_V(FW_PORT_CAP32_SPEED_M) | \
FW_PORT_CAP32_ANEG)
/** * fwcaps16_to_caps32 - convert 16-bit Port Capabilities to 32-bits * @caps16: a 16-bit Port Capabilities value * * Returns the equivalent 32-bit Port Capabilities value.
*/ static fw_port_cap32_t fwcaps16_to_caps32(fw_port_cap16_t caps16)
{
fw_port_cap32_t caps32 = 0;
#define CAP16_TO_CAP32(__cap) \ do { \ if (caps16 & FW_PORT_CAP_##__cap) \
caps32 |= FW_PORT_CAP32_##__cap; \
} while (0)
/** * fwcaps32_to_caps16 - convert 32-bit Port Capabilities to 16-bits * @caps32: a 32-bit Port Capabilities value * * Returns the equivalent 16-bit Port Capabilities value. Note that * not all 32-bit Port Capabilities can be represented in the 16-bit * Port Capabilities and some fields/values may not make it.
*/ static fw_port_cap16_t fwcaps32_to_caps16(fw_port_cap32_t caps32)
{
fw_port_cap16_t caps16 = 0;
#define CAP32_TO_CAP16(__cap) \ do { \ if (caps32 & FW_PORT_CAP32_##__cap) \
caps16 |= FW_PORT_CAP_##__cap; \
} while (0)
/* Translate Firmware Port Capabilities Pause specification to Common Code */ staticinlineenum cc_pause fwcap_to_cc_pause(fw_port_cap32_t fw_pause)
{ enum cc_pause cc_pause = 0;
if (fw_pause & FW_PORT_CAP32_FC_RX)
cc_pause |= PAUSE_RX; if (fw_pause & FW_PORT_CAP32_FC_TX)
cc_pause |= PAUSE_TX;
return cc_pause;
}
/* Translate Common Code Pause specification into Firmware Port Capabilities */ staticinline fw_port_cap32_t cc_to_fwcap_pause(enum cc_pause cc_pause)
{ /* Translate orthogonal RX/TX Pause Controls for L1 Configure * commands, etc.
*/
fw_port_cap32_t fw_pause = 0;
if (cc_pause & PAUSE_RX)
fw_pause |= FW_PORT_CAP32_FC_RX; if (cc_pause & PAUSE_TX)
fw_pause |= FW_PORT_CAP32_FC_TX; if (!(cc_pause & PAUSE_AUTONEG))
fw_pause |= FW_PORT_CAP32_FORCE_PAUSE;
/* Translate orthogonal Pause controls into IEEE 802.3 Pause, * Asymmetrical Pause for use in reporting to upper layer OS code, etc. * Note that these bits are ignored in L1 Configure commands.
*/ if (cc_pause & PAUSE_RX) { if (cc_pause & PAUSE_TX)
fw_pause |= FW_PORT_CAP32_802_3_PAUSE; else
fw_pause |= FW_PORT_CAP32_802_3_ASM_DIR |
FW_PORT_CAP32_802_3_PAUSE;
} elseif (cc_pause & PAUSE_TX) {
fw_pause |= FW_PORT_CAP32_802_3_ASM_DIR;
}
if (cc_fec & FEC_RS)
fw_fec |= FW_PORT_CAP32_FEC_RS; if (cc_fec & FEC_BASER_RS)
fw_fec |= FW_PORT_CAP32_FEC_BASER_RS;
return fw_fec;
}
/** * t4_link_acaps - compute Link Advertised Port Capabilities * @adapter: the adapter * @port: the Port ID * @lc: the Port's Link Configuration * * Synthesize the Advertised Port Capabilities we'll be using based on * the base Advertised Port Capabilities (which have been filtered by * ADVERT_MASK) plus the individual controls for things like Pause * Frames, Forward Error Correction, MDI, etc.
*/
fw_port_cap32_t t4_link_acaps(struct adapter *adapter, unsignedint port, struct link_config *lc)
{
fw_port_cap32_t fw_fc, fw_fec, acaps; unsignedint fw_mdi; char cc_fec;
/* Convert driver coding of Pause Frame Flow Control settings into the * Firmware's API.
*/
fw_fc = cc_to_fwcap_pause(lc->requested_fc);
/* Convert Common Code Forward Error Control settings into the * Firmware's API. If the current Requested FEC has "Automatic" * (IEEE 802.3) specified, then we use whatever the Firmware * sent us as part of its IEEE 802.3-based interpretation of * the Transceiver Module EPROM FEC parameters. Otherwise we * use whatever is in the current Requested FEC settings.
*/ if (lc->requested_fec & FEC_AUTO)
cc_fec = fwcap_to_cc_fec(lc->def_acaps); else
cc_fec = lc->requested_fec;
fw_fec = cc_to_fwcap_fec(cc_fec);
/* Figure out what our Requested Port Capabilities are going to be. * Note parallel structure in t4_handle_get_port_info() and * init_link_config().
*/ if (!(lc->pcaps & FW_PORT_CAP32_ANEG)) {
acaps = lc->acaps | fw_fc | fw_fec;
lc->fc = lc->requested_fc & ~PAUSE_AUTONEG;
lc->fec = cc_fec;
} elseif (lc->autoneg == AUTONEG_DISABLE) {
acaps = lc->speed_caps | fw_fc | fw_fec | fw_mdi;
lc->fc = lc->requested_fc & ~PAUSE_AUTONEG;
lc->fec = cc_fec;
} else {
acaps = lc->acaps | fw_fc | fw_fec | fw_mdi;
}
/* Some Requested Port Capabilities are trivially wrong if they exceed * the Physical Port Capabilities. We can check that here and provide * moderately useful feedback in the system log. * * Note that older Firmware doesn't have FW_PORT_CAP32_FORCE_PAUSE, so * we need to exclude this from this check in order to maintain * compatibility ...
*/ if ((acaps & ~lc->pcaps) & ~FW_PORT_CAP32_FORCE_PAUSE) {
dev_err(adapter->pdev_dev, "Requested Port Capabilities %#x exceed Physical Port Capabilities %#x\n",
acaps, lc->pcaps); return -EINVAL;
}
return acaps;
}
/** * t4_link_l1cfg_core - apply link configuration to MAC/PHY * @adapter: the adapter * @mbox: the Firmware Mailbox to use * @port: the Port ID * @lc: the Port's Link Configuration * @sleep_ok: if true we may sleep while awaiting command completion * @timeout: time to wait for command to finish before timing out * (negative implies @sleep_ok=false) * * Set up a port's MAC and PHY according to a desired link configuration. * - If the PHY can auto-negotiate first decide what to advertise, then * enable/disable auto-negotiation as desired, and reset. * - If the PHY does not auto-negotiate just reset it. * - If auto-negotiation is off set the MAC to the proper speed/duplex/FC, * otherwise do it later based on the outcome of auto-negotiation.
*/ int t4_link_l1cfg_core(struct adapter *adapter, unsignedint mbox, unsignedint port, struct link_config *lc,
u8 sleep_ok, int timeout)
{ unsignedint fw_caps = adapter->params.fw_caps_support; struct fw_port_cmd cmd;
fw_port_cap32_t rcap; int ret;
/* Compute our Requested Port Capabilities and send that on to the * Firmware.
*/
rcap = t4_link_acaps(adapter, port, lc);
memset(&cmd, 0, sizeof(cmd));
cmd.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PORT_CMD) |
FW_CMD_REQUEST_F | FW_CMD_EXEC_F |
FW_PORT_CMD_PORTID_V(port));
cmd.action_to_len16 =
cpu_to_be32(FW_PORT_CMD_ACTION_V(fw_caps == FW_CAPS16
? FW_PORT_ACTION_L1_CFG
: FW_PORT_ACTION_L1_CFG32) |
FW_LEN16(cmd)); if (fw_caps == FW_CAPS16)
cmd.u.l1cfg.rcap = cpu_to_be32(fwcaps32_to_caps16(rcap)); else
cmd.u.l1cfg32.rcap32 = cpu_to_be32(rcap);
ret = t4_wr_mbox_meat_timeout(adapter, mbox, &cmd, sizeof(cmd), NULL,
sleep_ok, timeout);
/* Unfortunately, even if the Requested Port Capabilities "fit" within * the Physical Port Capabilities, some combinations of features may * still not be legal. For example, 40Gb/s and Reed-Solomon Forward * Error Correction. So if the Firmware rejects the L1 Configure * request, flag that here.
*/ if (ret) {
dev_err(adapter->pdev_dev, "Requested Port Capabilities %#x rejected, error %d\n",
rcap, -ret); return ret;
} return0;
}
/** * t4_restart_aneg - restart autonegotiation * @adap: the adapter * @mbox: mbox to use for the FW command * @port: the port id * * Restarts autonegotiation for the selected port.
*/ int t4_restart_aneg(struct adapter *adap, unsignedint mbox, unsignedint port)
{ unsignedint fw_caps = adap->params.fw_caps_support; struct fw_port_cmd c;
struct intr_info { unsignedint mask; /* bits to check in interrupt status */ constchar *msg; /* message to print or NULL */ short stat_idx; /* stat counter to increment or -1 */ unsignedshort fatal; /* whether the condition reported is fatal */
int_handler_t int_handler; /* platform-specific int handler */
};
/** * t4_handle_intr_status - table driven interrupt handler * @adapter: the adapter that generated the interrupt * @reg: the interrupt status register to process * @acts: table of interrupt actions * * A table driven interrupt handler that applies a set of masks to an * interrupt status word and performs the corresponding actions if the * interrupts described by the mask have occurred. The actions include * optionally emitting a warning or alert message. The table is terminated * by an entry specifying mask 0. Returns the number of fatal interrupt * conditions.
*/ staticint t4_handle_intr_status(struct adapter *adapter, unsignedint reg, conststruct intr_info *acts)
{ int fatal = 0; unsignedint mask = 0; unsignedint status = t4_read_reg(adapter, reg);
for ( ; acts->mask; ++acts) { if (!(status & acts->mask)) continue; if (acts->fatal) {
fatal++;
dev_alert(adapter->pdev_dev, "%s (0x%x)\n", acts->msg,
status & acts->mask);
} elseif (acts->msg && printk_ratelimit())
dev_warn(adapter->pdev_dev, "%s (0x%x)\n", acts->msg,
status & acts->mask); if (acts->int_handler)
acts->int_handler(adapter);
mask |= acts->mask;
}
status &= mask; if (status) /* clear processed interrupts */
t4_write_reg(adapter, reg, status); return fatal;
}
perr = t4_read_reg(adapter, SGE_INT_CAUSE1_A); if (perr) {
v |= perr;
dev_alert(adapter->pdev_dev, "SGE Cause1 Parity Error %#x\n",
perr);
}
perr = t4_read_reg(adapter, SGE_INT_CAUSE2_A); if (perr) {
v |= perr;
dev_alert(adapter->pdev_dev, "SGE Cause2 Parity Error %#x\n",
perr);
}
if (CHELSIO_CHIP_VERSION(adapter->params.chip) >= CHELSIO_T5) {
perr = t4_read_reg(adapter, SGE_INT_CAUSE5_A); /* Parity error (CRC) for err_T_RxCRC is trivial, ignore it */
perr &= ~ERR_T_RXCRC_F; if (perr) {
v |= perr;
dev_alert(adapter->pdev_dev, "SGE Cause5 Parity Error %#x\n", perr);
}
}
v |= t4_handle_intr_status(adapter, SGE_INT_CAUSE3_A, sge_intr_info); if (CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5)
v |= t4_handle_intr_status(adapter, SGE_INT_CAUSE3_A,
t4t5_sge_intr_info);
err = t4_read_reg(adapter, SGE_ERROR_STATS_A); if (err & ERROR_QID_VALID_F) {
dev_err(adapter->pdev_dev, "SGE error for queue %u\n",
ERROR_QID_G(err)); if (err & UNCAPTURED_ERROR_F)
dev_err(adapter->pdev_dev, "SGE UNCAPTURED_ERROR set (clearing)\n");
t4_write_reg(adapter, SGE_ERROR_STATS_A, ERROR_QID_VALID_F |
UNCAPTURED_ERROR_F);
}
fw_err = t4_read_reg(adapter, PCIE_FW_A); if (fw_err & PCIE_FW_ERR_F)
t4_report_fw_error(adapter);
/* When the Firmware detects an internal error which normally * wouldn't raise a Host Interrupt, it forces a CIM Timer0 interrupt * in order to make sure the Host sees the Firmware Crash. So * if we have a Timer0 interrupt and don't see a Firmware Crash, * ignore the Timer0 interrupt.
*/
val = t4_read_reg(adapter, CIM_HOST_INT_CAUSE_A); if (val & TIMER0INT_F) if (!(fw_err & PCIE_FW_ERR_F) ||
(PCIE_FW_EVAL_G(fw_err) != PCIE_FW_EVAL_CRASH))
t4_write_reg(adapter, CIM_HOST_INT_CAUSE_A,
TIMER0INT_F);
/** * t4_slow_intr_handler - control path interrupt handler * @adapter: the adapter * * T4 interrupt handler for non-data global interrupt events, e.g., errors. * The designation 'slow' is because it involves register reads, while * data interrupts typically don't involve any MMIOs.
*/ int t4_slow_intr_handler(struct adapter *adapter)
{ /* There are rare cases where a PL_INT_CAUSE bit may end up getting * set when the corresponding PL_INT_ENABLE bit isn't set. It's * easiest just to mask that case here.
*/
u32 raw_cause = t4_read_reg(adapter, PL_INT_CAUSE_A);
u32 enable = t4_read_reg(adapter, PL_INT_ENABLE_A);
u32 cause = raw_cause & enable;
if (!(cause & GLBL_INTR_MASK)) return0; if (cause & CIM_F)
cim_intr_handler(adapter); if (cause & MPS_F)
mps_intr_handler(adapter); if (cause & NCSI_F)
ncsi_intr_handler(adapter); if (cause & PL_F)
pl_intr_handler(adapter); if (cause & SMB_F)
smb_intr_handler(adapter); if (cause & XGMAC0_F)
xgmac_intr_handler(adapter, 0); if (cause & XGMAC1_F)
xgmac_intr_handler(adapter, 1); if (cause & XGMAC_KR0_F)
xgmac_intr_handler(adapter, 2); if (cause & XGMAC_KR1_F)
xgmac_intr_handler(adapter, 3); if (cause & PCIE_F)
pcie_intr_handler(adapter); if (cause & MC_F)
mem_intr_handler(adapter, MEM_MC); if (is_t5(adapter->params.chip) && (cause & MC1_F))
mem_intr_handler(adapter, MEM_MC1); if (cause & EDC0_F)
mem_intr_handler(adapter, MEM_EDC0); if (cause & EDC1_F)
mem_intr_handler(adapter, MEM_EDC1); if (cause & LE_F)
le_intr_handler(adapter); if (cause & TP_F)
tp_intr_handler(adapter); if (cause & MA_F)
ma_intr_handler(adapter); if (cause & PM_TX_F)
pmtx_intr_handler(adapter); if (cause & PM_RX_F)
pmrx_intr_handler(adapter); if (cause & ULP_RX_F)
ulprx_intr_handler(adapter); if (cause & CPL_SWITCH_F)
cplsw_intr_handler(adapter); if (cause & SGE_F)
sge_intr_handler(adapter); if (cause & ULP_TX_F)
ulptx_intr_handler(adapter);
/* Clear the interrupts just processed for which we are the master. */
t4_write_reg(adapter, PL_INT_CAUSE_A, raw_cause & GLBL_INTR_MASK);
(void)t4_read_reg(adapter, PL_INT_CAUSE_A); /* flush */ return1;
}
/** * t4_intr_enable - enable interrupts * @adapter: the adapter whose interrupts should be enabled * * Enable PF-specific interrupts for the calling function and the top-level * interrupt concentrator for global interrupts. Interrupts are already * enabled at each module, here we just enable the roots of the interrupt * hierarchies. * * Note: this function should be called only when the driver manages * non PF-specific interrupts from the various HW modules. Only one PCI * function at a time should be doing this.
*/ void t4_intr_enable(struct adapter *adapter)
{
u32 val = 0;
u32 whoami = t4_read_reg(adapter, PL_WHOAMI_A);
u32 pf = CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5 ?
SOURCEPF_G(whoami) : T6_SOURCEPF_G(whoami);
/** * t4_intr_disable - disable interrupts * @adapter: the adapter whose interrupts should be disabled * * Disable interrupts. We only disable the top-level interrupt * concentrators. The caller must be a PCI function managing global * interrupts.
*/ void t4_intr_disable(struct adapter *adapter)
{
u32 whoami, pf;
/** * t4_config_rss_range - configure a portion of the RSS mapping table * @adapter: the adapter * @mbox: mbox to use for the FW command * @viid: virtual interface whose RSS subtable is to be written * @start: start entry in the table to write * @n: how many table entries to write * @rspq: values for the response queue lookup table * @nrspq: number of values in @rspq * * Programs the selected part of the VI's RSS mapping table with the * provided values. If @nrspq < @n the supplied values are used repeatedly * until the full table range is populated. * * The caller must ensure the values in @rspq are in the range allowed for * @viid.
*/ int t4_config_rss_range(struct adapter *adapter, int mbox, unsignedint viid, int start, int n, const u16 *rspq, unsignedint nrspq)
{ int ret; const u16 *rsp = rspq; const u16 *rsp_end = rspq + nrspq; struct fw_rss_ind_tbl_cmd cmd;
v = FW_RSS_IND_TBL_CMD_IQ0_V(*rsp); if (++rsp >= rsp_end)
rsp = rspq;
v |= FW_RSS_IND_TBL_CMD_IQ1_V(*rsp); if (++rsp >= rsp_end)
rsp = rspq;
v |= FW_RSS_IND_TBL_CMD_IQ2_V(*rsp); if (++rsp >= rsp_end)
rsp = rspq;
*qp++ = cpu_to_be32(v);
nq -= 3;
}
ret = t4_wr_mbox(adapter, mbox, &cmd, sizeof(cmd), NULL); if (ret) return ret;
} return0;
}
/** * t4_config_glbl_rss - configure the global RSS mode * @adapter: the adapter * @mbox: mbox to use for the FW command * @mode: global RSS mode * @flags: mode-specific flags * * Sets the global RSS mode.
*/ int t4_config_glbl_rss(struct adapter *adapter, int mbox, unsignedint mode, unsignedint flags)
{ struct fw_rss_glb_config_cmd c;
/** * t4_config_vi_rss - configure per VI RSS settings * @adapter: the adapter * @mbox: mbox to use for the FW command * @viid: the VI id * @flags: RSS flags * @defq: id of the default RSS queue for the VI. * * Configures VI-specific RSS properties.
*/ int t4_config_vi_rss(struct adapter *adapter, int mbox, unsignedint viid, unsignedint flags, unsignedint defq)
{ struct fw_rss_vi_config_cmd c;
/** * t4_read_rss - read the contents of the RSS mapping table * @adapter: the adapter * @map: holds the contents of the RSS mapping table * * Reads the contents of the RSS hash->queue mapping table.
*/ int t4_read_rss(struct adapter *adapter, u16 *map)
{ int i, ret, nentries;
u32 val;
nentries = t4_chip_rss_size(adapter); for (i = 0; i < nentries / 2; ++i) {
ret = rd_rss_row(adapter, i, &val); if (ret) return ret;
*map++ = LKPTBLQUEUE0_G(val);
*map++ = LKPTBLQUEUE1_G(val);
} return0;
}
/** * t4_tp_fw_ldst_rw - Access TP indirect register through LDST * @adap: the adapter * @cmd: TP fw ldst address space type * @vals: where the indirect register values are stored/written * @nregs: how many indirect registers to read/write * @start_index: index of first indirect register to read/write * @rw: Read (1) or Write (0) * @sleep_ok: if true we may sleep while awaiting command completion * * Access TP indirect registers through LDST
*/ staticint t4_tp_fw_ldst_rw(struct adapter *adap, int cmd, u32 *vals, unsignedint nregs, unsignedint start_index, unsignedint rw, bool sleep_ok)
{ int ret = 0; unsignedint i; struct fw_ldst_cmd c;
for (i = 0; i < nregs; i++) {
memset(&c, 0, sizeof(c));
c.op_to_addrspace = cpu_to_be32(FW_CMD_OP_V(FW_LDST_CMD) |
FW_CMD_REQUEST_F |
(rw ? FW_CMD_READ_F :
FW_CMD_WRITE_F) |
FW_LDST_CMD_ADDRSPACE_V(cmd));
c.cycles_to_len16 = cpu_to_be32(FW_LEN16(c));
if (rw)
vals[i] = be32_to_cpu(c.u.addrval.val);
} return0;
}
/** * t4_tp_indirect_rw - Read/Write TP indirect register through LDST or backdoor * @adap: the adapter * @reg_addr: Address Register * @reg_data: Data register * @buff: where the indirect register values are stored/written * @nregs: how many indirect registers to read/write * @start_index: index of first indirect register to read/write * @rw: READ(1) or WRITE(0) * @sleep_ok: if true we may sleep while awaiting command completion * * Read/Write TP indirect registers through LDST if possible. * Else, use backdoor access
**/ staticvoid t4_tp_indirect_rw(struct adapter *adap, u32 reg_addr, u32 reg_data,
u32 *buff, u32 nregs, u32 start_index, int rw, bool sleep_ok)
{ int rc = -EINVAL; int cmd;
switch (reg_addr) { case TP_PIO_ADDR_A:
cmd = FW_LDST_ADDRSPC_TP_PIO; break; case TP_TM_PIO_ADDR_A:
cmd = FW_LDST_ADDRSPC_TP_TM_PIO; break; case TP_MIB_INDEX_A:
cmd = FW_LDST_ADDRSPC_TP_MIB; break; default: goto indirect_access;
}
if (rc) { if (rw)
t4_read_indirect(adap, reg_addr, reg_data, buff, nregs,
start_index); else
t4_write_indirect(adap, reg_addr, reg_data, buff, nregs,
start_index);
}
}
/** * t4_tp_pio_read - Read TP PIO registers * @adap: the adapter * @buff: where the indirect register values are written * @nregs: how many indirect registers to read * @start_index: index of first indirect register to read * @sleep_ok: if true we may sleep while awaiting command completion * * Read TP PIO Registers
**/ void t4_tp_pio_read(struct adapter *adap, u32 *buff, u32 nregs,
u32 start_index, bool sleep_ok)
{
t4_tp_indirect_rw(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, buff, nregs,
start_index, 1, sleep_ok);
}
/** * t4_tp_pio_write - Write TP PIO registers * @adap: the adapter * @buff: where the indirect register values are stored * @nregs: how many indirect registers to write * @start_index: index of first indirect register to write * @sleep_ok: if true we may sleep while awaiting command completion * * Write TP PIO Registers
**/ staticvoid t4_tp_pio_write(struct adapter *adap, u32 *buff, u32 nregs,
u32 start_index, bool sleep_ok)
{
t4_tp_indirect_rw(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, buff, nregs,
start_index, 0, sleep_ok);
}
/** * t4_tp_tm_pio_read - Read TP TM PIO registers * @adap: the adapter * @buff: where the indirect register values are written * @nregs: how many indirect registers to read * @start_index: index of first indirect register to read * @sleep_ok: if true we may sleep while awaiting command completion * * Read TP TM PIO Registers
**/ void t4_tp_tm_pio_read(struct adapter *adap, u32 *buff, u32 nregs,
u32 start_index, bool sleep_ok)
{
t4_tp_indirect_rw(adap, TP_TM_PIO_ADDR_A, TP_TM_PIO_DATA_A, buff,
nregs, start_index, 1, sleep_ok);
}
/** * t4_tp_mib_read - Read TP MIB registers * @adap: the adapter * @buff: where the indirect register values are written * @nregs: how many indirect registers to read * @start_index: index of first indirect register to read * @sleep_ok: if true we may sleep while awaiting command completion * * Read TP MIB Registers
**/ void t4_tp_mib_read(struct adapter *adap, u32 *buff, u32 nregs, u32 start_index, bool sleep_ok)
{
t4_tp_indirect_rw(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, buff, nregs,
start_index, 1, sleep_ok);
}
/** * t4_read_rss_key - read the global RSS key * @adap: the adapter * @key: 10-entry array holding the 320-bit RSS key * @sleep_ok: if true we may sleep while awaiting command completion * * Reads the global 320-bit RSS key.
*/ void t4_read_rss_key(struct adapter *adap, u32 *key, bool sleep_ok)
{
t4_tp_pio_read(adap, key, 10, TP_RSS_SECRET_KEY0_A, sleep_ok);
}
/** * t4_write_rss_key - program one of the RSS keys * @adap: the adapter * @key: 10-entry array holding the 320-bit RSS key * @idx: which RSS key to write * @sleep_ok: if true we may sleep while awaiting command completion * * Writes one of the RSS keys with the given 320-bit value. If @idx is * 0..15 the corresponding entry in the RSS key table is written, * otherwise the global RSS key is written.
*/ void t4_write_rss_key(struct adapter *adap, const u32 *key, int idx, bool sleep_ok)
{
u8 rss_key_addr_cnt = 16;
u32 vrt = t4_read_reg(adap, TP_RSS_CONFIG_VRT_A);
/* T6 and later: for KeyMode 3 (per-vf and per-vf scramble), * allows access to key addresses 16-63 by using KeyWrAddrX * as index[5:4](upper 2) into key table
*/ if ((CHELSIO_CHIP_VERSION(adap->params.chip) > CHELSIO_T5) &&
(vrt & KEYEXTEND_F) && (KEYMODE_G(vrt) == 3))
rss_key_addr_cnt = 32;
/** * t4_read_rss_pf_config - read PF RSS Configuration Table * @adapter: the adapter * @index: the entry in the PF RSS table to read * @valp: where to store the returned value * @sleep_ok: if true we may sleep while awaiting command completion * * Reads the PF RSS Configuration Table at the specified index and returns * the value found there.
*/ void t4_read_rss_pf_config(struct adapter *adapter, unsignedint index,
u32 *valp, bool sleep_ok)
{
t4_tp_pio_read(adapter, valp, 1, TP_RSS_PF0_CONFIG_A + index, sleep_ok);
}
/** * t4_read_rss_vf_config - read VF RSS Configuration Table * @adapter: the adapter * @index: the entry in the VF RSS table to read * @vfl: where to store the returned VFL * @vfh: where to store the returned VFH * @sleep_ok: if true we may sleep while awaiting command completion * * Reads the VF RSS Configuration Table at the specified index and returns * the (VFL, VFH) values found there.
*/ void t4_read_rss_vf_config(struct adapter *adapter, unsignedint index,
u32 *vfl, u32 *vfh, bool sleep_ok)
{
u32 vrt, mask, data;
if (CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5) {
mask = VFWRADDR_V(VFWRADDR_M);
data = VFWRADDR_V(index);
} else {
mask = T6_VFWRADDR_V(T6_VFWRADDR_M);
data = T6_VFWRADDR_V(index);
}
/* Request that the index'th VF Table values be read into VFL/VFH.
*/
vrt = t4_read_reg(adapter, TP_RSS_CONFIG_VRT_A);
vrt &= ~(VFRDRG_F | VFWREN_F | KEYWREN_F | mask);
vrt |= data | VFRDEN_F;
t4_write_reg(adapter, TP_RSS_CONFIG_VRT_A, vrt);
/** * t4_tp_get_rdma_stats - read TP's RDMA MIB counters * @adap: the adapter * @st: holds the counter values * @sleep_ok: if true we may sleep while awaiting command completion * * Returns the values of TP's RDMA counters.
*/ void t4_tp_get_rdma_stats(struct adapter *adap, struct tp_rdma_stats *st, bool sleep_ok)
{
t4_tp_mib_read(adap, &st->rqe_dfr_pkt, 2, TP_MIB_RQE_DFR_PKT_A,
sleep_ok);
}
/** * t4_get_fcoe_stats - read TP's FCoE MIB counters for a port * @adap: the adapter * @idx: the port index * @st: holds the counter values * @sleep_ok: if true we may sleep while awaiting command completion * * Returns the values of TP's FCoE counters for the selected port.
*/ void t4_get_fcoe_stats(struct adapter *adap, unsignedint idx, struct tp_fcoe_stats *st, bool sleep_ok)
{
u32 val[2];
/** * t4_read_mtu_tbl - returns the values in the HW path MTU table * @adap: the adapter * @mtus: where to store the MTU values * @mtu_log: where to store the MTU base-2 log (may be %NULL) * * Reads the HW path MTU table.
*/ void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log)
{
u32 v; int i;
for (i = 0; i < NMTUS; ++i) {
t4_write_reg(adap, TP_MTU_TABLE_A,
MTUINDEX_V(0xff) | MTUVALUE_V(i));
v = t4_read_reg(adap, TP_MTU_TABLE_A);
mtus[i] = MTUVALUE_G(v); if (mtu_log)
mtu_log[i] = MTUWIDTH_G(v);
}
}
/** * t4_read_cong_tbl - reads the congestion control table * @adap: the adapter * @incr: where to store the alpha values * * Reads the additive increments programmed into the HW congestion * control table.
*/ void t4_read_cong_tbl(struct adapter *adap, u16 incr[NMTUS][NCCTRL_WIN])
{ unsignedint mtu, w;
for (mtu = 0; mtu < NMTUS; ++mtu) for (w = 0; w < NCCTRL_WIN; ++w) {
t4_write_reg(adap, TP_CCTRL_TABLE_A,
ROWINDEX_V(0xffff) | (mtu << 5) | w);
incr[mtu][w] = (u16)t4_read_reg(adap,
TP_CCTRL_TABLE_A) & 0x1fff;
}
}
/** * t4_tp_wr_bits_indirect - set/clear bits in an indirect TP register * @adap: the adapter * @addr: the indirect TP register address * @mask: specifies the field within the register to modify * @val: new value for the field * * Sets a field of an indirect TP register to the given value.
*/ void t4_tp_wr_bits_indirect(struct adapter *adap, unsignedint addr, unsignedint mask, unsignedint val)
{
t4_write_reg(adap, TP_PIO_ADDR_A, addr);
val |= t4_read_reg(adap, TP_PIO_DATA_A) & ~mask;
t4_write_reg(adap, TP_PIO_DATA_A, val);
}
/* The minimum additive increment value for the congestion control table */ #define CC_MIN_INCR 2U
/** * t4_load_mtus - write the MTU and congestion control HW tables * @adap: the adapter * @mtus: the values for the MTU table * @alpha: the values for the congestion control alpha parameter * @beta: the values for the congestion control beta parameter * * Write the HW MTU table with the supplied MTUs and the high-speed * congestion control table with the supplied alpha, beta, and MTUs. * We write the two tables together because the additive increments * depend on the MTUs.
*/ void t4_load_mtus(struct adapter *adap, constunsignedshort *mtus, constunsignedshort *alpha, constunsignedshort *beta)
{ staticconstunsignedint avg_pkts[NCCTRL_WIN] = { 2, 6, 10, 14, 20, 28, 40, 56, 80, 112, 160, 224, 320, 448, 640, 896, 1281, 1792, 2560, 3584, 5120, 7168, 10240, 14336, 20480, 28672, 40960, 57344, 81920, 114688, 163840, 229376
};
unsignedint i, w;
for (i = 0; i < NMTUS; ++i) { unsignedint mtu = mtus[i]; unsignedint log2 = fls(mtu);
t4_write_reg(adap, TP_CCTRL_TABLE_A, (i << 21) |
(w << 16) | (beta[w] << 13) | inc);
}
}
}
/* Calculates a rate in bytes/s given the number of 256-byte units per 4K core * clocks. The formula is * * bytes/s = bytes256 * 256 * ClkFreq / 4096 * * which is equivalent to * * bytes/s = 62.5 * bytes256 * ClkFreq_ms
*/ static u64 chan_rate(struct adapter *adap, unsignedint bytes256)
{
u64 v = bytes256 * adap->params.vpd.cclk;
return v * 62 + v / 2;
}
/** * t4_get_chan_txrate - get the current per channel Tx rates * @adap: the adapter * @nic_rate: rates for NIC traffic * @ofld_rate: rates for offloaded traffic * * Return the current Tx rates in bytes/s for NIC and offloaded traffic * for each channel.
*/ void t4_get_chan_txrate(struct adapter *adap, u64 *nic_rate, u64 *ofld_rate)
{
u32 v;
/** * t4_set_trace_filter - configure one of the tracing filters * @adap: the adapter * @tp: the desired trace filter parameters * @idx: which filter to configure * @enable: whether to enable or disable the filter * * Configures one of the tracing filters available in HW. If @enable is * %0 @tp is not examined and may be %NULL. The user is responsible to * set the single/multiple trace mode by writing to MPS_TRC_CFG_A register
*/ int t4_set_trace_filter(struct adapter *adap, conststruct trace_params *tp, int idx, int enable)
{ int i, ofst = idx * 4;
u32 data_reg, mask_reg, cfg;
if (!enable) {
t4_write_reg(adap, MPS_TRC_FILTER_MATCH_CTL_A_A + ofst, 0); return0;
}
cfg = t4_read_reg(adap, MPS_TRC_CFG_A); if (cfg & TRCMULTIFILTER_F) { /* If multiple tracers are enabled, then maximum * capture size is 2.5KB (FIFO size of a single channel) * minus 2 flits for CPL_TRACE_PKT header.
*/ if (tp->snap_len > ((10 * 1024 / 4) - (2 * 8))) return -EINVAL;
} else { /* If multiple tracers are disabled, to avoid deadlocks * maximum packet capture size of 9600 bytes is recommended. * Also in this mode, only trace0 can be enabled and running.
*/ if (tp->snap_len > 9600 || idx) return -EINVAL;
}
/** * t4_get_trace_filter - query one of the tracing filters * @adap: the adapter * @tp: the current trace filter parameters * @idx: which trace filter to query * @enabled: non-zero if the filter is enabled * * Returns the current settings of one of the HW tracing filters.
*/ void t4_get_trace_filter(struct adapter *adap, struct trace_params *tp, int idx, int *enabled)
{
u32 ctla, ctlb; int i, ofst = idx * 4;
u32 data_reg, mask_reg;
for (i = 0; i < TRACE_LEN / 4; i++, data_reg += 4, mask_reg += 4) {
tp->mask[i] = ~t4_read_reg(adap, mask_reg);
tp->data[i] = t4_read_reg(adap, data_reg) & tp->mask[i];
}
}
/** * t4_pmtx_get_stats - returns the HW stats from PMTX * @adap: the adapter * @cnt: where to store the count statistics * @cycles: where to store the cycle statistics * * Returns performance statistics from PMTX.
*/ void t4_pmtx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[])
{ int i;
u32 data[2];
for (i = 0; i < adap->params.arch.pm_stats_cnt; i++) {
t4_write_reg(adap, PM_TX_STAT_CONFIG_A, i + 1);
cnt[i] = t4_read_reg(adap, PM_TX_STAT_COUNT_A); if (is_t4(adap->params.chip)) {
cycles[i] = t4_read_reg64(adap, PM_TX_STAT_LSB_A);
} else {
t4_read_indirect(adap, PM_TX_DBG_CTRL_A,
PM_TX_DBG_DATA_A, data, 2,
PM_TX_DBG_STAT_MSB_A);
cycles[i] = (((u64)data[0] << 32) | data[1]);
}
}
}
/** * t4_pmrx_get_stats - returns the HW stats from PMRX * @adap: the adapter * @cnt: where to store the count statistics * @cycles: where to store the cycle statistics * * Returns performance statistics from PMRX.
*/ void t4_pmrx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[])
{ int i;
u32 data[2];
for (i = 0; i < adap->params.arch.pm_stats_cnt; i++) {
t4_write_reg(adap, PM_RX_STAT_CONFIG_A, i + 1);
cnt[i] = t4_read_reg(adap, PM_RX_STAT_COUNT_A); if (is_t4(adap->params.chip)) {
cycles[i] = t4_read_reg64(adap, PM_RX_STAT_LSB_A);
} else {
t4_read_indirect(adap, PM_RX_DBG_CTRL_A,
PM_RX_DBG_DATA_A, data, 2,
PM_RX_DBG_STAT_MSB_A);
cycles[i] = (((u64)data[0] << 32) | data[1]);
}
}
}
/** * compute_mps_bg_map - compute the MPS Buffer Group Map for a Port * @adapter: the adapter * @pidx: the port index * * Computes and returns a bitmap indicating which MPS buffer groups are * associated with the given Port. Bit i is set if buffer group i is * used by the Port.
*/ staticinlineunsignedint compute_mps_bg_map(struct adapter *adapter, int pidx)
{ unsignedint chip_version, nports;
dev_err(adapter->pdev_dev, "Need MPS Buffer Group Map for Chip %0x, Nports %d\n",
chip_version, nports);
return0;
}
/** * t4_get_mps_bg_map - return the buffer groups associated with a port * @adapter: the adapter * @pidx: the port index * * Returns a bitmap indicating which MPS buffer groups are associated * with the given Port. Bit i is set if buffer group i is used by the * Port.
*/ unsignedint t4_get_mps_bg_map(struct adapter *adapter, int pidx)
{
u8 *mps_bg_map; unsignedint nports;
nports = 1 << NUMPORTS_G(t4_read_reg(adapter, MPS_CMN_CTL_A)); if (pidx >= nports) {
CH_WARN(adapter, "MPS Port Index %d >= Nports %d\n",
pidx, nports); return0;
}
/* If we've already retrieved/computed this, just return the result.
*/
mps_bg_map = adapter->params.mps_bg_map; if (mps_bg_map[pidx]) return mps_bg_map[pidx];
/* Newer Firmware can tell us what the MPS Buffer Group Map is. * If we're talking to such Firmware, let it tell us. If the new * API isn't supported, revert back to old hardcoded way. The value * obtained from Firmware is encoded in below format: * * val = (( MPSBGMAP[Port 3] << 24 ) | * ( MPSBGMAP[Port 2] << 16 ) | * ( MPSBGMAP[Port 1] << 8 ) | * ( MPSBGMAP[Port 0] << 0 ))
*/ if (adapter->flags & CXGB4_FW_OK) {
u32 param, val; int ret;
param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_MPSBGMAP));
ret = t4_query_params_ns(adapter, adapter->mbox, adapter->pf, 0, 1, ¶m, &val); if (!ret) { int p;
/* Store the BG Map for all of the Ports in order to * avoid more calls to the Firmware in the future.
*/ for (p = 0; p < MAX_NPORTS; p++, val >>= 8)
mps_bg_map[p] = val & 0xff;
return mps_bg_map[pidx];
}
}
/* Either we're not talking to the Firmware or we're dealing with * older Firmware which doesn't support the new API to get the MPS * Buffer Group Map. Fall back to computing it ourselves.
*/
mps_bg_map[pidx] = compute_mps_bg_map(adapter, pidx); return mps_bg_map[pidx];
}
/** * t4_get_tp_e2c_map - return the E2C channel map associated with a port * @adapter: the adapter * @pidx: the port index
*/ staticunsignedint t4_get_tp_e2c_map(struct adapter *adapter, int pidx)
{ unsignedint nports;
u32 param, val = 0; int ret;
nports = 1 << NUMPORTS_G(t4_read_reg(adapter, MPS_CMN_CTL_A)); if (pidx >= nports) {
CH_WARN(adapter, "TP E2C Channel Port Index %d >= Nports %d\n",
pidx, nports); return0;
}
/* FW version >= 1.16.44.0 can determine E2C channel map using * FW_PARAMS_PARAM_DEV_TPCHMAP API.
*/
param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_TPCHMAP));
ret = t4_query_params_ns(adapter, adapter->mbox, adapter->pf, 0, 1, ¶m, &val); if (!ret) return (val >> (8 * pidx)) & 0xff;
return0;
}
/** * t4_get_tp_ch_map - return TP ingress channels associated with a port * @adap: the adapter * @pidx: the port index * * Returns a bitmap indicating which TP Ingress Channels are associated * with a given Port. Bit i is set if TP Ingress Channel i is used by * the Port.
*/ unsignedint t4_get_tp_ch_map(struct adapter *adap, int pidx)
{ unsignedint chip_version = CHELSIO_CHIP_VERSION(adap->params.chip); unsignedint nports = 1 << NUMPORTS_G(t4_read_reg(adap, MPS_CMN_CTL_A));
if (pidx >= nports) {
dev_warn(adap->pdev_dev, "TP Port Index %d >= Nports %d\n",
pidx, nports); return0;
}
switch (chip_version) { case CHELSIO_T4: case CHELSIO_T5: /* Note that this happens to be the same values as the MPS * Buffer Group Map for these Chips. But we replicate the code * here because they're really separate concepts.
*/ switch (nports) { case1: return0xf; case2: return3 << (2 * pidx); case4: return1 << pidx;
} break;
if (port_type < ARRAY_SIZE(port_type_description)) return port_type_description[port_type]; return"UNKNOWN";
}
/** * t4_get_port_stats_offset - collect port stats relative to a previous * snapshot * @adap: The adapter * @idx: The port * @stats: Current stats to fill * @offset: Previous stats snapshot
*/ void t4_get_port_stats_offset(struct adapter *adap, int idx, struct port_stats *stats, struct port_stats *offset)
{
u64 *s, *o; int i;
t4_get_port_stats(adap, idx, stats); for (i = 0, s = (u64 *)stats, o = (u64 *)offset;
i < (sizeof(struct port_stats) / sizeof(u64));
i++, s++, o++)
*s -= *o;
}
/** * t4_get_port_stats - collect port statistics * @adap: the adapter * @idx: the port index * @p: the stats structure to fill * * Collect statistics related to the given port from HW.
*/ void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p)
{
u32 bgmap = t4_get_mps_bg_map(adap, idx);
u32 stat_ctl = t4_read_reg(adap, MPS_STAT_CTL_A);
/** * t4_get_lb_stats - collect loopback port statistics * @adap: the adapter * @idx: the loopback port index * @p: the stats structure to fill * * Return HW statistics for the given loopback port.
*/ void t4_get_lb_stats(struct adapter *adap, int idx, struct lb_port_stats *p)
{
u32 bgmap = t4_get_mps_bg_map(adap, idx);
/** * t4_mdio_rd - read a PHY register through MDIO * @adap: the adapter * @mbox: mailbox to use for the FW command * @phy_addr: the PHY address * @mmd: the PHY MMD to access (0 for clause 22 PHYs) * @reg: the register to read * @valp: where to store the value * * Issues a FW command through the given mailbox to read a PHY register.
*/ int t4_mdio_rd(struct adapter *adap, unsignedint mbox, unsignedint phy_addr, unsignedint mmd, unsignedint reg, u16 *valp)
{ int ret;
u32 ldst_addrspace; struct fw_ldst_cmd c;
ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); if (ret == 0)
*valp = be16_to_cpu(c.u.mdio.rval); return ret;
}
/** * t4_mdio_wr - write a PHY register through MDIO * @adap: the adapter * @mbox: mailbox to use for the FW command * @phy_addr: the PHY address * @mmd: the PHY MMD to access (0 for clause 22 PHYs) * @reg: the register to write * @val: value to write * * Issues a FW command through the given mailbox to write a PHY register.
*/ int t4_mdio_wr(struct adapter *adap, unsignedint mbox, unsignedint phy_addr, unsignedint mmd, unsignedint reg, u16 val)
{
u32 ldst_addrspace; struct fw_ldst_cmd c;
/* Select the right set of decode strings to dump depending on the * adapter chip type.
*/ switch (chip_version) { case CHELSIO_T4:
sge_idma_decode = (constchar **)t4_decode;
sge_idma_decode_nstates = ARRAY_SIZE(t4_decode); break;
case CHELSIO_T5:
sge_idma_decode = (constchar **)t5_decode;
sge_idma_decode_nstates = ARRAY_SIZE(t5_decode); break;
case CHELSIO_T6:
sge_idma_decode = (constchar **)t6_decode;
sge_idma_decode_nstates = ARRAY_SIZE(t6_decode); break;
default:
dev_err(adapter->pdev_dev, "Unsupported chip version %d\n", chip_version); return;
}
if (state < sge_idma_decode_nstates)
CH_WARN(adapter, "idma state %s\n", sge_idma_decode[state]); else
CH_WARN(adapter, "idma state %d unknown\n", state);
for (i = 0; i < ARRAY_SIZE(sge_regs); i++)
CH_WARN(adapter, "SGE register %#x value %#x\n",
sge_regs[i], t4_read_reg(adapter, sge_regs[i]));
}
/** * t4_sge_ctxt_flush - flush the SGE context cache * @adap: the adapter * @mbox: mailbox to use for the FW command * @ctxt_type: Egress or Ingress * * Issues a FW command through the given mailbox to flush the * SGE context cache.
*/ int t4_sge_ctxt_flush(struct adapter *adap, unsignedint mbox, int ctxt_type)
{ int ret;
u32 ldst_addrspace; struct fw_ldst_cmd c;
/** * t4_fw_hello - establish communication with FW * @adap: the adapter * @mbox: mailbox to use for the FW command * @evt_mbox: mailbox to receive async FW events * @master: specifies the caller's willingness to be the device master * @state: returns the current device state (if non-NULL) * * Issues a command to establish communication with FW. Returns either * an error (negative integer) or the mailbox of the Master PF.
*/ int t4_fw_hello(struct adapter *adap, unsignedint mbox, unsignedint evt_mbox, enum dev_master master, enum dev_state *state)
{ int ret; struct fw_hello_cmd c;
u32 v; unsignedint master_mbox; int retries = FW_CMD_HELLO_RETRIES;
/* * Issue the HELLO command to the firmware. If it's not successful * but indicates that we got a "busy" or "timeout" condition, retry * the HELLO until we exhaust our retry limit. If we do exceed our * retry limit, check to see if the firmware left us any error * information and report that if so.
*/
ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); if (ret < 0) { if ((ret == -EBUSY || ret == -ETIMEDOUT) && retries-- > 0) goto retry; if (t4_read_reg(adap, PCIE_FW_A) & PCIE_FW_ERR_F)
t4_report_fw_error(adap); return ret;
}
v = be32_to_cpu(c.err_to_clearinit);
master_mbox = FW_HELLO_CMD_MBMASTER_G(v); if (state) { if (v & FW_HELLO_CMD_ERR_F)
*state = DEV_STATE_ERR; elseif (v & FW_HELLO_CMD_INIT_F)
*state = DEV_STATE_INIT; else
*state = DEV_STATE_UNINIT;
}
/* * If we're not the Master PF then we need to wait around for the * Master PF Driver to finish setting up the adapter. * * Note that we also do this wait if we're a non-Master-capable PF and * there is no current Master PF; a Master PF may show up momentarily * and we wouldn't want to fail pointlessly. (This can happen when an * OS loads lots of different drivers rapidly at the same time). In * this case, the Master PF returned by the firmware will be * PCIE_FW_MASTER_M so the test below will work ...
*/ if ((v & (FW_HELLO_CMD_ERR_F|FW_HELLO_CMD_INIT_F)) == 0 &&
master_mbox != mbox) { int waiting = FW_CMD_HELLO_TIMEOUT;
/* * Wait for the firmware to either indicate an error or * initialized state. If we see either of these we bail out * and report the issue to the caller. If we exhaust the * "hello timeout" and we haven't exhausted our retries, try * again. Otherwise bail with a timeout error.
*/ for (;;) {
u32 pcie_fw;
msleep(50);
waiting -= 50;
/* * If neither Error nor Initialized are indicated * by the firmware keep waiting till we exhaust our * timeout ... and then retry if we haven't exhausted * our retries ...
*/
pcie_fw = t4_read_reg(adap, PCIE_FW_A); if (!(pcie_fw & (PCIE_FW_ERR_F|PCIE_FW_INIT_F))) { if (waiting <= 0) { if (retries-- > 0) goto retry;
return -ETIMEDOUT;
} continue;
}
/* * We either have an Error or Initialized condition * report errors preferentially.
*/ if (state) { if (pcie_fw & PCIE_FW_ERR_F)
*state = DEV_STATE_ERR; elseif (pcie_fw & PCIE_FW_INIT_F)
*state = DEV_STATE_INIT;
}
/* * If we arrived before a Master PF was selected and * there's not a valid Master PF, grab its identity * for our caller.
*/ if (master_mbox == PCIE_FW_MASTER_M &&
(pcie_fw & PCIE_FW_MASTER_VLD_F))
master_mbox = PCIE_FW_MASTER_G(pcie_fw); break;
}
}
return master_mbox;
}
/** * t4_fw_bye - end communication with FW * @adap: the adapter * @mbox: mailbox to use for the FW command * * Issues a command to terminate communication with FW.
*/ int t4_fw_bye(struct adapter *adap, unsignedint mbox)
{ struct fw_bye_cmd c;
/** * t4_early_init - ask FW to initialize the device * @adap: the adapter * @mbox: mailbox to use for the FW command * * Issues a command to FW to partially initialize the device. This * performs initialization that generally doesn't depend on user input.
*/ int t4_early_init(struct adapter *adap, unsignedint mbox)
{ struct fw_initialize_cmd c;
/** * t4_fw_reset - issue a reset to FW * @adap: the adapter * @mbox: mailbox to use for the FW command * @reset: specifies the type of reset to perform * * Issues a reset command of the specified type to FW.
*/ int t4_fw_reset(struct adapter *adap, unsignedint mbox, int reset)
{ struct fw_reset_cmd c;
/** * t4_fw_halt - issue a reset/halt to FW and put uP into RESET * @adap: the adapter * @mbox: mailbox to use for the FW RESET command (if desired) * @force: force uP into RESET even if FW RESET command fails * * Issues a RESET command to firmware (if desired) with a HALT indication * and then puts the microprocessor into RESET state. The RESET command * will only be issued if a legitimate mailbox is provided (mbox <= * PCIE_FW_MASTER_M). * * This is generally used in order for the host to safely manipulate the * adapter without fear of conflicting with whatever the firmware might * be doing. The only way out of this state is to RESTART the firmware * ...
*/ staticint t4_fw_halt(struct adapter *adap, unsignedint mbox, int force)
{ int ret = 0;
/* * If a legitimate mailbox is provided, issue a RESET command * with a HALT indication.
*/ if (mbox <= PCIE_FW_MASTER_M) { struct fw_reset_cmd c;
/* * Normally we won't complete the operation if the firmware RESET * command fails but if our caller insists we'll go ahead and put the * uP into RESET. This can be useful if the firmware is hung or even * missing ... We'll have to take the risk of putting the uP into * RESET without the cooperation of firmware in that case. * * We also force the firmware's HALT flag to be on in case we bypassed * the firmware RESET command above or we're dealing with old firmware * which doesn't have the HALT capability. This will serve as a flag * for the incoming firmware to know that it's coming out of a HALT * rather than a RESET ... if it's new enough to understand that ...
*/ if (ret == 0 || force) {
t4_set_reg_field(adap, CIM_BOOT_CFG_A, UPCRST_F, UPCRST_F);
t4_set_reg_field(adap, PCIE_FW_A, PCIE_FW_HALT_F,
PCIE_FW_HALT_F);
}
/* * And we always return the result of the firmware RESET command * even when we force the uP into RESET ...
*/ return ret;
}
/** * t4_fw_restart - restart the firmware by taking the uP out of RESET * @adap: the adapter * @mbox: mailbox to use for the FW command * @reset: if we want to do a RESET to restart things * * Restart firmware previously halted by t4_fw_halt(). On successful * return the previous PF Master remains as the new PF Master and there * is no need to issue a new HELLO command, etc. * * We do this in two ways: * * 1. If we're dealing with newer firmware we'll simply want to take * the chip's microprocessor out of RESET. This will cause the * firmware to start up from its start vector. And then we'll loop * until the firmware indicates it's started again (PCIE_FW.HALT * reset to 0) or we timeout. * * 2. If we're dealing with older firmware then we'll need to RESET * the chip since older firmware won't recognize the PCIE_FW.HALT * flag and automatically RESET itself on startup.
*/ staticint t4_fw_restart(struct adapter *adap, unsignedint mbox, int reset)
{ if (reset) { /* * Since we're directing the RESET instead of the firmware * doing it automatically, we need to clear the PCIE_FW.HALT * bit.
*/
t4_set_reg_field(adap, PCIE_FW_A, PCIE_FW_HALT_F, 0);
/* * If we've been given a valid mailbox, first try to get the * firmware to do the RESET. If that works, great and we can * return success. Otherwise, if we haven't been given a * valid mailbox or the RESET command failed, fall back to * hitting the chip with a hammer.
*/ if (mbox <= PCIE_FW_MASTER_M) {
t4_set_reg_field(adap, CIM_BOOT_CFG_A, UPCRST_F, 0);
msleep(100); if (t4_fw_reset(adap, mbox,
PIORST_F | PIORSTMODE_F) == 0) return0;
}
t4_set_reg_field(adap, CIM_BOOT_CFG_A, UPCRST_F, 0); for (ms = 0; ms < FW_CMD_MAX_TIMEOUT; ) { if (!(t4_read_reg(adap, PCIE_FW_A) & PCIE_FW_HALT_F)) return0;
msleep(100);
ms += 100;
} return -ETIMEDOUT;
} return0;
}
/** * t4_fw_upgrade - perform all of the steps necessary to upgrade FW * @adap: the adapter * @mbox: mailbox to use for the FW RESET command (if desired) * @fw_data: the firmware image to write * @size: image size * @force: force upgrade even if firmware doesn't cooperate * * Perform all of the steps necessary for upgrading an adapter's * firmware image. Normally this requires the cooperation of the * existing firmware in order to halt all existing activities * but if an invalid mailbox token is passed in we skip that step * (though we'll still put the adapter microprocessor into RESET in * that case). * * On successful return the new firmware will have been loaded and * the adapter will have been fully RESET losing all previous setup * state. On unsuccessful return the adapter may be completely hosed ... * positive errno indicates that the adapter is ~probably~ intact, a * negative errno indicates that things are looking bad ...
*/ int t4_fw_upgrade(struct adapter *adap, unsignedint mbox, const u8 *fw_data, unsignedint size, int force)
{ conststruct fw_hdr *fw_hdr = (conststruct fw_hdr *)fw_data; int reset, ret;
if (!t4_fw_matches_chip(adap, fw_hdr)) return -EINVAL;
/* Disable CXGB4_FW_OK flag so that mbox commands with CXGB4_FW_OK flag * set wont be sent when we are flashing FW.
*/
adap->flags &= ~CXGB4_FW_OK;
ret = t4_fw_halt(adap, mbox, force); if (ret < 0 && !force) goto out;
ret = t4_load_fw(adap, fw_data, size); if (ret < 0) goto out;
/* * If there was a Firmware Configuration File stored in FLASH, * there's a good chance that it won't be compatible with the new * Firmware. In order to prevent difficult to diagnose adapter * initialization issues, we clear out the Firmware Configuration File * portion of the FLASH . The user will need to re-FLASH a new * Firmware Configuration File which is compatible with the new * Firmware if that's desired.
*/
(void)t4_load_cfg(adap, NULL, 0);
/* * Older versions of the firmware don't understand the new * PCIE_FW.HALT flag and so won't know to perform a RESET when they * restart. So for newly loaded older firmware we'll have to do the * RESET for it so it starts up on a clean slate. We can tell if * the newly loaded firmware will handle this right by checking * its header flags to see if it advertises the capability.
*/
reset = ((be32_to_cpu(fw_hdr->flags) & FW_HDR_FLAGS_RESET_HALT) == 0);
ret = t4_fw_restart(adap, mbox, reset);
/* Grab potentially new Firmware Device Log parameters so we can see * how healthy the new Firmware is. It's okay to contact the new * Firmware for these parameters even though, as far as it's * concerned, we've never said "HELLO" to it ...
*/
(void)t4_init_devlog_params(adap);
out:
adap->flags |= CXGB4_FW_OK; return ret;
}
/** * t4_fl_pkt_align - return the fl packet alignment * @adap: the adapter * * T4 has a single field to specify the packing and padding boundary. * T5 onwards has separate fields for this and hence the alignment for * next packet offset is maximum of these two. *
*/ int t4_fl_pkt_align(struct adapter *adap)
{
u32 sge_control, sge_control2; unsignedint ingpadboundary, ingpackboundary, fl_align, ingpad_shift;
sge_control = t4_read_reg(adap, SGE_CONTROL_A);
/* T4 uses a single control field to specify both the PCIe Padding and * Packing Boundary. T5 introduced the ability to specify these * separately. The actual Ingress Packet Data alignment boundary * within Packed Buffer Mode is the maximum of these two * specifications. (Note that it makes no real practical sense to * have the Padding Boundary be larger than the Packing Boundary but you * could set the chip up that way and, in fact, legacy T4 code would * end doing this because it would initialize the Padding Boundary and * leave the Packing Boundary initialized to 0 (16 bytes).) * Padding Boundary values in T6 starts from 8B, * where as it is 32B for T4 and T5.
*/ if (CHELSIO_CHIP_VERSION(adap->params.chip) <= CHELSIO_T5)
ingpad_shift = INGPADBOUNDARY_SHIFT_X; else
ingpad_shift = T6_INGPADBOUNDARY_SHIFT_X;
fl_align = ingpadboundary; if (!is_t4(adap->params.chip)) { /* T5 has a weird interpretation of one of the PCIe Packing * Boundary values. No idea why ...
*/
sge_control2 = t4_read_reg(adap, SGE_CONTROL2_A);
ingpackboundary = INGPACKBOUNDARY_G(sge_control2); if (ingpackboundary == INGPACKBOUNDARY_16B_X)
ingpackboundary = 16; else
ingpackboundary = 1 << (ingpackboundary +
INGPACKBOUNDARY_SHIFT_X);
/** * t4_fixup_host_params - fix up host-dependent parameters * @adap: the adapter * @page_size: the host's Base Page Size * @cache_line_size: the host's Cache Line Size * * Various registers in T4 contain values which are dependent on the * host's Base Page and Cache Line Sizes. This function will fix all of * those registers with the appropriate values as passed in ...
*/ int t4_fixup_host_params(struct adapter *adap, unsignedint page_size, unsignedint cache_line_size)
{ unsignedint page_shift = fls(page_size) - 1; unsignedint sge_hps = page_shift - 10; unsignedint stat_len = cache_line_size > 64 ? 128 : 64; unsignedint fl_align = cache_line_size < 32 ? 32 : cache_line_size; unsignedint fl_align_log = fls(fl_align) - 1;
/* T5 introduced the separation of the Free List Padding and * Packing Boundaries. Thus, we can select a smaller Padding * Boundary to avoid uselessly chewing up PCIe Link and Memory * Bandwidth, and use a Packing Boundary which is large enough * to avoid false sharing between CPUs, etc. * * For the PCI Link, the smaller the Padding Boundary the * better. For the Memory Controller, a smaller Padding * Boundary is better until we cross under the Memory Line * Size (the minimum unit of transfer to/from Memory). If we * have a Padding Boundary which is smaller than the Memory * Line Size, that'll involve a Read-Modify-Write cycle on the * Memory Controller which is never good.
*/
/* We want the Packing Boundary to be based on the Cache Line * Size in order to help avoid False Sharing performance * issues between CPUs, etc. We also want the Packing * Boundary to incorporate the PCI-E Maximum Payload Size. We * get best performance when the Packing Boundary is a * multiple of the Maximum Payload Size.
*/
pack_align = fl_align; if (pci_is_pcie(adap->pdev)) { unsignedint mps, mps_log;
u16 devctl;
/* The PCIe Device Control Maximum Payload Size field * [bits 7:5] encodes sizes as powers of 2 starting at * 128 bytes.
*/
pcie_capability_read_word(adap->pdev, PCI_EXP_DEVCTL,
&devctl);
mps_log = ((devctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5) + 7;
mps = 1 << mps_log; if (mps > pack_align)
pack_align = mps;
}
/* N.B. T5/T6 have a crazy special interpretation of the "0" * value for the Packing Boundary. This corresponds to 16 * bytes instead of the expected 32 bytes. So if we want 32 * bytes, the best we can really do is 64 bytes ...
*/ if (pack_align <= 16) {
ingpack = INGPACKBOUNDARY_16B_X;
fl_align = 16;
} elseif (pack_align == 32) {
ingpack = INGPACKBOUNDARY_64B_X;
fl_align = 64;
} else { unsignedint pack_align_log = fls(pack_align) - 1;
/* Use the smallest Ingress Padding which isn't smaller than * the Memory Controller Read/Write Size. We'll take that as * being 8 bytes since we don't know of any system with a * wider Memory Controller Bus Width.
*/ if (is_t5(adap->params.chip))
ingpad = INGPADBOUNDARY_32B_X; else
ingpad = T6_INGPADBOUNDARY_8B_X;
t4_set_reg_field(adap, SGE_CONTROL_A,
INGPADBOUNDARY_V(INGPADBOUNDARY_M) |
EGRSTATUSPAGESIZE_F,
INGPADBOUNDARY_V(ingpad) |
EGRSTATUSPAGESIZE_V(stat_len != 64));
t4_set_reg_field(adap, SGE_CONTROL2_A,
INGPACKBOUNDARY_V(INGPACKBOUNDARY_M),
INGPACKBOUNDARY_V(ingpack));
} /* * Adjust various SGE Free List Host Buffer Sizes. * * This is something of a crock since we're using fixed indices into * the array which are also known by the sge.c code and the T4 * Firmware Configuration File. We need to come up with a much better * approach to managing this array. For now, the first four entries * are: * * 0: Host Page Size * 1: 64KB * 2: Buffer size corresponding to 1500 byte MTU (unpacked mode) * 3: Buffer size corresponding to 9000 byte MTU (unpacked mode) * * For the single-MTU buffers in unpacked mode we need to include * space for the SGE Control Packet Shift, 14 byte Ethernet header, * possible 4 byte VLAN tag, all rounded up to the next Ingress Packet * Padding boundary. All of these are accommodated in the Factory * Default Firmware Configuration File but we need to adjust it for * this host's cache line size.
*/
t4_write_reg(adap, SGE_FL_BUFFER_SIZE0_A, page_size);
t4_write_reg(adap, SGE_FL_BUFFER_SIZE2_A,
(t4_read_reg(adap, SGE_FL_BUFFER_SIZE2_A) + fl_align-1)
& ~(fl_align-1));
t4_write_reg(adap, SGE_FL_BUFFER_SIZE3_A,
(t4_read_reg(adap, SGE_FL_BUFFER_SIZE3_A) + fl_align-1)
& ~(fl_align-1));
/** * t4_fw_initialize - ask FW to initialize the device * @adap: the adapter * @mbox: mailbox to use for the FW command * * Issues a command to FW to partially initialize the device. This * performs initialization that generally doesn't depend on user input.
*/ int t4_fw_initialize(struct adapter *adap, unsignedint mbox)
{ struct fw_initialize_cmd c;
/** * t4_query_params_rw - query FW or device parameters * @adap: the adapter * @mbox: mailbox to use for the FW command * @pf: the PF * @vf: the VF * @nparams: the number of parameters * @params: the parameter names * @val: the parameter values * @rw: Write and read flag * @sleep_ok: if true, we may sleep awaiting mbox cmd completion * * Reads the value of FW or device parameters. Up to 7 parameters can be * queried at once.
*/ int t4_query_params_rw(struct adapter *adap, unsignedint mbox, unsignedint pf, unsignedint vf, unsignedint nparams, const u32 *params,
u32 *val, int rw, bool sleep_ok)
{ int i, ret; struct fw_params_cmd c;
__be32 *p = &c.param[0].mnem;
for (i = 0; i < nparams; i++) {
*p++ = cpu_to_be32(*params++); if (rw)
*p = cpu_to_be32(*(val + i));
p++;
}
ret = t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), &c, sleep_ok); if (ret == 0) for (i = 0, p = &c.param[0].val; i < nparams; i++, p += 2)
*val++ = be32_to_cpu(*p); return ret;
}
/** * t4_set_params_timeout - sets FW or device parameters * @adap: the adapter * @mbox: mailbox to use for the FW command * @pf: the PF * @vf: the VF * @nparams: the number of parameters * @params: the parameter names * @val: the parameter values * @timeout: the timeout time * * Sets the value of FW or device parameters. Up to 7 parameters can be * specified at once.
*/ int t4_set_params_timeout(struct adapter *adap, unsignedint mbox, unsignedint pf, unsignedint vf, unsignedint nparams, const u32 *params, const u32 *val, int timeout)
{ struct fw_params_cmd c;
__be32 *p = &c.param[0].mnem;
/** * t4_set_params - sets FW or device parameters * @adap: the adapter * @mbox: mailbox to use for the FW command * @pf: the PF * @vf: the VF * @nparams: the number of parameters * @params: the parameter names * @val: the parameter values * * Sets the value of FW or device parameters. Up to 7 parameters can be * specified at once.
*/ int t4_set_params(struct adapter *adap, unsignedint mbox, unsignedint pf, unsignedint vf, unsignedint nparams, const u32 *params, const u32 *val)
{ return t4_set_params_timeout(adap, mbox, pf, vf, nparams, params, val,
FW_CMD_MAX_TIMEOUT);
}
/** * t4_cfg_pfvf - configure PF/VF resource limits * @adap: the adapter * @mbox: mailbox to use for the FW command * @pf: the PF being configured * @vf: the VF being configured * @txq: the max number of egress queues * @txq_eth_ctrl: the max number of egress Ethernet or control queues * @rxqi: the max number of interrupt-capable ingress queues * @rxq: the max number of interruptless ingress queues * @tc: the PCI traffic class * @vi: the max number of virtual interfaces * @cmask: the channel access rights mask for the PF/VF * @pmask: the port access rights mask for the PF/VF * @nexact: the maximum number of exact MPS filters * @rcaps: read capabilities * @wxcaps: write/execute capabilities * * Configures resource limits and capabilities for a physical or virtual * function.
*/ int t4_cfg_pfvf(struct adapter *adap, unsignedint mbox, unsignedint pf, unsignedint vf, unsignedint txq, unsignedint txq_eth_ctrl, unsignedint rxqi, unsignedint rxq, unsignedint tc, unsignedint vi, unsignedint cmask, unsignedint pmask, unsignedint nexact, unsignedint rcaps, unsignedint wxcaps)
{ struct fw_pfvf_cmd c;
/** * t4_alloc_vi - allocate a virtual interface * @adap: the adapter * @mbox: mailbox to use for the FW command * @port: physical port associated with the VI * @pf: the PF owning the VI * @vf: the VF owning the VI * @nmac: number of MAC addresses needed (1 to 5) * @mac: the MAC addresses of the VI * @rss_size: size of RSS table slice associated with this VI * @vivld: the destination to store the VI Valid value. * @vin: the destination to store the VIN value. * * Allocates a virtual interface for the given physical port. If @mac is * not %NULL it contains the MAC addresses of the VI as assigned by FW. * @mac should be large enough to hold @nmac Ethernet addresses, they are * stored consecutively so the space needed is @nmac * 6 bytes. * Returns a negative error number or the non-negative VI id.
*/ int t4_alloc_vi(struct adapter *adap, unsignedint mbox, unsignedint port, unsignedint pf, unsignedint vf, unsignedint nmac, u8 *mac, unsignedint *rss_size, u8 *vivld, u8 *vin)
{ int ret; struct fw_vi_cmd c;
/** * t4_free_vi - free a virtual interface * @adap: the adapter * @mbox: mailbox to use for the FW command * @pf: the PF owning the VI * @vf: the VF owning the VI * @viid: virtual interface identifiler * * Free a previously allocated virtual interface.
*/ int t4_free_vi(struct adapter *adap, unsignedint mbox, unsignedint pf, unsignedint vf, unsignedint viid)
{ struct fw_vi_cmd c;
/** * t4_set_rxmode - set Rx properties of a virtual interface * @adap: the adapter * @mbox: mailbox to use for the FW command * @viid: the VI id * @viid_mirror: the mirror VI id * @mtu: the new MTU or -1 * @promisc: 1 to enable promiscuous mode, 0 to disable it, -1 no change * @all_multi: 1 to enable all-multi mode, 0 to disable it, -1 no change * @bcast: 1 to enable broadcast Rx, 0 to disable it, -1 no change * @vlanex: 1 to enable HW VLAN extraction, 0 to disable it, -1 no change * @sleep_ok: if true we may sleep while awaiting command completion * * Sets Rx properties of a virtual interface.
*/ int t4_set_rxmode(struct adapter *adap, unsignedint mbox, unsignedint viid, unsignedint viid_mirror, int mtu, int promisc, int all_multi, int bcast, int vlanex, bool sleep_ok)
{ struct fw_vi_rxmode_cmd c, c_mirror; int ret;
/* convert to FW values */ if (mtu < 0)
mtu = FW_RXMODE_MTU_NO_CHG; if (promisc < 0)
promisc = FW_VI_RXMODE_CMD_PROMISCEN_M; if (all_multi < 0)
all_multi = FW_VI_RXMODE_CMD_ALLMULTIEN_M; if (bcast < 0)
bcast = FW_VI_RXMODE_CMD_BROADCASTEN_M; if (vlanex < 0)
vlanex = FW_VI_RXMODE_CMD_VLANEXEN_M;
ret = t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), NULL, sleep_ok); if (ret) return ret;
if (viid_mirror)
ret = t4_wr_mbox_meat(adap, mbox, &c_mirror, sizeof(c_mirror),
NULL, sleep_ok);
return ret;
}
/** * t4_free_encap_mac_filt - frees MPS entry at given index * @adap: the adapter * @viid: the VI id * @idx: index of MPS entry to be freed * @sleep_ok: call is allowed to sleep * * Frees the MPS entry at supplied index * * Returns a negative error number or zero on success
*/ int t4_free_encap_mac_filt(struct adapter *adap, unsignedint viid, int idx, bool sleep_ok)
{ struct fw_vi_mac_exact *p; struct fw_vi_mac_cmd c; int ret = 0;
u32 exact;
/** * t4_free_raw_mac_filt - Frees a raw mac entry in mps tcam * @adap: the adapter * @viid: the VI id * @addr: the MAC address * @mask: the mask * @idx: index of the entry in mps tcam * @lookup_type: MAC address for inner (1) or outer (0) header * @port_id: the port index * @sleep_ok: call is allowed to sleep * * Removes the mac entry at the specified index using raw mac interface. * * Returns a negative error number on failure.
*/ int t4_free_raw_mac_filt(struct adapter *adap, unsignedint viid, const u8 *addr, const u8 *mask, unsignedint idx,
u8 lookup_type, u8 port_id, bool sleep_ok)
{ struct fw_vi_mac_cmd c; struct fw_vi_mac_raw *p = &c.u.raw;
u32 val;
/** * t4_alloc_encap_mac_filt - Adds a mac entry in mps tcam with VNI support * @adap: the adapter * @viid: the VI id * @addr: the MAC address * @mask: the mask * @vni: the VNI id for the tunnel protocol * @vni_mask: mask for the VNI id * @dip_hit: to enable DIP match for the MPS entry * @lookup_type: MAC address for inner (1) or outer (0) header * @sleep_ok: call is allowed to sleep * * Allocates an MPS entry with specified MAC address and VNI value. * * Returns a negative error number or the allocated index for this mac.
*/ int t4_alloc_encap_mac_filt(struct adapter *adap, unsignedint viid, const u8 *addr, const u8 *mask, unsignedint vni, unsignedint vni_mask, u8 dip_hit, u8 lookup_type, bool sleep_ok)
{ struct fw_vi_mac_cmd c; struct fw_vi_mac_vni *p = c.u.exact_vni; int ret = 0;
u32 val;
p->lookup_type_to_vni =
cpu_to_be32(FW_VI_MAC_CMD_VNI_V(vni) |
FW_VI_MAC_CMD_DIP_HIT_V(dip_hit) |
FW_VI_MAC_CMD_LOOKUP_TYPE_V(lookup_type));
p->vni_mask_pkd = cpu_to_be32(FW_VI_MAC_CMD_VNI_MASK_V(vni_mask));
ret = t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, sleep_ok); if (ret == 0)
ret = FW_VI_MAC_CMD_IDX_G(be16_to_cpu(p->valid_to_idx)); return ret;
}
/** * t4_alloc_raw_mac_filt - Adds a mac entry in mps tcam * @adap: the adapter * @viid: the VI id * @addr: the MAC address * @mask: the mask * @idx: index at which to add this entry * @lookup_type: MAC address for inner (1) or outer (0) header * @port_id: the port index * @sleep_ok: call is allowed to sleep * * Adds the mac entry at the specified index using raw mac interface. * * Returns a negative error number or the allocated index for this mac.
*/ int t4_alloc_raw_mac_filt(struct adapter *adap, unsignedint viid, const u8 *addr, const u8 *mask, unsignedint idx,
u8 lookup_type, u8 port_id, bool sleep_ok)
{ int ret = 0; struct fw_vi_mac_cmd c; struct fw_vi_mac_raw *p = &c.u.raw;
u32 val;
/* Copy the address and the mask */
memcpy((u8 *)&p->data1[0] + 2, addr, ETH_ALEN);
memcpy((u8 *)&p->data1m[0] + 2, mask, ETH_ALEN);
ret = t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, sleep_ok); if (ret == 0) {
ret = FW_VI_MAC_CMD_RAW_IDX_G(be32_to_cpu(p->raw_idx_pkd)); if (ret != idx)
ret = -ENOMEM;
}
return ret;
}
/** * t4_alloc_mac_filt - allocates exact-match filters for MAC addresses * @adap: the adapter * @mbox: mailbox to use for the FW command * @viid: the VI id * @free: if true any existing filters for this VI id are first removed * @naddr: the number of MAC addresses to allocate filters for (up to 7) * @addr: the MAC address(es) * @idx: where to store the index of each allocated filter * @hash: pointer to hash address filter bitmap * @sleep_ok: call is allowed to sleep * * Allocates an exact-match filter for each of the supplied addresses and * sets it to the corresponding address. If @idx is not %NULL it should * have at least @naddr entries, each of which will be set to the index of * the filter allocated for the corresponding MAC address. If a filter * could not be allocated for an address its index is set to 0xffff. * If @hash is not %NULL addresses that fail to allocate an exact filter * are hashed and update the hash filter bitmap pointed at by @hash. * * Returns a negative error number or the number of filters allocated.
*/ int t4_alloc_mac_filt(struct adapter *adap, unsignedint mbox, unsignedint viid, bool free, unsignedint naddr, const u8 **addr, u16 *idx, u64 *hash, bool sleep_ok)
{ int offset, ret = 0; struct fw_vi_mac_cmd c; unsignedint nfilters = 0; unsignedint max_naddr = adap->params.arch.mps_tcam_size; unsignedint rem = naddr;
for (i = 0, p = c.u.exact; i < fw_naddr; i++, p++) {
p->valid_to_idx =
cpu_to_be16(FW_VI_MAC_CMD_VALID_F |
FW_VI_MAC_CMD_IDX_V(
FW_VI_MAC_ADD_MAC));
memcpy(p->macaddr, addr[offset + i], sizeof(p->macaddr));
}
/* It's okay if we run out of space in our MAC address arena. * Some of the addresses we submit may get stored so we need * to run through the reply to see what the results were ...
*/
ret = t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), &c, sleep_ok); if (ret && ret != -FW_ENOMEM) break;
for (i = 0, p = c.u.exact; i < fw_naddr; i++, p++) {
u16 index = FW_VI_MAC_CMD_IDX_G(
be16_to_cpu(p->valid_to_idx));
free = false;
offset += fw_naddr;
rem -= fw_naddr;
}
if (ret == 0 || ret == -FW_ENOMEM)
ret = nfilters; return ret;
}
/** * t4_free_mac_filt - frees exact-match filters of given MAC addresses * @adap: the adapter * @mbox: mailbox to use for the FW command * @viid: the VI id * @naddr: the number of MAC addresses to allocate filters for (up to 7) * @addr: the MAC address(es) * @sleep_ok: call is allowed to sleep * * Frees the exact-match filter for each of the supplied addresses * * Returns a negative error number or the number of filters freed.
*/ int t4_free_mac_filt(struct adapter *adap, unsignedint mbox, unsignedint viid, unsignedint naddr, const u8 **addr, bool sleep_ok)
{ int offset, ret = 0; struct fw_vi_mac_cmd c; unsignedint nfilters = 0; unsignedint max_naddr = is_t4(adap->params.chip) ?
NUM_MPS_CLS_SRAM_L_INSTANCES :
NUM_MPS_T5_CLS_SRAM_L_INSTANCES; unsignedint rem = naddr;
for (i = 0, p = c.u.exact; i < (int)fw_naddr; i++, p++) {
p->valid_to_idx = cpu_to_be16(
FW_VI_MAC_CMD_VALID_F |
FW_VI_MAC_CMD_IDX_V(FW_VI_MAC_MAC_BASED_FREE));
memcpy(p->macaddr, addr[offset+i], sizeof(p->macaddr));
}
ret = t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), &c, sleep_ok); if (ret) break;
for (i = 0, p = c.u.exact; i < fw_naddr; i++, p++) {
u16 index = FW_VI_MAC_CMD_IDX_G(
be16_to_cpu(p->valid_to_idx));
if (index < max_naddr)
nfilters++;
}
offset += fw_naddr;
rem -= fw_naddr;
}
if (ret == 0)
ret = nfilters; return ret;
}
/** * t4_change_mac - modifies the exact-match filter for a MAC address * @adap: the adapter * @mbox: mailbox to use for the FW command * @viid: the VI id * @idx: index of existing filter for old value of MAC address, or -1 * @addr: the new MAC address value * @persist: whether a new MAC allocation should be persistent * @smt_idx: the destination to store the new SMT index. * * Modifies an exact-match filter and sets it to the new MAC address. * Note that in general it is not possible to modify the value of a given * filter so the generic way to modify an address filter is to free the one * being used by the old address value and allocate a new filter for the * new address value. @idx can be -1 if the address is a new addition. * * Returns a negative error number or the index of the filter with the new * MAC value.
*/ int t4_change_mac(struct adapter *adap, unsignedint mbox, unsignedint viid, int idx, const u8 *addr, bool persist, u8 *smt_idx)
{ int ret, mode; struct fw_vi_mac_cmd c; struct fw_vi_mac_exact *p = c.u.exact; unsignedint max_mac_addr = adap->params.arch.mps_tcam_size;
ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); if (ret == 0) {
ret = FW_VI_MAC_CMD_IDX_G(be16_to_cpu(p->valid_to_idx)); if (ret >= max_mac_addr)
ret = -ENOMEM; if (smt_idx) { if (adap->params.viid_smt_extn_support) {
*smt_idx = FW_VI_MAC_CMD_SMTID_G
(be32_to_cpu(c.op_to_viid));
} else { /* In T4/T5, SMT contains 256 SMAC entries * organized in 128 rows of 2 entries each. * In T6, SMT contains 256 SMAC entries in * 256 rows.
*/ if (CHELSIO_CHIP_VERSION(adap->params.chip) <=
CHELSIO_T5)
*smt_idx = (viid & FW_VIID_VIN_M) << 1; else
*smt_idx = (viid & FW_VIID_VIN_M);
}
}
} return ret;
}
/** * t4_set_addr_hash - program the MAC inexact-match hash filter * @adap: the adapter * @mbox: mailbox to use for the FW command * @viid: the VI id * @ucast: whether the hash filter should also match unicast addresses * @vec: the value to be written to the hash filter * @sleep_ok: call is allowed to sleep * * Sets the 64-bit inexact-match hash filter for a virtual interface.
*/ int t4_set_addr_hash(struct adapter *adap, unsignedint mbox, unsignedint viid, bool ucast, u64 vec, bool sleep_ok)
{ struct fw_vi_mac_cmd c;
/** * t4_enable_vi_params - enable/disable a virtual interface * @adap: the adapter * @mbox: mailbox to use for the FW command * @viid: the VI id * @rx_en: 1=enable Rx, 0=disable Rx * @tx_en: 1=enable Tx, 0=disable Tx * @dcb_en: 1=enable delivery of Data Center Bridging messages. * * Enables/disables a virtual interface. Note that setting DCB Enable * only makes sense when enabling a Virtual Interface ...
*/ int t4_enable_vi_params(struct adapter *adap, unsignedint mbox, unsignedint viid, bool rx_en, bool tx_en, bool dcb_en)
{ struct fw_vi_enable_cmd c;
/** * t4_enable_vi - enable/disable a virtual interface * @adap: the adapter * @mbox: mailbox to use for the FW command * @viid: the VI id * @rx_en: 1=enable Rx, 0=disable Rx * @tx_en: 1=enable Tx, 0=disable Tx * * Enables/disables a virtual interface.
*/ int t4_enable_vi(struct adapter *adap, unsignedint mbox, unsignedint viid, bool rx_en, bool tx_en)
{ return t4_enable_vi_params(adap, mbox, viid, rx_en, tx_en, 0);
}
/** * t4_enable_pi_params - enable/disable a Port's Virtual Interface * @adap: the adapter * @mbox: mailbox to use for the FW command * @pi: the Port Information structure * @rx_en: 1=enable Rx, 0=disable Rx * @tx_en: 1=enable Tx, 0=disable Tx * @dcb_en: 1=enable delivery of Data Center Bridging messages. * * Enables/disables a Port's Virtual Interface. Note that setting DCB * Enable only makes sense when enabling a Virtual Interface ... * If the Virtual Interface enable/disable operation is successful, * we notify the OS-specific code of a potential Link Status change * via the OS Contract API t4_os_link_changed().
*/ int t4_enable_pi_params(struct adapter *adap, unsignedint mbox, struct port_info *pi, bool rx_en, bool tx_en, bool dcb_en)
{ int ret = t4_enable_vi_params(adap, mbox, pi->viid,
rx_en, tx_en, dcb_en); if (ret) return ret;
t4_os_link_changed(adap, pi->port_id,
rx_en && tx_en && pi->link_cfg.link_ok); return0;
}
/** * t4_identify_port - identify a VI's port by blinking its LED * @adap: the adapter * @mbox: mailbox to use for the FW command * @viid: the VI id * @nblinks: how many times to blink LED at 2.5 Hz * * Identifies a VI's port by blinking its LED.
*/ int t4_identify_port(struct adapter *adap, unsignedint mbox, unsignedint viid, unsignedint nblinks)
{ struct fw_vi_enable_cmd c;
/** * t4_iq_stop - stop an ingress queue and its FLs * @adap: the adapter * @mbox: mailbox to use for the FW command * @pf: the PF owning the queues * @vf: the VF owning the queues * @iqtype: the ingress queue type (FW_IQ_TYPE_FL_INT_CAP, etc.) * @iqid: ingress queue id * @fl0id: FL0 queue id or 0xffff if no attached FL0 * @fl1id: FL1 queue id or 0xffff if no attached FL1 * * Stops an ingress queue and its associated FLs, if any. This causes * any current or future data/messages destined for these queues to be * tossed.
*/ int t4_iq_stop(struct adapter *adap, unsignedint mbox, unsignedint pf, unsignedint vf, unsignedint iqtype, unsignedint iqid, unsignedint fl0id, unsignedint fl1id)
{ struct fw_iq_cmd c;
/** * t4_iq_free - free an ingress queue and its FLs * @adap: the adapter * @mbox: mailbox to use for the FW command * @pf: the PF owning the queues * @vf: the VF owning the queues * @iqtype: the ingress queue type * @iqid: ingress queue id * @fl0id: FL0 queue id or 0xffff if no attached FL0 * @fl1id: FL1 queue id or 0xffff if no attached FL1 * * Frees an ingress queue and its associated FLs, if any.
*/ int t4_iq_free(struct adapter *adap, unsignedint mbox, unsignedint pf, unsignedint vf, unsignedint iqtype, unsignedint iqid, unsignedint fl0id, unsignedint fl1id)
{ struct fw_iq_cmd c;
/** * t4_eth_eq_free - free an Ethernet egress queue * @adap: the adapter * @mbox: mailbox to use for the FW command * @pf: the PF owning the queue * @vf: the VF owning the queue * @eqid: egress queue id * * Frees an Ethernet egress queue.
*/ int t4_eth_eq_free(struct adapter *adap, unsignedint mbox, unsignedint pf, unsignedint vf, unsignedint eqid)
{ struct fw_eq_eth_cmd c;
/** * t4_ctrl_eq_free - free a control egress queue * @adap: the adapter * @mbox: mailbox to use for the FW command * @pf: the PF owning the queue * @vf: the VF owning the queue * @eqid: egress queue id * * Frees a control egress queue.
*/ int t4_ctrl_eq_free(struct adapter *adap, unsignedint mbox, unsignedint pf, unsignedint vf, unsignedint eqid)
{ struct fw_eq_ctrl_cmd c;
/** * t4_ofld_eq_free - free an offload egress queue * @adap: the adapter * @mbox: mailbox to use for the FW command * @pf: the PF owning the queue * @vf: the VF owning the queue * @eqid: egress queue id * * Frees a control egress queue.
*/ int t4_ofld_eq_free(struct adapter *adap, unsignedint mbox, unsignedint pf, unsignedint vf, unsignedint eqid)
{ struct fw_eq_ofld_cmd c;
/** * t4_link_down_rc_str - return a string for a Link Down Reason Code * @link_down_rc: Link Down Reason Code * * Returns a string representation of the Link Down Reason Code.
*/ staticconstchar *t4_link_down_rc_str(unsignedchar link_down_rc)
{ staticconstchar * const reason[] = { "Link Down", "Remote Fault", "Auto-negotiation Failure", "Reserved", "Insufficient Airflow", "Unable To Determine Reason", "No RX Signal Detected", "Reserved",
};
if (link_down_rc >= ARRAY_SIZE(reason)) return"Bad Reason Code";
return reason[link_down_rc];
}
/* Return the highest speed set in the port capabilities, in Mb/s. */ staticunsignedint fwcap_to_speed(fw_port_cap32_t caps)
{ #define TEST_SPEED_RETURN(__caps_speed, __speed) \ do { \ if (caps & FW_PORT_CAP32_SPEED_##__caps_speed) \ return __speed; \
} while (0)
/** * fwcap_to_fwspeed - return highest speed in Port Capabilities * @acaps: advertised Port Capabilities * * Get the highest speed for the port from the advertised Port * Capabilities. It will be either the highest speed from the list of * speeds or whatever user has set using ethtool.
*/ static fw_port_cap32_t fwcap_to_fwspeed(fw_port_cap32_t acaps)
{ #define TEST_SPEED_RETURN(__caps_speed) \ do { \ if (acaps & FW_PORT_CAP32_SPEED_##__caps_speed) \ return FW_PORT_CAP32_SPEED_##__caps_speed; \
} while (0)
/** * lstatus_to_fwcap - translate old lstatus to 32-bit Port Capabilities * @lstatus: old FW_PORT_ACTION_GET_PORT_INFO lstatus value * * Translates old FW_PORT_ACTION_GET_PORT_INFO lstatus field into new * 32-bit Port Capabilities value.
*/ static fw_port_cap32_t lstatus_to_fwcap(u32 lstatus)
{
fw_port_cap32_t linkattr = 0;
/* Unfortunately the format of the Link Status in the old * 16-bit Port Information message isn't the same as the * 16-bit Port Capabilities bitfield used everywhere else ...
*/ if (lstatus & FW_PORT_CMD_RXPAUSE_F)
linkattr |= FW_PORT_CAP32_FC_RX; if (lstatus & FW_PORT_CMD_TXPAUSE_F)
linkattr |= FW_PORT_CAP32_FC_TX; if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100M))
linkattr |= FW_PORT_CAP32_SPEED_100M; if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_1G))
linkattr |= FW_PORT_CAP32_SPEED_1G; if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_10G))
linkattr |= FW_PORT_CAP32_SPEED_10G; if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_25G))
linkattr |= FW_PORT_CAP32_SPEED_25G; if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_40G))
linkattr |= FW_PORT_CAP32_SPEED_40G; if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100G))
linkattr |= FW_PORT_CAP32_SPEED_100G;
return linkattr;
}
/** * t4_handle_get_port_info - process a FW reply message * @pi: the port info * @rpl: start of the FW message * * Processes a GET_PORT_INFO FW reply message.
*/ void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl)
{ conststruct fw_port_cmd *cmd = (constvoid *)rpl;
fw_port_cap32_t pcaps, acaps, lpacaps, linkattr; struct link_config *lc = &pi->link_cfg; struct adapter *adapter = pi->adapter; unsignedint speed, fc, fec, adv_fc; enum fw_port_module_type mod_type; int action, link_ok, linkdnrc; enum fw_port_type port_type;
/* Extract the various fields from the Port Information message.
*/
action = FW_PORT_CMD_ACTION_G(be32_to_cpu(cmd->action_to_len16)); switch (action) { case FW_PORT_ACTION_GET_PORT_INFO: {
u32 lstatus = be32_to_cpu(cmd->u.info.lstatus_to_modtype);
/* Reset state for communicating new Transceiver Module status and * whether the OS-dependent layer wants us to redo the current * "sticky" L1 Configure Link Parameters.
*/
lc->new_module = false;
lc->redo_l1cfg = false;
if (mod_type != pi->mod_type) { /* With the newer SFP28 and QSFP28 Transceiver Module Types, * various fundamental Port Capabilities which used to be * immutable can now change radically. We can now have * Speeds, Auto-Negotiation, Forward Error Correction, etc. * all change based on what Transceiver Module is inserted. * So we need to record the Physical "Port" Capabilities on * every Transceiver Module change.
*/
lc->pcaps = pcaps;
/* When a new Transceiver Module is inserted, the Firmware * will examine its i2c EPROM to determine its type and * general operating parameters including things like Forward * Error Control, etc. Various IEEE 802.3 standards dictate * how to interpret these i2c values to determine default * "sutomatic" settings. We record these for future use when * the user explicitly requests these standards-based values.
*/
lc->def_acaps = acaps;
/* Some versions of the early T6 Firmware "cheated" when * handling different Transceiver Modules by changing the * underlaying Port Type reported to the Host Drivers. As * such we need to capture whatever Port Type the Firmware * sends us and record it in case it's different from what we * were told earlier. Unfortunately, since Firmware is * forever, we'll need to keep this code here forever, but in * later T6 Firmware it should just be an assignment of the * same value already recorded.
*/
pi->port_type = port_type;
/* Record new Module Type information.
*/
pi->mod_type = mod_type;
/* Let the OS-dependent layer know if we have a new * Transceiver Module inserted.
*/
lc->new_module = t4_is_inserted_mod_type(mod_type);
/* If we're not physically capable of Auto-Negotiation, note * this as Auto-Negotiation disabled. Otherwise, we track * what Auto-Negotiation settings we have. Note parallel * structure in t4_link_l1cfg_core() and init_link_config().
*/ if (!(lc->acaps & FW_PORT_CAP32_ANEG)) {
lc->autoneg = AUTONEG_DISABLE;
} elseif (lc->acaps & FW_PORT_CAP32_ANEG) {
lc->autoneg = AUTONEG_ENABLE;
} else { /* When Autoneg is disabled, user needs to set * single speed. * Similar to cxgb4_ethtool.c: set_link_ksettings
*/
lc->acaps = 0;
lc->speed_caps = fwcap_to_fwspeed(acaps);
lc->autoneg = AUTONEG_DISABLE;
}
/* If we have a new Transceiver Module and the OS-dependent code has * told us that it wants us to redo whatever "sticky" L1 Configuration * Link Parameters are set, do that now.
*/ if (lc->new_module && lc->redo_l1cfg) { struct link_config old_lc; int ret;
/* Save the current L1 Configuration and restore it if an * error occurs. We probably should fix the l1_cfg*() * routines not to change the link_config when an error * occurs ...
*/
old_lc = *lc;
ret = t4_link_l1cfg_ns(adapter, adapter->mbox, pi->lport, lc); if (ret) {
*lc = old_lc;
dev_warn(adapter->pdev_dev, "Attempt to update new Transceiver Module settings failed\n");
}
}
lc->new_module = false;
lc->redo_l1cfg = false;
}
/** * t4_update_port_info - retrieve and update port information if changed * @pi: the port_info * * We issue a Get Port Information Command to the Firmware and, if * successful, we check to see if anything is different from what we * last recorded and update things accordingly.
*/ int t4_update_port_info(struct port_info *pi)
{ unsignedint fw_caps = pi->adapter->params.fw_caps_support; struct fw_port_cmd port_cmd; int ret;
/** * t4_get_link_params - retrieve basic link parameters for given port * @pi: the port * @link_okp: value return pointer for link up/down * @speedp: value return pointer for speed (Mb/s) * @mtup: value return pointer for mtu * * Retrieves basic link parameters for a port: link up/down, speed (Mb/s), * and MTU for a specified port. A negative error is returned on * failure; 0 on success.
*/ int t4_get_link_params(struct port_info *pi, unsignedint *link_okp, unsignedint *speedp, unsignedint *mtup)
{ unsignedint fw_caps = pi->adapter->params.fw_caps_support; unsignedint action, link_ok, mtu; struct fw_port_cmd port_cmd;
fw_port_cap32_t linkattr; int ret;
if (link_okp)
*link_okp = link_ok; if (speedp)
*speedp = fwcap_to_speed(linkattr); if (mtup)
*mtup = mtu;
return0;
}
/** * t4_handle_fw_rpl - process a FW reply message * @adap: the adapter * @rpl: start of the FW message * * Processes a FW message, such as link state change messages.
*/ int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl)
{
u8 opcode = *(const u8 *)rpl;
/* This might be a port command ... this simplifies the following * conditionals ... We can get away with pre-dereferencing * action_to_len16 because it's in the first 16 bytes and all messages * will be at least that long.
*/ conststruct fw_port_cmd *p = (constvoid *)rpl; unsignedint action =
FW_PORT_CMD_ACTION_G(be32_to_cpu(p->action_to_len16));
if (opcode == FW_PORT_CMD &&
(action == FW_PORT_ACTION_GET_PORT_INFO ||
action == FW_PORT_ACTION_GET_PORT_INFO32)) { int i; int chan = FW_PORT_CMD_PORTID_G(be32_to_cpu(p->op_to_portid)); struct port_info *pi = NULL;
for_each_port(adap, i) {
pi = adap2pinfo(adap, i); if (pi->tx_chan == chan) break;
}
if (pci_is_pcie(adapter->pdev)) {
pcie_capability_read_word(adapter->pdev, PCI_EXP_LNKSTA, &val);
p->speed = val & PCI_EXP_LNKSTA_CLS;
p->width = (val & PCI_EXP_LNKSTA_NLW) >> 4;
}
}
/** * init_link_config - initialize a link's SW state * @lc: pointer to structure holding the link state * @pcaps: link Port Capabilities * @acaps: link current Advertised Port Capabilities * * Initializes the SW state maintained for each link, including the link's * capabilities and default speed/flow-control/autonegotiation settings.
*/ staticvoid init_link_config(struct link_config *lc, fw_port_cap32_t pcaps,
fw_port_cap32_t acaps)
{
lc->pcaps = pcaps;
lc->def_acaps = acaps;
lc->lpacaps = 0;
lc->speed_caps = 0;
lc->speed = 0;
lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX;
/* For Forward Error Control, we default to whatever the Firmware * tells us the Link is currently advertising.
*/
lc->requested_fec = FEC_AUTO;
lc->fec = fwcap_to_cc_fec(lc->def_acaps);
/* If the Port is capable of Auto-Negtotiation, initialize it as * "enabled" and copy over all of the Physical Port Capabilities * to the Advertised Port Capabilities. Otherwise mark it as * Auto-Negotiate disabled and select the highest supported speed * for the link. Note parallel structure in t4_link_l1cfg_core() * and t4_handle_get_port_info().
*/ if (lc->pcaps & FW_PORT_CAP32_ANEG) {
lc->acaps = lc->pcaps & ADVERT_MASK;
lc->autoneg = AUTONEG_ENABLE;
lc->requested_fc |= PAUSE_AUTONEG;
} else {
lc->acaps = 0;
lc->autoneg = AUTONEG_DISABLE;
lc->speed_caps = fwcap_to_fwspeed(acaps);
}
}
#define CIM_PF_NOACCESS 0xeeeeeeee
int t4_wait_dev_ready(void __iomem *regs)
{
u32 whoami;
staticint t4_get_flash_params(struct adapter *adap)
{ /* Table for non-Numonix supported flash parts. Numonix parts are left * to the preexisting code. All flash parts have 64KB sectors.
*/ staticstruct flash_desc supported_flash[] = {
{ 0x150201, 4 << 20 }, /* Spansion 4MB S25FL032P */
};
/* Issue a Read ID Command to the Flash part. We decode supported * Flash parts and their sizes from this. There's a newer Query * Command which can retrieve detailed geometry information but many * Flash parts don't support it.
*/
ret = sf1_write(adap, 1, 1, 0, SF_RD_ID); if (!ret)
ret = sf1_read(adap, 3, 0, 1, &flashid);
t4_write_reg(adap, SF_OP_A, 0); /* unlock SF */ if (ret) return ret;
/* Check to see if it's one of our non-standard supported Flash parts.
*/ for (part = 0; part < ARRAY_SIZE(supported_flash); part++) if (supported_flash[part].vendor_and_model_id == flashid) {
adap->params.sf_size = supported_flash[part].size_mb;
adap->params.sf_nsec =
adap->params.sf_size / SF_SEC_SIZE; goto found;
}
/* Decode Flash part size. The code below looks repetitive with * common encodings, but that's not guaranteed in the JEDEC * specification for the Read JEDEC ID command. The only thing that * we're guaranteed by the JEDEC specification is where the * Manufacturer ID is in the returned result. After that each * Manufacturer ~could~ encode things completely differently. * Note, all Flash parts must have 64KB sectors.
*/
manufacturer = flashid & 0xff; switch (manufacturer) { case0x20: { /* Micron/Numonix */ /* This Density -> Size decoding table is taken from Micron * Data Sheets.
*/
density = (flashid >> 16) & 0xff; switch (density) { case0x14: /* 1MB */
size = 1 << 20; break; case0x15: /* 2MB */
size = 1 << 21; break; case0x16: /* 4MB */
size = 1 << 22; break; case0x17: /* 8MB */
size = 1 << 23; break; case0x18: /* 16MB */
size = 1 << 24; break; case0x19: /* 32MB */
size = 1 << 25; break; case0x20: /* 64MB */
size = 1 << 26; break; case0x21: /* 128MB */
size = 1 << 27; break; case0x22: /* 256MB */
size = 1 << 28; break;
} break;
} case0x9d: { /* ISSI -- Integrated Silicon Solution, Inc. */ /* This Density -> Size decoding table is taken from ISSI * Data Sheets.
*/
density = (flashid >> 16) & 0xff; switch (density) { case0x16: /* 32 MB */
size = 1 << 25; break; case0x17: /* 64MB */
size = 1 << 26; break;
} break;
} case0xc2: { /* Macronix */ /* This Density -> Size decoding table is taken from Macronix * Data Sheets.
*/
density = (flashid >> 16) & 0xff; switch (density) { case0x17: /* 8MB */
size = 1 << 23; break; case0x18: /* 16MB */
size = 1 << 24; break;
} break;
} case0xef: { /* Winbond */ /* This Density -> Size decoding table is taken from Winbond * Data Sheets.
*/
density = (flashid >> 16) & 0xff; switch (density) { case0x17: /* 8MB */
size = 1 << 23; break; case0x18: /* 16MB */
size = 1 << 24; break;
} break;
}
}
/* If we didn't recognize the FLASH part, that's no real issue: the * Hardware/Software contract says that Hardware will _*ALWAYS*_ * use a FLASH part which is at least 4MB in size and has 64KB * sectors. The unrecognized FLASH part is likely to be much larger * than 4MB, but that's all we really need.
*/ if (size == 0) {
dev_warn(adap->pdev_dev, "Unknown Flash Part, ID = %#x, assuming 4MB\n",
flashid);
size = 1 << 22;
}
/* Store decoded Flash size and fall through into vetting code. */
adap->params.sf_size = size;
adap->params.sf_nsec = size / SF_SEC_SIZE;
found: if (adap->params.sf_size < FLASH_MIN_SIZE)
dev_warn(adap->pdev_dev, "WARNING: Flash Part ID %#x, size %#x < %#x\n",
flashid, adap->params.sf_size, FLASH_MIN_SIZE); return0;
}
/** * t4_prep_adapter - prepare SW and HW for operation * @adapter: the adapter * * Initialize adapter SW state for the various HW modules, set initial * values for some adapter tunables, take PHYs out of reset, and * initialize the MDIO interface.
*/ int t4_prep_adapter(struct adapter *adapter)
{ int ret, ver;
uint16_t device_id;
u32 pl_rev;
/* * Default port for debugging in case we can't reach FW.
*/
adapter->params.nports = 1;
adapter->params.portvec = 1;
adapter->params.vpd.cclk = 50000;
/* Set PCIe completion timeout to 4 seconds. */
pcie_capability_clear_and_set_word(adapter->pdev, PCI_EXP_DEVCTL2,
PCI_EXP_DEVCTL2_COMP_TIMEOUT, 0xd); return0;
}
/** * t4_shutdown_adapter - shut down adapter, host & wire * @adapter: the adapter * * Perform an emergency shutdown of the adapter and stop it from * continuing any further communication on the ports or DMA to the * host. This is typically used when the adapter and/or firmware * have crashed and we want to prevent any further accidental * communication with the rest of the world. This will also force * the port Link Status to go down -- if register writes work -- * which should help our peers figure out that we're down.
*/ int t4_shutdown_adapter(struct adapter *adapter)
{ int port;
/** * t4_bar2_sge_qregs - return BAR2 SGE Queue register information * @adapter: the adapter * @qid: the Queue ID * @qtype: the Ingress or Egress type for @qid * @user: true if this request is for a user mode queue * @pbar2_qoffset: BAR2 Queue Offset * @pbar2_qid: BAR2 Queue ID or 0 for Queue ID inferred SGE Queues * * Returns the BAR2 SGE Queue Registers information associated with the * indicated Absolute Queue ID. These are passed back in return value * pointers. @qtype should be T4_BAR2_QTYPE_EGRESS for Egress Queue * and T4_BAR2_QTYPE_INGRESS for Ingress Queues. * * This may return an error which indicates that BAR2 SGE Queue * registers aren't available. If an error is not returned, then the * following values are returned: * * *@pbar2_qoffset: the BAR2 Offset of the @qid Registers * *@pbar2_qid: the BAR2 SGE Queue ID or 0 of @qid * * If the returned BAR2 Queue ID is 0, then BAR2 SGE registers which * require the "Inferred Queue ID" ability may be used. E.g. the * Write Combining Doorbell Buffer. If the BAR2 Queue ID is not 0, * then these "Inferred Queue ID" register may not be used.
*/ int t4_bar2_sge_qregs(struct adapter *adapter, unsignedint qid, enum t4_bar2_qtype qtype, int user,
u64 *pbar2_qoffset, unsignedint *pbar2_qid)
{ unsignedint page_shift, page_size, qpp_shift, qpp_mask;
u64 bar2_page_offset, bar2_qoffset; unsignedint bar2_qid, bar2_qid_offset, bar2_qinferred;
/* T4 doesn't support BAR2 SGE Queue registers for kernel mode queues */ if (!user && is_t4(adapter->params.chip)) return -EINVAL;
/* Get the right Queues per Page parameters for our Queue.
*/
qpp_shift = (qtype == T4_BAR2_QTYPE_EGRESS
? adapter->params.sge.eq_qpp
: adapter->params.sge.iq_qpp);
qpp_mask = (1 << qpp_shift) - 1;
/* Calculate the basics of the BAR2 SGE Queue register area: * o The BAR2 page the Queue registers will be in. * o The BAR2 Queue ID. * o The BAR2 Queue ID Offset into the BAR2 page.
*/
bar2_page_offset = ((u64)(qid >> qpp_shift) << page_shift);
bar2_qid = qid & qpp_mask;
bar2_qid_offset = bar2_qid * SGE_UDB_SIZE;
/* If the BAR2 Queue ID Offset is less than the Page Size, then the * hardware will infer the Absolute Queue ID simply from the writes to * the BAR2 Queue ID Offset within the BAR2 Page (and we need to use a * BAR2 Queue ID of 0 for those writes). Otherwise, we'll simply * write to the first BAR2 SGE Queue Area within the BAR2 Page with * the BAR2 Queue ID and the hardware will infer the Absolute Queue ID * from the BAR2 Page and BAR2 Queue ID. * * One important censequence of this is that some BAR2 SGE registers * have a "Queue ID" field and we can write the BAR2 SGE Queue ID * there. But other registers synthesize the SGE Queue ID purely * from the writes to the registers -- the Write Combined Doorbell * Buffer is a good example. These BAR2 SGE Registers are only * available for those BAR2 SGE Register areas where the SGE Absolute * Queue ID can be inferred from simple writes.
*/
bar2_qoffset = bar2_page_offset;
bar2_qinferred = (bar2_qid_offset < page_size); if (bar2_qinferred) {
bar2_qoffset += bar2_qid_offset;
bar2_qid = 0;
}
/** * t4_init_devlog_params - initialize adapter->params.devlog * @adap: the adapter * * Initialize various fields of the adapter's Firmware Device Log * Parameters structure.
*/ int t4_init_devlog_params(struct adapter *adap)
{ struct devlog_params *dparams = &adap->params.devlog;
u32 pf_dparams; unsignedint devlog_meminfo; struct fw_devlog_cmd devlog_cmd; int ret;
/* If we're dealing with newer firmware, the Device Log Parameters * are stored in a designated register which allows us to access the * Device Log even if we can't talk to the firmware.
*/
pf_dparams =
t4_read_reg(adap, PCIE_FW_REG(PCIE_FW_PF_A, PCIE_FW_PF_DEVLOG)); if (pf_dparams) { unsignedint nentries, nentries128;
/** * t4_init_tp_params - initialize adap->params.tp * @adap: the adapter * @sleep_ok: if true we may sleep while awaiting command completion * * Initialize various fields of the adapter's TP Parameters structure.
*/ int t4_init_tp_params(struct adapter *adap, bool sleep_ok)
{
u32 param, val, v; int chan, ret;
v = t4_read_reg(adap, TP_TIMER_RESOLUTION_A);
adap->params.tp.tre = TIMERRESOLUTION_G(v);
adap->params.tp.dack_re = DELAYEDACKRESOLUTION_G(v);
/* MODQ_REQ_MAP defaults to setting queues 0-3 to chan 0-3 */ for (chan = 0; chan < NCHAN; chan++)
adap->params.tp.tx_modq[chan] = chan;
/* Cache the adapter's Compressed Filter Mode/Mask and global Ingress * Configuration.
*/
param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_FILTER) |
FW_PARAMS_PARAM_Y_V(FW_PARAM_DEV_FILTER_MODE_MASK));
/* Read current value */
ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1,
¶m, &val); if (ret == 0) {
dev_info(adap->pdev_dev, "Current filter mode/mask 0x%x:0x%x\n",
FW_PARAMS_PARAM_FILTER_MODE_G(val),
FW_PARAMS_PARAM_FILTER_MASK_G(val));
adap->params.tp.vlan_pri_map =
FW_PARAMS_PARAM_FILTER_MODE_G(val);
adap->params.tp.filter_mask =
FW_PARAMS_PARAM_FILTER_MASK_G(val);
} else {
dev_info(adap->pdev_dev, "Failed to read filter mode/mask via fw api, using indirect-reg-read\n");
/* Incase of older-fw (which doesn't expose the api * FW_PARAM_DEV_FILTER_MODE_MASK) and newer-driver (which uses * the fw api) combination, fall-back to older method of reading * the filter mode from indirect-register
*/
t4_tp_pio_read(adap, &adap->params.tp.vlan_pri_map, 1,
TP_VLAN_PRI_MAP_A, sleep_ok);
/* With the older-fw and newer-driver combination we might run * into an issue when user wants to use hash filter region but * the filter_mask is zero, in this case filter_mask validation * is tough. To avoid that we set the filter_mask same as filter * mode, which will behave exactly as the older way of ignoring * the filter mask validation.
*/
adap->params.tp.filter_mask = adap->params.tp.vlan_pri_map;
}
/* For T6, cache the adapter's compressed error vector * and passing outer header info for encapsulated packets.
*/ if (CHELSIO_CHIP_VERSION(adap->params.chip) > CHELSIO_T5) {
v = t4_read_reg(adap, TP_OUT_CONFIG_A);
adap->params.tp.rx_pkt_encap = (v & CRXPKTENC_F) ? 1 : 0;
}
/* Now that we have TP_VLAN_PRI_MAP cached, we can calculate the field * shift positions of several elements of the Compressed Filter Tuple * for this adapter which we need frequently ...
*/
adap->params.tp.fcoe_shift = t4_filter_field_shift(adap, FCOE_F);
adap->params.tp.port_shift = t4_filter_field_shift(adap, PORT_F);
adap->params.tp.vnic_shift = t4_filter_field_shift(adap, VNIC_ID_F);
adap->params.tp.vlan_shift = t4_filter_field_shift(adap, VLAN_F);
adap->params.tp.tos_shift = t4_filter_field_shift(adap, TOS_F);
adap->params.tp.protocol_shift = t4_filter_field_shift(adap,
PROTOCOL_F);
adap->params.tp.ethertype_shift = t4_filter_field_shift(adap,
ETHERTYPE_F);
adap->params.tp.macmatch_shift = t4_filter_field_shift(adap,
MACMATCH_F);
adap->params.tp.matchtype_shift = t4_filter_field_shift(adap,
MPSHITTYPE_F);
adap->params.tp.frag_shift = t4_filter_field_shift(adap,
FRAGMENTATION_F);
/* If TP_INGRESS_CONFIG.VNID == 0, then TP_VLAN_PRI_MAP.VNIC_ID * represents the presence of an Outer VLAN instead of a VNIC ID.
*/ if ((adap->params.tp.ingress_config & VNIC_F) == 0)
adap->params.tp.vnic_shift = -1;
v = t4_read_reg(adap, LE_3_DB_HASH_MASK_GEN_IPV4_T6_A);
adap->params.tp.hash_filter_mask = v;
v = t4_read_reg(adap, LE_4_DB_HASH_MASK_GEN_IPV4_T6_A);
adap->params.tp.hash_filter_mask |= ((u64)v << 32); return0;
}
/** * t4_filter_field_shift - calculate filter field shift * @adap: the adapter * @filter_sel: the desired field (from TP_VLAN_PRI_MAP bits) * * Return the shift position of a filter field within the Compressed * Filter Tuple. The filter field is specified via its selection bit * within TP_VLAN_PRI_MAL (filter mode). E.g. F_VLAN.
*/ int t4_filter_field_shift(conststruct adapter *adap, int filter_sel)
{ unsignedint filter_mode = adap->params.tp.vlan_pri_map; unsignedint sel; int field_shift;
if ((filter_mode & filter_sel) == 0) return -1;
for (sel = 1, field_shift = 0; sel < filter_sel; sel <<= 1) { switch (filter_mode & sel) { case FCOE_F:
field_shift += FT_FCOE_W; break; case PORT_F:
field_shift += FT_PORT_W; break; case VNIC_ID_F:
field_shift += FT_VNIC_ID_W; break; case VLAN_F:
field_shift += FT_VLAN_W; break; case TOS_F:
field_shift += FT_TOS_W; break; case PROTOCOL_F:
field_shift += FT_PROTOCOL_W; break; case ETHERTYPE_F:
field_shift += FT_ETHERTYPE_W; break; case MACMATCH_F:
field_shift += FT_MACMATCH_W; break; case MPSHITTYPE_F:
field_shift += FT_MPSHITTYPE_W; break; case FRAGMENTATION_F:
field_shift += FT_FRAGMENTATION_W; break;
}
} return field_shift;
}
int t4_init_rss_mode(struct adapter *adap, int mbox)
{ int i, ret; struct fw_rss_vi_config_cmd rvc;
/** * t4_init_portinfo - allocate a virtual interface and initialize port_info * @pi: the port_info * @mbox: mailbox to use for the FW command * @port: physical port associated with the VI * @pf: the PF owning the VI * @vf: the VF owning the VI * @mac: the MAC address of the VI * * Allocates a virtual interface for the given physical port. If @mac is * not %NULL it contains the MAC address of the VI as assigned by FW. * @mac should be large enough to hold an Ethernet address. * Returns < 0 on error.
*/ int t4_init_portinfo(struct port_info *pi, int mbox, int port, int pf, int vf, u8 mac[])
{ struct adapter *adapter = pi->adapter; unsignedint fw_caps = adapter->params.fw_caps_support; struct fw_port_cmd cmd; unsignedint rss_size; enum fw_port_type port_type; int mdio_addr;
fw_port_cap32_t pcaps, acaps;
u8 vivld = 0, vin = 0; int ret;
/* If we haven't yet determined whether we're talking to Firmware * which knows the new 32-bit Port Capabilities, it's time to find * out now. This will also tell new Firmware to send us Port Status * Updates using the new 32-bit Port Capabilities version of the * Port Information message.
*/ if (fw_caps == FW_CAPS_UNKNOWN) {
u32 param, val;
/* Extract the various fields from the Port Information message.
*/ if (fw_caps == FW_CAPS16) {
u32 lstatus = be32_to_cpu(cmd.u.info.lstatus_to_modtype);
/* If fw supports returning the VIN as part of FW_VI_CMD, * save the returned values.
*/ if (adapter->params.viid_smt_extn_support) {
pi->vivld = vivld;
pi->vin = vin;
} else { /* Retrieve the values from VIID */
pi->vivld = FW_VIID_VIVLD_G(pi->viid);
pi->vin = FW_VIID_VIN_G(pi->viid);
}
int t4_init_port_mirror(struct port_info *pi, u8 mbox, u8 port, u8 pf, u8 vf,
u16 *mirror_viid)
{ int ret;
ret = t4_alloc_vi(pi->adapter, mbox, port, pf, vf, 1, NULL, NULL,
NULL, NULL); if (ret < 0) return ret;
if (mirror_viid)
*mirror_viid = ret;
return0;
}
/** * t4_read_cimq_cfg - read CIM queue configuration * @adap: the adapter * @base: holds the queue base addresses in bytes * @size: holds the queue sizes in bytes * @thres: holds the queue full thresholds in bytes * * Returns the current configuration of the CIM queues, starting with * the IBQs, then the OBQs.
*/ void t4_read_cimq_cfg(struct adapter *adap, u16 *base, u16 *size, u16 *thres)
{ unsignedint i, v; int cim_num_obq = is_t4(adap->params.chip) ?
CIM_NUM_OBQ : CIM_NUM_OBQ_T5;
for (i = 0; i < CIM_NUM_IBQ; i++) {
t4_write_reg(adap, CIM_QUEUE_CONFIG_REF_A, IBQSELECT_F |
QUENUMSELECT_V(i));
v = t4_read_reg(adap, CIM_QUEUE_CONFIG_CTRL_A); /* value is in 256-byte units */
*base++ = CIMQBASE_G(v) * 256;
*size++ = CIMQSIZE_G(v) * 256;
*thres++ = QUEFULLTHRSH_G(v) * 8; /* 8-byte unit */
} for (i = 0; i < cim_num_obq; i++) {
t4_write_reg(adap, CIM_QUEUE_CONFIG_REF_A, OBQSELECT_F |
QUENUMSELECT_V(i));
v = t4_read_reg(adap, CIM_QUEUE_CONFIG_CTRL_A); /* value is in 256-byte units */
*base++ = CIMQBASE_G(v) * 256;
*size++ = CIMQSIZE_G(v) * 256;
}
}
/** * t4_read_cim_ibq - read the contents of a CIM inbound queue * @adap: the adapter * @qid: the queue index * @data: where to store the queue contents * @n: capacity of @data in 32-bit words * * Reads the contents of the selected CIM queue starting at address 0 up * to the capacity of @data. @n must be a multiple of 4. Returns < 0 on * error and the number of 32-bit words actually read on success.
*/ int t4_read_cim_ibq(struct adapter *adap, unsignedint qid, u32 *data, size_t n)
{ int i, err, attempts; unsignedint addr; constunsignedint nwords = CIM_IBQ_SIZE * 4;
if (qid > 5 || (n & 3)) return -EINVAL;
addr = qid * nwords; if (n > nwords)
n = nwords;
/* It might take 3-10ms before the IBQ debug read access is allowed. * Wait for 1 Sec with a delay of 1 usec.
*/
attempts = 1000000;
for (i = 0; i < n; i++, addr++) {
t4_write_reg(adap, CIM_IBQ_DBG_CFG_A, IBQDBGADDR_V(addr) |
IBQDBGEN_F);
err = t4_wait_op_done(adap, CIM_IBQ_DBG_CFG_A, IBQDBGBUSY_F, 0,
attempts, 1); if (err) return err;
*data++ = t4_read_reg(adap, CIM_IBQ_DBG_DATA_A);
}
t4_write_reg(adap, CIM_IBQ_DBG_CFG_A, 0); return i;
}
/** * t4_read_cim_obq - read the contents of a CIM outbound queue * @adap: the adapter * @qid: the queue index * @data: where to store the queue contents * @n: capacity of @data in 32-bit words * * Reads the contents of the selected CIM queue starting at address 0 up * to the capacity of @data. @n must be a multiple of 4. Returns < 0 on * error and the number of 32-bit words actually read on success.
*/ int t4_read_cim_obq(struct adapter *adap, unsignedint qid, u32 *data, size_t n)
{ int i, err; unsignedint addr, v, nwords; int cim_num_obq = is_t4(adap->params.chip) ?
CIM_NUM_OBQ : CIM_NUM_OBQ_T5;
t4_write_reg(adap, CIM_QUEUE_CONFIG_REF_A, OBQSELECT_F |
QUENUMSELECT_V(qid));
v = t4_read_reg(adap, CIM_QUEUE_CONFIG_CTRL_A);
addr = CIMQBASE_G(v) * 64; /* muliple of 256 -> muliple of 4 */
nwords = CIMQSIZE_G(v) * 64; /* same */ if (n > nwords)
n = nwords;
for (i = 0; i < n; i++, addr++) {
t4_write_reg(adap, CIM_OBQ_DBG_CFG_A, OBQDBGADDR_V(addr) |
OBQDBGEN_F);
err = t4_wait_op_done(adap, CIM_OBQ_DBG_CFG_A, OBQDBGBUSY_F, 0, 2, 1); if (err) return err;
*data++ = t4_read_reg(adap, CIM_OBQ_DBG_DATA_A);
}
t4_write_reg(adap, CIM_OBQ_DBG_CFG_A, 0); return i;
}
/** * t4_cim_read - read a block from CIM internal address space * @adap: the adapter * @addr: the start address within the CIM address space * @n: number of words to read * @valp: where to store the result * * Reads a block of 4-byte words from the CIM intenal address space.
*/ int t4_cim_read(struct adapter *adap, unsignedint addr, unsignedint n, unsignedint *valp)
{ int ret = 0;
if (t4_read_reg(adap, CIM_HOST_ACC_CTRL_A) & HOSTBUSY_F) return -EBUSY;
/** * t4_cim_write - write a block into CIM internal address space * @adap: the adapter * @addr: the start address within the CIM address space * @n: number of words to write * @valp: set of values to write * * Writes a block of 4-byte words into the CIM intenal address space.
*/ int t4_cim_write(struct adapter *adap, unsignedint addr, unsignedint n, constunsignedint *valp)
{ int ret = 0;
if (t4_read_reg(adap, CIM_HOST_ACC_CTRL_A) & HOSTBUSY_F) return -EBUSY;
/** * t4_cim_read_la - read CIM LA capture buffer * @adap: the adapter * @la_buf: where to store the LA data * @wrptr: the HW write pointer within the capture buffer * * Reads the contents of the CIM LA buffer with the most recent entry at * the end of the returned data and with the entry at @wrptr first. * We try to leave the LA in the running state we find it in.
*/ int t4_cim_read_la(struct adapter *adap, u32 *la_buf, unsignedint *wrptr)
{ int i, ret; unsignedint cfg, val, idx;
ret = t4_cim_read(adap, UP_UP_DBG_LA_CFG_A, 1, &cfg); if (ret) return ret;
if (cfg & UPDBGLAEN_F) { /* LA is running, freeze it */
ret = t4_cim_write1(adap, UP_UP_DBG_LA_CFG_A, 0); if (ret) return ret;
}
ret = t4_cim_read(adap, UP_UP_DBG_LA_CFG_A, 1, &val); if (ret) goto restart;
idx = UPDBGLAWRPTR_G(val); if (wrptr)
*wrptr = idx;
for (i = 0; i < adap->params.cim_la_size; i++) {
ret = t4_cim_write1(adap, UP_UP_DBG_LA_CFG_A,
UPDBGLARDPTR_V(idx) | UPDBGLARDEN_F); if (ret) break;
ret = t4_cim_read(adap, UP_UP_DBG_LA_CFG_A, 1, &val); if (ret) break; if (val & UPDBGLARDEN_F) {
ret = -ETIMEDOUT; break;
}
ret = t4_cim_read(adap, UP_UP_DBG_LA_DATA_A, 1, &la_buf[i]); if (ret) break;
/* Bits 0-3 of UpDbgLaRdPtr can be between 0000 to 1001 to * identify the 32-bit portion of the full 312-bit data
*/ if (is_t6(adap->params.chip) && (idx & 0xf) >= 9)
idx = (idx & 0xff0) + 0x10; else
idx++; /* address can't exceed 0xfff */
idx &= UPDBGLARDPTR_M;
}
restart: if (cfg & UPDBGLAEN_F) { int r = t4_cim_write1(adap, UP_UP_DBG_LA_CFG_A,
cfg & ~UPDBGLARDEN_F); if (!ret)
ret = r;
} return ret;
}
/** * t4_tp_read_la - read TP LA capture buffer * @adap: the adapter * @la_buf: where to store the LA data * @wrptr: the HW write pointer within the capture buffer * * Reads the contents of the TP LA buffer with the most recent entry at * the end of the returned data and with the entry at @wrptr first. * We leave the LA in the running state we find it in.
*/ void t4_tp_read_la(struct adapter *adap, u64 *la_buf, unsignedint *wrptr)
{ bool last_incomplete; unsignedint i, cfg, val, idx;
val &= 0xffff;
val &= ~DBGLARPTR_V(DBGLARPTR_M);
val |= adap->params.tp.la_mask;
for (i = 0; i < TPLA_SIZE; i++) {
t4_write_reg(adap, TP_DBG_LA_CONFIG_A, DBGLARPTR_V(idx) | val);
la_buf[i] = t4_read_reg64(adap, TP_DBG_LA_DATAL_A);
idx = (idx + 1) & DBGLARPTR_M;
}
/* Wipe out last entry if it isn't valid */ if (last_incomplete)
la_buf[TPLA_SIZE - 1] = ~0ULL;
if (cfg & DBGLAENABLE_F) /* restore running state */
t4_write_reg(adap, TP_DBG_LA_CONFIG_A,
cfg | adap->params.tp.la_mask);
}
/* SGE Hung Ingress DMA Warning Threshold time and Warning Repeat Rate (in * seconds). If we find one of the SGE Ingress DMA State Machines in the same * state for more than the Warning Threshold then we'll issue a warning about * a potential hang. We'll repeat the warning as the SGE Ingress DMA Channel * appears to be hung every Warning Repeat second till the situation clears. * If the situation clears, we'll note that as well.
*/ #define SGE_IDMA_WARN_THRESH 1 #define SGE_IDMA_WARN_REPEAT 300
/** * t4_idma_monitor_init - initialize SGE Ingress DMA Monitor * @adapter: the adapter * @idma: the adapter IDMA Monitor state * * Initialize the state of an SGE Ingress DMA Monitor.
*/ void t4_idma_monitor_init(struct adapter *adapter, struct sge_idma_monitor_state *idma)
{ /* Initialize the state variables for detecting an SGE Ingress DMA * hang. The SGE has internal counters which count up on each clock * tick whenever the SGE finds its Ingress DMA State Engines in the * same state they were on the previous clock tick. The clock used is * the Core Clock so we have a limit on the maximum "time" they can * record; typically a very small number of seconds. For instance, * with a 600MHz Core Clock, we can only count up to a bit more than * 7s. So we'll synthesize a larger counter in order to not run the * risk of having the "timers" overflow and give us the flexibility to * maintain a Hung SGE State Machine of our own which operates across * a longer time frame.
*/
idma->idma_1s_thresh = core_ticks_per_usec(adapter) * 1000000; /* 1s */
idma->idma_stalled[0] = 0;
idma->idma_stalled[1] = 0;
}
/** * t4_idma_monitor - monitor SGE Ingress DMA state * @adapter: the adapter * @idma: the adapter IDMA Monitor state * @hz: number of ticks/second * @ticks: number of ticks since the last IDMA Monitor call
*/ void t4_idma_monitor(struct adapter *adapter, struct sge_idma_monitor_state *idma, int hz, int ticks)
{ int i, idma_same_state_cnt[2];
/* Read the SGE Debug Ingress DMA Same State Count registers. These * are counters inside the SGE which count up on each clock when the * SGE finds its Ingress DMA State Engines in the same states they * were in the previous clock. The counters will peg out at * 0xffffffff without wrapping around so once they pass the 1s * threshold they'll stay above that till the IDMA state changes.
*/
t4_write_reg(adapter, SGE_DEBUG_INDEX_A, 13);
idma_same_state_cnt[0] = t4_read_reg(adapter, SGE_DEBUG_DATA_HIGH_A);
idma_same_state_cnt[1] = t4_read_reg(adapter, SGE_DEBUG_DATA_LOW_A);
for (i = 0; i < 2; i++) {
u32 debug0, debug11;
/* If the Ingress DMA Same State Counter ("timer") is less * than 1s, then we can reset our synthesized Stall Timer and * continue. If we have previously emitted warnings about a * potential stalled Ingress Queue, issue a note indicating * that the Ingress Queue has resumed forward progress.
*/ if (idma_same_state_cnt[i] < idma->idma_1s_thresh) { if (idma->idma_stalled[i] >= SGE_IDMA_WARN_THRESH * hz)
dev_warn(adapter->pdev_dev, "SGE idma%d, queue %u, " "resumed after %d seconds\n",
i, idma->idma_qid[i],
idma->idma_stalled[i] / hz);
idma->idma_stalled[i] = 0; continue;
}
/* Synthesize an SGE Ingress DMA Same State Timer in the Hz * domain. The first time we get here it'll be because we * passed the 1s Threshold; each additional time it'll be * because the RX Timer Callback is being fired on its regular * schedule. * * If the stall is below our Potential Hung Ingress Queue * Warning Threshold, continue.
*/ if (idma->idma_stalled[i] == 0) {
idma->idma_stalled[i] = hz;
idma->idma_warn[i] = 0;
} else {
idma->idma_stalled[i] += ticks;
idma->idma_warn[i] -= ticks;
}
if (idma->idma_stalled[i] < SGE_IDMA_WARN_THRESH * hz) continue;
/* We'll issue a warning every SGE_IDMA_WARN_REPEAT seconds.
*/ if (idma->idma_warn[i] > 0) continue;
idma->idma_warn[i] = SGE_IDMA_WARN_REPEAT * hz;
/* Read and save the SGE IDMA State and Queue ID information. * We do this every time in case it changes across time ... * can't be too careful ...
*/
t4_write_reg(adapter, SGE_DEBUG_INDEX_A, 0);
debug0 = t4_read_reg(adapter, SGE_DEBUG_DATA_LOW_A);
idma->idma_state[i] = (debug0 >> (i * 9)) & 0x3f;
dev_warn(adapter->pdev_dev, "SGE idma%u, queue %u, potentially stuck in " "state %u for %d seconds (debug0=%#x, debug11=%#x)\n",
i, idma->idma_qid[i], idma->idma_state[i],
idma->idma_stalled[i] / hz,
debug0, debug11);
t4_sge_decode_idma_state(adapter, idma->idma_state[i]);
}
}
/** * t4_load_cfg - download config file * @adap: the adapter * @cfg_data: the cfg text file to write * @size: text file size * * Write the supplied config text file to the card's serial flash.
*/ int t4_load_cfg(struct adapter *adap, const u8 *cfg_data, unsignedint size)
{ int ret, i, n, cfg_addr; unsignedint addr; unsignedint flash_cfg_start_sec; unsignedint sf_sec_size = adap->params.sf_size / adap->params.sf_nsec;
cfg_addr = t4_flash_cfg_addr(adap); if (cfg_addr < 0) return cfg_addr;
if (size > FLASH_CFG_MAX_SIZE) {
dev_err(adap->pdev_dev, "cfg file too large, max is %u bytes\n",
FLASH_CFG_MAX_SIZE); return -EFBIG;
}
i = DIV_ROUND_UP(FLASH_CFG_MAX_SIZE, /* # of sectors spanned */
sf_sec_size);
ret = t4_flash_erase_sectors(adap, flash_cfg_start_sec,
flash_cfg_start_sec + i - 1); /* If size == 0 then we're simply erasing the FLASH sectors associated * with the on-adapter Firmware Configuration File.
*/ if (ret || size == 0) goto out;
/* this will write to the flash up to SF_PAGE_SIZE at a time */ for (i = 0; i < size; i += SF_PAGE_SIZE) { if ((size - i) < SF_PAGE_SIZE)
n = size - i; else
n = SF_PAGE_SIZE;
ret = t4_write_flash(adap, addr, n, cfg_data, true); if (ret) goto out;
/** * t4_set_vf_mac_acl - Set MAC address for the specified VF * @adapter: The adapter * @vf: one of the VFs instantiated by the specified PF * @start: The start port id associated with specified VF * @naddr: the number of MAC addresses * @addr: the MAC address(es) to be set to the specified VF
*/ int t4_set_vf_mac_acl(struct adapter *adapter, unsignedint vf,
u8 start, unsignedint naddr, u8 *addr)
{ struct fw_acl_mac_cmd cmd;
/** * t4_read_pace_tbl - read the pace table * @adap: the adapter * @pace_vals: holds the returned values * * Returns the values of TP's pace table in microseconds.
*/ void t4_read_pace_tbl(struct adapter *adap, unsignedint pace_vals[NTX_SCHED])
{ unsignedint i, v;
for (i = 0; i < NTX_SCHED; i++) {
t4_write_reg(adap, TP_PACE_TABLE_A, 0xffff0000 + i);
v = t4_read_reg(adap, TP_PACE_TABLE_A);
pace_vals[i] = dack_ticks_to_usec(adap, v);
}
}
/** * t4_get_tx_sched - get the configuration of a Tx HW traffic scheduler * @adap: the adapter * @sched: the scheduler index * @kbps: the byte rate in Kbps * @ipg: the interpacket delay in tenths of nanoseconds * @sleep_ok: if true we may sleep while awaiting command completion * * Return the current configuration of a HW Tx scheduler.
*/ void t4_get_tx_sched(struct adapter *adap, unsignedint sched, unsignedint *kbps, unsignedint *ipg, bool sleep_ok)
{ unsignedint v, addr, bpt, cpt;
if (kbps) {
addr = TP_TX_MOD_Q1_Q0_RATE_LIMIT_A - sched / 2;
t4_tp_tm_pio_read(adap, &v, 1, addr, sleep_ok); if (sched & 1)
v >>= 16;
bpt = (v >> 8) & 0xff;
cpt = v & 0xff; if (!cpt) {
*kbps = 0; /* scheduler disabled */
} else {
v = (adap->params.vpd.cclk * 1000) / cpt; /* ticks/s */
*kbps = (v * bpt) / 125;
}
} if (ipg) {
addr = TP_TX_MOD_Q1_Q0_TIMER_SEPARATOR_A - sched / 2;
t4_tp_tm_pio_read(adap, &v, 1, addr, sleep_ok); if (sched & 1)
v >>= 16;
v &= 0xffff;
*ipg = (10000 * v) / core_ticks_per_usec(adap);
}
}
/* t4_sge_ctxt_rd - read an SGE context through FW * @adap: the adapter * @mbox: mailbox to use for the FW command * @cid: the context id * @ctype: the context type * @data: where to store the context data * * Issues a FW command through the given mailbox to read an SGE context.
*/ int t4_sge_ctxt_rd(struct adapter *adap, unsignedint mbox, unsignedint cid, enum ctxt_type ctype, u32 *data)
{ struct fw_ldst_cmd c; int ret;
if (ctype == CTXT_FLM)
ret = FW_LDST_ADDRSPC_SGE_FLMC; else
ret = FW_LDST_ADDRSPC_SGE_CONMC;
/** * t4_sge_ctxt_rd_bd - read an SGE context bypassing FW * @adap: the adapter * @cid: the context id * @ctype: the context type * @data: where to store the context data * * Reads an SGE context directly, bypassing FW. This is only for * debugging when FW is unavailable.
*/ int t4_sge_ctxt_rd_bd(struct adapter *adap, unsignedint cid, enum ctxt_type ctype, u32 *data)
{ int i, ret;
t4_write_reg(adap, SGE_CTXT_CMD_A, CTXTQID_V(cid) | CTXTTYPE_V(ctype));
ret = t4_wait_op_done(adap, SGE_CTXT_CMD_A, BUSY_F, 0, 3, 1); if (!ret) for (i = SGE_CTXT_DATA0_A; i <= SGE_CTXT_DATA5_A; i += 4)
*data++ = t4_read_reg(adap, i); return ret;
}
/** * t4_i2c_rd - read I2C data from adapter * @adap: the adapter * @mbox: mailbox to use for the FW command * @port: Port number if per-port device; <0 if not * @devid: per-port device ID or absolute device ID * @offset: byte offset into device I2C space * @len: byte length of I2C space data * @buf: buffer in which to return I2C data * * Reads the I2C data from the indicated device and location.
*/ int t4_i2c_rd(struct adapter *adap, unsignedint mbox, int port, unsignedint devid, unsignedint offset, unsignedint len, u8 *buf)
{ struct fw_ldst_cmd ldst_cmd, ldst_rpl; unsignedint i2c_max = sizeof(ldst_cmd.u.i2c.data); int ret = 0;
if (len > I2C_PAGE_SIZE) return -EINVAL;
/* Dont allow reads that spans multiple pages */ if (offset < I2C_PAGE_SIZE && offset + len > I2C_PAGE_SIZE) return -EINVAL;
/** * t4_set_vlan_acl - Set a VLAN id for the specified VF * @adap: the adapter * @mbox: mailbox to use for the FW command * @vf: one of the VFs instantiated by the specified PF * @vlan: The vlanid to be set
*/ int t4_set_vlan_acl(struct adapter *adap, unsignedint mbox, unsignedint vf,
u16 vlan)
{ struct fw_acl_vlan_cmd vlan_cmd; unsignedint enable;
enable = (vlan ? FW_ACL_VLAN_CMD_EN_F : 0);
memset(&vlan_cmd, 0, sizeof(vlan_cmd));
vlan_cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_ACL_VLAN_CMD) |
FW_CMD_REQUEST_F |
FW_CMD_WRITE_F |
FW_CMD_EXEC_F |
FW_ACL_VLAN_CMD_PFN_V(adap->pf) |
FW_ACL_VLAN_CMD_VFN_V(vf));
vlan_cmd.en_to_len16 = cpu_to_be32(enable | FW_LEN16(vlan_cmd)); /* Drop all packets that donot match vlan id */
vlan_cmd.dropnovlan_fm = (enable
? (FW_ACL_VLAN_CMD_DROPNOVLAN_F |
FW_ACL_VLAN_CMD_FM_F) : 0); if (enable != 0) {
vlan_cmd.nvlan = 1;
vlan_cmd.vlanid[0] = cpu_to_be16(vlan);
}
/** * modify_device_id - Modifies the device ID of the Boot BIOS image * @device_id: the device ID to write. * @boot_data: the boot image to modify. * * Write the supplied device ID to the boot BIOS image.
*/ staticvoid modify_device_id(int device_id, u8 *boot_data)
{ struct cxgb4_pcir_data *pcir_header; struct legacy_pci_rom_hdr *header;
u8 *cur_header = boot_data;
u16 pcir_offset;
/* Loop through all chained images and change the device ID's */ do {
header = (struct legacy_pci_rom_hdr *)cur_header;
pcir_offset = le16_to_cpu(header->pcir_offset);
pcir_header = (struct cxgb4_pcir_data *)(cur_header +
pcir_offset);
/** * Only modify the Device ID if code type is Legacy or HP. * 0x00: Okay to modify * 0x01: FCODE. Do not modify * 0x03: Okay to modify * 0x04-0xFF: Do not modify
*/ if (pcir_header->code_type == CXGB4_HDR_CODE1) {
u8 csum = 0; int i;
/** * Modify Device ID to match current adatper
*/
pcir_header->device_id = cpu_to_le16(device_id);
/** * Set checksum temporarily to 0. * We will recalculate it later.
*/
header->cksum = 0x0;
/** * Calculate and update checksum
*/ for (i = 0; i < (header->size512 * 512); i++)
csum += cur_header[i];
/** * Invert summed value to create the checksum * Writing new checksum value directly to the boot data
*/
cur_header[7] = -csum;
} elseif (pcir_header->code_type == CXGB4_HDR_CODE2) { /** * Modify Device ID to match current adatper
*/
pcir_header->device_id = cpu_to_le16(device_id);
}
/** * Move header pointer up to the next image in the ROM.
*/
cur_header += header->size512 * 512;
} while (!(pcir_header->indicator & CXGB4_HDR_INDI));
}
/** * t4_load_boot - download boot flash * @adap: the adapter * @boot_data: the boot image to write * @boot_addr: offset in flash to write boot_data * @size: image size * * Write the supplied boot image to the card's serial flash. * The boot image has the following sections: a 28-byte header and the * boot image.
*/ int t4_load_boot(struct adapter *adap, u8 *boot_data, unsignedint boot_addr, unsignedint size)
{ unsignedint sf_sec_size = adap->params.sf_size / adap->params.sf_nsec; unsignedint boot_sector = (boot_addr * 1024); struct cxgb4_pci_exp_rom_header *header; struct cxgb4_pcir_data *pcir_header; int pcir_offset; unsignedint i;
u16 device_id; int ret, addr;
/** * Make sure the boot image does not encroach on the firmware region
*/ if ((boot_sector + size) >> 16 > FLASH_FW_START_SEC) {
dev_err(adap->pdev_dev, "boot image encroaching on firmware region\n"); return -EFBIG;
}
/** * Perform some primitive sanity testing to avoid accidentally * writing garbage over the boot sectors. We ought to check for * more but it's not worth it for now ...
*/ if (size < BOOT_MIN_SIZE || size > BOOT_MAX_SIZE) {
dev_err(adap->pdev_dev, "boot image too small/large\n"); return -EFBIG;
}
/* Check Vendor ID matches Chelsio ID*/ if (le16_to_cpu(pcir_header->vendor_id) != PCI_VENDOR_ID_CHELSIO) {
dev_err(adap->pdev_dev, "Vendor ID missing signature\n"); return -EINVAL;
}
/** * The boot sector is comprised of the Expansion-ROM boot, iSCSI boot, * and Boot configuration data sections. These 3 boot sections span * sectors 0 to 7 in flash and live right before the FW image location.
*/
i = DIV_ROUND_UP(size ? size : FLASH_FW_START, sf_sec_size);
ret = t4_flash_erase_sectors(adap, boot_sector >> 16,
(boot_sector >> 16) + i - 1);
/** * If size == 0 then we're simply erasing the FLASH sectors associated * with the on-adapter option ROM file
*/ if (ret || size == 0) goto out; /* Retrieve adapter's device ID */
pci_read_config_word(adap->pdev, PCI_DEVICE_ID, &device_id); /* Want to deal with PF 0 so I strip off PF 4 indicator */
device_id = device_id & 0xf0ff;
/* Check PCIE Device ID */ if (le16_to_cpu(pcir_header->device_id) != device_id) { /** * Change the device ID in the Boot BIOS image to match * the Device ID of the current adapter.
*/
modify_device_id(device_id, boot_data);
}
/** * Skip over the first SF_PAGE_SIZE worth of data and write it after * we finish copying the rest of the boot image. This will ensure * that the BIOS boot header will only be written if the boot image * was written in full.
*/
addr = boot_sector; for (size -= SF_PAGE_SIZE; size; size -= SF_PAGE_SIZE) {
addr += SF_PAGE_SIZE;
boot_data += SF_PAGE_SIZE;
ret = t4_write_flash(adap, addr, SF_PAGE_SIZE, boot_data, false); if (ret) goto out;
}
ret = t4_write_flash(adap, boot_sector, SF_PAGE_SIZE,
(const u8 *)header, false);
/** * t4_flash_bootcfg_addr - return the address of the flash * optionrom configuration * @adapter: the adapter * * Return the address within the flash where the OptionROM Configuration * is stored, or an error if the device FLASH is too small to contain * a OptionROM Configuration.
*/ staticint t4_flash_bootcfg_addr(struct adapter *adapter)
{ /** * If the device FLASH isn't large enough to hold a Firmware * Configuration File, return an error.
*/ if (adapter->params.sf_size <
FLASH_BOOTCFG_START + FLASH_BOOTCFG_MAX_SIZE) return -ENOSPC;
return FLASH_BOOTCFG_START;
}
int t4_load_bootcfg(struct adapter *adap, const u8 *cfg_data, unsignedint size)
{ unsignedint sf_sec_size = adap->params.sf_size / adap->params.sf_nsec; struct cxgb4_bootcfg_data *header; unsignedint flash_cfg_start_sec; unsignedint addr, npad; int ret, i, n, cfg_addr;
cfg_addr = t4_flash_bootcfg_addr(adap); if (cfg_addr < 0) return cfg_addr;
if (size > FLASH_BOOTCFG_MAX_SIZE) {
dev_err(adap->pdev_dev, "bootcfg file too large, max is %u bytes\n",
FLASH_BOOTCFG_MAX_SIZE); return -EFBIG;
}
header = (struct cxgb4_bootcfg_data *)cfg_data; if (le16_to_cpu(header->signature) != BOOT_CFG_SIG) {
dev_err(adap->pdev_dev, "Wrong bootcfg signature\n");
ret = -EINVAL; goto out;
}
i = DIV_ROUND_UP(FLASH_BOOTCFG_MAX_SIZE,
sf_sec_size);
ret = t4_flash_erase_sectors(adap, flash_cfg_start_sec,
flash_cfg_start_sec + i - 1);
/** * If size == 0 then we're simply erasing the FLASH sectors associated * with the on-adapter OptionROM Configuration File.
*/ if (ret || size == 0) goto out;
/* this will write to the flash up to SF_PAGE_SIZE at a time */ for (i = 0; i < size; i += SF_PAGE_SIZE) {
n = min_t(u32, size - i, SF_PAGE_SIZE);
ret = t4_write_flash(adap, addr, n, cfg_data, false); if (ret) goto out;
addr += SF_PAGE_SIZE;
cfg_data += SF_PAGE_SIZE;
}
npad = ((size + 4 - 1) & ~3) - size; for (i = 0; i < npad; i++) {
u8 data = 0;
ret = t4_write_flash(adap, cfg_addr + size + i, 1, &data, false); if (ret) goto out;
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.451Bemerkung:
(vorverarbeitet am 2026-06-07)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.