Commit 636f9d37 authored by Vipul Pandya's avatar Vipul Pandya Committed by David S. Miller

cxgb4: Add support for T4 configuration file

Starting with T4 firmware version 1.3.11.0 the firmware now supports device
configuration via a Firmware Configuration File. The Firmware Configuration
File was primarily developed in order to centralize all of the configuration,
resource allocation, etc. for Unified Wire operation where multiple
Physical / Virtual Function Drivers would be using a T4 adapter simultaneously.

The Firmware Configuration file can live in three locations as shown below
in order of precedence.
1) User defined configuration file: /lib/firmware/cxgb4/t4-config.txt
2) Factory Default configuration file written to FLASH within
   the manufacturing process.
3) Hardwired driver configuration.
Signed-off-by: default avatarJay Hernandez <jay@chelsio.com>
Signed-off-by: default avatarVipul Pandya <vipul@chelsio.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 52367a76
...@@ -211,6 +211,9 @@ struct tp_err_stats { ...@@ -211,6 +211,9 @@ struct tp_err_stats {
struct tp_params { struct tp_params {
unsigned int ntxchan; /* # of Tx channels */ unsigned int ntxchan; /* # of Tx channels */
unsigned int tre; /* log2 of core clocks per TP tick */ unsigned int tre; /* log2 of core clocks per TP tick */
uint32_t dack_re; /* DACK timer resolution */
unsigned short tx_modq[NCHAN]; /* channel to modulation queue map */
}; };
struct vpd_params { struct vpd_params {
...@@ -519,6 +522,8 @@ struct adapter { ...@@ -519,6 +522,8 @@ struct adapter {
struct net_device *port[MAX_NPORTS]; struct net_device *port[MAX_NPORTS];
u8 chan_map[NCHAN]; /* channel -> port map */ u8 chan_map[NCHAN]; /* channel -> port map */
unsigned int l2t_start;
unsigned int l2t_end;
struct l2t_data *l2t; struct l2t_data *l2t;
void *uld_handle[CXGB4_ULD_MAX]; void *uld_handle[CXGB4_ULD_MAX];
struct list_head list_node; struct list_head list_node;
...@@ -683,7 +688,9 @@ int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port); ...@@ -683,7 +688,9 @@ int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port);
int t4_memory_write(struct adapter *adap, int mtype, u32 addr, u32 len, int t4_memory_write(struct adapter *adap, int mtype, u32 addr, u32 len,
__be32 *buf); __be32 *buf);
int t4_seeprom_wp(struct adapter *adapter, bool enable); int t4_seeprom_wp(struct adapter *adapter, bool enable);
int get_vpd_params(struct adapter *adapter, struct vpd_params *p);
int t4_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size); int t4_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size);
unsigned int t4_flash_cfg_addr(struct adapter *adapter);
int t4_check_fw_version(struct adapter *adapter); int t4_check_fw_version(struct adapter *adapter);
int t4_prep_adapter(struct adapter *adapter); int t4_prep_adapter(struct adapter *adapter);
int t4_port_init(struct adapter *adap, int mbox, int pf, int vf); int t4_port_init(struct adapter *adap, int mbox, int pf, int vf);
...@@ -698,6 +705,8 @@ int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, ...@@ -698,6 +705,8 @@ int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data,
void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p); void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p);
void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log); void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log);
void t4_tp_wr_bits_indirect(struct adapter *adap, unsigned int addr,
unsigned int mask, unsigned int val);
void t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4, void t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4,
struct tp_tcp_stats *v6); struct tp_tcp_stats *v6);
void t4_load_mtus(struct adapter *adap, const unsigned short *mtus, void t4_load_mtus(struct adapter *adap, const unsigned short *mtus,
...@@ -713,6 +722,12 @@ int t4_fw_hello(struct adapter *adap, unsigned int mbox, unsigned int evt_mbox, ...@@ -713,6 +722,12 @@ int t4_fw_hello(struct adapter *adap, unsigned int mbox, unsigned int evt_mbox,
int t4_fw_bye(struct adapter *adap, unsigned int mbox); int t4_fw_bye(struct adapter *adap, unsigned int mbox);
int t4_early_init(struct adapter *adap, unsigned int mbox); int t4_early_init(struct adapter *adap, unsigned int mbox);
int t4_fw_reset(struct adapter *adap, unsigned int mbox, int reset); int t4_fw_reset(struct adapter *adap, unsigned int mbox, int reset);
int t4_fw_config_file(struct adapter *adap, unsigned int mbox,
unsigned int mtype, unsigned int maddr,
u32 *finiver, u32 *finicsum, u32 *cfcsum);
int t4_fixup_host_params(struct adapter *adap, unsigned int page_size,
unsigned int cache_line_size);
int t4_fw_initialize(struct adapter *adap, unsigned int mbox);
int t4_query_params(struct adapter *adap, unsigned int mbox, unsigned int pf, int t4_query_params(struct adapter *adap, unsigned int mbox, unsigned int pf,
unsigned int vf, unsigned int nparams, const u32 *params, unsigned int vf, unsigned int nparams, const u32 *params,
u32 *val); u32 *val);
......
...@@ -193,6 +193,7 @@ static DEFINE_PCI_DEVICE_TABLE(cxgb4_pci_tbl) = { ...@@ -193,6 +193,7 @@ static DEFINE_PCI_DEVICE_TABLE(cxgb4_pci_tbl) = {
}; };
#define FW_FNAME "cxgb4/t4fw.bin" #define FW_FNAME "cxgb4/t4fw.bin"
#define FW_CFNAME "cxgb4/t4-config.txt"
MODULE_DESCRIPTION(DRV_DESC); MODULE_DESCRIPTION(DRV_DESC);
MODULE_AUTHOR("Chelsio Communications"); MODULE_AUTHOR("Chelsio Communications");
...@@ -201,6 +202,17 @@ MODULE_VERSION(DRV_VERSION); ...@@ -201,6 +202,17 @@ MODULE_VERSION(DRV_VERSION);
MODULE_DEVICE_TABLE(pci, cxgb4_pci_tbl); MODULE_DEVICE_TABLE(pci, cxgb4_pci_tbl);
MODULE_FIRMWARE(FW_FNAME); MODULE_FIRMWARE(FW_FNAME);
/*
* Normally we're willing to become the firmware's Master PF but will be happy
* if another PF has already become the Master and initialized the adapter.
* Setting "force_init" will cause this driver to forcibly establish itself as
* the Master PF and initialize the adapter.
*/
static uint force_init;
module_param(force_init, uint, 0644);
MODULE_PARM_DESC(force_init, "Forcibly become Master PF and initialize adapter");
static int dflt_msg_enable = DFLT_MSG_ENABLE; static int dflt_msg_enable = DFLT_MSG_ENABLE;
module_param(dflt_msg_enable, int, 0644); module_param(dflt_msg_enable, int, 0644);
...@@ -236,6 +248,20 @@ module_param_array(intr_cnt, uint, NULL, 0644); ...@@ -236,6 +248,20 @@ module_param_array(intr_cnt, uint, NULL, 0644);
MODULE_PARM_DESC(intr_cnt, MODULE_PARM_DESC(intr_cnt,
"thresholds 1..3 for queue interrupt packet counters"); "thresholds 1..3 for queue interrupt packet counters");
/*
* Normally we tell the chip to deliver Ingress Packets into our DMA buffers
* offset by 2 bytes in order to have the IP headers line up on 4-byte
* boundaries. This is a requirement for many architectures which will throw
* a machine check fault if an attempt is made to access one of the 4-byte IP
* header fields on a non-4-byte boundary. And it's a major performance issue
* even on some architectures which allow it like some implementations of the
* x86 ISA. However, some architectures don't mind this and for some very
* edge-case performance sensitive applications (like forwarding large volumes
* of small packets), setting this DMA offset to 0 will decrease the number of
* PCI-E Bus transfers enough to measurably affect performance.
*/
static int rx_dma_offset = 2;
static bool vf_acls; static bool vf_acls;
#ifdef CONFIG_PCI_IOV #ifdef CONFIG_PCI_IOV
...@@ -3076,6 +3102,10 @@ static void setup_memwin(struct adapter *adap) ...@@ -3076,6 +3102,10 @@ static void setup_memwin(struct adapter *adap)
t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 2), t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 2),
(bar0 + MEMWIN2_BASE) | BIR(0) | (bar0 + MEMWIN2_BASE) | BIR(0) |
WINDOW(ilog2(MEMWIN2_APERTURE) - 10)); WINDOW(ilog2(MEMWIN2_APERTURE) - 10));
}
static void setup_memwin_rdma(struct adapter *adap)
{
if (adap->vres.ocq.size) { if (adap->vres.ocq.size) {
unsigned int start, sz_kb; unsigned int start, sz_kb;
...@@ -3153,6 +3183,232 @@ static int adap_init1(struct adapter *adap, struct fw_caps_config_cmd *c) ...@@ -3153,6 +3183,232 @@ static int adap_init1(struct adapter *adap, struct fw_caps_config_cmd *c)
*/ */
#define MAX_ATIDS 8192U #define MAX_ATIDS 8192U
/*
* Phase 0 of initialization: contact FW, obtain config, perform basic init.
*
* If the firmware we're dealing with has Configuration File support, then
* we use that to perform all configuration
*/
/*
* Tweak configuration based on module parameters, etc. Most of these have
* defaults assigned to them by Firmware Configuration Files (if we're using
* them) but need to be explicitly set if we're using hard-coded
* initialization. But even in the case of using Firmware Configuration
* Files, we'd like to expose the ability to change these via module
* parameters so these are essentially common tweaks/settings for
* Configuration Files and hard-coded initialization ...
*/
static int adap_init0_tweaks(struct adapter *adapter)
{
/*
* Fix up various Host-Dependent Parameters like Page Size, Cache
* Line Size, etc. The firmware default is for a 4KB Page Size and
* 64B Cache Line Size ...
*/
t4_fixup_host_params(adapter, PAGE_SIZE, L1_CACHE_BYTES);
/*
* Process module parameters which affect early initialization.
*/
if (rx_dma_offset != 2 && rx_dma_offset != 0) {
dev_err(&adapter->pdev->dev,
"Ignoring illegal rx_dma_offset=%d, using 2\n",
rx_dma_offset);
rx_dma_offset = 2;
}
t4_set_reg_field(adapter, SGE_CONTROL,
PKTSHIFT_MASK,
PKTSHIFT(rx_dma_offset));
/*
* Don't include the "IP Pseudo Header" in CPL_RX_PKT checksums: Linux
* adds the pseudo header itself.
*/
t4_tp_wr_bits_indirect(adapter, TP_INGRESS_CONFIG,
CSUM_HAS_PSEUDO_HDR, 0);
return 0;
}
/*
* Attempt to initialize the adapter via a Firmware Configuration File.
*/
static int adap_init0_config(struct adapter *adapter, int reset)
{
struct fw_caps_config_cmd caps_cmd;
const struct firmware *cf;
unsigned long mtype = 0, maddr = 0;
u32 finiver, finicsum, cfcsum;
int ret, using_flash;
/*
* Reset device if necessary.
*/
if (reset) {
ret = t4_fw_reset(adapter, adapter->mbox,
PIORSTMODE | PIORST);
if (ret < 0)
goto bye;
}
/*
* If we have a T4 configuration file under /lib/firmware/cxgb4/,
* then use that. Otherwise, use the configuration file stored
* in the adapter flash ...
*/
ret = request_firmware(&cf, FW_CFNAME, adapter->pdev_dev);
if (ret < 0) {
using_flash = 1;
mtype = FW_MEMTYPE_CF_FLASH;
maddr = t4_flash_cfg_addr(adapter);
} else {
u32 params[7], val[7];
using_flash = 0;
if (cf->size >= FLASH_CFG_MAX_SIZE)
ret = -ENOMEM;
else {
params[0] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) |
FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_CF));
ret = t4_query_params(adapter, adapter->mbox,
adapter->fn, 0, 1, params, val);
if (ret == 0) {
/*
* For t4_memory_write() below addresses and
* sizes have to be in terms of multiples of 4
* bytes. So, if the Configuration File isn't
* a multiple of 4 bytes in length we'll have
* to write that out separately since we can't
* guarantee that the bytes following the
* residual byte in the buffer returned by
* request_firmware() are zeroed out ...
*/
size_t resid = cf->size & 0x3;
size_t size = cf->size & ~0x3;
__be32 *data = (__be32 *)cf->data;
mtype = FW_PARAMS_PARAM_Y_GET(val[0]);
maddr = FW_PARAMS_PARAM_Z_GET(val[0]) << 16;
ret = t4_memory_write(adapter, mtype, maddr,
size, data);
if (ret == 0 && resid != 0) {
union {
__be32 word;
char buf[4];
} last;
int i;
last.word = data[size >> 2];
for (i = resid; i < 4; i++)
last.buf[i] = 0;
ret = t4_memory_write(adapter, mtype,
maddr + size,
4, &last.word);
}
}
}
release_firmware(cf);
if (ret)
goto bye;
}
/*
* Issue a Capability Configuration command to the firmware to get it
* to parse the Configuration File. We don't use t4_fw_config_file()
* because we want the ability to modify various features after we've
* processed the configuration file ...
*/
memset(&caps_cmd, 0, sizeof(caps_cmd));
caps_cmd.op_to_write =
htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
FW_CMD_REQUEST |
FW_CMD_READ);
caps_cmd.retval_len16 =
htonl(FW_CAPS_CONFIG_CMD_CFVALID |
FW_CAPS_CONFIG_CMD_MEMTYPE_CF(mtype) |
FW_CAPS_CONFIG_CMD_MEMADDR64K_CF(maddr >> 16) |
FW_LEN16(caps_cmd));
ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd, sizeof(caps_cmd),
&caps_cmd);
if (ret < 0)
goto bye;
finiver = ntohl(caps_cmd.finiver);
finicsum = ntohl(caps_cmd.finicsum);
cfcsum = ntohl(caps_cmd.cfcsum);
if (finicsum != cfcsum)
dev_warn(adapter->pdev_dev, "Configuration File checksum "\
"mismatch: [fini] csum=%#x, computed csum=%#x\n",
finicsum, cfcsum);
/*
* If we're a pure NIC driver then disable all offloading facilities.
* This will allow the firmware to optimize aspects of the hardware
* configuration which will result in improved performance.
*/
caps_cmd.ofldcaps = 0;
caps_cmd.iscsicaps = 0;
caps_cmd.rdmacaps = 0;
caps_cmd.fcoecaps = 0;
/*
* And now tell the firmware to use the configuration we just loaded.
*/
caps_cmd.op_to_write =
htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
FW_CMD_REQUEST |
FW_CMD_WRITE);
caps_cmd.retval_len16 = htonl(FW_LEN16(caps_cmd));
ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd, sizeof(caps_cmd),
NULL);
if (ret < 0)
goto bye;
/*
* Tweak configuration based on system architecture, module
* parameters, etc.
*/
ret = adap_init0_tweaks(adapter);
if (ret < 0)
goto bye;
/*
* And finally tell the firmware to initialize itself using the
* parameters from the Configuration File.
*/
ret = t4_fw_initialize(adapter, adapter->mbox);
if (ret < 0)
goto bye;
/*
* Return successfully and note that we're operating with parameters
* not supplied by the driver, rather than from hard-wired
* initialization constants burried in the driver.
*/
adapter->flags |= USING_SOFT_PARAMS;
dev_info(adapter->pdev_dev, "Successfully configured using Firmware "\
"Configuration File %s, version %#x, computed checksum %#x\n",
(using_flash
? "in device FLASH"
: "/lib/firmware/" FW_CFNAME),
finiver, cfcsum);
return 0;
/*
* Something bad happened. Return the error ... (If the "error"
* is that there's no Configuration File on the adapter we don't
* want to issue a warning since this is fairly common.)
*/
bye:
if (ret != -ENOENT)
dev_warn(adapter->pdev_dev, "Configuration file error %d\n",
-ret);
return ret;
}
/* /*
* Phase 0 of initialization: contact FW, obtain config, perform basic init. * Phase 0 of initialization: contact FW, obtain config, perform basic init.
*/ */
...@@ -3162,72 +3418,197 @@ static int adap_init0(struct adapter *adap) ...@@ -3162,72 +3418,197 @@ static int adap_init0(struct adapter *adap)
u32 v, port_vec; u32 v, port_vec;
enum dev_state state; enum dev_state state;
u32 params[7], val[7]; u32 params[7], val[7];
struct fw_caps_config_cmd c; int reset = 1, j;
/*
* Contact FW, advertising Master capability (and potentially forcing
* ourselves as the Master PF if our module parameter force_init is
* set).
*/
ret = t4_fw_hello(adap, adap->mbox, adap->fn,
force_init ? MASTER_MUST : MASTER_MAY,
&state);
if (ret < 0) {
dev_err(adap->pdev_dev, "could not connect to FW, error %d\n",
ret);
return ret;
}
if (ret == adap->mbox)
adap->flags |= MASTER_PF;
if (force_init && state == DEV_STATE_INIT)
state = DEV_STATE_UNINIT;
/*
* If we're the Master PF Driver and the device is uninitialized,
* then let's consider upgrading the firmware ... (We always want
* to check the firmware version number in order to A. get it for
* later reporting and B. to warn if the currently loaded firmware
* is excessively mismatched relative to the driver.)
*/
ret = t4_check_fw_version(adap); ret = t4_check_fw_version(adap);
if ((adap->flags & MASTER_PF) && state != DEV_STATE_INIT) {
if (ret == -EINVAL || ret > 0) { if (ret == -EINVAL || ret > 0) {
if (upgrade_fw(adap) >= 0) /* recache FW version */ if (upgrade_fw(adap) >= 0) {
/*
* Note that the chip was reset as part of the
* firmware upgrade so we don't reset it again
* below and grab the new firmware version.
*/
reset = 0;
ret = t4_check_fw_version(adap); ret = t4_check_fw_version(adap);
} }
}
if (ret < 0) if (ret < 0)
return ret; return ret;
/* contact FW, request master */
ret = t4_fw_hello(adap, adap->fn, adap->fn, MASTER_MUST, &state);
if (ret < 0) {
dev_err(adap->pdev_dev, "could not connect to FW, error %d\n",
ret);
return ret;
} }
/* reset device */ /*
ret = t4_fw_reset(adap, adap->fn, PIORSTMODE | PIORST); * Grab VPD parameters. This should be done after we establish a
* connection to the firmware since some of the VPD parameters
* (notably the Core Clock frequency) are retrieved via requests to
* the firmware. On the other hand, we need these fairly early on
* so we do this right after getting ahold of the firmware.
*/
ret = get_vpd_params(adap, &adap->params.vpd);
if (ret < 0) if (ret < 0)
goto bye; goto bye;
for (v = 0; v < SGE_NTIMERS - 1; v++) /*
adap->sge.timer_val[v] = min(intr_holdoff[v], MAX_SGE_TIMERVAL); * Find out what ports are available to us.
adap->sge.timer_val[SGE_NTIMERS - 1] = MAX_SGE_TIMERVAL; */
adap->sge.counter_val[0] = 1; v =
for (v = 1; v < SGE_NCOUNTERS; v++) FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) |
adap->sge.counter_val[v] = min(intr_cnt[v - 1], FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_PORTVEC);
THRESHOLD_3_MASK); ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 1, &v, &port_vec);
#define FW_PARAM_DEV(param) \ if (ret < 0)
(FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | \ goto bye;
FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_##param))
adap->params.nports = hweight32(port_vec);
adap->params.portvec = port_vec;
params[0] = FW_PARAM_DEV(CCLK); /*
ret = t4_query_params(adap, adap->fn, adap->fn, 0, 1, params, val); * If the firmware is initialized already (and we're not forcing a
* master initialization), note that we're living with existing
* adapter parameters. Otherwise, it's time to try initializing the
* adapter ...
*/
if (state == DEV_STATE_INIT) {
dev_info(adap->pdev_dev, "Coming up as %s: "\
"Adapter already initialized\n",
adap->flags & MASTER_PF ? "MASTER" : "SLAVE");
adap->flags |= USING_SOFT_PARAMS;
} else {
dev_info(adap->pdev_dev, "Coming up as MASTER: "\
"Initializing adapter\n");
/*
* Find out whether we're dealing with a version of
* the firmware which has configuration file support.
*/
params[0] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) |
FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_CF));
ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 1,
params, val);
/*
* If the firmware doesn't support Configuration
* Files warn user and exit,
*/
if (ret < 0) if (ret < 0)
dev_warn(adap->pdev_dev, "Firmware doesn't support "\
"configuration file.\n");
else {
/*
* The firmware provides us with a memory
* buffer where we can load a Configuration
* File from the host if we want to override
* the Configuration File in flash.
*/
ret = adap_init0_config(adap, reset);
if (ret == -ENOENT) {
dev_info(adap->pdev_dev,
"No Configuration File present "
"on adapter.\n");
}
}
if (ret < 0) {
dev_err(adap->pdev_dev,
"could not initialize adapter, error %d\n",
-ret);
goto bye; goto bye;
adap->params.vpd.cclk = val[0]; }
}
ret = adap_init1(adap, &c); /*
* If we're living with non-hard-coded parameters (either from a
* Firmware Configuration File or values programmed by a different PF
* Driver), give the SGE code a chance to pull in anything that it
* needs ... Note that this must be called after we retrieve our VPD
* parameters in order to know how to convert core ticks to seconds.
*/
if (adap->flags & USING_SOFT_PARAMS) {
ret = t4_sge_init(adap);
if (ret < 0) if (ret < 0)
goto bye; goto bye;
}
/*
* Grab some of our basic fundamental operating parameters.
*/
#define FW_PARAM_DEV(param) \
(FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | \
FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_##param))
#define FW_PARAM_PFVF(param) \ #define FW_PARAM_PFVF(param) \
(FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | \ FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | \
FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param) | \ FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param)| \
FW_PARAMS_PARAM_Y(adap->fn)) FW_PARAMS_PARAM_Y(0) | \
FW_PARAMS_PARAM_Z(0)
params[0] = FW_PARAM_DEV(PORTVEC); params[0] = FW_PARAM_PFVF(EQ_START);
params[1] = FW_PARAM_PFVF(L2T_START); params[1] = FW_PARAM_PFVF(L2T_START);
params[2] = FW_PARAM_PFVF(L2T_END); params[2] = FW_PARAM_PFVF(L2T_END);
params[3] = FW_PARAM_PFVF(FILTER_START); params[3] = FW_PARAM_PFVF(FILTER_START);
params[4] = FW_PARAM_PFVF(FILTER_END); params[4] = FW_PARAM_PFVF(FILTER_END);
params[5] = FW_PARAM_PFVF(IQFLINT_START); params[5] = FW_PARAM_PFVF(IQFLINT_START);
params[6] = FW_PARAM_PFVF(EQ_START); ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 6, params, val);
ret = t4_query_params(adap, adap->fn, adap->fn, 0, 7, params, val);
if (ret < 0) if (ret < 0)
goto bye; goto bye;
port_vec = val[0]; adap->sge.egr_start = val[0];
adap->l2t_start = val[1];
adap->l2t_end = val[2];
adap->tids.ftid_base = val[3]; adap->tids.ftid_base = val[3];
adap->tids.nftids = val[4] - val[3] + 1; adap->tids.nftids = val[4] - val[3] + 1;
adap->sge.ingr_start = val[5]; adap->sge.ingr_start = val[5];
adap->sge.egr_start = val[6];
if (c.ofldcaps) { /* query params related to active filter region */
params[0] = FW_PARAM_PFVF(ACTIVE_FILTER_START);
params[1] = FW_PARAM_PFVF(ACTIVE_FILTER_END);
ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 2, params, val);
/* If Active filter size is set we enable establishing
* offload connection through firmware work request
*/
if ((val[0] != val[1]) && (ret >= 0)) {
adap->flags |= FW_OFLD_CONN;
adap->tids.aftid_base = val[0];
adap->tids.aftid_end = val[1];
}
#ifdef CONFIG_CHELSIO_T4_OFFLOAD
/*
* Get device capabilities so we can determine what resources we need
* to manage.
*/
memset(&caps_cmd, 0, sizeof(caps_cmd));
caps_cmd.op_to_write = htonl(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
F_FW_CMD_REQUEST | F_FW_CMD_READ);
caps_cmd.cfvalid_to_len16 = htonl(FW_LEN16(caps_cmd));
ret = t4_wr_mbox(adap, adap->mbox, &caps_cmd, sizeof(caps_cmd),
&caps_cmd);
if (ret < 0)
goto bye;
if (caps_cmd.toecaps) {
/* query offload-related parameters */ /* query offload-related parameters */
params[0] = FW_PARAM_DEV(NTID); params[0] = FW_PARAM_DEV(NTID);
params[1] = FW_PARAM_PFVF(SERVER_START); params[1] = FW_PARAM_PFVF(SERVER_START);
...@@ -3235,28 +3616,55 @@ static int adap_init0(struct adapter *adap) ...@@ -3235,28 +3616,55 @@ static int adap_init0(struct adapter *adap)
params[3] = FW_PARAM_PFVF(TDDP_START); params[3] = FW_PARAM_PFVF(TDDP_START);
params[4] = FW_PARAM_PFVF(TDDP_END); params[4] = FW_PARAM_PFVF(TDDP_END);
params[5] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ); params[5] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ);
ret = t4_query_params(adap, adap->fn, adap->fn, 0, 6, params, ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 6,
val); params, val);
if (ret < 0) if (ret < 0)
goto bye; goto bye;
adap->tids.ntids = val[0]; adap->tids.ntids = val[0];
adap->tids.natids = min(adap->tids.ntids / 2, MAX_ATIDS); adap->tids.natids = min(adap->tids.ntids / 2, MAX_ATIDS);
adap->tids.stid_base = val[1]; adap->tids.stid_base = val[1];
adap->tids.nstids = val[2] - val[1] + 1; adap->tids.nstids = val[2] - val[1] + 1;
/*
* Setup server filter region. Divide the availble filter
* region into two parts. Regular filters get 1/3rd and server
* filters get 2/3rd part. This is only enabled if workarond
* path is enabled.
* 1. For regular filters.
* 2. Server filter: This are special filters which are used
* to redirect SYN packets to offload queue.
*/
if (adap->flags & FW_OFLD_CONN && !is_bypass(adap)) {
adap->tids.sftid_base = adap->tids.ftid_base +
DIV_ROUND_UP(adap->tids.nftids, 3);
adap->tids.nsftids = adap->tids.nftids -
DIV_ROUND_UP(adap->tids.nftids, 3);
adap->tids.nftids = adap->tids.sftid_base -
adap->tids.ftid_base;
}
adap->vres.ddp.start = val[3]; adap->vres.ddp.start = val[3];
adap->vres.ddp.size = val[4] - val[3] + 1; adap->vres.ddp.size = val[4] - val[3] + 1;
adap->params.ofldq_wr_cred = val[5]; adap->params.ofldq_wr_cred = val[5];
params[0] = FW_PARAM_PFVF(ETHOFLD_START);
params[1] = FW_PARAM_PFVF(ETHOFLD_END);
ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 2,
params, val);
if ((val[0] != val[1]) && (ret >= 0)) {
adap->tids.uotid_base = val[0];
adap->tids.nuotids = val[1] - val[0] + 1;
}
adap->params.offload = 1; adap->params.offload = 1;
} }
if (c.rdmacaps) { if (caps_cmd.rdmacaps) {
params[0] = FW_PARAM_PFVF(STAG_START); params[0] = FW_PARAM_PFVF(STAG_START);
params[1] = FW_PARAM_PFVF(STAG_END); params[1] = FW_PARAM_PFVF(STAG_END);
params[2] = FW_PARAM_PFVF(RQ_START); params[2] = FW_PARAM_PFVF(RQ_START);
params[3] = FW_PARAM_PFVF(RQ_END); params[3] = FW_PARAM_PFVF(RQ_END);
params[4] = FW_PARAM_PFVF(PBL_START); params[4] = FW_PARAM_PFVF(PBL_START);
params[5] = FW_PARAM_PFVF(PBL_END); params[5] = FW_PARAM_PFVF(PBL_END);
ret = t4_query_params(adap, adap->fn, adap->fn, 0, 6, params, ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 6,
val); params, val);
if (ret < 0) if (ret < 0)
goto bye; goto bye;
adap->vres.stag.start = val[0]; adap->vres.stag.start = val[0];
...@@ -3272,8 +3680,7 @@ static int adap_init0(struct adapter *adap) ...@@ -3272,8 +3680,7 @@ static int adap_init0(struct adapter *adap)
params[3] = FW_PARAM_PFVF(CQ_END); params[3] = FW_PARAM_PFVF(CQ_END);
params[4] = FW_PARAM_PFVF(OCQ_START); params[4] = FW_PARAM_PFVF(OCQ_START);
params[5] = FW_PARAM_PFVF(OCQ_END); params[5] = FW_PARAM_PFVF(OCQ_END);
ret = t4_query_params(adap, adap->fn, adap->fn, 0, 6, params, ret = t4_query_params(adap, 0, 0, 0, 6, params, val);
val);
if (ret < 0) if (ret < 0)
goto bye; goto bye;
adap->vres.qp.start = val[0]; adap->vres.qp.start = val[0];
...@@ -3283,11 +3690,11 @@ static int adap_init0(struct adapter *adap) ...@@ -3283,11 +3690,11 @@ static int adap_init0(struct adapter *adap)
adap->vres.ocq.start = val[4]; adap->vres.ocq.start = val[4];
adap->vres.ocq.size = val[5] - val[4] + 1; adap->vres.ocq.size = val[5] - val[4] + 1;
} }
if (c.iscsicaps) { if (caps_cmd.iscsicaps) {
params[0] = FW_PARAM_PFVF(ISCSI_START); params[0] = FW_PARAM_PFVF(ISCSI_START);
params[1] = FW_PARAM_PFVF(ISCSI_END); params[1] = FW_PARAM_PFVF(ISCSI_END);
ret = t4_query_params(adap, adap->fn, adap->fn, 0, 2, params, ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 2,
val); params, val);
if (ret < 0) if (ret < 0)
goto bye; goto bye;
adap->vres.iscsi.start = val[0]; adap->vres.iscsi.start = val[0];
...@@ -3295,63 +3702,33 @@ static int adap_init0(struct adapter *adap) ...@@ -3295,63 +3702,33 @@ static int adap_init0(struct adapter *adap)
} }
#undef FW_PARAM_PFVF #undef FW_PARAM_PFVF
#undef FW_PARAM_DEV #undef FW_PARAM_DEV
#endif /* CONFIG_CHELSIO_T4_OFFLOAD */
adap->params.nports = hweight32(port_vec); /*
adap->params.portvec = port_vec; * These are finalized by FW initialization, load their values now.
adap->flags |= FW_OK; */
/* These are finalized by FW initialization, load their values now */
v = t4_read_reg(adap, TP_TIMER_RESOLUTION); v = t4_read_reg(adap, TP_TIMER_RESOLUTION);
adap->params.tp.tre = TIMERRESOLUTION_GET(v); adap->params.tp.tre = TIMERRESOLUTION_GET(v);
adap->params.tp.dack_re = DELAYEDACKRESOLUTION_GET(v);
t4_read_mtu_tbl(adap, adap->params.mtus, NULL); t4_read_mtu_tbl(adap, adap->params.mtus, NULL);
t4_load_mtus(adap, adap->params.mtus, adap->params.a_wnd, t4_load_mtus(adap, adap->params.mtus, adap->params.a_wnd,
adap->params.b_wnd); adap->params.b_wnd);
#ifdef CONFIG_PCI_IOV /* MODQ_REQ_MAP defaults to setting queues 0-3 to chan 0-3 */
/* for (j = 0; j < NCHAN; j++)
* Provision resource limits for Virtual Functions. We currently adap->params.tp.tx_modq[j] = j;
* grant them all the same static resource limits except for the Port
* Access Rights Mask which we're assigning based on the PF. All of
* the static provisioning stuff for both the PF and VF really needs
* to be managed in a persistent manner for each device which the
* firmware controls.
*/
{
int pf, vf;
for (pf = 0; pf < ARRAY_SIZE(num_vf); pf++) {
if (num_vf[pf] <= 0)
continue;
/* VF numbering starts at 1! */ adap->flags |= FW_OK;
for (vf = 1; vf <= num_vf[pf]; vf++) {
ret = t4_cfg_pfvf(adap, adap->fn, pf, vf,
VFRES_NEQ, VFRES_NETHCTRL,
VFRES_NIQFLINT, VFRES_NIQ,
VFRES_TC, VFRES_NVI,
FW_PFVF_CMD_CMASK_MASK,
pfvfres_pmask(adap, pf, vf),
VFRES_NEXACTF,
VFRES_R_CAPS, VFRES_WX_CAPS);
if (ret < 0)
dev_warn(adap->pdev_dev, "failed to "
"provision pf/vf=%d/%d; "
"err=%d\n", pf, vf, ret);
}
}
}
#endif
setup_memwin(adap);
return 0; return 0;
/* /*
* If a command timed out or failed with EIO FW does not operate within * Something bad happened. If a command timed out or failed with EIO
* its spec or something catastrophic happened to HW/FW, stop issuing * FW does not operate within its spec or something catastrophic
* commands. * happened to HW/FW, stop issuing commands.
*/ */
bye: if (ret != -ETIMEDOUT && ret != -EIO) bye:
t4_fw_bye(adap, adap->fn); if (ret != -ETIMEDOUT && ret != -EIO)
t4_fw_bye(adap, adap->mbox);
return ret; return ret;
} }
...@@ -3814,7 +4191,9 @@ static int __devinit init_one(struct pci_dev *pdev, ...@@ -3814,7 +4191,9 @@ static int __devinit init_one(struct pci_dev *pdev,
err = t4_prep_adapter(adapter); err = t4_prep_adapter(adapter);
if (err) if (err)
goto out_unmap_bar; goto out_unmap_bar;
setup_memwin(adapter);
err = adap_init0(adapter); err = adap_init0(adapter);
setup_memwin_rdma(adapter);
if (err) if (err)
goto out_unmap_bar; goto out_unmap_bar;
...@@ -3956,8 +4335,11 @@ static void __devexit remove_one(struct pci_dev *pdev) ...@@ -3956,8 +4335,11 @@ static void __devexit remove_one(struct pci_dev *pdev)
{ {
struct adapter *adapter = pci_get_drvdata(pdev); struct adapter *adapter = pci_get_drvdata(pdev);
#ifdef CONFIG_PCI_IOV
pci_disable_sriov(pdev); pci_disable_sriov(pdev);
#endif
if (adapter) { if (adapter) {
int i; int i;
......
...@@ -100,6 +100,8 @@ struct tid_info { ...@@ -100,6 +100,8 @@ struct tid_info {
unsigned int nftids; unsigned int nftids;
unsigned int ftid_base; unsigned int ftid_base;
unsigned int aftid_base;
unsigned int aftid_end;
spinlock_t atid_lock ____cacheline_aligned_in_smp; spinlock_t atid_lock ____cacheline_aligned_in_smp;
union aopen_entry *afree; union aopen_entry *afree;
......
...@@ -492,8 +492,9 @@ int t4_seeprom_wp(struct adapter *adapter, bool enable) ...@@ -492,8 +492,9 @@ int t4_seeprom_wp(struct adapter *adapter, bool enable)
* *
* Reads card parameters stored in VPD EEPROM. * Reads card parameters stored in VPD EEPROM.
*/ */
static int get_vpd_params(struct adapter *adapter, struct vpd_params *p) int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
{ {
u32 cclk_param, cclk_val;
int i, ret; int i, ret;
int ec, sn; int ec, sn;
u8 vpd[VPD_LEN], csum; u8 vpd[VPD_LEN], csum;
...@@ -555,6 +556,19 @@ static int get_vpd_params(struct adapter *adapter, struct vpd_params *p) ...@@ -555,6 +556,19 @@ static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
i = pci_vpd_info_field_size(vpd + sn - PCI_VPD_INFO_FLD_HDR_SIZE); i = pci_vpd_info_field_size(vpd + sn - PCI_VPD_INFO_FLD_HDR_SIZE);
memcpy(p->sn, vpd + sn, min(i, SERNUM_LEN)); memcpy(p->sn, vpd + sn, min(i, SERNUM_LEN));
strim(p->sn); strim(p->sn);
/*
* 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(FW_PARAMS_MNEM_DEV) |
FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_CCLK));
ret = t4_query_params(adapter, adapter->mbox, 0, 0,
1, &cclk_param, &cclk_val);
if (ret)
return ret;
p->cclk = cclk_val;
return 0; return 0;
} }
...@@ -854,6 +868,77 @@ static int t4_flash_erase_sectors(struct adapter *adapter, int start, int end) ...@@ -854,6 +868,77 @@ static int t4_flash_erase_sectors(struct adapter *adapter, int start, int end)
return ret; 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 t4_flash_cfg_addr(struct adapter *adapter)
{
if (adapter->params.sf_size == 0x100000)
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 t4_load_cfg(struct adapter *adap, const u8 *cfg_data, unsigned int size)
{
int ret, i, n;
unsigned int addr;
unsigned int flash_cfg_start_sec;
unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec;
addr = t4_flash_cfg_addr(adap);
flash_cfg_start_sec = addr / SF_SEC_SIZE;
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);
if (ret)
goto out;
addr += SF_PAGE_SIZE;
cfg_data += SF_PAGE_SIZE;
}
out:
if (ret)
dev_err(adap->pdev_dev, "config file %s failed %d\n",
(size == 0 ? "clear" : "download"), ret);
return ret;
}
/** /**
* t4_load_fw - download firmware * t4_load_fw - download firmware
* @adap: the adapter * @adap: the adapter
...@@ -1853,6 +1938,23 @@ void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log) ...@@ -1853,6 +1938,23 @@ void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log)
} }
} }
/**
* 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, unsigned int addr,
unsigned int mask, unsigned int val)
{
t4_write_reg(adap, TP_PIO_ADDR, addr);
val |= t4_read_reg(adap, TP_PIO_DATA) & ~mask;
t4_write_reg(adap, TP_PIO_DATA, val);
}
/** /**
* init_cong_ctrl - initialize congestion control parameters * init_cong_ctrl - initialize congestion control parameters
* @a: the alpha values for congestion control * @a: the alpha values for congestion control
...@@ -2137,9 +2239,9 @@ int t4_fwaddrspace_write(struct adapter *adap, unsigned int mbox, ...@@ -2137,9 +2239,9 @@ int t4_fwaddrspace_write(struct adapter *adap, unsigned int mbox,
struct fw_ldst_cmd c; struct fw_ldst_cmd c;
memset(&c, 0, sizeof(c)); memset(&c, 0, sizeof(c));
c.op_to_addrspace = htonl(V_FW_CMD_OP(FW_LDST_CMD) | F_FW_CMD_REQUEST | c.op_to_addrspace = htonl(FW_CMD_OP(FW_LDST_CMD) | FW_CMD_REQUEST |
F_FW_CMD_WRITE | FW_CMD_WRITE |
V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_FIRMWARE)); FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_FIRMWARE));
c.cycles_to_len16 = htonl(FW_LEN16(c)); c.cycles_to_len16 = htonl(FW_LEN16(c));
c.u.addrval.addr = htonl(addr); c.u.addrval.addr = htonl(addr);
c.u.addrval.val = htonl(val); c.u.addrval.val = htonl(val);
...@@ -2244,34 +2346,124 @@ int t4_mdio_wr(struct adapter *adap, unsigned int mbox, unsigned int phy_addr, ...@@ -2244,34 +2346,124 @@ int t4_mdio_wr(struct adapter *adap, unsigned int mbox, unsigned int phy_addr,
* @mbox: mailbox to use for the FW command * @mbox: mailbox to use for the FW command
* @evt_mbox: mailbox to receive async FW events * @evt_mbox: mailbox to receive async FW events
* @master: specifies the caller's willingness to be the device master * @master: specifies the caller's willingness to be the device master
* @state: returns the current device state * @state: returns the current device state (if non-NULL)
* *
* Issues a command to establish communication with FW. * 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, unsigned int mbox, unsigned int evt_mbox, int t4_fw_hello(struct adapter *adap, unsigned int mbox, unsigned int evt_mbox,
enum dev_master master, enum dev_state *state) enum dev_master master, enum dev_state *state)
{ {
int ret; int ret;
struct fw_hello_cmd c; struct fw_hello_cmd c;
u32 v;
unsigned int master_mbox;
int retries = FW_CMD_HELLO_RETRIES;
retry:
memset(&c, 0, sizeof(c));
INIT_CMD(c, HELLO, WRITE); INIT_CMD(c, HELLO, WRITE);
c.err_to_mbasyncnot = htonl( c.err_to_mbasyncnot = htonl(
FW_HELLO_CMD_MASTERDIS(master == MASTER_CANT) | FW_HELLO_CMD_MASTERDIS(master == MASTER_CANT) |
FW_HELLO_CMD_MASTERFORCE(master == MASTER_MUST) | FW_HELLO_CMD_MASTERFORCE(master == MASTER_MUST) |
FW_HELLO_CMD_MBMASTER(master == MASTER_MUST ? mbox : 0xff) | FW_HELLO_CMD_MBMASTER(master == MASTER_MUST ? mbox :
FW_HELLO_CMD_MBASYNCNOT(evt_mbox)); FW_HELLO_CMD_MBMASTER_MASK) |
FW_HELLO_CMD_MBASYNCNOT(evt_mbox) |
FW_HELLO_CMD_STAGE(fw_hello_cmd_stage_os) |
FW_HELLO_CMD_CLEARINIT);
/*
* 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.
*/
ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
if (ret == 0 && state) { if (ret < 0) {
u32 v = ntohl(c.err_to_mbasyncnot); if ((ret == -EBUSY || ret == -ETIMEDOUT) && retries-- > 0)
if (v & FW_HELLO_CMD_INIT) goto retry;
*state = DEV_STATE_INIT; return ret;
else if (v & FW_HELLO_CMD_ERR) }
v = ntohl(c.err_to_mbasyncnot);
master_mbox = FW_HELLO_CMD_MBMASTER_GET(v);
if (state) {
if (v & FW_HELLO_CMD_ERR)
*state = DEV_STATE_ERR; *state = DEV_STATE_ERR;
else if (v & FW_HELLO_CMD_INIT)
*state = DEV_STATE_INIT;
else else
*state = DEV_STATE_UNINIT; *state = DEV_STATE_UNINIT;
} }
return ret;
/*
* 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
* FW_PCIE_FW_MASTER_MASK so the test below will work ...
*/
if ((v & (FW_HELLO_CMD_ERR|FW_HELLO_CMD_INIT)) == 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 Initialialized are indicated
* by the firmware keep waiting till we exaust our
* timeout ... and then retry if we haven't exhausted
* our retries ...
*/
pcie_fw = t4_read_reg(adap, MA_PCIE_FW);
if (!(pcie_fw & (FW_PCIE_FW_ERR|FW_PCIE_FW_INIT))) {
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 & FW_PCIE_FW_ERR)
*state = DEV_STATE_ERR;
else if (pcie_fw & FW_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 == FW_PCIE_FW_MASTER_MASK &&
(pcie_fw & FW_PCIE_FW_MASTER_VLD))
master_mbox = FW_PCIE_FW_MASTER_GET(pcie_fw);
break;
}
}
return master_mbox;
} }
/** /**
...@@ -2322,6 +2514,163 @@ int t4_fw_reset(struct adapter *adap, unsigned int mbox, int reset) ...@@ -2322,6 +2514,163 @@ int t4_fw_reset(struct adapter *adap, unsigned int mbox, int reset)
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
} }
/**
* 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 located at the specified mtype/maddress. If 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 t4_fw_config_file(struct adapter *adap, unsigned int mbox,
unsigned int mtype, unsigned int maddr,
u32 *finiver, u32 *finicsum, u32 *cfcsum)
{
struct fw_caps_config_cmd caps_cmd;
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.
*/
memset(&caps_cmd, 0, sizeof(caps_cmd));
caps_cmd.op_to_write =
htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
FW_CMD_REQUEST |
FW_CMD_READ);
caps_cmd.retval_len16 =
htonl(FW_CAPS_CONFIG_CMD_CFVALID |
FW_CAPS_CONFIG_CMD_MEMTYPE_CF(mtype) |
FW_CAPS_CONFIG_CMD_MEMADDR64K_CF(maddr >> 16) |
FW_LEN16(caps_cmd));
ret = t4_wr_mbox(adap, mbox, &caps_cmd, sizeof(caps_cmd), &caps_cmd);
if (ret < 0)
return ret;
if (finiver)
*finiver = ntohl(caps_cmd.finiver);
if (finicsum)
*finicsum = ntohl(caps_cmd.finicsum);
if (cfcsum)
*cfcsum = ntohl(caps_cmd.cfcsum);
/*
* And now tell the firmware to use the configuration we just loaded.
*/
caps_cmd.op_to_write =
htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
FW_CMD_REQUEST |
FW_CMD_WRITE);
caps_cmd.retval_len16 = htonl(FW_LEN16(caps_cmd));
return t4_wr_mbox(adap, mbox, &caps_cmd, sizeof(caps_cmd), NULL);
}
/**
* 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, unsigned int page_size,
unsigned int cache_line_size)
{
unsigned int page_shift = fls(page_size) - 1;
unsigned int sge_hps = page_shift - 10;
unsigned int stat_len = cache_line_size > 64 ? 128 : 64;
unsigned int fl_align = cache_line_size < 32 ? 32 : cache_line_size;
unsigned int fl_align_log = fls(fl_align) - 1;
t4_write_reg(adap, SGE_HOST_PAGE_SIZE,
HOSTPAGESIZEPF0(sge_hps) |
HOSTPAGESIZEPF1(sge_hps) |
HOSTPAGESIZEPF2(sge_hps) |
HOSTPAGESIZEPF3(sge_hps) |
HOSTPAGESIZEPF4(sge_hps) |
HOSTPAGESIZEPF5(sge_hps) |
HOSTPAGESIZEPF6(sge_hps) |
HOSTPAGESIZEPF7(sge_hps));
t4_set_reg_field(adap, SGE_CONTROL,
INGPADBOUNDARY(INGPADBOUNDARY_MASK) |
EGRSTATUSPAGESIZE_MASK,
INGPADBOUNDARY(fl_align_log - 5) |
EGRSTATUSPAGESIZE(stat_len != 64));
/*
* 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.
*/
t4_write_reg(adap, SGE_FL_BUFFER_SIZE0, page_size);
t4_write_reg(adap, SGE_FL_BUFFER_SIZE2,
(t4_read_reg(adap, SGE_FL_BUFFER_SIZE2) + fl_align-1)
& ~(fl_align-1));
t4_write_reg(adap, SGE_FL_BUFFER_SIZE3,
(t4_read_reg(adap, SGE_FL_BUFFER_SIZE3) + fl_align-1)
& ~(fl_align-1));
t4_write_reg(adap, ULP_RX_TDDP_PSZ, HPZ0(page_shift - 12));
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 t4_fw_initialize(struct adapter *adap, unsigned int mbox)
{
struct fw_initialize_cmd c;
memset(&c, 0, sizeof(c));
INIT_CMD(c, INITIALIZE, WRITE);
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
}
/** /**
* t4_query_params - query FW or device parameters * t4_query_params - query FW or device parameters
* @adap: the adapter * @adap: the adapter
...@@ -2974,10 +3323,6 @@ int __devinit t4_prep_adapter(struct adapter *adapter) ...@@ -2974,10 +3323,6 @@ int __devinit t4_prep_adapter(struct adapter *adapter)
return ret; return ret;
} }
ret = get_vpd_params(adapter, &adapter->params.vpd);
if (ret < 0)
return ret;
init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd); init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd);
/* /*
...@@ -2985,6 +3330,7 @@ int __devinit t4_prep_adapter(struct adapter *adapter) ...@@ -2985,6 +3330,7 @@ int __devinit t4_prep_adapter(struct adapter *adapter)
*/ */
adapter->params.nports = 1; adapter->params.nports = 1;
adapter->params.portvec = 1; adapter->params.portvec = 1;
adapter->params.vpd.cclk = 50000;
return 0; return 0;
} }
......
...@@ -115,6 +115,35 @@ ...@@ -115,6 +115,35 @@
#define GLOBALENABLE 0x00000001U #define GLOBALENABLE 0x00000001U
#define SGE_HOST_PAGE_SIZE 0x100c #define SGE_HOST_PAGE_SIZE 0x100c
#define HOSTPAGESIZEPF7_MASK 0x0000000fU
#define HOSTPAGESIZEPF7_SHIFT 28
#define HOSTPAGESIZEPF7(x) ((x) << HOSTPAGESIZEPF7_SHIFT)
#define HOSTPAGESIZEPF6_MASK 0x0000000fU
#define HOSTPAGESIZEPF6_SHIFT 24
#define HOSTPAGESIZEPF6(x) ((x) << HOSTPAGESIZEPF6_SHIFT)
#define HOSTPAGESIZEPF5_MASK 0x0000000fU
#define HOSTPAGESIZEPF5_SHIFT 20
#define HOSTPAGESIZEPF5(x) ((x) << HOSTPAGESIZEPF5_SHIFT)
#define HOSTPAGESIZEPF4_MASK 0x0000000fU
#define HOSTPAGESIZEPF4_SHIFT 16
#define HOSTPAGESIZEPF4(x) ((x) << HOSTPAGESIZEPF4_SHIFT)
#define HOSTPAGESIZEPF3_MASK 0x0000000fU
#define HOSTPAGESIZEPF3_SHIFT 12
#define HOSTPAGESIZEPF3(x) ((x) << HOSTPAGESIZEPF3_SHIFT)
#define HOSTPAGESIZEPF2_MASK 0x0000000fU
#define HOSTPAGESIZEPF2_SHIFT 8
#define HOSTPAGESIZEPF2(x) ((x) << HOSTPAGESIZEPF2_SHIFT)
#define HOSTPAGESIZEPF1_MASK 0x0000000fU
#define HOSTPAGESIZEPF1_SHIFT 4
#define HOSTPAGESIZEPF1(x) ((x) << HOSTPAGESIZEPF1_SHIFT)
#define HOSTPAGESIZEPF0_MASK 0x0000000fU #define HOSTPAGESIZEPF0_MASK 0x0000000fU
#define HOSTPAGESIZEPF0_SHIFT 0 #define HOSTPAGESIZEPF0_SHIFT 0
#define HOSTPAGESIZEPF0(x) ((x) << HOSTPAGESIZEPF0_SHIFT) #define HOSTPAGESIZEPF0(x) ((x) << HOSTPAGESIZEPF0_SHIFT)
...@@ -162,6 +191,8 @@ ...@@ -162,6 +191,8 @@
#define SGE_INT_ENABLE3 0x1040 #define SGE_INT_ENABLE3 0x1040
#define SGE_FL_BUFFER_SIZE0 0x1044 #define SGE_FL_BUFFER_SIZE0 0x1044
#define SGE_FL_BUFFER_SIZE1 0x1048 #define SGE_FL_BUFFER_SIZE1 0x1048
#define SGE_FL_BUFFER_SIZE2 0x104c
#define SGE_FL_BUFFER_SIZE3 0x1050
#define SGE_INGRESS_RX_THRESHOLD 0x10a0 #define SGE_INGRESS_RX_THRESHOLD 0x10a0
#define THRESHOLD_0_MASK 0x3f000000U #define THRESHOLD_0_MASK 0x3f000000U
#define THRESHOLD_0_SHIFT 24 #define THRESHOLD_0_SHIFT 24
...@@ -367,7 +398,7 @@ ...@@ -367,7 +398,7 @@
#define MEM_WRAP_CLIENT_NUM_MASK 0x0000000fU #define MEM_WRAP_CLIENT_NUM_MASK 0x0000000fU
#define MEM_WRAP_CLIENT_NUM_SHIFT 0 #define MEM_WRAP_CLIENT_NUM_SHIFT 0
#define MEM_WRAP_CLIENT_NUM_GET(x) (((x) & MEM_WRAP_CLIENT_NUM_MASK) >> MEM_WRAP_CLIENT_NUM_SHIFT) #define MEM_WRAP_CLIENT_NUM_GET(x) (((x) & MEM_WRAP_CLIENT_NUM_MASK) >> MEM_WRAP_CLIENT_NUM_SHIFT)
#define MA_PCIE_FW 0x30b8
#define MA_PARITY_ERROR_STATUS 0x77f4 #define MA_PARITY_ERROR_STATUS 0x77f4
#define EDC_0_BASE_ADDR 0x7900 #define EDC_0_BASE_ADDR 0x7900
...@@ -469,6 +500,10 @@ ...@@ -469,6 +500,10 @@
#define TIMERRESOLUTION_MASK 0x00ff0000U #define TIMERRESOLUTION_MASK 0x00ff0000U
#define TIMERRESOLUTION_SHIFT 16 #define TIMERRESOLUTION_SHIFT 16
#define TIMERRESOLUTION_GET(x) (((x) & TIMERRESOLUTION_MASK) >> TIMERRESOLUTION_SHIFT) #define TIMERRESOLUTION_GET(x) (((x) & TIMERRESOLUTION_MASK) >> TIMERRESOLUTION_SHIFT)
#define DELAYEDACKRESOLUTION_MASK 0x000000ffU
#define DELAYEDACKRESOLUTION_SHIFT 0
#define DELAYEDACKRESOLUTION_GET(x) \
(((x) & DELAYEDACKRESOLUTION_MASK) >> DELAYEDACKRESOLUTION_SHIFT)
#define TP_SHIFT_CNT 0x7dc0 #define TP_SHIFT_CNT 0x7dc0
......
...@@ -155,6 +155,17 @@ struct fw_eth_tx_pkt_vm_wr { ...@@ -155,6 +155,17 @@ struct fw_eth_tx_pkt_vm_wr {
#define FW_CMD_MAX_TIMEOUT 3000 #define FW_CMD_MAX_TIMEOUT 3000
/*
* If a host driver does a HELLO and discovers that there's already a MASTER
* selected, we may have to wait for that MASTER to finish issuing RESET,
* configuration and INITIALIZE commands. Also, there's a possibility that
* our own HELLO may get lost if it happens right as the MASTER is issuign a
* RESET command, so we need to be willing to make a few retries of our HELLO.
*/
#define FW_CMD_HELLO_TIMEOUT (3 * FW_CMD_MAX_TIMEOUT)
#define FW_CMD_HELLO_RETRIES 3
enum fw_cmd_opcodes { enum fw_cmd_opcodes {
FW_LDST_CMD = 0x01, FW_LDST_CMD = 0x01,
FW_RESET_CMD = 0x03, FW_RESET_CMD = 0x03,
...@@ -307,6 +318,10 @@ struct fw_reset_cmd { ...@@ -307,6 +318,10 @@ struct fw_reset_cmd {
__be32 r3; __be32 r3;
}; };
enum fw_hellow_cmd {
fw_hello_cmd_stage_os = 0x0
};
struct fw_hello_cmd { struct fw_hello_cmd {
__be32 op_to_write; __be32 op_to_write;
__be32 retval_len16; __be32 retval_len16;
...@@ -315,8 +330,14 @@ struct fw_hello_cmd { ...@@ -315,8 +330,14 @@ struct fw_hello_cmd {
#define FW_HELLO_CMD_INIT (1U << 30) #define FW_HELLO_CMD_INIT (1U << 30)
#define FW_HELLO_CMD_MASTERDIS(x) ((x) << 29) #define FW_HELLO_CMD_MASTERDIS(x) ((x) << 29)
#define FW_HELLO_CMD_MASTERFORCE(x) ((x) << 28) #define FW_HELLO_CMD_MASTERFORCE(x) ((x) << 28)
#define FW_HELLO_CMD_MBMASTER(x) ((x) << 24) #define FW_HELLO_CMD_MBMASTER_MASK 0xfU
#define FW_HELLO_CMD_MBMASTER_SHIFT 24
#define FW_HELLO_CMD_MBMASTER(x) ((x) << FW_HELLO_CMD_MBMASTER_SHIFT)
#define FW_HELLO_CMD_MBMASTER_GET(x) \
(((x) >> FW_HELLO_CMD_MBMASTER_SHIFT) & FW_HELLO_CMD_MBMASTER_MASK)
#define FW_HELLO_CMD_MBASYNCNOT(x) ((x) << 20) #define FW_HELLO_CMD_MBASYNCNOT(x) ((x) << 20)
#define FW_HELLO_CMD_STAGE(x) ((x) << 17)
#define FW_HELLO_CMD_CLEARINIT (1U << 16)
__be32 fwrev; __be32 fwrev;
}; };
...@@ -1654,18 +1675,4 @@ struct fw_hdr { ...@@ -1654,18 +1675,4 @@ struct fw_hdr {
#define FW_HDR_FW_VER_MICRO_GET(x) (((x) >> 8) & 0xff) #define FW_HDR_FW_VER_MICRO_GET(x) (((x) >> 8) & 0xff)
#define FW_HDR_FW_VER_BUILD_GET(x) (((x) >> 0) & 0xff) #define FW_HDR_FW_VER_BUILD_GET(x) (((x) >> 0) & 0xff)
#define S_FW_CMD_OP 24
#define V_FW_CMD_OP(x) ((x) << S_FW_CMD_OP)
#define S_FW_CMD_REQUEST 23
#define V_FW_CMD_REQUEST(x) ((x) << S_FW_CMD_REQUEST)
#define F_FW_CMD_REQUEST V_FW_CMD_REQUEST(1U)
#define S_FW_CMD_WRITE 21
#define V_FW_CMD_WRITE(x) ((x) << S_FW_CMD_WRITE)
#define F_FW_CMD_WRITE V_FW_CMD_WRITE(1U)
#define S_FW_LDST_CMD_ADDRSPACE 0
#define V_FW_LDST_CMD_ADDRSPACE(x) ((x) << S_FW_LDST_CMD_ADDRSPACE)
#endif /* _T4FW_INTERFACE_H_ */ #endif /* _T4FW_INTERFACE_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment