/*
* This file and its contents are supplied under the terms of the
* Common Development and Distribution License ("CDDL"), version 1.0.
* You may only use this file in accordance with the terms of version
* 1.0 of the CDDL.
*
* A full copy of the text of the CDDL should have accompanied this
* source. A copy of the CDDL is also available via the Internet at
*/
/*
* This file is part of the Chelsio T4 Ethernet driver.
*
* Copyright (C) 2003-2013 Chelsio Communications. All rights reserved.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the LICENSE file included in this
* release for licensing terms and conditions.
*/
#include "common.h"
#include "t4_regs.h"
#include "t4_regs_values.h"
#include "t4fw_interface.h"
#include "t4_fw.h"
/*
* 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.
*/
int
{
int rc = 0;
/* LINTED: E_CONSTANT_CONDITION */
while (1) {
goto done;
}
if (--attempts == 0) {
goto done;
}
if (d != 0)
udelay(d);
}
done:
return (rc);
}
/*
* 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_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
*
* register pair.
*/
void
unsigned int start_idx)
{
while (nregs--) {
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
*/
void
unsigned int start_idx)
{
while (nregs--) {
}
}
/*
* Get the reply to a mailbox command and store it in @rpl in big-endian order.
*/
static void
{
}
/*
* Handle a FW assertion reported in a mailbox.
*/
static void
{
}
/*
* t4_wr_mbox_meat - 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
*
* 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. Some FW commands like RESET and
* INITIALIZE can take a considerable amount of time to execute.
* @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
{
/*
* We delay in small increments at first in an effort to maintain
* responsiveness for simple, fast executing commands but then back
* off to larger delays to a maximum retry delay.
*/
static const int d[] = {
1, 1, 3, 5, 10, 10, 20, 50, 100, 200
};
u32 v;
return (-EINVAL);
for (i = 0; v == X_MBOWNER_NONE && i < 3; i++)
if (v != X_MBOWNER_PL)
for (i = 0; i < size; i += 8, p++)
delay_idx = 0;
ms = d[0];
for (i = 0; i < FW_CMD_MAX_TIMEOUT; i += ms) {
if (sleep_ok != 0) {
delay_idx++;
} else
if (v == X_CIM_PF_NOACCESS)
continue;
if (G_MBOWNER(v) == X_MBOWNER_PL) {
if (!(v & F_MBMSGVALID)) {
continue;
}
return (-G_FW_CMD_RETVAL((int)res));
}
}
return (-ETIMEDOUT);
}
/*
* t4_mc_read - read from MC through backdoor accesses
* @adap: the adapter
* @addr: address of first byte requested
* @data: 64 bytes of data containing the requested address
* @ecc: where to store the corresponding 64-bit ECC word
*
* Read 64 bytes of data from MC starting at a 64-byte-aligned address
* that covers the requested address @addr. If @parity is not %NULL it
* is assigned the 64-bit ECC word for the read data.
*/
int
{
int i;
return (-EBUSY);
V_BIST_CMD_GAP(1));
if (i != 0)
return (i);
for (i = 15; i >= 0; i--)
return (0);
}
/*
* t4_edc_read - read from EDC through backdoor accesses
* @adap: the adapter
* @idx: which EDC to access
* @addr: address of first byte requested
* @data: 64 bytes of data containing the requested address
* @ecc: where to store the corresponding 64-bit ECC word
*
* Read 64 bytes of data from EDC starting at a 64-byte-aligned address
* that covers the requested address @addr. If @parity is not %NULL it
* is assigned the 64-bit ECC word for the read data.
*/
int
{
int i;
idx *= EDC_STRIDE;
return (-EBUSY);
if (i != 0)
return (i);
for (i = 15; i >= 0; i--)
return (0);
}
/*
* t4_mem_read - read EDC 0, EDC 1 or MC into buffer
* @adap: the adapter
* @mtype: memory type: MEM_EDC0, MEM_EDC1 or MEM_MC
* @addr: address within indicated memory type
* @len: amount of memory to read
* @buf: host memory buffer
*
* Reads an [almost] arbitrary memory region in the firmware: the
* firmware memory address, length and host buffer must be aligned on
* 32-bit boudaries. The memory is returned as a raw byte sequence from
* the firmware's memory. If this memory contains data structures which
* contain multi-byte integers, it's the callers responsibility to
* perform appropriate byte order conversions.
*/
int
{
int ret;
/*
* Argument sanity checks ...
*/
return (-EINVAL);
/*
* need to round down the start and round up the end. We'll start
* copying out of the first line at (addr - start) a word at a time.
*/
/*
* Read the chip's memory block and bail if there's an error.
*/
else
if (ret != 0)
return (ret);
/*
* Copy the data into the caller's memory buffer.
*/
}
}
return (0);
}
/*
* @adap: the adapter
* @addr: address of first byte requested
* @data: MEMWIN0_APERTURE bytes of data containing the requested address
* @dir: direction of transfer 1 => read, 0 => write
*
* MEMWIN0_APERTURE-byte-aligned address that covers the requested
* address @addr.
*/
static int
{
int i;
/*
* Setup offset into PCIE memory window. Address must be a
* MEMWIN0_APERTURE-byte-aligned address. (Read back MA register to
* ensure that changes propagate before we attempt to use the new
* values.)
*/
0));
/* Collecting data 4 bytes at a time upto MEMWIN0_APERTURE */
for (i = 0; i < MEMWIN0_APERTURE; i = i + 0x4) {
if (dir != 0)
else
}
return (0);
}
int
{
}
/*
* Partial EEPROM Vital Product Data structure. Includes only the ID and
* VPD-R header.
*/
struct t4_vpd_hdr {
};
/*
* EEPROM reads take a few tens of us while writes can take a bit over 5 ms.
*/
#define VPD_BASE_OLD 0
/*
* t4_seeprom_read - read a serial EEPROM location
* @adapter: adapter to read
* @addr: EEPROM virtual address
* @data: where to store the read data
*
* Read a 32-bit word from a location in serial EEPROM using the card's PCI
* VPD capability. Note that this function must be called with a virtual
* address.
*/
int
{
return (-EINVAL);
do {
udelay(10);
if (!(val & PCI_VPD_ADDR_F)) {
return (-EIO);
}
return (0);
}
/*
* t4_seeprom_write - write a serial EEPROM location
* @adapter: adapter to write
* @addr: virtual EEPROM address
* @data: value to write
*
* Write a 32-bit word to a location in serial EEPROM using the card's PCI
* VPD capability. Note that this function must be called with a virtual
* address.
*/
int
{
return (-EINVAL);
cpu_to_le32(data));
do {
msleep(1);
if (val & PCI_VPD_ADDR_F) {
return (-EIO);
}
return (0);
}
/*
* 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) -> [ES-A..ES)
* [1K+A..ES) -> [0..ES-A-1K)
*
* where A = @fn * @sz, and ES = EEPROM size.
*/
int
{
if (phys_addr < 1024)
if (phys_addr < EEPROMSIZE)
return (-EINVAL);
}
/*
* @adapter: the adapter
* @enable: whether to enable or disable write protection
*
* Enables or disables write protection on the serial EEPROM.
*/
int
{
}
/*
* get_vpd_keyword_val - Locates an information field keyword in the VPD
* @v: Pointer to buffered vpd data structure
* @kw: The keyword to search for
*
* Returns the value of the information field keyword or
* -ENOENT otherwise.
*/
static int
{
int i;
offset = sizeof (struct t4_vpd_hdr);
return (-ENOENT);
}
i += VPD_INFO_FLD_HDR_SIZE;
return (i);
}
}
return (-ENOENT);
}
/*
* get_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.
*/
static int
{
const struct t4_vpd_hdr *v;
/*
* Card information normally starts at VPD_BASE but early cards had
* it at 0.
*/
/* LINTED: E_BAD_PTR_CAST_ALIGN */
for (i = 0; i < sizeof (vpd); i += 4) {
/* LINTED: E_BAD_PTR_CAST_ALIGN */
if (ret != 0)
return (ret);
}
v = (const struct t4_vpd_hdr *)vpd;
if (var < 0) { \
return (-EINVAL); \
} \
} while (0)
/* LINTED: E_CONSTANT_CONDITION */
FIND_VPD_KW(i, "RV");
for (csum = 0; i >= 0; i--)
if (csum != 0) {
return (-EINVAL);
}
/* LINTED: E_CONSTANT_CONDITION */
/* LINTED: E_CONSTANT_CONDITION */
/* LINTED: E_CONSTANT_CONDITION */
/* LINTED: E_CONSTANT_CONDITION */
return (0);
}
/* serial flash and firmware constants and flash config file constants */
enum {
/* flash command opcodes */
};
/*
* 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.
*/
static int
{
int ret;
return (-EINVAL);
return (-EBUSY);
if (!ret)
return (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.
*/
static int
{
return (-EINVAL);
return (-EBUSY);
}
/*
* 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.
*/
static int
{
int ret = 0;
/* LINTED: E_CONSTANT_CONDITION */
while (1) {
goto done;
if (!(status & 1))
goto done;
if (--attempts == 0) {
goto done;
}
if (d != 0)
msleep(d);
}
done:
return (ret);
}
/*
* 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 endianess.
*/
int
{
int ret;
(addr & 3))
return (-EINVAL);
return (ret);
if (nwords == 1)
if (ret != 0)
return (ret);
if (byte_oriented != 0)
}
return (0);
}
/*
* 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
*
* 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.
*/
static int
{
int ret;
return (-EINVAL);
goto unlock;
for (val = 0, i = 0; i < c; ++i)
if (ret != 0)
goto unlock;
}
if (ret != 0)
goto unlock;
/* Read the page to verify the write succeeded */
if (ret != 0)
return (ret);
"at %x", addr);
return (-EIO);
}
return (0);
return (ret);
}
/*
* t4_get_fw_version - read the firmware version
* @adapter: the adapter
* @vers: where to place the version
*
* Reads the FW version from flash.
*/
int
{
return (t4_read_flash(adapter,
}
/*
* 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_check_fw_version - check if the FW is compatible with this driver
* @adapter: 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, and a positive value if the
* expected major version is found but there's a minor version mismatch.
*/
int
{
if (!ret)
if (!ret)
api_vers, 1);
if (ret != 0)
return (ret);
return (-EINVAL);
}
return (0); /* perfect match */
return (1);
}
/*
* 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.
*/
static int
{
int ret = 0;
break;
}
start++;
}
return (ret);
}
/*
* 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.
*/
unsigned int
{
return (FLASH_FPGA_CFG_START);
else
return (FLASH_CFG_START);
}
/*
* 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
{
int ret, i, n;
unsigned int addr;
unsigned int flash_cfg_start_sec;
if (!size) {
return (-EINVAL);
}
if (size > FLASH_CFG_MAX_SIZE) {
return (-EFBIG);
}
flash_cfg_start_sec + i - 1);
if (ret != 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;
if (ret != 0)
goto out;
addr += SF_PAGE_SIZE;
cfg_data += SF_PAGE_SIZE;
}
out:
if (ret != 0)
return (ret);
}
/*
* 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
{
unsigned int i;
/* LINTED: E_BAD_PTR_CAST_ALIGN */
/* LINTED: E_BAD_PTR_CAST_ALIGN */
if (!size) {
return (-EINVAL);
}
if (size & 511) {
return (-EINVAL);
}
return (-EINVAL);
}
if (size > FLASH_FW_MAX_SIZE) {
return (-EFBIG);
}
if (csum != 0xffffffff) {
csum);
return (-EINVAL);
}
FLASH_FW_START_SEC + i - 1);
if (ret != 0)
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.
*/
/* LINTED: E_BAD_PTR_CAST_ALIGN */
if (ret != 0)
goto out;
addr += SF_PAGE_SIZE;
fw_data += SF_PAGE_SIZE;
if (ret != 0)
goto out;
}
out:
if (ret != 0)
return (ret);
}
/*
* 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
{
unsigned int i, v;
for (i = 0; i < CIM_NUM_IBQ; i++) {
V_QUENUMSELECT(i));
}
for (i = 0; i < CIM_NUM_OBQ; i++) {
V_QUENUMSELECT(i));
}
}
/*
* 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
{
int i, err;
unsigned int addr;
return (-EINVAL);
if (n > nwords)
n = nwords;
for (i = 0; i < n; i++, addr++) {
2, 1);
if (err != 0)
return (err);
}
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
{
int i, err;
return (-EINVAL);
if (n > nwords)
n = nwords;
for (i = 0; i < n; i++, addr++) {
2, 1);
if (err != 0)
return (err);
}
return (i);
}
enum {
CIM_QCTL_BASE = 0,
};
/*
* 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
unsigned int *valp)
{
int ret = 0;
return (-EBUSY);
0, 5, 2);
if (!ret)
}
return (ret);
}
/*
* 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
const unsigned int *valp)
{
int ret = 0;
return (-EBUSY);
0, 5, 2);
}
return (ret);
}
static int
{
}
/*
* t4_cim_ctl_read - read a block from CIM control region
* @adap: the adapter
* @addr: the start address within the CIM control region
* @n: number of words to read
* @valp: where to store the result
*
* Reads a block of 4-byte words from the CIM control region.
*/
int
unsigned int *valp)
{
}
/*
* 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
{
int i, ret;
if (ret != 0)
return (ret);
if (ret != 0)
return (ret);
}
if (ret != 0)
goto restart;
if (wrptr != 0)
if (ret != 0)
break;
if (ret != 0)
break;
if (val & F_UPDBGLARDEN) {
break;
}
if (ret != 0)
break;
}
if (cfg & F_UPDBGLAEN) {
cfg & ~F_UPDBGLARDEN);
if (!ret)
ret = r;
}
return (ret);
}
void
unsigned int *pif_req_wrptr, unsigned int *pif_rsp_wrptr)
{
int i, j;
if (pif_req_wrptr != NULL)
*pif_req_wrptr = req;
if (pif_rsp_wrptr != NULL)
*pif_rsp_wrptr = rsp;
for (i = 0; i < CIM_PIFLA_SIZE; i++) {
for (j = 0; j < 6; j++) {
req++;
rsp++;
}
}
}
void
{
int i, j, idx;
for (i = 0; i < CIM_MALA_SIZE; i++) {
for (j = 0; j < 5; j++) {
idx = 8 * i + j;
}
}
}
/*
* 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
{
bool last_incomplete;
if (last_incomplete != 0)
val &= 0xffff;
for (i = 0; i < TPLA_SIZE; i++) {
}
/* Wipe out last entry if it isn't valid */
if (last_incomplete != 0)
}
void
{
unsigned int i, j;
for (i = 0; i < 8; i++) {
for (j = 0; j < ULPRX_LA_SIZE; j++, p += 8)
}
}
/*
* @phy: the PHY to setup
* @mac: the MAC to setup
* @lc: the requested link configuration
*
* 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
* - If the PHY does not auto-negotiate just reset it.
* otherwise do it later based on the outcome of auto-negotiation.
*/
int
struct link_config *lc)
{
struct fw_port_cmd c;
fc |= FW_PORT_CAP_FC_RX;
fc |= FW_PORT_CAP_FC_TX;
(void) memset(&c, 0, sizeof (c));
FW_LEN16(c));
} else
}
/*
* 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
{
struct fw_port_cmd c;
(void) memset(&c, 0, sizeof (c));
FW_LEN16(c));
}
struct intr_info {
};
/*
* 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 occured. 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.
*/
static int
{
int fatal = 0;
unsigned int mask = 0;
continue;
fatal++;
}
if (status != 0) /* clear processed interrupts */
return (fatal);
}
/*
* Interrupt handler for the PCIE module.
*/
static void
{
{ 0 }
};
{ 0 }
};
0 },
{ 0 }
};
int fat;
if (fat != 0)
}
/*
* TP interrupt handler.
*/
static void
{
{ 0x3fffffff, "TP parity error", -1, 1 },
{ 0 }
};
}
/*
* SGE interrupt handler.
*/
static void
{
u64 v;
"SGE received CPL exceeding IQE size", -1, 1 },
"SGE GTS CIDX increment too large", -1, 0 },
"SGE IQID > 1023 received CPL for FL", -1, 0 },
0 },
0 },
0 },
0 },
"SGE too many priority ingress contexts", -1, 0 },
"SGE too many priority egress contexts", -1, 0 },
{ 0 }
};
if (v != 0) {
(unsigned long long)v);
}
if (err & F_ERROR_QID_VALID) {
}
if (v != 0)
}
/*
* CIM interrupt handler.
*/
static void
{
{ 0 }
};
{ 0 }
};
int fat;
if (fat != 0)
}
/*
* ULP RX interrupt handler.
*/
static void
{
{ 0x7fffff, "ULPRX parity error", -1, 1 },
{ 0 }
};
!= 0)
}
/*
* ULP TX interrupt handler.
*/
static void
{
0 },
0 },
0 },
0 },
{ 0xfffffff, "ULPTX parity error", -1, 1 },
{ 0 }
};
!= 0)
}
/*
* PM TX interrupt handler.
*/
static void
{
{ 0xffffff0, "PMTX framing error", -1, 1 },
1 },
{ 0 }
};
}
/*
* PM RX interrupt handler.
*/
static void
{
{ 0x3ffff0, "PMRX framing error", -1, 1 },
1 },
{ 0 }
};
}
/*
* CPL switch interrupt handler.
*/
static void
{
{ 0 }
};
}
/*
* LE interrupt handler.
*/
static void
{
{ 0 }
};
}
/*
* MPS interrupt handler.
*/
static void
{
{ 0xffffff, "MPS Rx parity error", -1, 1 },
{ 0 }
};
-1, 1 },
-1, 1 },
{ 0 }
};
1 },
{ 0 }
};
{ 0x1fffff, "MPS statistics SRAM parity error", -1, 1 },
{ 0 }
};
{ 0xfffff, "MPS statistics Tx FIFO parity error", -1, 1 },
{ 0 }
};
{ 0xffffff, "MPS statistics Rx FIFO parity error", -1, 1 },
{ 0 }
};
{ 0 }
};
int fat;
if (fat != 0)
}
#define MEM_INT_MASK \
/*
*/
static void
{
} else {
}
if (v & F_PERR_INT_CAUSE)
if (v & F_ECC_CE_INT_CAUSE) {
}
if (v & F_ECC_UE_INT_CAUSE)
if (v & (F_PERR_INT_CAUSE | F_ECC_UE_INT_CAUSE))
}
/*
* MA interrupt handler.
*/
static void
{
if (status & F_MEM_PERR_INT_CAUSE)
if (status & F_MEM_WRAP_INT_CAUSE) {
" address %x", G_MEM_WRAP_CLIENT_NUM(v),
G_MEM_WRAP_ADDRESS(v) << 4);
}
}
/*
* SMB interrupt handler.
*/
static void
{
{ 0 }
};
}
/*
* NC-SI interrupt handler.
*/
static void
{
{ 0 }
};
}
/*
* XGMAC interrupt handler.
*/
static void
{
v &= F_TXFIFO_PRTY_ERR | F_RXFIFO_PRTY_ERR;
if (!v)
return;
if (v & F_TXFIFO_PRTY_ERR)
if (v & F_RXFIFO_PRTY_ERR)
}
/*
* PL interrupt handler.
*/
static void
{
{ 0 }
};
}
/*
* 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
{
if (!(cause & GLBL_INTR_MASK))
return (0);
if (cause & F_XGMAC_KR0)
if (cause & F_XGMAC_KR1)
if (cause & F_CPL_SWITCH)
/* Clear the interrupts just processed for which we are the master. */
return (1);
}
/*
* 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_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_clear - clear all interrupts
* @adapter: the adapter whose interrupts should be cleared
*
* Clears all interrupts. The caller must be a PCI function managing
* global interrupts.
*/
void
{
static const unsigned int cause_reg[] = {
};
unsigned int i;
for (i = 0; i < ARRAY_SIZE(cause_reg); ++i)
}
/*
* hash_mac_addr - return the hash value of a MAC address
* @addr: the 48-bit Ethernet MAC address
*
* Hashes a MAC address according to the hash function used by HW inexact
* (hash) address matching.
*/
static int
{
a ^= b;
a ^= (a >> 12);
a ^= (a >> 6);
return (a & 0x3f);
}
/*
* 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" (Ingress 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
{
int ret;
/*
* Each firmware RSS command can accommodate up to 32 RSS Ingress
* Queue Identifiers. These Ingress Queue IDs are packed three to
* a 32-bit word as 10-bit values with the upper remaining 2 bits
* reserved.
*/
while (n > 0) {
/*
* Set up the firmware RSS command header to send the next
* "nq" Ingress Queue IDs to the firmware.
*/
/*
* "nq" more done for the start of the next loop.
*/
n -= nq;
/*
* While there are still Ingress Queue IDs to stuff into the
* current firmware RSS command, retrieve them from the
* Ingress Queue ID array and insert them into the command.
*/
while (nq > 0) {
unsigned int v;
/*
* Grab up to the next 3 Ingress Queue IDs (wrapping
* around the Ingress Queue ID array if necessary) and
* insert them into the firmware RSS command at the
* current 3-tuple position within the commad.
*/
v = V_FW_RSS_IND_TBL_CMD_IQ0(*rsp);
v |= V_FW_RSS_IND_TBL_CMD_IQ1(*rsp);
v |= V_FW_RSS_IND_TBL_CMD_IQ2(*rsp);
nq -= 3;
}
/*
* Send this portion of the RRS table update to the firmware;
* bail out on any errors.
*/
if (ret != 0)
return (ret);
}
return (0);
}
/*
* 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
unsigned int flags)
{
struct fw_rss_glb_config_cmd c;
(void) memset(&c, 0, sizeof (c));
if (mode == FW_RSS_GLB_CONFIG_CMD_MODE_MANUAL) {
} else if (mode == FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL) {
c.u.basicvirtual.mode_pkd =
} else
return (-EINVAL);
}
/*
* 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
{
struct fw_rss_vi_config_cmd c;
(void) memset(&c, 0, sizeof (c));
}
/* Read an RSS table row */
static int
{
5, 0, val));
}
/*
* 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
{
int i, ret;
for (i = 0; i < RSS_NENTRIES / 2; ++i) {
if (ret != 0)
return (ret);
}
return (0);
}
/*
* t4_read_rss_key - read the global RSS key
* @adap: the adapter
* @key: 10-entry array holding the 320-bit RSS key
*
* Reads the global 320-bit RSS key.
*/
void
{
}
/*
* 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
*
* 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_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
*
* Reads the PF RSS Configuration Table at the specified index and returns
* the value found there.
*/
void
{
}
/*
* t4_write_rss_pf_config - write PF RSS Configuration Table
* @adapter: the adapter
* @index: the entry in the VF RSS table to read
* @val: the value to store
*
* Writes the PF RSS Configuration Table at the specified index with the
* specified value.
*/
void
{
}
/*
* 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
*
* Reads the VF RSS Configuration Table at the specified index and returns
* the (VFL, VFH) values found there.
*/
void
{
/*
*/
/*
*/
}
/*
* t4_write_rss_vf_config - write VF RSS Configuration Table
*
* @adapter: the adapter
* @index: the entry in the VF RSS table to write
* @vfl: the VFL to store
* @vfh: the VFH to store
*
* Writes the VF RSS Configuration Table at the specified index with the
* specified (VFL, VFH) values.
*/
void
{
/*
*/
/*
*/
}
/*
* t4_read_rss_pf_map - read PF RSS Map
* @adapter: the adapter
*
* Reads the PF RSS Map register and returns its value.
*/
{
return (pfmap);
}
/*
* t4_write_rss_pf_map - write PF RSS Map
* @adapter: the adapter
* @pfmap: PF RSS Map value
*
* Writes the specified value to the PF RSS Map register.
*/
void
{
}
/*
* t4_read_rss_pf_mask - read PF RSS Mask
* @adapter: the adapter
*
* Reads the PF RSS Mask register and returns its value.
*/
{
return (pfmask);
}
/*
* t4_write_rss_pf_mask - write PF RSS Mask
* @adapter: the adapter
* @pfmask: PF RSS Mask value
*
* Writes the specified value to the PF RSS Mask register.
*/
void
{
}
/*
* t4_set_filter_mode - configure the optional components of filter tuples
* @adap: the adapter
* @mode_map: a bitmap selcting which optional filter components to enable
*
* Sets the filter mode by selecting the optional components to enable
* in filter tuples. Returns 0 on success and a negative error if the
* requested mode needs more bits than are available for optional
* components.
*/
int
{
int i, nbits = 0;
for (i = S_FCOE; i <= S_FRAGMENTATION; i++)
if (mode_map & (1 << i))
if (nbits > FILTER_OPT_LEN)
return (-EINVAL);
return (0);
}
/*
* t4_tp_get_tcp_stats - read TP's TCP MIB counters
* @adap: the adapter
*
* Either @v4 or @v6 may be %NULL to skip the corresponding stats.
*/
void
struct tp_tcp_stats *v6)
{
}
}
}
/*
* t4_tp_get_err_stats - read TP's error MIB counters
* @adap: the adapter
* @st: holds the counter values
*
* Returns the values of TP's error counters.
*/
void
{
12, A_TP_MIB_MAC_IN_ERR_0);
4, A_TP_MIB_TNL_DROP_0);
}
/*
* t4_tp_get_proxy_stats - read TP's proxy MIB counters
* @adap: the adapter
* @st: holds the counter values
*
* Returns the values of TP's proxy counters.
*/
void
{
4, A_TP_MIB_TNL_LPBK_0);
}
/*
* t4_tp_get_cpl_stats - read TP's CPL MIB counters
* @adap: the adapter
* @st: holds the counter values
*
* Returns the values of TP's CPL counters.
*/
void
{
}
/*
* t4_tp_get_rdma_stats - read TP's RDMA MIB counters
* @adap: the adapter
* @st: holds the counter values
*
* Returns the values of TP's RDMA counters.
*/
void
{
2, A_TP_MIB_RQE_DFR_MOD);
}
/*
* 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
*
* Returns the values of TP's FCoE counters for the selected port.
*/
void
struct tp_fcoe_stats *st)
{
}
/*
* t4_get_usm_stats - read TP's non-TCP DDP MIB counters
* @adap: the adapter
* @st: holds the counter values
*
* Returns the values of TP's counters for non-TCP directly-placed packets.
*/
void
{
}
/*
* 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
{
u32 v;
int i;
for (i = 0; i < NMTUS; ++i) {
mtus[i] = G_MTUVALUE(v);
mtu_log[i] = G_MTUWIDTH(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
{
unsigned int mtu, w;
for (w = 0; w < NCCTRL_WIN; ++w) {
A_TP_CCTRL_TABLE) & 0x1fff;
}
}
/*
* 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
{
unsigned int i, v;
for (i = 0; i < NTX_SCHED; i++) {
}
}
/*
* @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
{
}
/*
* init_cong_ctrl - initialize congestion control parameters
* @a: the alpha values for congestion control
* @b: the beta values for congestion control
*
* Initialize the congestion control parameters.
*/
static void __devinit
init_cong_ctrl(unsigned short *a, unsigned short *b)
{
a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = a[8] = 1;
a[9] = 2;
a[10] = 3;
a[11] = 4;
a[12] = 5;
a[13] = 6;
a[14] = 7;
a[15] = 8;
a[16] = 9;
a[17] = 10;
a[18] = 14;
a[19] = 17;
a[20] = 21;
a[21] = 25;
a[22] = 30;
a[23] = 35;
a[24] = 45;
a[25] = 60;
a[26] = 80;
a[27] = 100;
a[28] = 200;
a[29] = 300;
a[30] = 400;
a[31] = 500;
b[0] = b[1] = b[2] = b[3] = b[4] = b[5] = b[6] = b[7] = b[8] = 0;
b[9] = b[10] = 1;
b[11] = b[12] = 2;
b[13] = b[14] = b[15] = b[16] = 3;
b[17] = b[18] = b[19] = b[20] = b[21] = 4;
b[22] = b[23] = b[24] = b[25] = b[26] = b[27] = 5;
b[28] = b[29] = 6;
b[30] = b[31] = 7;
}
/* The minimum additive increment value for the congestion control table */
/*
* 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
{
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
};
unsigned int i, w;
for (i = 0; i < NMTUS; ++i) {
log2--;
for (w = 0; w < NCCTRL_WIN; ++w) {
unsigned int inc;
}
}
}
/*
* t4_set_pace_tbl - set the pace table
* @adap: the adapter
* @pace_vals: the pace values in microseconds
* @start: index of the first entry in the HW pace table to set
* @n: how many entries to set
*
* Sets (a subset of the) HW pace table.
*/
int
unsigned int start, unsigned int n)
{
if (n > NTX_SCHED)
return (-ERANGE);
/* convert values from us to dack ticks, rounding to closest value */
for (i = 0; i < n; i++, pace_vals++) {
if (vals[i] > 0x7ff)
return (-ERANGE);
return (-ERANGE);
}
for (i = 0; i < n; i++, start++)
return (0);
}
/*
* t4_set_sched_bps - set the bit rate for a HW traffic scheduler
* @adap: the adapter
* @kbps: target rate in Kbps
* @sched: the scheduler index
*
* Configure a Tx HW scheduler for the target rate.
*/
int
{
if (kbps > 0) {
selected_cpt = cpt;
selected_bpt = bpt;
}
} else if (selected_cpt != 0)
break;
}
if (!selected_cpt)
return (-EINVAL);
}
if (sched & 1)
else
return (0);
}
/*
* t4_set_sched_ipg - set the IPG for a Tx HW packet rate scheduler
* @adap: the adapter
* @sched: the scheduler index
* @ipg: the interpacket delay in tenths of nanoseconds
*
* Set the interpacket delay for a HW packet rate scheduler.
*/
int
{
/* convert ipg to nearest number of core clocks */
if (ipg > M_TXTIMERSEPQ0)
return (-EINVAL);
if (sched & 1)
else
return (0);
}
/*
* 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
*
* Return the current configuration of a HW Tx scheduler.
*/
void
unsigned int *ipg)
{
if (sched & 1)
v >>= 16;
cpt = v & 0xff;
if (!cpt)
*kbps = 0; /* scheduler disabled */
else {
}
}
if (sched & 1)
v >>= 16;
v &= 0xffff;
}
}
/*
* 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
{
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
{
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.
*/
int
{
if (!enable) {
goto out;
}
return (-EINVAL);
return (-EINVAL); /* other tracers are enabled */
multitrc = 0;
} else if (idx != 0) {
if (G_TFCAPTUREMAX(i) > 256 &&
return (-EINVAL);
}
/* stop the tracer we'll be changing */
msleep(1);
return (-ETIMEDOUT);
}
/*
* At this point either the tracing is enabled and in the right mode or
* disabled.
*/
}
cfg &= ~F_TRCMULTIFILTER;
return (0);
}
/*
* 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
int *enabled)
{
}
}
/*
* 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
{
int i;
for (i = 0; i < PM_NSTATS; i++) {
}
}
/*
* 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
{
int i;
for (i = 0; i < PM_NSTATS; i++) {
}
}
/*
* get_mps_bg_map - return the buffer groups associated with a port
* @adap: the adapter
* @idx: 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.
*/
static unsigned int
{
if (n == 0)
return (idx == 0 ? 0xf : 0);
if (n == 1)
return (1 << idx);
}
/*
* 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_clr_port_stats - clear port statistics
* @adap: the adapter
* @idx: the port index
*
* Clear HW statistics for the given port.
*/
void
{
unsigned int i;
for (i = A_MPS_PORT_STAT_TX_PORT_BYTES_L;
i <= A_MPS_PORT_STAT_TX_PORT_PPP7_H; i += 8)
for (i = A_MPS_PORT_STAT_RX_PORT_BYTES_L;
i <= A_MPS_PORT_STAT_RX_PORT_LESS_64B_H; i += 8)
for (i = 0; i < 4; i++)
if (bgmap & (1 << i)) {
A_MPS_STAT_RX_BG_0_MAC_DROP_FRAME_L + i * 8, 0);
A_MPS_STAT_RX_BG_0_MAC_TRUNC_FRAME_L + i * 8, 0);
}
}
/*
* 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
{
}
/*
* @adap: the adapter
* @port: the physical port index
* @addr: MAC address expected in magic packets, %NULL to disable
*
*/
void
{
}
}
/*
* @adap: the adapter
* @port: the physical port index
* @map: bitmap of which HW pattern filters to set
* @mask0: byte mask for bytes 0-63 of a packet
* @mask1: byte mask for bytes 64-127 of a packet
* @crc: Ethernet CRC for selected bytes
*
* Sets the pattern filters indicated in @map to mask out the bytes
* specified in @mask0/@mask1 in received packets and compare the CRC of
* the resulting packet against @crc. If @enable is %true pattern-based
* WoL is enabled, otherwise disabled.
*/
int
{
int i;
if (!enable) {
F_PATEN, 0);
return (0);
}
if (map > 0xff)
return (-EINVAL);
if (!(map & 1))
continue;
/* write byte masks */
return (-ETIMEDOUT);
/* write CRC */
return (-ETIMEDOUT);
}
return (0);
}
/*
* t4_mk_filtdelwr - create a delete filter WR
* @ftid: the filter ID
* @wr: the filter work request to populate
* @qid: ingress queue to receive the delete notification
*
* Creates a filter work request to delete the supplied filter. If @qid is
* negative the delete notification is suppressed.
*/
void
{
V_FW_FILTER_WR_NOREPLY(qid < 0));
if (qid >= 0)
}
} while (0)
/*
* 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
{
int ret;
struct fw_ldst_cmd c;
(void) memset(&c, 0, sizeof (c));
if (ret == 0)
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
* @valp: value to write
*
* Issues a FW command through the given mailbox to write a PHY register.
*/
int
{
struct fw_ldst_cmd c;
(void) memset(&c, 0, sizeof (c));
}
/*
* 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
{
int ret;
struct fw_ldst_cmd c;
if (ctype == CTXT_EGRESS)
else if (ctype == CTXT_INGRESS)
else
(void) memset(&c, 0, sizeof (c));
if (ret == 0) {
}
return (ret);
}
/*
* 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
{
int i, ret;
if (!ret)
return (ret);
}
/*
* 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
{
int ret;
struct fw_hello_cmd c;
u32 v;
unsigned int master_mbox;
(void) memset(&c, 0, sizeof (c));
/* LINTED: E_CONSTANT_CONDITION */
c.err_to_clearinit = htonl(
/*
* 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 (ret != FW_SUCCESS) {
goto retry;
return (ret);
}
v = ntohl(c.err_to_clearinit);
if (v & F_FW_HELLO_CMD_ERR)
*state = DEV_STATE_ERR;
else if (v & F_FW_HELLO_CMD_INIT)
*state = DEV_STATE_INIT;
else
}
/*
* 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
* M_PCIE_FW_MASTER so the test below will work ...
*/
if ((v & (F_FW_HELLO_CMD_ERR|F_FW_HELLO_CMD_INIT)) == 0 &&
master_mbox != mbox) {
/*
* 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 (;;) {
msleep(50);
waiting -= 50;
/*
* If neither Error nor Initialialized are indicated
* by the firmware keep waiting till we exaust our
* timeout ... and then retry if we haven't exhausted
* our retries ...
*/
if (waiting <= 0) {
if (retries-- > 0)
goto retry;
return (-ETIMEDOUT);
}
continue;
}
/*
* We either have an Error or Initialized condition
* report errors preferentially.
*/
if (pcie_fw & F_PCIE_FW_ERR)
*state = DEV_STATE_ERR;
else if (pcie_fw & F_PCIE_FW_INIT)
*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 == M_PCIE_FW_MASTER &&
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
{
struct fw_bye_cmd c;
(void) memset(&c, 0, sizeof (c));
/* LINTED: E_CONSTANT_CONDITION */
}
/*
* t4_init_cmd - 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
{
struct fw_initialize_cmd c;
(void) memset(&c, 0, sizeof (c));
/* LINTED: E_CONSTANT_CONDITION */
}
/*
* 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
{
struct fw_reset_cmd c;
(void) memset(&c, 0, sizeof (c));
/* LINTED: E_CONSTANT_CONDITION */
}
/*
* t4_fw_config_file - setup an adapter via a Configuration File
* @adap: the adapter
* @mbox: mailbox to use for the FW command
* @mtype: the memory type where the Configuration File is located
* @maddr: the memory address where the Configuration File is located
* @finiver: return value for CF [fini] version
* @finicsum: return value for CF [fini] checksum
* @cfcsum: return value for CF computed checksum
*
* Issue a command to get the firmware to process the Configuration
* File is processed successfully and return value pointers are
* provided, the Configuration File "[fini] section version and
* checksum values will be returned along with the computed checksum.
* It's up to the caller to decide how it wants to respond to the
* checksums not matching but it recommended that a prominant warning
* be emitted in order to help people rapidly identify changed or
* corrupted Configuration Files.
*
* Also note that it's possible to modify things like "niccaps",
* "toecaps",etc. between processing the Configuration File and telling
* the firmware to use the new configuration. Callers which want to
* do this will need to "hand-roll" their own CAPS_CONFIGS commands for
* Configuration Files if they want to do this.
*/
int
{
int ret;
/*
* Tell the firmware to process the indicated Configuration File.
* If there are no errors and the caller has provided return value
* pointers for the [fini] section version, checksum and computed
* checksum, pass those back to the caller.
*/
if (ret < 0)
return (ret);
/*
* And now tell the firmware to use the configuration we just loaded.
*/
}
/*
* 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
unsigned int cache_line_size)
{
/*
* 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 boundry. 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.
*/
~(fl_align-1));
~(fl_align-1));
return (0);
}
/*
* 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
{
struct fw_initialize_cmd c;
(void) memset(&c, 0, sizeof (c));
/* LINTED: E_CONSTANT_CONDITION */
}
/*
* t4_query_params - 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
*
* Reads the value of FW or device parameters. Up to 7 parameters can be
* queried at once.
*/
int
{
int i, ret;
struct fw_params_cmd c;
if (nparams > 7)
return (-EINVAL);
(void) memset(&c, 0, sizeof (c));
for (i = 0; i < nparams; i++, p += 2)
if (ret == 0)
return (ret);
}
/*
* 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
{
struct fw_params_cmd c;
if (nparams > 7)
return (-EINVAL);
(void) memset(&c, 0, sizeof (c));
while (nparams--) {
}
}
/*
* @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
* @nexact: the maximum number of exact MPS filters
* @rcaps: read capabilities
*
* Configures resource limits and capabilities for a physical or virtual
* function.
*/
int
{
struct fw_pfvf_cmd c;
(void) memset(&c, 0, sizeof (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
*
* 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
unsigned int *rss_size)
{
int ret;
struct fw_vi_cmd c;
(void) memset(&c, 0, sizeof (c));
if (ret != 0)
return (ret);
switch (nmac) {
case 5:
/* FALLTHRU */
case 4:
/* FALLTHRU */
case 3:
/* FALLTHRU */
case 2:
}
}
}
/*
* 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
{
struct fw_vi_cmd c;
(void) memset(&c, 0, sizeof (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
* @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 HVLAN 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
{
struct fw_vi_rxmode_cmd c;
/* convert to FW values */
if (mtu < 0)
if (promisc < 0)
if (all_multi < 0)
if (bcast < 0)
if (vlanex < 0)
(void) memset(&c, 0, sizeof (c));
}
/*
* 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
bool sleep_ok)
{
struct fw_vi_mac_cmd c;
unsigned int nfilters = 0;
return (-EINVAL);
struct fw_vi_mac_exact *p;
int i;
(void) memset(&c, 0, sizeof (c));
p->valid_to_idx = htons(
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 ...
*/
break;
0xffff : index);
nfilters++;
*hash |=
}
free = false;
}
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
* @add_smt: if true also add the address to the HW SMT
*
* Modifies an exact-match filter and sets it to the new MAC address if
* @idx >= 0, or adds the MAC address to a new filter if @idx < 0. In the
* latter case the address is added persistently if @persist is %true.
*
* 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.
*
* Returns a negative error number or the index of the filter with the new
* MAC value. Note that this index may differ from @idx.
*/
int
{
struct fw_vi_mac_cmd c;
struct fw_vi_mac_exact *p = c.u.exact;
if (idx < 0) /* new allocation */
(void) memset(&c, 0, sizeof (c));
if (ret == 0) {
if (ret >= NUM_MPS_CLS_SRAM_L_INSTANCES)
}
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
{
struct fw_vi_mac_cmd c;
(void) memset(&c, 0, sizeof (c));
}
/*
* @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
*
*/
int
{
struct fw_vi_enable_cmd c;
(void) memset(&c, 0, sizeof (c));
}
/*
* 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
unsigned int nblinks)
{
struct fw_vi_enable_cmd c;
(void) memset(&c, 0, sizeof (c));
}
/*
* @adap: the adapter
* @mbox: mailbox to use for the FW command
* @start: %true to enable the queues, %false to disable them
* @pf: the PF owning the queues
* @vf: the VF owning the queues
* @iqid: ingress queue id
* @fl0id: FL0 queue id or 0xffff if no attached FL0
* @fl1id: FL1 queue id or 0xffff if no attached FL1
*
* Starts or stops an ingress queue and its associated FLs, if any.
*/
int
unsigned int fl1id)
{
struct fw_iq_cmd c;
(void) memset(&c, 0, sizeof (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 (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
*
* Frees an ingress queue and its associated FLs, if any.
*/
int
unsigned int fl1id)
{
struct fw_iq_cmd c;
(void) memset(&c, 0, sizeof (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
{
struct fw_eq_eth_cmd c;
(void) memset(&c, 0, sizeof (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
{
struct fw_eq_ctrl_cmd c;
(void) memset(&c, 0, sizeof (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
{
struct fw_eq_ofld_cmd c;
(void) memset(&c, 0, sizeof (c));
}
/*
* 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
{
int i;
const struct fw_port_cmd *p = (const void *)rpl;
unsigned char fc = 0;
unsigned short speed = 0;
if (stat & F_FW_PORT_CMD_RXPAUSE)
if (stat & F_FW_PORT_CMD_TXPAUSE)
speed = SPEED_1000;
speed = SPEED_10000;
break;
}
}
/* LINTED: E_ASSIGN_NARROW_CONV */
}
}
return (0);
}
/*
* get_pci_mode - determine a card's PCI mode
* @adapter: the adapter
* @p: where to store the PCI settings
*
* Determines a card's PCI mode and associated parameters, such as speed
* and width.
*/
static void __devinit
{
}
}
/*
* init_link_config - initialize a link's SW state
* @lc: structure holding the link state
* @caps: link capabilities
*
* Initializes the SW state maintained for each link, including the link's
* capabilities and default speed/flow-control/autonegotiation settings.
*/
static void __devinit
{
lc->requested_speed = 0;
} else {
lc->advertising = 0;
}
}
static int __devinit
{
return (0);
msleep(500);
0 : -EIO));
}
static int __devinit
{
int ret;
if (!ret)
if (ret < 0)
return (ret);
return (-EINVAL);
else if (info == 0x18)
else
return (-EINVAL);
return (0);
}
/*
* t4_prep_adapter - prepare SW and HW for operation
* @adapter: the adapter
* @reset: if true perform a HW reset
*
* 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 __devinit
{
int ret;
if (ret < 0)
return (ret);
return (-EINVAL);
}
if (ret < 0)
return (ret);
if (ret < 0)
return (ret);
else
/*
* Default port for debugging in case we can't reach FW.
*/
return (0);
}
int __devinit
{
int ret, i, j;
struct fw_port_cmd c;
unsigned int rss_size;
(void) memset(&c, 0, sizeof (c));
for (i = 0, j = -1; i <= p->port_id; i++) {
do {
j++;
}
c.action_to_len16 = htonl(
FW_LEN16(c));
if (ret != 0)
return (ret);
if (ret < 0)
return (ret);
return (0);
}