/* Reset ENABLE to 0 so reads of PCIE_CFG_SPACE_DATA won't cause a *ConfigurationSpaceread.(Noneoftheotherfieldsmatterwhen *ENABLEis0soasimpleregisterwriteiseasierthana *read-modify-writeviat4_set_reg_field().)
*/
t4_write_reg(adap, PCIE_CFG_SPACE_REQ_A, 0);
}
if ((size & 15) || size > MBOX_LEN) return -EINVAL;
/* *Ifthedeviceisoff-line,asinEEH,commandswilltimeout. *Failthemearlysowedon'twastetimewaiting.
*/ if (adap->pdev->error_state != pci_channel_io_normal) return -EIO;
/* If we have a negative timeout, that implies that we can't sleep. */ if (timeout < 0) {
sleep_ok = false;
timeout = -timeout;
}
/* Queue ourselves onto the mailbox access list. When our entry is at *thefrontofthelist,wehaverightstoaccessthemailbox.Sowe *wait[forawhile]tillwe'reatthefront[orbailoutwithan *EBUSY]...
*/
spin_lock_bh(&adap->mbox_lock);
list_add_tail(&entry.list, &adap->mlist.list);
spin_unlock_bh(&adap->mbox_lock);
delay_idx = 0;
ms = delay[0];
for (i = 0; ; i += ms) { /* If we've waited too long, return a busy indication. This *reallyoughttobebasedonourinitialpositioninthe *mailboxaccesslistbutthisisastart.Weveryrarely *contendonaccesstothemailbox...
*/
pcie_fw = t4_read_reg(adap, PCIE_FW_A); if (i > FW_CMD_MAX_TIMEOUT || (pcie_fw & PCIE_FW_ERR_F)) {
spin_lock_bh(&adap->mbox_lock);
list_del(&entry.list);
spin_unlock_bh(&adap->mbox_lock);
ret = (pcie_fw & PCIE_FW_ERR_F) ? -ENXIO : -EBUSY;
t4_record_mbox(adap, cmd, size, access, ret); return ret;
}
/* If we're at the head, break out and start the mailbox *protocol.
*/ if (list_first_entry(&adap->mlist.list, struct mbox_list,
list) == &entry) break;
/* Delay for a bit before checking again ... */ if (sleep_ok) {
ms = delay[delay_idx]; /* last element may repeat */ if (delay_idx < ARRAY_SIZE(delay) - 1)
delay_idx++;
msleep(ms);
} else {
mdelay(ms);
}
}
/* Loop trying to get ownership of the mailbox. Return an error *ifwecan'tgainownership.
*/
v = MBOWNER_G(t4_read_reg(adap, ctl_reg)); for (i = 0; v == MBOX_OWNER_NONE && i < 3; i++)
v = MBOWNER_G(t4_read_reg(adap, ctl_reg)); if (v != MBOX_OWNER_DRV) {
spin_lock_bh(&adap->mbox_lock);
list_del(&entry.list);
spin_unlock_bh(&adap->mbox_lock);
ret = (v == MBOX_OWNER_FW) ? -EBUSY : -ETIMEDOUT;
t4_record_mbox(adap, cmd, size, access, ret); return ret;
}
/* Copy in the new mailbox command and send it on its way ... */
t4_record_mbox(adap, cmd, size, access, 0); for (i = 0; i < size; i += 8)
t4_write_reg64(adap, data_reg + i, be64_to_cpu(*p++));
for (i = 0;
!((pcie_fw = t4_read_reg(adap, PCIE_FW_A)) & PCIE_FW_ERR_F) &&
i < timeout;
i += ms) { if (sleep_ok) {
ms = delay[delay_idx]; /* last element may repeat */ if (delay_idx < ARRAY_SIZE(delay) - 1)
delay_idx++;
msleep(ms);
} else
mdelay(ms);
v = t4_read_reg(adap, ctl_reg); if (MBOWNER_G(v) == MBOX_OWNER_DRV) { if (!(v & MBMSGVALID_F)) {
t4_write_reg(adap, ctl_reg, 0); continue;
}
get_mbox_rpl(adap, cmd_rpl, MBOX_LEN / 8, data_reg);
res = be64_to_cpu(cmd_rpl[0]);
if (FW_CMD_OP_G(res >> 32) == FW_DEBUG_CMD) {
fw_asrt(adap, data_reg);
res = FW_CMD_RETVAL_V(EIO);
} elseif (rpl) {
memcpy(rpl, cmd_rpl, size);
}
/** *t4_memory_rw_init-Getmemorywindowrelativeoffset,base,andsize. *@adap:theadapter *@win:PCI-EMemoryWindowtouse *@mtype:memorytype:MEM_EDC0,MEM_EDC1,MEM_HMAorMEM_MC *@mem_off:memoryrelativeoffsetwithrespectto@mtype. *@mem_base:configuredmemorybaseaddress. *@mem_aperture:configuredmemorywindowaperture. * *Gettheconfiguredmemorywindow'srelativeoffset,base,andsize.
*/ int t4_memory_rw_init(struct adapter *adap, int win, int mtype, u32 *mem_off,
u32 *mem_base, u32 *mem_aperture)
{
u32 edc_size, mc_size, mem_reg;
/* Offset into the region of memory which is being accessed *MEM_EDC0=0 *MEM_EDC1=1 *MEM_MC=2--MEM_MCforchipswithonly1memorycontroller *MEM_MC1=3--forchipswith2memorycontrollers(e.g.T5) *MEM_HMA=4
*/
edc_size = EDRAM0_SIZE_G(t4_read_reg(adap, MA_EDRAM0_BAR_A)); if (mtype == MEM_HMA) {
*mem_off = 2 * (edc_size * 1024 * 1024);
} elseif (mtype != MEM_MC1) {
*mem_off = (mtype * (edc_size * 1024 * 1024));
} else {
mc_size = EXT_MEM0_SIZE_G(t4_read_reg(adap,
MA_EXT_MEMORY0_BAR_A));
*mem_off = (MEM_MC0 * edc_size + mc_size) * 1024 * 1024;
}
/* Each PCI-E Memory Window is programmed with a window size -- or *"aperture"--whichcontrolsthegranularityofitsmappingonto *adaptermemory.Weneedtograbthatapertureinordertoknow *howtousethespecifiedwindow.Thewindowisalsoprogrammed *withthebaseaddressoftheMemoryWindowinBAR0'saddress *space.ForT4thisisanabsolutePCI-EBusAddress.ForT5 *theaddressisrelativetoBAR0.
*/
mem_reg = t4_read_reg(adap,
PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A,
win)); /* a dead adapter will return 0xffffffff for PIO reads */ if (mem_reg == 0xffffffff) return -ENXIO;
/* It's convenient to be able to handle lengths which aren't a *multipleof32-bitsbecauseweoftenenduptransferringfilesto *thefirmware.Sowe'llhandlethatbynormalizingthelengthhere *andthenhandlinganyresidualtransferattheend.
*/
resid = len & 0x3;
len -= resid;
ret = t4_memory_rw_init(adap, win, mtype, &memoffset, &mem_base,
&mem_aperture); if (ret) return ret;
/* Determine the PCIE_MEM_ACCESS_OFFSET */
addr = addr + memoffset;
/* Calculate our initial PCI-E Memory Window Position and Offset into *thatWindow.
*/
pos = addr & ~(mem_aperture - 1);
offset = addr - pos;
/* Set up initial PCI-E Memory Window to cover the start of our *transfer.
*/
t4_memory_update_win(adap, win, pos | win_pf);
/* Transfer data to/from the adapter as long as there's an integral *numberof32-bittransferstocomplete. * *AnoteonEndiannessissues: * *The"register"readsandwritesbelowfrom/tothePCI-EMemory *WindowinvokethestandardadapterBig-EndiantoPCI-ELink *Little-Endian"swizzel."Asaresult,ifwehavethefollowing *datainadaptermemory: * *Memory:...|b0|b1|b2|b3|... *Address:i+0i+1i+2i+3 * *ThenareadoftheadaptermemoryviathePCI-EMemoryWindow *willyield: * *x=readl(i) *310 *[b3|b2|b1|b0] * *IfthisvalueisstoredintolocalmemoryonaLittle-Endiansystem *itwillshowupcorrectlyinlocalmemoryas: * *(...,b0,b1,b2,b3,...) * *ButonaBig-Endiansystem,thestorewillshowupinmemory *incorrectlyswizzledas: * *(...,b3,b2,b1,b0,...) * *Soweneedtoaccountforthisinthereadsandwritestothe *PCI-EMemoryWindowbelowbyundoingtheregisterread/write *swizzels.
*/ while (len > 0) { if (dir == T4_MEMORY_READ)
*buf++ = le32_to_cpu((__force __le32)t4_read_reg(adap,
mem_base + offset)); else
t4_write_reg(adap, mem_base + offset,
(__force u32)cpu_to_le32(*buf++));
offset += sizeof(__be32);
len -= sizeof(__be32);
/* If we've reached the end of our current window aperture, *movethePCI-EMemoryWindowontothenext.Notethat *doingthishereafter"len"maybe0allowsustosetup *thePCI-EMemoryWindowforapossiblefinalresidual *transferbelow...
*/ if (offset == mem_aperture) {
pos += mem_aperture;
offset = 0;
t4_memory_update_win(adap, win, pos | win_pf);
}
}
/* If the original transfer had a length which wasn't a multiple of *32-bits,now'swhereweneedtofinishoffthetransferofthe *residualamount.ThePCI-EMemoryWindowhasalreadybeenmoved *above(ifnecessary)tocoverthisfinaltransfer.
*/ if (resid)
t4_memory_rw_residual(adap, resid, mem_base + offset,
(u8 *)buf, dir);
return0;
}
/* Return the specified PCI-E Configuration Space register from our Physical *Function.WetryfirstviaaFirmwareLDSTCommandsinceweprefertolet *thefirmwareownalloftheseregisters,butifthatfailswegoforit *directlyourselves.
*/
u32 t4_read_pcie_cfg4(struct adapter *adap, int reg)
{
u32 val, ldst_addrspace;
/* If fw_attach != 0, construct and send the Firmware LDST Command to *retrievethespecifiedPCI-EConfigurationSpaceregister.
*/ struct fw_ldst_cmd ldst_cmd; int ret;
/* If the LDST Command succeeds, return the result, otherwise *fallthroughtoreadingitdirectlyourselves...
*/
ret = t4_wr_mbox(adap, adap->mbox, &ldst_cmd, sizeof(ldst_cmd),
&ldst_cmd); if (ret == 0)
val = be32_to_cpu(ldst_cmd.u.pcie.data[0]); else /* Read the desired Configuration Space register via the PCI-E *Backdoormechanism.
*/
t4_hw_pci_read_cfg4(adap, reg, &val); return val;
}
/* Get the window based on base passed to it. *Windowapertureiscurrentlyunhandled,butthereisnousecaseforit *rightnow
*/ static u32 t4_get_window(struct adapter *adap, u32 pci_base, u64 pci_mask,
u32 memwin_base)
{
u32 ret;
if (is_t4(adap->params.chip)) {
u32 bar0;
/* Truncation intentional: we only read the bottom 32-bits of *the64-bitBAR0/BAR1...Weusethehardwarebackdoor *mechanismtoreadBAR0insteadofusing *pci_resource_start()becausewecouldbeoperatingfrom *withinaVirtualMachinewhichistrappingouraccessesto *ourConfigurationSpaceandweneedtosetupthePCI-E *MemoryWindowdecoderswiththeactualaddresseswhichwill *becomingacrossthePCI-Elink.
*/
bar0 = t4_read_pcie_cfg4(adap, pci_base);
bar0 &= pci_mask;
adap->t4_bar0 = bar0;
ret = bar0 + memwin_base;
} else { /* For T5, only relative offset inside the PCIe BAR is passed */
ret = memwin_base;
} return ret;
}
/* Get the default utility window (win0) used by everyone */
u32 t4_get_util_window(struct adapter *adap)
{ return t4_get_window(adap, PCI_BASE_ADDRESS_0,
PCI_BASE_ADDRESS_MEM_MASK, MEMWIN0_BASE);
}
/* Select the right set of register ranges to dump depending on the *adapterchiptype.
*/ switch (chip_version) { case CHELSIO_T4:
reg_ranges = t4_reg_ranges;
reg_ranges_size = ARRAY_SIZE(t4_reg_ranges); break;
case CHELSIO_T5:
reg_ranges = t5_reg_ranges;
reg_ranges_size = ARRAY_SIZE(t5_reg_ranges); break;
case CHELSIO_T6:
reg_ranges = t6_reg_ranges;
reg_ranges_size = ARRAY_SIZE(t6_reg_ranges); break;
default:
dev_err(adap->pdev_dev, "Unsupported chip version %d\n", chip_version); return;
}
/* Clear the register buffer and insert the appropriate register *valuesselectedbytheaboveregisterranges.
*/
memset(buf, 0, buf_size); for (range = 0; range < reg_ranges_size; range += 2) { unsignedint reg = reg_ranges[range]; unsignedint last_reg = reg_ranges[range + 1];
u32 *bufp = (u32 *)((char *)buf + reg);
/* Iterate across the register range filling in the register *bufferbutdon'twritepasttheendoftheregisterbuffer.
*/ while (reg <= last_reg && bufp < buf_end) {
*bufp++ = t4_read_reg(adap, reg);
reg += sizeof(u32);
}
}
}
/* Card information normally starts at VPD_BASE but early cards had *itat0.
*/
ret = pci_read_vpd(adapter->pdev, VPD_BASE, 1, &base_val); if (ret < 0) goto out;
/* Grab the raw VPD parameters.
*/
ret = t4_get_raw_vpd_params(adapter, p); if (ret) return ret;
/* Ask firmware for the Core Clock since it knows how to translate the *ReferenceClock('V2')VPDfieldintoaCoreClockvalue...
*/
cclk_param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_CCLK));
ret = t4_query_params(adapter, adapter->mbox, adapter->pf, 0, 1, &cclk_param, &cclk_val);
for (left = n; left; left -= c, data += c) {
c = min(left, 4U); for (val = 0, i = 0; i < c; ++i) { if (byte_oriented)
val = (val << 8) + data[i]; else
val = (val << 8) + data[c - i - 1];
}
ret = sf1_write(adapter, c, c != left, 1, val); if (ret) goto unlock;
}
ret = flash_wait_op(adapter, 8, 1); if (ret) goto unlock;
t4_write_reg(adapter, SF_OP_A, 0); /* unlock SF */
/* Read the page to verify the write succeeded */
ret = t4_read_flash(adapter, addr & ~0xff, ARRAY_SIZE(buf), buf,
byte_oriented); if (ret) return ret;
if (memcmp(data - n, (u8 *)buf + offset, n)) {
dev_err(adapter->pdev_dev, "failed to correctly write the flash page at %#x\n",
addr); return -EIO;
} return0;
/* Firmware Version */ if (!adapter->params.fw_vers)
dev_warn(adapter->pdev_dev, "No firmware loaded\n"); else
dev_info(adapter->pdev_dev, "Firmware version: %u.%u.%u.%u\n",
FW_HDR_FW_VER_MAJOR_G(adapter->params.fw_vers),
FW_HDR_FW_VER_MINOR_G(adapter->params.fw_vers),
FW_HDR_FW_VER_MICRO_G(adapter->params.fw_vers),
FW_HDR_FW_VER_BUILD_G(adapter->params.fw_vers));
/* Bootstrap Firmware Version. (Some adapters don't have Bootstrap *Firmware,sodev_info()ismoreappropriatehere.)
*/ if (!adapter->params.bs_vers)
dev_info(adapter->pdev_dev, "No bootstrap loaded\n"); else
dev_info(adapter->pdev_dev, "Bootstrap version: %u.%u.%u.%u\n",
FW_HDR_FW_VER_MAJOR_G(adapter->params.bs_vers),
FW_HDR_FW_VER_MINOR_G(adapter->params.bs_vers),
FW_HDR_FW_VER_MICRO_G(adapter->params.bs_vers),
FW_HDR_FW_VER_BUILD_G(adapter->params.bs_vers));
/* TP Microcode Version */ if (!adapter->params.tp_vers)
dev_warn(adapter->pdev_dev, "No TP Microcode loaded\n"); else
dev_info(adapter->pdev_dev, "TP Microcode version: %u.%u.%u.%u\n",
FW_HDR_FW_VER_MAJOR_G(adapter->params.tp_vers),
FW_HDR_FW_VER_MINOR_G(adapter->params.tp_vers),
FW_HDR_FW_VER_MICRO_G(adapter->params.tp_vers),
FW_HDR_FW_VER_BUILD_G(adapter->params.tp_vers));
/* Expansion ROM version */ if (!adapter->params.er_vers)
dev_info(adapter->pdev_dev, "No Expansion ROM loaded\n"); else
dev_info(adapter->pdev_dev, "Expansion ROM version: %u.%u.%u.%u\n",
FW_HDR_FW_VER_MAJOR_G(adapter->params.er_vers),
FW_HDR_FW_VER_MINOR_G(adapter->params.er_vers),
FW_HDR_FW_VER_MICRO_G(adapter->params.er_vers),
FW_HDR_FW_VER_BUILD_G(adapter->params.er_vers));
/* Serial Configuration version */
dev_info(adapter->pdev_dev, "Serial Configuration version: %#x\n",
adapter->params.scfg_vers);
/* VPD Version */
dev_info(adapter->pdev_dev, "VPD version: %#x\n",
adapter->params.vpd_vers);
}
/** *t4_check_fw_version-checkiftheFWissupportedwiththisdriver *@adap:theadapter * *Checksifanadapter'sFWiscompatiblewiththedriver.Returns0 *ifthere'sexactmatch,anegativeerroriftheversioncouldnotbe *readorthere'samajorversionmismatch
*/ int t4_check_fw_version(struct adapter *adap)
{ int i, ret, major, minor, micro; int exp_major, exp_minor, exp_micro; unsignedint chip_version = CHELSIO_CHIP_VERSION(adap->params.chip);
ret = t4_get_fw_version(adap, &adap->params.fw_vers); /* Try multiple times before returning error */ for (i = 0; (ret == -EBUSY || ret == -EAGAIN) && i < 3; i++)
ret = t4_get_fw_version(adap, &adap->params.fw_vers);
if (ret) return ret;
major = FW_HDR_FW_VER_MAJOR_G(adap->params.fw_vers);
minor = FW_HDR_FW_VER_MINOR_G(adap->params.fw_vers);
micro = FW_HDR_FW_VER_MICRO_G(adap->params.fw_vers);
if (major < exp_major || (major == exp_major && minor < exp_minor) ||
(major == exp_major && minor == exp_minor && micro < exp_micro)) {
dev_err(adap->pdev_dev, "Card has firmware version %u.%u.%u, minimum " "supported firmware is %u.%u.%u.\n", major, minor,
micro, exp_major, exp_minor, exp_micro); return -EFAULT;
} return0;
}
/* Is the given firmware API compatible with the one the driver was compiled *with?
*/ staticint fw_compatible(conststruct fw_hdr *hdr1, conststruct fw_hdr *hdr2)
{
/* short circuit if it's the exact same firmware version */ if (hdr1->chip == hdr2->chip && hdr1->fw_ver == hdr2->fw_ver) return1;
/* The firmware in the filesystem is usable, but should it be installed? *Thisroutineexplainsitselfindetailifitindicatesthefilesystem *firmwareshouldbeinstalled.
*/ staticint should_install_fs_fw(struct adapter *adap, int card_fw_usable, int k, int c)
{ constchar *reason;
if (!card_fw_usable) {
reason = "incompatible or unusable"; goto install;
}
if (k > c) {
reason = "older than the version supported with this driver"; goto install;
}
return0;
install:
dev_err(adap->pdev_dev, "firmware on card (%u.%u.%u.%u) is %s, " "installing firmware %u.%u.%u.%u on card.\n",
FW_HDR_FW_VER_MAJOR_G(c), FW_HDR_FW_VER_MINOR_G(c),
FW_HDR_FW_VER_MICRO_G(c), FW_HDR_FW_VER_BUILD_G(c), reason,
FW_HDR_FW_VER_MAJOR_G(k), FW_HDR_FW_VER_MINOR_G(k),
FW_HDR_FW_VER_MICRO_G(k), FW_HDR_FW_VER_BUILD_G(k));
if (card_fw_usable && card_fw->fw_ver == drv_fw->fw_ver &&
(!fs_fw_usable || fs_fw->fw_ver == drv_fw->fw_ver)) { /* Common case: the firmware on the card is an exact match and *thefilesystemoneisanexactmatchtoo,orthefilesystem *oneisabsent/incompatible.
*/
} elseif (fs_fw_usable && state == DEV_STATE_UNINIT &&
should_install_fs_fw(adap, card_fw_usable,
be32_to_cpu(fs_fw->fw_ver),
be32_to_cpu(card_fw->fw_ver))) {
ret = t4_fw_upgrade(adap, adap->mbox, fw_data,
fw_size, 0); if (ret != 0) {
dev_err(adap->pdev_dev, "failed to install firmware: %d\n", ret); goto bye;
}
/* Installed successfully, update the cached header too. */
*card_fw = *fs_fw;
card_fw_usable = 1;
*reset = 0; /* already reset as part of load_fw */
}
if (!card_fw_usable) {
uint32_t d, c, k;
d = be32_to_cpu(drv_fw->fw_ver);
c = be32_to_cpu(card_fw->fw_ver);
k = fs_fw ? be32_to_cpu(fs_fw->fw_ver) : 0;
dev_err(adap->pdev_dev, "Cannot find a usable firmware: " "chip state %d, " "driver compiled with %d.%d.%d.%d, " "card has %d.%d.%d.%d, filesystem has %d.%d.%d.%d\n",
state,
FW_HDR_FW_VER_MAJOR_G(d), FW_HDR_FW_VER_MINOR_G(d),
FW_HDR_FW_VER_MICRO_G(d), FW_HDR_FW_VER_BUILD_G(d),
FW_HDR_FW_VER_MAJOR_G(c), FW_HDR_FW_VER_MINOR_G(c),
FW_HDR_FW_VER_MICRO_G(c), FW_HDR_FW_VER_BUILD_G(c),
FW_HDR_FW_VER_MAJOR_G(k), FW_HDR_FW_VER_MINOR_G(k),
FW_HDR_FW_VER_MICRO_G(k), FW_HDR_FW_VER_BUILD_G(k));
ret = -EINVAL; goto bye;
}
/* We're using whatever's on the card and it's known to be good. */
adap->params.fw_vers = be32_to_cpu(card_fw->fw_ver);
adap->params.tp_vers = be32_to_cpu(card_fw->tp_microcode_ver);
bye: return ret;
}
/** *t4_flash_erase_sectors-erasearangeofflashsectors *@adapter:theadapter *@start:thefirstsectortoerase *@end:thelastsectortoerase * *Erasesthesectorsinthegiveninclusiverange.
*/ staticint t4_flash_erase_sectors(struct adapter *adapter, int start, int end)
{ int ret = 0;
if (end >= adapter->params.sf_nsec) return -EINVAL;
i = DIV_ROUND_UP(size, sf_sec_size); /* # of sectors spanned */
ret = t4_flash_erase_sectors(adap, fw_start_sec, fw_start_sec + i - 1); if (ret) goto out;
/* If we have version number support, then check to see if the adapter *alreadyhasup-to-datePHYfirmwareloaded.
*/ if (phy_fw_version) {
new_phy_fw_vers = phy_fw_version(phy_fw_data, phy_fw_size);
ret = t4_phy_fw_ver(adap, &cur_phy_fw_ver); if (ret < 0) return ret;
/* Ask the firmware where it wants us to copy the PHY firmware image. *ThesizeofthefilerequiresaspecialversionoftheREADcommand *whichwillpassthefilesizeviathevaluesfieldinPARAMS_CMDand *retrievethereturnvaluefromfirmwareandplaceitinthesame *buffervalues
*/
param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_PHYFW) |
FW_PARAMS_PARAM_Y_V(adap->params.portvec) |
FW_PARAMS_PARAM_Z_V(FW_PARAMS_PARAM_DEV_PHYFW_DOWNLOAD));
val = phy_fw_size;
ret = t4_query_params_rw(adap, adap->mbox, adap->pf, 0, 1,
¶m, &val, 1, true); if (ret < 0) return ret;
mtype = val >> 8;
maddr = (val & 0xff) << 16;
/* Copy the supplied PHY Firmware image to the adapter memory location *allocatedbytheadapterfirmware.
*/
spin_lock_bh(&adap->win0_lock);
ret = t4_memory_rw(adap, win, mtype, maddr,
phy_fw_size, (__be32 *)phy_fw_data,
T4_MEMORY_WRITE);
spin_unlock_bh(&adap->win0_lock); if (ret) return ret;
/* Tell the firmware that the PHY firmware image has been written to *RAManditcannowstartcopyingitovertothePHYs.Thechip *firmwarewillRESETtheaffectedPHYsaspartofthisoperation *leavingthemrunningthenewPHYfirmwareimage.
*/
param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_PHYFW) |
FW_PARAMS_PARAM_Y_V(adap->params.portvec) |
FW_PARAMS_PARAM_Z_V(FW_PARAMS_PARAM_DEV_PHYFW_DOWNLOAD));
ret = t4_set_params_timeout(adap, adap->mbox, adap->pf, 0, 1,
¶m, &val, 30000); if (ret) return ret;
/* If we have version number support, then check to see that the new *firmwaregotloadedproperly.
*/ if (phy_fw_version) {
ret = t4_phy_fw_ver(adap, &cur_phy_fw_ver); if (ret < 0) return ret;
if (cur_phy_fw_ver != new_phy_fw_vers) {
CH_WARN(adap, "PHY Firmware did not update: " "version on adapter %#x, " "version flashed %#x\n",
cur_phy_fw_ver, new_phy_fw_vers); return -ENXIO;
}
}
/* The ADVERT_MASK is used to mask out all of the Advertised Firmware Port *Capabilitieswhichwecontrolwithseparatecontrols--see,forinstance, *PauseFramesandForwardErrorCorrection.Inordertodeterminewhatthe *fullsetofAdvertisedPortCapabilitiesare,thebaseAdvertisedPort *Capabilities(maskedbyADVERT_MASK)mustbecombinedwiththeAdvertised *PortCapabilitiesassociatedwiththoseothercontrols.See *t4_link_acaps()forhowthisisdone.
*/ #define ADVERT_MASK (FW_PORT_CAP32_SPEED_V(FW_PORT_CAP32_SPEED_M) | \
FW_PORT_CAP32_ANEG)
/* Some Requested Port Capabilities are trivially wrong if they exceed *thePhysicalPortCapabilities.Wecancheckthathereandprovide *moderatelyusefulfeedbackinthesystemlog. * *NotethatolderFirmwaredoesn'thaveFW_PORT_CAP32_FORCE_PAUSE,so *weneedtoexcludethisfromthischeckinordertomaintain *compatibility...
*/ if ((acaps & ~lc->pcaps) & ~FW_PORT_CAP32_FORCE_PAUSE) {
dev_err(adapter->pdev_dev, "Requested Port Capabilities %#x exceed Physical Port Capabilities %#x\n",
acaps, lc->pcaps); return -EINVAL;
}
/* Compute our Requested Port Capabilities and send that on to the *Firmware.
*/
rcap = t4_link_acaps(adapter, port, lc);
memset(&cmd, 0, sizeof(cmd));
cmd.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PORT_CMD) |
FW_CMD_REQUEST_F | FW_CMD_EXEC_F |
FW_PORT_CMD_PORTID_V(port));
cmd.action_to_len16 =
cpu_to_be32(FW_PORT_CMD_ACTION_V(fw_caps == FW_CAPS16
? FW_PORT_ACTION_L1_CFG
: FW_PORT_ACTION_L1_CFG32) |
FW_LEN16(cmd)); if (fw_caps == FW_CAPS16)
cmd.u.l1cfg.rcap = cpu_to_be32(fwcaps32_to_caps16(rcap)); else
cmd.u.l1cfg32.rcap32 = cpu_to_be32(rcap);
ret = t4_wr_mbox_meat_timeout(adapter, mbox, &cmd, sizeof(cmd), NULL,
sleep_ok, timeout);
/* Unfortunately, even if the Requested Port Capabilities "fit" within *thePhysicalPortCapabilities,somecombinationsoffeaturesmay *stillnotbelegal.Forexample,40Gb/sandReed-SolomonForward *ErrorCorrection.SoiftheFirmwarerejectstheL1Configure *request,flagthathere.
*/ if (ret) {
dev_err(adapter->pdev_dev, "Requested Port Capabilities %#x rejected, error %d\n",
rcap, -ret); return ret;
} return0;
}
struct intr_info { unsignedint mask; /* bits to check in interrupt status */ constchar *msg; /* message to print or NULL */ short stat_idx; /* stat counter to increment or -1 */ unsignedshort fatal; /* whether the condition reported is fatal */
int_handler_t int_handler; /* platform-specific int handler */
};
perr = t4_read_reg(adapter, SGE_INT_CAUSE1_A); if (perr) {
v |= perr;
dev_alert(adapter->pdev_dev, "SGE Cause1 Parity Error %#x\n",
perr);
}
perr = t4_read_reg(adapter, SGE_INT_CAUSE2_A); if (perr) {
v |= perr;
dev_alert(adapter->pdev_dev, "SGE Cause2 Parity Error %#x\n",
perr);
}
if (CHELSIO_CHIP_VERSION(adapter->params.chip) >= CHELSIO_T5) {
perr = t4_read_reg(adapter, SGE_INT_CAUSE5_A); /* Parity error (CRC) for err_T_RxCRC is trivial, ignore it */
perr &= ~ERR_T_RXCRC_F; if (perr) {
v |= perr;
dev_alert(adapter->pdev_dev, "SGE Cause5 Parity Error %#x\n", perr);
}
}
v |= t4_handle_intr_status(adapter, SGE_INT_CAUSE3_A, sge_intr_info); if (CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5)
v |= t4_handle_intr_status(adapter, SGE_INT_CAUSE3_A,
t4t5_sge_intr_info);
err = t4_read_reg(adapter, SGE_ERROR_STATS_A); if (err & ERROR_QID_VALID_F) {
dev_err(adapter->pdev_dev, "SGE error for queue %u\n",
ERROR_QID_G(err)); if (err & UNCAPTURED_ERROR_F)
dev_err(adapter->pdev_dev, "SGE UNCAPTURED_ERROR set (clearing)\n");
t4_write_reg(adapter, SGE_ERROR_STATS_A, ERROR_QID_VALID_F |
UNCAPTURED_ERROR_F);
}
fw_err = t4_read_reg(adapter, PCIE_FW_A); if (fw_err & PCIE_FW_ERR_F)
t4_report_fw_error(adapter);
/* When the Firmware detects an internal error which normally *wouldn'traiseaHostInterrupt,itforcesaCIMTimer0interrupt *inordertomakesuretheHostseestheFirmwareCrash.So *ifwehaveaTimer0interruptanddon'tseeaFirmwareCrash, *ignoretheTimer0interrupt.
*/
val = t4_read_reg(adapter, CIM_HOST_INT_CAUSE_A); if (val & TIMER0INT_F) if (!(fw_err & PCIE_FW_ERR_F) ||
(PCIE_FW_EVAL_G(fw_err) != PCIE_FW_EVAL_CRASH))
t4_write_reg(adapter, CIM_HOST_INT_CAUSE_A,
TIMER0INT_F);
/**
* t4_slow_intr_handler - control path interrupt handler
* @adapter: the adapter
*
* T4 interrupt handler for non-data global interrupt events, e.g., errors.
* The designation 'slow' is because it involves register reads, while
* data interrupts typically don't involve any MMIOs.
*/
int t4_slow_intr_handler(struct adapter *adapter)
{
/* There are rare cases where a PL_INT_CAUSE bit may end up getting
* set when the corresponding PL_INT_ENABLE bit isn't set. It's
* easiest just to mask that case here.
*/
u32 raw_cause = t4_read_reg(adapter, PL_INT_CAUSE_A);
u32 enable = t4_read_reg(adapter, PL_INT_ENABLE_A);
u32 cause = raw_cause & enable;
if (!(cause & GLBL_INTR_MASK))
return 0;
if (cause & CIM_F)
cim_intr_handler(adapter);
if (cause & MPS_F)
mps_intr_handler(adapter);
if (cause & NCSI_F)
ncsi_intr_handler(adapter);
if (cause & PL_F)
pl_intr_handler(adapter);
if (cause & SMB_F)
smb_intr_handler(adapter);
if (cause & XGMAC0_F)
xgmac_intr_handler(adapter, 0);
if (cause & XGMAC1_F)
xgmac_intr_handler(adapter, 1);
if (cause & XGMAC_KR0_F)
xgmac_intr_handler(adapter, 2);
if (cause & XGMAC_KR1_F)
xgmac_intr_handler(adapter, 3);
if (cause & PCIE_F)
pcie_intr_handler(adapter);
if (cause & MC_F)
mem_intr_handler(adapter, MEM_MC);
if (is_t5(adapter->params.chip) && (cause & MC1_F))
mem_intr_handler(adapter, MEM_MC1);
if (cause & EDC0_F)
mem_intr_handler(adapter, MEM_EDC0);
if (cause & EDC1_F)
mem_intr_handler(adapter, MEM_EDC1);
if (cause & LE_F)
le_intr_handler(adapter);
if (cause & TP_F)
tp_intr_handler(adapter);
if (cause & MA_F)
ma_intr_handler(adapter);
if (cause & PM_TX_F)
pmtx_intr_handler(adapter);
if (cause & PM_RX_F)
pmrx_intr_handler(adapter);
if (cause & ULP_RX_F)
ulprx_intr_handler(adapter);
if (cause & CPL_SWITCH_F)
cplsw_intr_handler(adapter);
if (cause & SGE_F)
sge_intr_handler(adapter);
if (cause & ULP_TX_F)
ulptx_intr_handler(adapter);
/* Clear the interrupts just processed for which we are the master. */
t4_write_reg(adapter, PL_INT_CAUSE_A, raw_cause & GLBL_INTR_MASK);
(void)t4_read_reg(adapter, PL_INT_CAUSE_A); /* flush */
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_enable(struct adapter *adapter)
{
u32 val = 0;
u32 whoami = t4_read_reg(adapter, PL_WHOAMI_A);
u32 pf = CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5 ?
SOURCEPF_G(whoami) : T6_SOURCEPF_G(whoami);
/**
* t4_intr_disable - disable interrupts
* @adapter: the adapter whose interrupts should be disabled
*
* Disable interrupts. We only disable the top-level interrupt
* concentrators. The caller must be a PCI function managing global
* interrupts.
*/
void t4_intr_disable(struct adapter *adapter)
{
u32 whoami, pf;
unsigned int t4_chip_rss_size(struct adapter *adap)
{
if (CHELSIO_CHIP_VERSION(adap->params.chip) <= CHELSIO_T5)
return RSS_NENTRIES;
else
return T6_RSS_NENTRIES;
}
/**
* t4_config_rss_range - configure a portion of the RSS mapping table
* @adapter: the adapter
* @mbox: mbox to use for the FW command
* @viid: virtual interface whose RSS subtable is to be written
* @start: start entry in the table to write
* @n: how many table entries to write
* @rspq: values for the response queue lookup table
* @nrspq: number of values in @rspq
*
* Programs the selected part of the VI's RSS mapping table with the
* provided values. If @nrspq < @n the supplied values are used repeatedly
* until the full table range is populated.
*
* The caller must ensure the values in @rspq are in the range allowed for
* @viid.
*/
int t4_config_rss_range(struct adapter *adapter, int mbox, unsigned int viid,
int start, int n, const u16 *rspq, unsigned int nrspq)
{
int ret;
const u16 *rsp = rspq;
const u16 *rsp_end = rspq + nrspq;
struct fw_rss_ind_tbl_cmd cmd;
v = FW_RSS_IND_TBL_CMD_IQ0_V(*rsp);
if (++rsp >= rsp_end)
rsp = rspq;
v |= FW_RSS_IND_TBL_CMD_IQ1_V(*rsp);
if (++rsp >= rsp_end)
rsp = rspq;
v |= FW_RSS_IND_TBL_CMD_IQ2_V(*rsp);
if (++rsp >= rsp_end)
rsp = rspq;
*qp++ = cpu_to_be32(v);
nq -= 3;
}
ret = t4_wr_mbox(adapter, mbox, &cmd, sizeof(cmd), NULL);
if (ret)
return ret;
}
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 t4_config_glbl_rss(struct adapter *adapter, int mbox, unsigned int mode,
unsigned int flags)
{
struct fw_rss_glb_config_cmd c;
/**
* t4_config_vi_rss - configure per VI RSS settings
* @adapter: the adapter
* @mbox: mbox to use for the FW command
* @viid: the VI id
* @flags: RSS flags
* @defq: id of the default RSS queue for the VI.
*
* Configures VI-specific RSS properties.
*/
int t4_config_vi_rss(struct adapter *adapter, int mbox, unsigned int viid,
unsigned int flags, unsigned int defq)
{
struct fw_rss_vi_config_cmd c;
/**
* t4_read_rss - read the contents of the RSS mapping table
* @adapter: the adapter
* @map: holds the contents of the RSS mapping table
*
* Reads the contents of the RSS hash->queue mapping table.
*/
int t4_read_rss(struct adapter *adapter, u16 *map)
{
int i, ret, nentries;
u32 val;
nentries = t4_chip_rss_size(adapter);
for (i = 0; i < nentries / 2; ++i) {
ret = rd_rss_row(adapter, i, &val);
if (ret)
return ret;
*map++ = LKPTBLQUEUE0_G(val);
*map++ = LKPTBLQUEUE1_G(val);
}
return 0;
}
/**
* t4_tp_fw_ldst_rw - Access TP indirect register through LDST
* @adap: the adapter
* @cmd: TP fw ldst address space type
* @vals: where the indirect register values are stored/written
* @nregs: how many indirect registers to read/write
* @start_index: index of first indirect register to read/write
* @rw: Read (1) or Write (0)
* @sleep_ok: if true we may sleep while awaiting command completion
*
* Access TP indirect registers through LDST
*/
static int t4_tp_fw_ldst_rw(struct adapter *adap, int cmd, u32 *vals,
unsigned int nregs, unsigned int start_index,
unsigned int rw, bool sleep_ok)
{
int ret = 0;
unsigned int i;
struct fw_ldst_cmd c;
for (i = 0; i < nregs; i++) {
memset(&c, 0, sizeof(c));
c.op_to_addrspace = cpu_to_be32(FW_CMD_OP_V(FW_LDST_CMD) |
FW_CMD_REQUEST_F |
(rw ? FW_CMD_READ_F :
FW_CMD_WRITE_F) |
FW_LDST_CMD_ADDRSPACE_V(cmd));
c.cycles_to_len16 = cpu_to_be32(FW_LEN16(c));
if (rw)
vals[i] = be32_to_cpu(c.u.addrval.val);
}
return 0;
}
/**
* t4_tp_indirect_rw - Read/Write TP indirect register through LDST or backdoor
* @adap: the adapter
* @reg_addr: Address Register
* @reg_data: Data register
* @buff: where the indirect register values are stored/written
* @nregs: how many indirect registers to read/write
* @start_index: index of first indirect register to read/write
* @rw: READ(1) or WRITE(0)
* @sleep_ok: if true we may sleep while awaiting command completion
*
* Read/Write TP indirect registers through LDST if possible.
* Else, use backdoor access
**/
static void t4_tp_indirect_rw(struct adapter *adap, u32 reg_addr, u32 reg_data,
u32 *buff, u32 nregs, u32 start_index, int rw,
bool sleep_ok)
{
int rc = -EINVAL;
int cmd;
switch (reg_addr) {
case TP_PIO_ADDR_A:
cmd = FW_LDST_ADDRSPC_TP_PIO;
break;
case TP_TM_PIO_ADDR_A:
cmd = FW_LDST_ADDRSPC_TP_TM_PIO;
break;
case TP_MIB_INDEX_A:
cmd = FW_LDST_ADDRSPC_TP_MIB;
break;
default:
goto indirect_access;
}
if (rc) {
if (rw)
t4_read_indirect(adap, reg_addr, reg_data, buff, nregs,
start_index);
else
t4_write_indirect(adap, reg_addr, reg_data, buff, nregs,
start_index);
}
}
/**
* t4_tp_pio_read - Read TP PIO registers
* @adap: the adapter
* @buff: where the indirect register values are written
* @nregs: how many indirect registers to read
* @start_index: index of first indirect register to read
* @sleep_ok: if true we may sleep while awaiting command completion
*
* Read TP PIO Registers
**/
void t4_tp_pio_read(struct adapter *adap, u32 *buff, u32 nregs,
u32 start_index, bool sleep_ok)
{
t4_tp_indirect_rw(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, buff, nregs,
start_index, 1, sleep_ok);
}
/**
* t4_tp_pio_write - Write TP PIO registers
* @adap: the adapter
* @buff: where the indirect register values are stored
* @nregs: how many indirect registers to write
* @start_index: index of first indirect register to write
* @sleep_ok: if true we may sleep while awaiting command completion
*
* Write TP PIO Registers
**/
static void t4_tp_pio_write(struct adapter *adap, u32 *buff, u32 nregs,
u32 start_index, bool sleep_ok)
{
t4_tp_indirect_rw(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, buff, nregs,
start_index, 0, sleep_ok);
}
/**
* t4_tp_tm_pio_read - Read TP TM PIO registers
* @adap: the adapter
* @buff: where the indirect register values are written
* @nregs: how many indirect registers to read
* @start_index: index of first indirect register to read
* @sleep_ok: if true we may sleep while awaiting command completion
*
* Read TP TM PIO Registers
**/
void t4_tp_tm_pio_read(struct adapter *adap, u32 *buff, u32 nregs,
u32 start_index, bool sleep_ok)
{
t4_tp_indirect_rw(adap, TP_TM_PIO_ADDR_A, TP_TM_PIO_DATA_A, buff,
nregs, start_index, 1, sleep_ok);
}
/**
* t4_tp_mib_read - Read TP MIB registers
* @adap: the adapter
* @buff: where the indirect register values are written
* @nregs: how many indirect registers to read
* @start_index: index of first indirect register to read
* @sleep_ok: if true we may sleep while awaiting command completion
*
* Read TP MIB Registers
**/
void t4_tp_mib_read(struct adapter *adap, u32 *buff, u32 nregs, u32 start_index,
bool sleep_ok)
{
t4_tp_indirect_rw(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, buff, nregs,
start_index, 1, sleep_ok);
}
/**
* t4_read_rss_key - read the global RSS key
* @adap: the adapter
* @key: 10-entry array holding the 320-bit RSS key
* @sleep_ok: if true we may sleep while awaiting command completion
*
* Reads the global 320-bit RSS key.
*/
void t4_read_rss_key(struct adapter *adap, u32 *key, bool sleep_ok)
{
t4_tp_pio_read(adap, key, 10, TP_RSS_SECRET_KEY0_A, sleep_ok);
}
/**
* t4_write_rss_key - program one of the RSS keys
* @adap: the adapter
* @key: 10-entry array holding the 320-bit RSS key
* @idx: which RSS key to write
* @sleep_ok: if true we may sleep while awaiting command completion
*
* Writes one of the RSS keys with the given 320-bit value. If @idx is
* 0..15 the corresponding entry in the RSS key table is written,
* otherwise the global RSS key is written.
*/
void t4_write_rss_key(struct adapter *adap, const u32 *key, int idx,
bool sleep_ok)
{
u8 rss_key_addr_cnt = 16;
u32 vrt = t4_read_reg(adap, TP_RSS_CONFIG_VRT_A);
/* T6 and later: for KeyMode 3 (per-vf and per-vf scramble),
* allows access to key addresses 16-63 by using KeyWrAddrX
* as index[5:4](upper 2) into key table
*/
if ((CHELSIO_CHIP_VERSION(adap->params.chip) > CHELSIO_T5) &&
(vrt & KEYEXTEND_F) && (KEYMODE_G(vrt) == 3))
rss_key_addr_cnt = 32;
/**
* t4_read_rss_pf_config - read PF RSS Configuration Table
* @adapter: the adapter
* @index: the entry in the PF RSS table to read
* @valp: where to store the returned value
* @sleep_ok: if true we may sleep while awaiting command completion
*
* Reads the PF RSS Configuration Table at the specified index and returns
* the value found there.
*/
void t4_read_rss_pf_config(struct adapter *adapter, unsigned int index,
u32 *valp, bool sleep_ok)
{
t4_tp_pio_read(adapter, valp, 1, TP_RSS_PF0_CONFIG_A + index, sleep_ok);
}
/**
* t4_read_rss_vf_config - read VF RSS Configuration Table
* @adapter: the adapter
* @index: the entry in the VF RSS table to read
* @vfl: where to store the returned VFL
* @vfh: where to store the returned VFH
* @sleep_ok: if true we may sleep while awaiting command completion
*
* Reads the VF RSS Configuration Table at the specified index and returns
* the (VFL, VFH) values found there.
*/
void t4_read_rss_vf_config(struct adapter *adapter, unsigned int index,
u32 *vfl, u32 *vfh, bool sleep_ok)
{
u32 vrt, mask, data;
if (CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5) {
mask = VFWRADDR_V(VFWRADDR_M);
data = VFWRADDR_V(index);
} else {
mask = T6_VFWRADDR_V(T6_VFWRADDR_M);
data = T6_VFWRADDR_V(index);
}
/* Request that the index'th VF Table values be read into VFL/VFH.
*/
vrt = t4_read_reg(adapter, TP_RSS_CONFIG_VRT_A);
vrt &= ~(VFRDRG_F | VFWREN_F | KEYWREN_F | mask);
vrt |= data | VFRDEN_F;
t4_write_reg(adapter, TP_RSS_CONFIG_VRT_A, vrt);
/**
* t4_tp_get_rdma_stats - read TP's RDMA MIB counters
* @adap: the adapter
* @st: holds the counter values
* @sleep_ok: if true we may sleep while awaiting command completion
*
* Returns the values of TP's RDMA counters.
*/
void t4_tp_get_rdma_stats(struct adapter *adap, struct tp_rdma_stats *st,
bool sleep_ok)
{
t4_tp_mib_read(adap, &st->rqe_dfr_pkt, 2, TP_MIB_RQE_DFR_PKT_A,
sleep_ok);
}
/**
* t4_get_fcoe_stats - read TP's FCoE MIB counters for a port
* @adap: the adapter
* @idx: the port index
* @st: holds the counter values
* @sleep_ok: if true we may sleep while awaiting command completion
*
* Returns the values of TP's FCoE counters for the selected port.
*/
void t4_get_fcoe_stats(struct adapter *adap, unsigned int idx,
struct tp_fcoe_stats *st, bool sleep_ok)
{
u32 val[2];
/**
* t4_read_mtu_tbl - returns the values in the HW path MTU table
* @adap: the adapter
* @mtus: where to store the MTU values
* @mtu_log: where to store the MTU base-2 log (may be %NULL)
*
* Reads the HW path MTU table.
*/
void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log)
{
u32 v;
int i;
for (i = 0; i < NMTUS; ++i) {
t4_write_reg(adap, TP_MTU_TABLE_A,
MTUINDEX_V(0xff) | MTUVALUE_V(i));
v = t4_read_reg(adap, TP_MTU_TABLE_A);
mtus[i] = MTUVALUE_G(v);
if (mtu_log)
mtu_log[i] = MTUWIDTH_G(v);
}
}
/**
* t4_read_cong_tbl - reads the congestion control table
* @adap: the adapter
* @incr: where to store the alpha values
*
* Reads the additive increments programmed into the HW congestion
* control table.
*/
void t4_read_cong_tbl(struct adapter *adap, u16 incr[NMTUS][NCCTRL_WIN])
{
unsigned int mtu, w;
for (mtu = 0; mtu < NMTUS; ++mtu)
for (w = 0; w < NCCTRL_WIN; ++w) {
t4_write_reg(adap, TP_CCTRL_TABLE_A,
ROWINDEX_V(0xffff) | (mtu << 5) | w);
incr[mtu][w] = (u16)t4_read_reg(adap,
TP_CCTRL_TABLE_A) & 0x1fff;
}
}
/**
* t4_tp_wr_bits_indirect - set/clear bits in an indirect TP register
* @adap: the adapter
* @addr: the indirect TP register address
* @mask: specifies the field within the register to modify
* @val: new value for the field
*
* Sets a field of an indirect TP register to the given value.
*/
void t4_tp_wr_bits_indirect(struct adapter *adap, unsigned int addr,
unsigned int mask, unsigned int val)
{
t4_write_reg(adap, TP_PIO_ADDR_A, addr);
val |= t4_read_reg(adap, TP_PIO_DATA_A) & ~mask;
t4_write_reg(adap, TP_PIO_DATA_A, val);
}
/* The minimum additive increment value for the congestion control table */
#define CC_MIN_INCR 2U
/**
* t4_load_mtus - write the MTU and congestion control HW tables
* @adap: the adapter
* @mtus: the values for the MTU table
* @alpha: the values for the congestion control alpha parameter
* @beta: the values for the congestion control beta parameter
*
* Write the HW MTU table with the supplied MTUs and the high-speed
* congestion control table with the supplied alpha, beta, and MTUs.
* We write the two tables together because the additive increments
* depend on the MTUs.
*/
void t4_load_mtus(struct adapter *adap, const unsigned short *mtus,
const unsigned short *alpha, const unsigned short *beta)
{
static const unsigned int avg_pkts[NCCTRL_WIN] = { 2, 6, 10, 14, 20, 28, 40, 56, 80, 112, 160, 224, 320, 448, 640, 896, 1281, 1792, 2560, 3584, 5120, 7168, 10240, 14336, 20480, 28672, 40960, 57344, 81920, 114688, 163840, 229376
};
unsigned int i, w;
for (i = 0; i < NMTUS; ++i) {
unsigned int mtu = mtus[i];
unsigned int log2 = fls(mtu);
t4_write_reg(adap, TP_CCTRL_TABLE_A, (i << 21) |
(w << 16) | (beta[w] << 13) | inc);
}
}
}
/* Calculates a rate in bytes/s given the number of 256-byte units per 4K core
* clocks. The formula is
*
* bytes/s = bytes256 * 256 * ClkFreq / 4096
*
* which is equivalent to
*
* bytes/s = 62.5 * bytes256 * ClkFreq_ms
*/
static u64 chan_rate(struct adapter *adap, unsigned int bytes256)
{
u64 v = bytes256 * adap->params.vpd.cclk;
return v * 62 + v / 2;
}
/**
* t4_get_chan_txrate - get the current per channel Tx rates
* @adap: the adapter
* @nic_rate: rates for NIC traffic
* @ofld_rate: rates for offloaded traffic
*
* Return the current Tx rates in bytes/s for NIC and offloaded traffic
* for each channel.
*/
void t4_get_chan_txrate(struct adapter *adap, u64 *nic_rate, u64 *ofld_rate)
{
u32 v;
/**
* t4_set_trace_filter - configure one of the tracing filters
* @adap: the adapter
* @tp: the desired trace filter parameters
* @idx: which filter to configure
* @enable: whether to enable or disable the filter
*
* Configures one of the tracing filters available in HW. If @enable is
* %0 @tp is not examined and may be %NULL. The user is responsible to
* set the single/multiple trace mode by writing to MPS_TRC_CFG_A register
*/
int t4_set_trace_filter(struct adapter *adap, const struct trace_params *tp,
int idx, int enable)
{
int i, ofst = idx * 4;
u32 data_reg, mask_reg, cfg;
cfg = t4_read_reg(adap, MPS_TRC_CFG_A);
if (cfg & TRCMULTIFILTER_F) {
/* If multiple tracers are enabled, then maximum
* capture size is 2.5KB (FIFO size of a single channel)
* minus 2 flits for CPL_TRACE_PKT header.
*/
if (tp->snap_len > ((10 * 1024 / 4) - (2 * 8)))
return -EINVAL;
} else {
/* If multiple tracers are disabled, to avoid deadlocks
* maximum packet capture size of 9600 bytes is recommended.
* Also in this mode, only trace0 can be enabled and running.
*/
if (tp->snap_len > 9600 || idx)
return -EINVAL;
}
/**
* t4_get_trace_filter - query one of the tracing filters
* @adap: the adapter
* @tp: the current trace filter parameters
* @idx: which trace filter to query
* @enabled: non-zero if the filter is enabled
*
* Returns the current settings of one of the HW tracing filters.
*/
void t4_get_trace_filter(struct adapter *adap, struct trace_params *tp, int idx,
int *enabled)
{
u32 ctla, ctlb;
int i, ofst = idx * 4;
u32 data_reg, mask_reg;
for (i = 0; i < TRACE_LEN / 4; i++, data_reg += 4, mask_reg += 4) {
tp->mask[i] = ~t4_read_reg(adap, mask_reg);
tp->data[i] = t4_read_reg(adap, data_reg) & tp->mask[i];
}
}
/**
* t4_pmtx_get_stats - returns the HW stats from PMTX
* @adap: the adapter
* @cnt: where to store the count statistics
* @cycles: where to store the cycle statistics
*
* Returns performance statistics from PMTX.
*/
void t4_pmtx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[])
{
int i;
u32 data[2];
for (i = 0; i < adap->params.arch.pm_stats_cnt; i++) {
t4_write_reg(adap, PM_TX_STAT_CONFIG_A, i + 1);
cnt[i] = t4_read_reg(adap, PM_TX_STAT_COUNT_A);
if (is_t4(adap->params.chip)) {
cycles[i] = t4_read_reg64(adap, PM_TX_STAT_LSB_A);
} else {
t4_read_indirect(adap, PM_TX_DBG_CTRL_A,
PM_TX_DBG_DATA_A, data, 2,
PM_TX_DBG_STAT_MSB_A);
cycles[i] = (((u64)data[0] << 32) | data[1]);
}
}
}
/**
* t4_pmrx_get_stats - returns the HW stats from PMRX
* @adap: the adapter
* @cnt: where to store the count statistics
* @cycles: where to store the cycle statistics
*
* Returns performance statistics from PMRX.
*/
void t4_pmrx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[])
{
int i;
u32 data[2];
for (i = 0; i < adap->params.arch.pm_stats_cnt; i++) {
t4_write_reg(adap, PM_RX_STAT_CONFIG_A, i + 1);
cnt[i] = t4_read_reg(adap, PM_RX_STAT_COUNT_A);
if (is_t4(adap->params.chip)) {
cycles[i] = t4_read_reg64(adap, PM_RX_STAT_LSB_A);
} else {
t4_read_indirect(adap, PM_RX_DBG_CTRL_A,
PM_RX_DBG_DATA_A, data, 2,
PM_RX_DBG_STAT_MSB_A);
cycles[i] = (((u64)data[0] << 32) | data[1]);
}
}
}
/**
* compute_mps_bg_map - compute the MPS Buffer Group Map for a Port
* @adapter: the adapter
* @pidx: the port index
*
* Computes and returns a bitmap indicating which MPS buffer groups are
* associated with the given Port. Bit i is set if buffer group i is
* used by the Port.
*/
static inline unsigned int compute_mps_bg_map(struct adapter *adapter,
int pidx)
{
unsigned int chip_version, nports;
switch (chip_version) {
case CHELSIO_T4:
case CHELSIO_T5:
switch (nports) {
case 1: return 0xf;
case 2: return 3 << (2 * pidx);
case 4: return 1 << pidx;
}
break;
case CHELSIO_T6:
switch (nports) {
case 2: return 1 << (2 * pidx);
}
break;
}
dev_err(adapter->pdev_dev, "Need MPS Buffer Group Map for Chip %0x, Nports %d\n",
chip_version, nports);
return 0;
}
/**
* t4_get_mps_bg_map - return the buffer groups associated with a port
* @adapter: the adapter
* @pidx: the port index
*
* Returns a bitmap indicating which MPS buffer groups are associated
* with the given Port. Bit i is set if buffer group i is used by the
* Port.
*/
unsigned int t4_get_mps_bg_map(struct adapter *adapter, int pidx)
{
u8 *mps_bg_map;
unsigned int nports;
nports = 1 << NUMPORTS_G(t4_read_reg(adapter, MPS_CMN_CTL_A));
if (pidx >= nports) {
CH_WARN(adapter, "MPS Port Index %d >= Nports %d\n",
pidx, nports);
return 0;
}
/* If we've already retrieved/computed this, just return the result.
*/
mps_bg_map = adapter->params.mps_bg_map;
if (mps_bg_map[pidx])
return mps_bg_map[pidx];
/* Newer Firmware can tell us what the MPS Buffer Group Map is.
* If we're talking to such Firmware, let it tell us. If the new
* API isn't supported, revert back to old hardcoded way. The value
* obtained from Firmware is encoded in below format:
*
* val = (( MPSBGMAP[Port 3] << 24 ) |
* ( MPSBGMAP[Port 2] << 16 ) |
* ( MPSBGMAP[Port 1] << 8 ) |
* ( MPSBGMAP[Port 0] << 0 ))
*/
if (adapter->flags & CXGB4_FW_OK) {
u32 param, val;
int ret;
param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_MPSBGMAP));
ret = t4_query_params_ns(adapter, adapter->mbox, adapter->pf, 0, 1, ¶m, &val);
if (!ret) {
int p;
/* Store the BG Map for all of the Ports in order to
* avoid more calls to the Firmware in the future.
*/
for (p = 0; p < MAX_NPORTS; p++, val >>= 8)
mps_bg_map[p] = val & 0xff;
return mps_bg_map[pidx];
}
}
/* Either we're not talking to the Firmware or we're dealing with
* older Firmware which doesn't support the new API to get the MPS
* Buffer Group Map. Fall back to computing it ourselves.
*/
mps_bg_map[pidx] = compute_mps_bg_map(adapter, pidx);
return mps_bg_map[pidx];
}
/**
* t4_get_tp_e2c_map - return the E2C channel map associated with a port
* @adapter: the adapter
* @pidx: the port index
*/
static unsigned int t4_get_tp_e2c_map(struct adapter *adapter, int pidx)
{
unsigned int nports;
u32 param, val = 0;
int ret;
nports = 1 << NUMPORTS_G(t4_read_reg(adapter, MPS_CMN_CTL_A));
if (pidx >= nports) {
CH_WARN(adapter, "TP E2C Channel Port Index %d >= Nports %d\n",
pidx, nports);
return 0;
}
/* FW version >= 1.16.44.0 can determine E2C channel map using
* FW_PARAMS_PARAM_DEV_TPCHMAP API.
*/
param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_TPCHMAP));
ret = t4_query_params_ns(adapter, adapter->mbox, adapter->pf, 0, 1, ¶m, &val);
if (!ret)
return (val >> (8 * pidx)) & 0xff;
return 0;
}
/**
* t4_get_tp_ch_map - return TP ingress channels associated with a port
* @adap: the adapter
* @pidx: the port index
*
* Returns a bitmap indicating which TP Ingress Channels are associated
* with a given Port. Bit i is set if TP Ingress Channel i is used by
* the Port.
*/
unsigned int t4_get_tp_ch_map(struct adapter *adap, int pidx)
{
unsigned int chip_version = CHELSIO_CHIP_VERSION(adap->params.chip);
unsigned int nports = 1 << NUMPORTS_G(t4_read_reg(adap, MPS_CMN_CTL_A));
if (pidx >= nports) {
dev_warn(adap->pdev_dev, "TP Port Index %d >= Nports %d\n",
pidx, nports);
return 0;
}
switch (chip_version) {
case CHELSIO_T4:
case CHELSIO_T5:
/* Note that this happens to be the same values as the MPS
* Buffer Group Map for these Chips. But we replicate the code
* here because they're really separate concepts.
*/
switch (nports) {
case 1: return 0xf;
case 2: return 3 << (2 * pidx);
case 4: return 1 << pidx;
}
break;
case CHELSIO_T6:
switch (nports) {
case 1:
case 2: return 1 << pidx;
}
break;
}
if (port_type < ARRAY_SIZE(port_type_description))
return port_type_description[port_type];
return "UNKNOWN";
}
/**
* t4_get_port_stats_offset - collect port stats relative to a previous
* snapshot
* @adap: The adapter
* @idx: The port
* @stats: Current stats to fill
* @offset: Previous stats snapshot
*/
void t4_get_port_stats_offset(struct adapter *adap, int idx,
struct port_stats *stats,
struct port_stats *offset)
{
u64 *s, *o;
int i;
t4_get_port_stats(adap, idx, stats);
for (i = 0, s = (u64 *)stats, o = (u64 *)offset;
i < (sizeof(struct port_stats) / sizeof(u64));
i++, s++, o++)
*s -= *o;
}
/**
* t4_get_port_stats - collect port statistics
* @adap: the adapter
* @idx: the port index
* @p: the stats structure to fill
*
* Collect statistics related to the given port from HW.
*/
void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p)
{
u32 bgmap = t4_get_mps_bg_map(adap, idx);
u32 stat_ctl = t4_read_reg(adap, MPS_STAT_CTL_A);
/**
* t4_get_lb_stats - collect loopback port statistics
* @adap: the adapter
* @idx: the loopback port index
* @p: the stats structure to fill
*
* Return HW statistics for the given loopback port.
*/
void t4_get_lb_stats(struct adapter *adap, int idx, struct lb_port_stats *p)
{
u32 bgmap = t4_get_mps_bg_map(adap, idx);
/* t4_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 t4_mk_filtdelwr(unsigned int ftid, struct fw_filter_wr *wr, int qid)
{
memset(wr, 0, sizeof(*wr));
wr->op_pkd = cpu_to_be32(FW_WR_OP_V(FW_FILTER_WR));
wr->len16_pkd = cpu_to_be32(FW_WR_LEN16_V(sizeof(*wr) / 16));
wr->tid_to_iq = cpu_to_be32(FW_FILTER_WR_TID_V(ftid) |
FW_FILTER_WR_NOREPLY_V(qid < 0));
wr->del_filter_to_l2tix = cpu_to_be32(FW_FILTER_WR_DEL_FILTER_F);
if (qid >= 0)
wr->rx_chan_rx_rpl_iq =
cpu_to_be16(FW_FILTER_WR_RX_RPL_IQ_V(qid));
}
/* Select the right set of decode strings to dump depending on the *adapterchiptype.
*/ switch (chip_version) { case CHELSIO_T4:
sge_idma_decode = (constchar **)t4_decode;
sge_idma_decode_nstates = ARRAY_SIZE(t4_decode); break;
case CHELSIO_T5:
sge_idma_decode = (constchar **)t5_decode;
sge_idma_decode_nstates = ARRAY_SIZE(t5_decode); break;
case CHELSIO_T6:
sge_idma_decode = (constchar **)t6_decode;
sge_idma_decode_nstates = ARRAY_SIZE(t6_decode); break;
default:
dev_err(adapter->pdev_dev, "Unsupported chip version %d\n", chip_version); return;
}
/* *Waitforthefirmwaretoeitherindicateanerroror *initializedstate.Ifweseeeitherofthesewebailout *andreporttheissuetothecaller.Ifweexhaustthe *"hellotimeout"java.lang.StringIndexOutOfBoundsException: Index 22 out of bounds for length 0
*/
( java.lang.StringIndexOutOfBoundsException: Index 12 out of bounds for length 12
u32 pcie_fw;
(50;
waiting -= 50;
/* (0 *bythefirmwarekeepwaitingtilldriverjava.lang.StringIndexOutOfBoundsException: Index 12 out of bounds for length 12 *timeout...andthenretryifwehaven'texhausted *ourretries...
*/
pcie_fw = t4_read_reg(adap, PCIE_FW_A); if (!(pcie_fw & (PCIE_FW_ERR_F|PCIE_FW_INIT_F))) { if (waiting <= 0) { if (retries-- > 0) goto retry;
/* Grab potentially new Firmware Device Log parameters so we can see *howhealthythenewFirmwareis.It'sokaytocontactthenew *Firmwarefortheseparameterseventhough,asfarasit's *concerned,we'veneversaid"HELLO"toit...
*/
(void)t4_init_devlog_params(adap);
out:
adap->flags |= CXGB4_FW_OK; return ret;
}
/* T4 uses a single control field to specify both the PCIe Padding and *PackingBoundary.T5introducedtheabilitytospecifythese *separately.TheactualIngressPacketDataalignmentboundary *withinPackedBufferModeisthemaximumofthesetwo *specifications.(Notethatitmakesnorealpracticalsenseto *havethePaddingBoundarybelargerthanthePackingBoundarybutyou *couldsetthechipupthatwayand,infact,legacyT4codewould *enddoingthisbecauseitwouldinitializethePaddingBoundaryand *leavethePackingBoundaryinitializedto0(16bytes).) *PaddingBoundaryvaluesinT6startsfrom8B, *whereasitis32BforT4andT5.
*/ if (CHELSIO_CHIP_VERSION(adap->params.chip) <= CHELSIO_T5)
ingpad_shift = INGPADBOUNDARY_SHIFT_X; else
ingpad_shift = T6_INGPADBOUNDARY_SHIFT_X;
/* T5 introduced the separation of the Free List Padding and *PackingBoundaries.Thus,wecanselectasmallerPadding *BoundarytoavoiduselesslychewingupPCIeLinkandMemory *Bandwidth,anduseaPackingBoundarywhichislargeenough *toavoidfalsesharingbetweenCPUs,etc. * *ForthePCILink,thesmallerthePaddingBoundarythe *better.FortheMemoryController,asmallerPadding *BoundaryisbetteruntilwecrossundertheMemoryLine *Size(theminimumunitoftransferto/fromMemory).Ifwe *haveaPaddingBoundarywhichissmallerthantheMemory *LineSize,that'llinvolveaRead-Modify-Writecycleonthe *MemoryControllerwhichisnevergood.
*/
/* We want the Packing Boundary to be based on the Cache Line *SizeinordertohelpavoidFalseSharingperformance *issuesbetweenCPUs,etc.WealsowantthePacking *BoundarytoincorporatethePCI-EMaximumPayloadSize.We *getbestperformancewhenthePackingBoundaryisa *multipleoftheMaximumPayloadSize.
*/
pack_align = fl_align; if (pci_is_pcie(adap->pdev)) { unsignedint mps, mps_log;
u16 devctl;
/* The PCIe Device Control Maximum Payload Size field *[bits7:5]encodessizesaspowersof2startingat *128bytes.
*/
pcie_capability_read_word(adap->pdev, PCI_EXP_DEVCTL,
&devctl);
mps_log = ((devctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5) + 7;
mps = 1 << mps_log; if (mps > pack_align)
pack_align = mps;
}
/* N.B. T5/T6 have a crazy special interpretation of the "0" *valueforthePackingBoundary.Thiscorrespondsto16 *bytesinsteadoftheexpected32bytes.Soifwewant32 *bytes,thebestwecanreallydois64bytes...
*/ if (pack_align <= 16) {
ingpack = INGPACKBOUNDARY_16B_X;
fl_align = 16;
} elseif (pack_align == 32) {
ingpack = INGPACKBOUNDARY_64B_X;
fl_align = 64;
} else { unsignedint pack_align_log = fls(pack_align) - 1;
/* Use the smallest Ingress Padding which isn't smaller than *theMemoryControllerRead/WriteSize.We'lltakethatas *being8bytessincewedon'tknowofanysystemwitha *widerMemoryControllerBusWidth.
*/ if (is_t5(adap->params.chip))
ingpad = INGPADBOUNDARY_32B_X; else
ingpad = T6_INGPADBOUNDARY_8B_X;
for (i = 0; i < nparams; i++) {
*p++ = cpu_to_be32(*params++); if (rw)
*p = cpu_to_be32(*(val + i));
p++;
}
ret = t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), &c, sleep_ok); if (ret == 0) for (i = 0, p = &c.param[0].val; i < nparams; i++, p += 2)
*val++ = be32_to_cpu(*p); return ret;
}
/* Copy the address and the mask */
memcpy((u8 *)&p->data1[0] + 2, addr, ETH_ALEN);
memcpy((u8 *)&p->data1m[0] + 2, mask, ETH_ALEN);
ret = t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, sleep_ok); if (ret == 0) {
ret = FW_VI_MAC_CMD_RAW_IDX_G(be32_to_cpu(p->raw_idx_pkd)); if (ret != idx)
ret = -ENOMEM;
}
for (i = 0, p = c.u.exact; i < fw_naddr; i++, p++) {
p->valid_to_idx =
cpu_to_be16(FW_VI_MAC_CMD_VALID_F |
FW_VI_MAC_CMD_IDX_V(
FW_VI_MAC_ADD_MAC));
memcpy(p->macaddr, addr[offset + i], sizeof(p->macaddr));
}
/* It's okay if we run out of space in our MAC address arena. *Someoftheaddresseswesubmitmaygetstoredsoweneed *torunthroughthereplytoseewhattheresultswere...
*/
ret = t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), &c, sleep_ok); if (ret && ret != -FW_ENOMEM) break;
for (i = 0, p = c.u.exact; i < fw_naddr; i++, p++) {
u16 index = FW_VI_MAC_CMD_IDX_G(
be16_to_cpu(p->valid_to_idx));
if (link_down_rc >= ARRAY_SIZE(reason)) return"Bad Reason Code";
return reason[link_down_rc];
}
/* Return the highest speed set in the port capabilities, in Mb/s. */ staticunsignedint fwcap_to_speed(fw_port_cap32_t caps)
{ #define TEST_SPEED_RETURN(__caps_speed, __speed) \ do { \ if (caps & FW_PORT_CAP32_SPEED_##__caps_speed) \ return __speed; \
} while (0)
/* Unfortunately the format of the Link Status in the old *16-bitPortInformationmessageisn'tthesameasthe *16-bitPortCapabilitiesbitfieldusedeverywhereelse...
*/ if (lstatus & FW_PORT_CMD_RXPAUSE_F)
linkattr |= FW_PORT_CAP32_FC_RX; if (lstatus & FW_PORT_CMD_TXPAUSE_F)
linkattr |= FW_PORT_CAP32_FC_TX; if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100M))
linkattr |= FW_PORT_CAP32_SPEED_100M; if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_1G))
linkattr |= FW_PORT_CAP32_SPEED_1G; if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_10G))
linkattr |= FW_PORT_CAP32_SPEED_10G; if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_25G))
linkattr |= FW_PORT_CAP32_SPEED_25G; if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_40G))
linkattr |= FW_PORT_CAP32_SPEED_40G; if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100G))
linkattr |= FW_PORT_CAP32_SPEED_100G;
/* Extract the various fields from the Port Information message.
*/
action = FW_PORT_CMD_ACTION_G(be32_to_cpu(cmd->action_to_len16)); switch (action) { case FW_PORT_ACTION_GET_PORT_INFO: {
u32 lstatus = be32_to_cpu(cmd->u.info.lstatus_to_modtype);
/* Reset state for communicating new Transceiver Module status and *whethertheOS-dependentlayerwantsustoredothecurrent *"sticky"L1ConfigureLinkParameters.
*/
lc->new_module = false;
lc->redo_l1cfg = false;
if (mod_type != pi->mod_type) { /* With the newer SFP28 and QSFP28 Transceiver Module Types, *variousfundamentalPortCapabilitieswhichusedtobe *immutablecannowchangeradically.Wecannowhave *Speeds,Auto-Negotiation,ForwardErrorCorrection,etc. *allchangebasedonwhatTransceiverModuleisinserted. *SoweneedtorecordthePhysical"Port"Capabilitieson *everyTransceiverModulechange.
*/
lc->pcaps = pcaps;
/* When a new Transceiver Module is inserted, the Firmware *willexamineitsi2cEPROMtodetermineitstypeand *generaloperatingparametersincludingthingslikeForward *ErrorControl,etc.VariousIEEE802.3standardsdictate *howtointerpretthesei2cvaluestodeterminedefault *"sutomatic"settings.Werecordtheseforfutureusewhen *theuserexplicitlyrequeststhesestandards-basedvalues.
*/
lc->def_acaps = acaps;
/* Some versions of the early T6 Firmware "cheated" when *handlingdifferentTransceiverModulesbychangingthe *underlayingPortTypereportedtotheHostDrivers.As *suchweneedtocapturewhateverPortTypetheFirmware *sendsusandrecorditincaseit'sdifferentfromwhatwe *weretoldearlier.Unfortunately,sinceFirmwareis *forever,we'llneedtokeepthiscodehereforever,butin *laterT6Firmwareitshouldjustbeanassignmentofthe *samevaluealreadyrecorded.
*/
pi->port_type = port_type;
/* Record new Module Type information.
*/
pi->mod_type = mod_type;
/* Let the OS-dependent layer know if we have a new *TransceiverModuleinserted.
*/
lc->new_module = t4_is_inserted_mod_type(mod_type);
/* If we have a new Transceiver Module and the OS-dependent code has *toldusthatitwantsustoredowhatever"sticky"L1Configuration *LinkParametersareset,dothatnow.
*/ if (lc->new_module && lc->redo_l1cfg) { struct link_config old_lc; int ret;
/* Save the current L1 Configuration and restore it if an *erroroccurs.Weprobablyshouldfixthel1_cfg*() *routinesnottochangethelink_configwhenanerror *occurs...
*/
old_lc = *lc;
ret = t4_link_l1cfg_ns(adapter, adapter->mbox, pi->lport, lc); if (ret) {
*lc = old_lc;
dev_warn(adapter->pdev_dev, "Attempt to update new Transceiver Module settings failed\n");
}
}
lc->new_module = false;
lc->redo_l1cfg = false;
}
if (link_okp)
*link_okp = link_ok;
if (speedp)
*speedp = fwcap_to_speed(linkattr);
if (mtup)
*mtup = mtu;
return 0;
}
/**
* t4_handle_fw_rpl - process a FW reply message
* @adap: the adapter
* @rpl: start of the FW message
*
* Processes a FW message, such as link state change messages.
*/
int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl)
{
u8 opcode = *(const u8 *)rpl;
/* This might be a port command ... this simplifies the following
* conditionals ... We can get away with pre-dereferencing
* action_to_len16 because it's in the first 16 bytes and all messages
* will be at least that long.
*/
const struct fw_port_cmd *p = (const void *)rpl;
unsigned int action =
FW_PORT_CMD_ACTION_G(be32_to_cpu(p->action_to_len16));
if (opcode == FW_PORT_CMD &&
(action == FW_PORT_ACTION_GET_PORT_INFO ||
action == FW_PORT_ACTION_GET_PORT_INFO32)) {
int i;
int chan = FW_PORT_CMD_PORTID_G(be32_to_cpu(p->op_to_portid));
struct port_info *pi = NULL;
for_each_port(adap, i) {
pi = adap2pinfo(adap, i);
if (pi->tx_chan == chan)
break;
}
if (pci_is_pcie(adapter->pdev)) {
pcie_capability_read_word(adapter->pdev, PCI_EXP_LNKSTA, &val);
p->speed = val & PCI_EXP_LNKSTA_CLS;
p->width = (val & PCI_EXP_LNKSTA_NLW) >> 4;
}
}
/**
* init_link_config - initialize a link's SW state
* @lc: pointer to structure holding the link state
* @pcaps: link Port Capabilities
* @acaps: link current Advertised Port Capabilities
*
* Initializes the SW state maintained for each link, including the link's
* capabilities and default speed/flow-control/autonegotiation settings.
*/
static void init_link_config(struct link_config *lc, fw_port_cap32_t pcaps,
fw_port_cap32_t acaps)
{
lc->pcaps = pcaps;
lc->def_acaps = acaps;
lc->lpacaps = 0;
lc->speed_caps = 0;
lc->speed = 0;
lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX;
/* For Forward Error Control, we default to whatever the Firmware
* tells us the Link is currently advertising.
*/
lc->requested_fec = FEC_AUTO;
lc->fec = fwcap_to_cc_fec(lc->def_acaps);
/* If the Port is capable of Auto-Negtotiation, initialize it as
* "enabled" and copy over all of the Physical Port Capabilities
* to the Advertised Port Capabilities. Otherwise mark it as
* Auto-Negotiate disabled and select the highest supported speed
* for the link. Note parallel structure in t4_link_l1cfg_core()
* and t4_handle_get_port_info().
*/
if (lc->pcaps & FW_PORT_CAP32_ANEG) {
lc->acaps = lc->pcaps & ADVERT_MASK;
lc->autoneg = AUTONEG_ENABLE;
lc->requested_fc |= PAUSE_AUTONEG;
} else {
lc->acaps = 0;
lc->autoneg = AUTONEG_DISABLE;
lc->speed_caps = fwcap_to_fwspeed(acaps);
}
}
#define CIM_PF_NOACCESS 0xeeeeeeee
int t4_wait_dev_ready(void __iomem *regs)
{
u32 whoami;
static int t4_get_flash_params(struct adapter *adap)
{
/* Table for non-Numonix supported flash parts. Numonix parts are left
* to the preexisting code. All flash parts have 64KB sectors.
*/
static struct flash_desc supported_flash[] = {
{ 0x150201, 4 << 20 }, /* Spansion 4MB S25FL032P */
};
unsigned int part, manufacturer;
unsigned int density, size = 0;
u32 flashid = 0;
int ret;
/* Issue a Read ID Command to the Flash part. We decode supported
* Flash parts and their sizes from this. There's a newer Query
* Command which can retrieve detailed geometry information but many
* Flash parts don't support it.
*/
ret = sf1_write(adap, 1, 1, 0, SF_RD_ID);
if (!ret)
ret = sf1_read(adap, 3, 0, 1, &flashid);
t4_write_reg(adap, SF_OP_A, 0); /* unlock SF */
if (ret)
return ret;
/* Check to see if it's one of our non-standard supported Flash parts.
*/
for (part = 0; part < ARRAY_SIZE(supported_flash); part++)
if (supported_flash[part].vendor_and_model_id == flashid) {
adap->params.sf_size = supported_flash[part].size_mb;
adap->params.sf_nsec =
adap->params.sf_size / SF_SEC_SIZE;
goto found;
}
/* Decode Flash part size. The code below looks repetitive with
* common encodings, but that's not guaranteed in the JEDEC
* specification for the Read JEDEC ID command. The only thing that
* we're guaranteed by the JEDEC specification is where the
* Manufacturer ID is in the returned result. After that each
* Manufacturer ~could~ encode things completely differently.
* Note, all Flash parts must have 64KB sectors.
*/
manufacturer = flashid & 0xff;
switch (manufacturer) {
case 0x20: { /* Micron/Numonix */
/* This Density -> Size decoding table is taken from Micron
* Data Sheets.
*/
density = (flashid >> 16) & 0xff;
switch (density) {
case 0x14: /* 1MB */
size = 1 << 20;
break;
case 0x15: /* 2MB */
size = 1 << 21;
break;
case 0x16: /* 4MB */
size = 1 << 22;
break;
case 0x17: /* 8MB */
size = 1 << 23;
break;
case 0x18: /* 16MB */
size = 1 << 24;
break;
case 0x19: /* 32MB */
size = 1 << 25;
break;
case 0x20: /* 64MB */
size = 1 << 26;
break;
case 0x21: /* 128MB */
size = 1 << 27;
break;
case 0x22: /* 256MB */
size = 1 << 28;
break;
}
break;
}
case 0x9d: { /* ISSI -- Integrated Silicon Solution, Inc. */
/* This Density -> Size decoding table is taken from ISSI
* Data Sheets.
*/
density = (flashid >> 16) & 0xff;
switch (density) {
case 0x16: /* 32 MB */
size = 1 << 25;
break;
case 0x17: /* 64MB */
size = 1 << 26;
break;
}
break;
}
case 0xc2: { /* Macronix */
/* This Density -> Size decoding table is taken from Macronix
* Data Sheets.
*/
density = (flashid >> 16) & 0xff;
switch (density) {
case 0x17: /* 8MB */
size = 1 << 23;
break;
case 0x18: /* 16MB */
size = 1 << 24;
break;
}
break;
}
case 0xef: { /* Winbond */
/* This Density -> Size decoding table is taken from Winbond
* Data Sheets.
*/
density = (flashid >> 16) & 0xff;
switch (density) {
case 0x17: /* 8MB */
size = 1 << 23;
break;
case 0x18: /* 16MB */
size = 1 << 24;
break;
}
break;
}
}
/* If we didn't recognize the FLASH part, that's no real issue: the
* Hardware/Software contract says that Hardware will _*ALWAYS*_
* use a FLASH part which is at least 4MB in size and has 64KB
* sectors. The unrecognized FLASH part is likely to be much larger
* than 4MB, but that's all we really need.
*/
if (size == 0) {
dev_warn(adap->pdev_dev, "Unknown Flash Part, ID = %#x, assuming 4MB\n",
flashid);
size = 1 << 22;
}
/* Store decoded Flash size and fall through into vetting code. */
adap->params.sf_size = size;
adap->params.sf_nsec = size / SF_SEC_SIZE;
found:
if (adap->params.sf_size < FLASH_MIN_SIZE)
dev_warn(adap->pdev_dev, "WARNING: Flash Part ID %#x, size %#x < %#x\n",
flashid, adap->params.sf_size, FLASH_MIN_SIZE);
return 0;
}
/**
* t4_prep_adapter - prepare SW and HW for operation
* @adapter: the adapter
*
* Initialize adapter SW state for the various HW modules, set initial
* values for some adapter tunables, take PHYs out of reset, and
* initialize the MDIO interface.
*/
int t4_prep_adapter(struct adapter *adapter)
{
int ret, ver;
uint16_t device_id;
u32 pl_rev;
/*
* Default port for debugging in case we can't reach FW.
*/
adapter->params.nports = 1;
adapter->params.portvec = 1;
adapter->params.vpd.cclk = 50000;
/* Set PCIe completion timeout to 4 seconds. */
pcie_capability_clear_and_set_word(adapter->pdev, PCI_EXP_DEVCTL2,
PCI_EXP_DEVCTL2_COMP_TIMEOUT, 0xd);
return 0;
}
/**
* t4_shutdown_adapter - shut down adapter, host & wire
* @adapter: the adapter
*
* Perform an emergency shutdown of the adapter and stop it from
* continuing any further communication on the ports or DMA to the
* host. This is typically used when the adapter and/or firmware
* have crashed and we want to prevent any further accidental
* communication with the rest of the world. This will also force
* the port Link Status to go down -- if register writes work --
* which should help our peers figure out that we're down.
*/
int t4_shutdown_adapter(struct adapter *adapter)
{
int port;
/**
* t4_bar2_sge_qregs - return BAR2 SGE Queue register information
* @adapter: the adapter
* @qid: the Queue ID
* @qtype: the Ingress or Egress type for @qid
* @user: true if this request is for a user mode queue
* @pbar2_qoffset: BAR2 Queue Offset
* @pbar2_qid: BAR2 Queue ID or 0 for Queue ID inferred SGE Queues
*
* Returns the BAR2 SGE Queue Registers information associated with the
* indicated Absolute Queue ID. These are passed back in return value
* pointers. @qtype should be T4_BAR2_QTYPE_EGRESS for Egress Queue
* and T4_BAR2_QTYPE_INGRESS for Ingress Queues.
*
* This may return an error which indicates that BAR2 SGE Queue
* registers aren't available. If an error is not returned, then the
* following values are returned:
*
* *@pbar2_qoffset: the BAR2 Offset of the @qid Registers
* *@pbar2_qid: the BAR2 SGE Queue ID or 0 of @qid
*
* If the returned BAR2 Queue ID is 0, then BAR2 SGE registers which
* require the "Inferred Queue ID" ability may be used. E.g. the
* Write Combining Doorbell Buffer. If the BAR2 Queue ID is not 0,
* then these "Inferred Queue ID" register may not be used.
*/
int t4_bar2_sge_qregs(struct adapter *adapter,
unsigned int qid,
enum t4_bar2_qtype qtype,
int user,
u64 *pbar2_qoffset,
unsigned int *pbar2_qid)
{
unsigned int page_shift, page_size, qpp_shift, qpp_mask;
u64 bar2_page_offset, bar2_qoffset;
unsigned int bar2_qid, bar2_qid_offset, bar2_qinferred;
/* T4 doesn't support BAR2 SGE Queue registers for kernel mode queues */
if (!user && is_t4(adapter->params.chip))
return -EINVAL;
/* Get the right Queues per Page parameters for our Queue.
*/
qpp_shift = (qtype == T4_BAR2_QTYPE_EGRESS
? adapter->params.sge.eq_qpp
: adapter->params.sge.iq_qpp);
qpp_mask = (1 << qpp_shift) - 1;
/* Calculate the basics of the BAR2 SGE Queue register area:
* o The BAR2 page the Queue registers will be in.
* o The BAR2 Queue ID.
* o The BAR2 Queue ID Offset into the BAR2 page.
*/
bar2_page_offset = ((u64)(qid >> qpp_shift) << page_shift);
bar2_qid = qid & qpp_mask;
bar2_qid_offset = bar2_qid * SGE_UDB_SIZE;
/* If the BAR2 Queue ID Offset is less than the Page Size, then the
* hardware will infer the Absolute Queue ID simply from the writes to
* the BAR2 Queue ID Offset within the BAR2 Page (and we need to use a
* BAR2 Queue ID of 0 for those writes). Otherwise, we'll simply
* write to the first BAR2 SGE Queue Area within the BAR2 Page with
* the BAR2 Queue ID and the hardware will infer the Absolute Queue ID
* from the BAR2 Page and BAR2 Queue ID.
*
* One important censequence of this is that some BAR2 SGE registers
* have a "Queue ID" field and we can write the BAR2 SGE Queue ID
* there. But other registers synthesize the SGE Queue ID purely
* from the writes to the registers -- the Write Combined Doorbell
* Buffer is a good example. These BAR2 SGE Registers are only
* available for those BAR2 SGE Register areas where the SGE Absolute
* Queue ID can be inferred from simple writes.
*/
bar2_qoffset = bar2_page_offset;
bar2_qinferred = (bar2_qid_offset < page_size);
if (bar2_qinferred) {
bar2_qoffset += bar2_qid_offset;
bar2_qid = 0;
}
/**
* t4_init_devlog_params - initialize adapter->params.devlog
* @adap: the adapter
*
* Initialize various fields of the adapter's Firmware Device Log
* Parameters structure.
*/
int t4_init_devlog_params(struct adapter *adap)
{
struct devlog_params *dparams = &adap->params.devlog;
u32 pf_dparams;
unsigned int devlog_meminfo;
struct fw_devlog_cmd devlog_cmd;
int ret;
/* If we're dealing with newer firmware, the Device Log Parameters
* are stored in a designated register which allows us to access the
* Device Log even if we can't talk to the firmware.
*/
pf_dparams =
t4_read_reg(adap, PCIE_FW_REG(PCIE_FW_PF_A, PCIE_FW_PF_DEVLOG));
if (pf_dparams) {
unsigned int nentries, nentries128;
/**
* t4_init_tp_params - initialize adap->params.tp
* @adap: the adapter
* @sleep_ok: if true we may sleep while awaiting command completion
*
* Initialize various fields of the adapter's TP Parameters structure.
*/
int t4_init_tp_params(struct adapter *adap, bool sleep_ok)
{
u32 param, val, v;
int chan, ret;
v = t4_read_reg(adap, TP_TIMER_RESOLUTION_A);
adap->params.tp.tre = TIMERRESOLUTION_G(v);
adap->params.tp.dack_re = DELAYEDACKRESOLUTION_G(v);
/* MODQ_REQ_MAP defaults to setting queues 0-3 to chan 0-3 */
for (chan = 0; chan < NCHAN; chan++)
adap->params.tp.tx_modq[chan] = chan;
/* Cache the adapter's Compressed Filter Mode/Mask and global Ingress
* Configuration.
*/
param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_FILTER) |
FW_PARAMS_PARAM_Y_V(FW_PARAM_DEV_FILTER_MODE_MASK));
/* Read current value */
ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1,
¶m, &val);
if (ret == 0) {
dev_info(adap->pdev_dev,
"Current filter mode/mask 0x%x:0x%x\n",
FW_PARAMS_PARAM_FILTER_MODE_G(val),
FW_PARAMS_PARAM_FILTER_MASK_G(val));
adap->params.tp.vlan_pri_map =
FW_PARAMS_PARAM_FILTER_MODE_G(val);
adap->params.tp.filter_mask =
FW_PARAMS_PARAM_FILTER_MASK_G(val);
} else {
dev_info(adap->pdev_dev,
"Failed to read filter mode/mask via fw api, using indirect-reg-read\n");
/* Incase of older-fw (which doesn't expose the api
* FW_PARAM_DEV_FILTER_MODE_MASK) and newer-driver (which uses
* the fw api) combination, fall-back to older method of reading
* the filter mode from indirect-register
*/
t4_tp_pio_read(adap, &adap->params.tp.vlan_pri_map, 1,
TP_VLAN_PRI_MAP_A, sleep_ok);
/* With the older-fw and newer-driver combination we might run
* into an issue when user wants to use hash filter region but
* the filter_mask is zero, in this case filter_mask validation
* is tough. To avoid that we set the filter_mask same as filter
* mode, which will behave exactly as the older way of ignoring
* the filter mask validation.
*/
adap->params.tp.filter_mask = adap->params.tp.vlan_pri_map;
}
/* For T6, cache the adapter's compressed error vector
* and passing outer header info for encapsulated packets.
*/
if (CHELSIO_CHIP_VERSION(adap->params.chip) > CHELSIO_T5) {
v = t4_read_reg(adap, TP_OUT_CONFIG_A);
adap->params.tp.rx_pkt_encap = (v & CRXPKTENC_F) ? 1 : 0;
}
/* Now that we have TP_VLAN_PRI_MAP cached, we can calculate the field
* shift positions of several elements of the Compressed Filter Tuple
* for this adapter which we need frequently ...
*/
adap->params.tp.fcoe_shift = t4_filter_field_shift(adap, FCOE_F);
adap->params.tp.port_shift = t4_filter_field_shift(adap, PORT_F);
adap->params.tp.vnic_shift = t4_filter_field_shift(adap, VNIC_ID_F);
adap->params.tp.vlan_shift = t4_filter_field_shift(adap, VLAN_F);
adap->params.tp.tos_shift = t4_filter_field_shift(adap, TOS_F);
adap->params.tp.protocol_shift = t4_filter_field_shift(adap,
PROTOCOL_F);
adap->params.tp.ethertype_shift = t4_filter_field_shift(adap,
ETHERTYPE_F);
adap->params.tp.macmatch_shift = t4_filter_field_shift(adap,
MACMATCH_F);
adap->params.tp.matchtype_shift = t4_filter_field_shift(adap,
MPSHITTYPE_F);
adap->params.tp.frag_shift = t4_filter_field_shift(adap,
FRAGMENTATION_F);
/* If TP_INGRESS_CONFIG.VNID == 0, then TP_VLAN_PRI_MAP.VNIC_ID
* represents the presence of an Outer VLAN instead of a VNIC ID.
*/
if ((adap->params.tp.ingress_config & VNIC_F) == 0)
adap->params.tp.vnic_shift = -1;
v = t4_read_reg(adap, LE_3_DB_HASH_MASK_GEN_IPV4_T6_A);
adap->params.tp.hash_filter_mask = v;
v = t4_read_reg(adap, LE_4_DB_HASH_MASK_GEN_IPV4_T6_A);
adap->params.tp.hash_filter_mask |= ((u64)v << 32);
return 0;
}
/**
* t4_filter_field_shift - calculate filter field shift
* @adap: the adapter
* @filter_sel: the desired field (from TP_VLAN_PRI_MAP bits)
*
* Return the shift position of a filter field within the Compressed
* Filter Tuple. The filter field is specified via its selection bit
* within TP_VLAN_PRI_MAL (filter mode). E.g. F_VLAN.
*/
int t4_filter_field_shift(const struct adapter *adap, int filter_sel)
{
unsigned int filter_mode = adap->params.tp.vlan_pri_map;
unsigned int sel;
int field_shift;
if ((filter_mode & filter_sel) == 0)
return -1;
for (sel = 1, field_shift = 0; sel < filter_sel; sel <<= 1) {
switch (filter_mode & sel) {
case FCOE_F:
field_shift += FT_FCOE_W;
break;
case PORT_F:
field_shift += FT_PORT_W;
break;
case VNIC_ID_F:
field_shift += FT_VNIC_ID_W;
break;
case VLAN_F:
field_shift += FT_VLAN_W;
break;
case TOS_F:
field_shift += FT_TOS_W;
break;
case PROTOCOL_F:
field_shift += FT_PROTOCOL_W;
break;
case ETHERTYPE_F:
field_shift += FT_ETHERTYPE_W;
break;
case MACMATCH_F:
field_shift += FT_MACMATCH_W;
break;
case MPSHITTYPE_F:
field_shift += FT_MPSHITTYPE_W;
break;
case FRAGMENTATION_F:
field_shift += FT_FRAGMENTATION_W;
break;
}
}
return field_shift;
}
int t4_init_rss_mode(struct adapter *adap, int mbox)
{
int i, ret;
struct fw_rss_vi_config_cmd rvc;
/**
* t4_init_portinfo - allocate a virtual interface and initialize port_info
* @pi: the port_info
* @mbox: mailbox to use for the FW command
* @port: physical port associated with the VI
* @pf: the PF owning the VI
* @vf: the VF owning the VI
* @mac: the MAC address of the VI
*
* Allocates a virtual interface for the given physical port. If @mac is
* not %NULL it contains the MAC address of the VI as assigned by FW.
* @mac should be large enough to hold an Ethernet address.
* Returns < 0 on error.
*/
int t4_init_portinfo(struct port_info *pi, int mbox,
int port, int pf, int vf, u8 mac[])
{
struct adapter *adapter = pi->adapter;
unsigned int fw_caps = adapter->params.fw_caps_support;
struct fw_port_cmd cmd;
unsigned int rss_size;
enum fw_port_type port_type;
int mdio_addr;
fw_port_cap32_t pcaps, acaps;
u8 vivld = 0, vin = 0;
int ret;
/* If we haven't yet determined whether we're talking to Firmware
* which knows the new 32-bit Port Capabilities, it's time to find
* out now. This will also tell new Firmware to send us Port Status
* Updates using the new 32-bit Port Capabilities version of the
* Port Information message.
*/
if (fw_caps == FW_CAPS_UNKNOWN) {
u32 param, val;
/* Extract the various fields from the Port Information message.
*/
if (fw_caps == FW_CAPS16) {
u32 lstatus = be32_to_cpu(cmd.u.info.lstatus_to_modtype);
/* If fw supports returning the VIN as part of FW_VI_CMD,
* save the returned values.
*/
if (adapter->params.viid_smt_extn_support) {
pi->vivld = vivld;
pi->vin = vin;
} else {
/* Retrieve the values from VIID */
pi->vivld = FW_VIID_VIVLD_G(pi->viid);
pi->vin = FW_VIID_VIN_G(pi->viid);
}
int t4_init_port_mirror(struct port_info *pi, u8 mbox, u8 port, u8 pf, u8 vf,
u16 *mirror_viid)
{
int ret;
ret = t4_alloc_vi(pi->adapter, mbox, port, pf, vf, 1, NULL, NULL,
NULL, NULL);
if (ret < 0)
return ret;
if (mirror_viid)
*mirror_viid = ret;
return 0;
}
/**
* t4_read_cimq_cfg - read CIM queue configuration
* @adap: the adapter
* @base: holds the queue base addresses in bytes
* @size: holds the queue sizes in bytes
* @thres: holds the queue full thresholds in bytes
*
* Returns the current configuration of the CIM queues, starting with
* the IBQs, then the OBQs.
*/
void t4_read_cimq_cfg(struct adapter *adap, u16 *base, u16 *size, u16 *thres)
{
unsigned int i, v;
int cim_num_obq = is_t4(adap->params.chip) ?
CIM_NUM_OBQ : CIM_NUM_OBQ_T5;
for (i = 0; i < CIM_NUM_IBQ; i++) {
t4_write_reg(adap, CIM_QUEUE_CONFIG_REF_A, IBQSELECT_F |
QUENUMSELECT_V(i));
v = t4_read_reg(adap, CIM_QUEUE_CONFIG_CTRL_A);
/* value is in 256-byte units */
*base++ = CIMQBASE_G(v) * 256;
*size++ = CIMQSIZE_G(v) * 256;
*thres++ = QUEFULLTHRSH_G(v) * 8; /* 8-byte unit */
}
for (i = 0; i < cim_num_obq; i++) {
t4_write_reg(adap, CIM_QUEUE_CONFIG_REF_A, OBQSELECT_F |
QUENUMSELECT_V(i));
v = t4_read_reg(adap, CIM_QUEUE_CONFIG_CTRL_A);
/* value is in 256-byte units */
*base++ = CIMQBASE_G(v) * 256;
*size++ = CIMQSIZE_G(v) * 256;
}
}
/**
* t4_read_cim_ibq - read the contents of a CIM inbound queue
* @adap: the adapter
* @qid: the queue index
* @data: where to store the queue contents
* @n: capacity of @data in 32-bit words
*
* Reads the contents of the selected CIM queue starting at address 0 up
* to the capacity of @data. @n must be a multiple of 4. Returns < 0 on
* error and the number of 32-bit words actually read on success.
*/
int t4_read_cim_ibq(struct adapter *adap, unsigned int qid, u32 *data, size_t n)
{
int i, err, attempts;
unsigned int addr;
const unsigned int nwords = CIM_IBQ_SIZE * 4;
if (qid > 5 || (n & 3))
return -EINVAL;
addr = qid * nwords;
if (n > nwords)
n = nwords;
/* It might take 3-10ms before the IBQ debug read access is allowed.
* Wait for 1 Sec with a delay of 1 usec.
*/
attempts = 1000000;
for (i = 0; i < n; i++, addr++) {
t4_write_reg(adap, CIM_IBQ_DBG_CFG_A, IBQDBGADDR_V(addr) |
IBQDBGEN_F);
err = t4_wait_op_done(adap, CIM_IBQ_DBG_CFG_A, IBQDBGBUSY_F, 0,
attempts, 1);
if (err)
return err;
*data++ = t4_read_reg(adap, CIM_IBQ_DBG_DATA_A);
}
t4_write_reg(adap, CIM_IBQ_DBG_CFG_A, 0);
return i;
}
/**
* t4_read_cim_obq - read the contents of a CIM outbound queue
* @adap: the adapter
* @qid: the queue index
* @data: where to store the queue contents
* @n: capacity of @data in 32-bit words
*
* Reads the contents of the selected CIM queue starting at address 0 up
* to the capacity of @data. @n must be a multiple of 4. Returns < 0 on
* error and the number of 32-bit words actually read on success.
*/
int t4_read_cim_obq(struct adapter *adap, unsigned int qid, u32 *data, size_t n)
{
int i, err;
unsigned int addr, v, nwords;
int cim_num_obq = is_t4(adap->params.chip) ?
CIM_NUM_OBQ : CIM_NUM_OBQ_T5;
t4_write_reg(adap, CIM_QUEUE_CONFIG_REF_A, OBQSELECT_F |
QUENUMSELECT_V(qid));
v = t4_read_reg(adap, CIM_QUEUE_CONFIG_CTRL_A);
addr = CIMQBASE_G(v) * 64; /* muliple of 256 -> muliple of 4 */
nwords = CIMQSIZE_G(v) * 64; /* same */
if (n > nwords)
n = nwords;
for (i = 0; i < n; i++, addr++) {
t4_write_reg(adap, CIM_OBQ_DBG_CFG_A, OBQDBGADDR_V(addr) |
OBQDBGEN_F);
err = t4_wait_op_done(adap, CIM_OBQ_DBG_CFG_A, OBQDBGBUSY_F, 0, 2, 1);
if (err)
return err;
*data++ = t4_read_reg(adap, CIM_OBQ_DBG_DATA_A);
}
t4_write_reg(adap, CIM_OBQ_DBG_CFG_A, 0);
return i;
}
/**
* t4_cim_read - read a block from CIM internal address space
* @adap: the adapter
* @addr: the start address within the CIM address space
* @n: number of words to read
* @valp: where to store the result
*
* Reads a block of 4-byte words from the CIM intenal address space.
*/
int t4_cim_read(struct adapter *adap, unsigned int addr, unsigned int n,
unsigned int *valp)
{
int ret = 0;
if (t4_read_reg(adap, CIM_HOST_ACC_CTRL_A) & HOSTBUSY_F)
return -EBUSY;
/**
* t4_cim_write - write a block into CIM internal address space
* @adap: the adapter
* @addr: the start address within the CIM address space
* @n: number of words to write
* @valp: set of values to write
*
* Writes a block of 4-byte words into the CIM intenal address space.
*/
int t4_cim_write(struct adapter *adap, unsigned int addr, unsigned int n,
const unsigned int *valp)
{
int ret = 0;
if (t4_read_reg(adap, CIM_HOST_ACC_CTRL_A) & HOSTBUSY_F)
return -EBUSY;
static int t4_cim_write1(struct adapter *adap, unsigned int addr,
unsigned int val)
{
return t4_cim_write(adap, addr, 1, &val);
}
/**
* t4_cim_read_la - read CIM LA capture buffer
* @adap: the adapter
* @la_buf: where to store the LA data
* @wrptr: the HW write pointer within the capture buffer
*
* Reads the contents of the CIM LA buffer with the most recent entry at
* the end of the returned data and with the entry at @wrptr first.
* We try to leave the LA in the running state we find it in.
*/
int t4_cim_read_la(struct adapter *adap, u32 *la_buf, unsigned int *wrptr)
{
int i, ret;
unsigned int cfg, val, idx;
ret = t4_cim_read(adap, UP_UP_DBG_LA_CFG_A, 1, &cfg);
if (ret)
return ret;
if (cfg & UPDBGLAEN_F) { /* LA is running, freeze it */
ret = t4_cim_write1(adap, UP_UP_DBG_LA_CFG_A, 0);
if (ret)
return ret;
}
ret = t4_cim_read(adap, UP_UP_DBG_LA_CFG_A, 1, &val);
if (ret)
goto restart;
idx = UPDBGLAWRPTR_G(val);
if (wrptr)
*wrptr = idx;
for (i = 0; i < adap->params.cim_la_size; i++) {
ret = t4_cim_write1(adap, UP_UP_DBG_LA_CFG_A,
UPDBGLARDPTR_V(idx) | UPDBGLARDEN_F);
if (ret)
break;
ret = t4_cim_read(adap, UP_UP_DBG_LA_CFG_A, 1, &val);
if (ret)
break;
if (val & UPDBGLARDEN_F) {
ret = -ETIMEDOUT;
break;
}
ret = t4_cim_read(adap, UP_UP_DBG_LA_DATA_A, 1, &la_buf[i]);
if (ret)
break;
/* Bits 0-3 of UpDbgLaRdPtr can be between 0000 to 1001 to
* identify the 32-bit portion of the full 312-bit data
*/
if (is_t6(adap->params.chip) && (idx & 0xf) >= 9)
idx = (idx & 0xff0) + 0x10;
else
idx++;
/* address can't exceed 0xfff */
idx &= UPDBGLARDPTR_M;
}
restart:
if (cfg & UPDBGLAEN_F) {
int r = t4_cim_write1(adap, UP_UP_DBG_LA_CFG_A,
cfg & ~UPDBGLARDEN_F);
if (!ret)
ret = r;
}
return ret;
}
/**
* t4_tp_read_la - read TP LA capture buffer
* @adap: the adapter
* @la_buf: where to store the LA data
* @wrptr: the HW write pointer within the capture buffer
*
* Reads the contents of the TP LA buffer with the most recent entry at
* the end of the returned data and with the entry at @wrptr first.
* We leave the LA in the running state we find it in.
*/
void t4_tp_read_la(struct adapter *adap, u64 *la_buf, unsigned int *wrptr)
{
bool last_incomplete;
unsigned int i, cfg, val, idx;
val &= 0xffff;
val &= ~DBGLARPTR_V(DBGLARPTR_M);
val |= adap->params.tp.la_mask;
for (i = 0; i < TPLA_SIZE; i++) {
t4_write_reg(adap, TP_DBG_LA_CONFIG_A, DBGLARPTR_V(idx) | val);
la_buf[i] = t4_read_reg64(adap, TP_DBG_LA_DATAL_A);
idx = (idx + 1) & DBGLARPTR_M;
}
/* Wipe out last entry if it isn't valid */
if (last_incomplete)
la_buf[TPLA_SIZE - 1] = ~0ULL;
if (cfg & DBGLAENABLE_F) /* restore running state */
t4_write_reg(adap, TP_DBG_LA_CONFIG_A,
cfg | adap->params.tp.la_mask);
}
/* SGE Hung Ingress DMA Warning Threshold time and Warning Repeat Rate (in
* seconds). If we find one of the SGE Ingress DMA State Machines in the same
* state for more than the Warning Threshold then we'll issue a warning about
* a potential hang. We'll repeat the warning as the SGE Ingress DMA Channel
* appears to be hung every Warning Repeat second till the situation clears.
* If the situation clears, we'll note that as well.
*/
#define SGE_IDMA_WARN_THRESH 1
#define SGE_IDMA_WARN_REPEAT 300
/**
* t4_idma_monitor_init - initialize SGE Ingress DMA Monitor
* @adapter: the adapter
* @idma: the adapter IDMA Monitor state
*
* Initialize the state of an SGE Ingress DMA Monitor.
*/
void t4_idma_monitor_init(struct adapter *adapter,
struct sge_idma_monitor_state *idma)
{
/* Initialize the state variables for detecting an SGE Ingress DMA
* hang. The SGE has internal counters which count up on each clock
* tick whenever the SGE finds its Ingress DMA State Engines in the
* same state they were on the previous clock tick. The clock used is
* the Core Clock so we have a limit on the maximum "time" they can
* record; typically a very small number of seconds. For instance,
* with a 600MHz Core Clock, we can only count up to a bit more than
* 7s. So we'll synthesize a larger counter in order to not run the
* risk of having the "timers" overflow and give us the flexibility to
* maintain a Hung SGE State Machine of our own which operates across
* a longer time frame.
*/
idma->idma_1s_thresh = core_ticks_per_usec(adapter) * 1000000; /* 1s */
idma->idma_stalled[0] = 0;
idma->idma_stalled[1] = 0;
}
/**
* t4_idma_monitor - monitor SGE Ingress DMA state
* @adapter: the adapter
* @idma: the adapter IDMA Monitor state
* @hz: number of ticks/second
* @ticks: number of ticks since the last IDMA Monitor call
*/
void t4_idma_monitor(struct adapter *adapter,
struct sge_idma_monitor_state *idma,
int hz, int ticks)
{
int i, idma_same_state_cnt[2];
/* Read the SGE Debug Ingress DMA Same State Count registers. These
* are counters inside the SGE which count up on each clock when the
* SGE finds its Ingress DMA State Engines in the same states they
* were in the previous clock. The counters will peg out at
* 0xffffffff without wrapping around so once they pass the 1s
* threshold they'll stay above that till the IDMA state changes.
*/
t4_write_reg(adapter, SGE_DEBUG_INDEX_A, 13);
idma_same_state_cnt[0] = t4_read_reg(adapter, SGE_DEBUG_DATA_HIGH_A);
idma_same_state_cnt[1] = t4_read_reg(adapter, SGE_DEBUG_DATA_LOW_A);
for (i = 0; i < 2; i++) {
u32 debug0, debug11;
/* If the Ingress DMA Same State Counter ("timer") is less
* than 1s, then we can reset our synthesized Stall Timer and
* continue. If we have previously emitted warnings about a
* potential stalled Ingress Queue, issue a note indicating
* that the Ingress Queue has resumed forward progress.
*/
if (idma_same_state_cnt[i] < idma->idma_1s_thresh) {
if (idma->idma_stalled[i] >= SGE_IDMA_WARN_THRESH * hz)
dev_warn(adapter->pdev_dev, "SGE idma%d, queue %u, "
"resumed after %d seconds\n",
i, idma->idma_qid[i],
idma->idma_stalled[i] / hz);
idma->idma_stalled[i] = 0;
continue;
}
/* Synthesize an SGE Ingress DMA Same State Timer in the Hz
* domain. The first time we get here it'll be because we
* passed the 1s Threshold; each additional time it'll be
* because the RX Timer Callback is being fired on its regular
* schedule.
*
* If the stall is below our Potential Hung Ingress Queue
* Warning Threshold, continue.
*/
if (idma->idma_stalled[i] == 0) {
idma->idma_stalled[i] = hz;
idma->idma_warn[i] = 0;
} else {
idma->idma_stalled[i] += ticks;
idma->idma_warn[i] -= ticks;
}
if (idma->idma_stalled[i] < SGE_IDMA_WARN_THRESH * hz)
continue;
/* We'll issue a warning every SGE_IDMA_WARN_REPEAT seconds.
*/
if (idma->idma_warn[i] > 0)
continue;
idma->idma_warn[i] = SGE_IDMA_WARN_REPEAT * hz;
/* Read and save the SGE IDMA State and Queue ID information.
* We do this every time in case it changes across time ...
* can't be too careful ...
*/
t4_write_reg(adapter, SGE_DEBUG_INDEX_A, 0);
debug0 = t4_read_reg(adapter, SGE_DEBUG_DATA_LOW_A);
idma->idma_state[i] = (debug0 >> (i * 9)) & 0x3f;
dev_warn(adapter->pdev_dev, "SGE idma%u, queue %u, potentially stuck in "
"state %u for %d seconds (debug0=%#x, debug11=%#x)\n",
i, idma->idma_qid[i], idma->idma_state[i],
idma->idma_stalled[i] / hz,
debug0, debug11);
t4_sge_decode_idma_state(adapter, idma->idma_state[i]);
}
}
/**
* t4_load_cfg - download config file
* @adap: the adapter
* @cfg_data: the cfg text file to write
* @size: text file size
*
* Write the supplied config text file to the card's serial flash.
*/
int t4_load_cfg(struct adapter *adap, const u8 *cfg_data, unsigned int size)
{
int ret, i, n, cfg_addr;
unsigned int addr;
unsigned int flash_cfg_start_sec;
unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec;
cfg_addr = t4_flash_cfg_addr(adap);
if (cfg_addr < 0)
return cfg_addr;
if (size > FLASH_CFG_MAX_SIZE) {
dev_err(adap->pdev_dev, "cfg file too large, max is %u bytes\n",
FLASH_CFG_MAX_SIZE);
return -EFBIG;
}
i = DIV_ROUND_UP(FLASH_CFG_MAX_SIZE, /* # of sectors spanned */
sf_sec_size);
ret = t4_flash_erase_sectors(adap, flash_cfg_start_sec,
flash_cfg_start_sec + i - 1);
/* If size == 0 then we're simply erasing the FLASH sectors associated
* with the on-adapter Firmware Configuration File.
*/
if (ret || size == 0)
goto out;
/* this will write to the flash up to SF_PAGE_SIZE at a time */
for (i = 0; i < size; i += SF_PAGE_SIZE) {
if ((size - i) < SF_PAGE_SIZE)
n = size - i;
else
n = SF_PAGE_SIZE;
ret = t4_write_flash(adap, addr, n, cfg_data, true);
if (ret)
goto out;
/**
* t4_set_vf_mac_acl - Set MAC address for the specified VF
* @adapter: The adapter
* @vf: one of the VFs instantiated by the specified PF
* @start: The start port id associated with specified VF
* @naddr: the number of MAC addresses
* @addr: the MAC address(es) to be set to the specified VF
*/
int t4_set_vf_mac_acl(struct adapter *adapter, unsigned int vf,
u8 start, unsigned int naddr, u8 *addr)
{
struct fw_acl_mac_cmd cmd;
/**
* t4_read_pace_tbl - read the pace table
* @adap: the adapter
* @pace_vals: holds the returned values
*
* Returns the values of TP's pace table in microseconds.
*/
void t4_read_pace_tbl(struct adapter *adap, unsigned int pace_vals[NTX_SCHED])
{
unsigned int i, v;
for (i = 0; i < NTX_SCHED; i++) {
t4_write_reg(adap, TP_PACE_TABLE_A, 0xffff0000 + i);
v = t4_read_reg(adap, TP_PACE_TABLE_A);
pace_vals[i] = dack_ticks_to_usec(adap, v);
}
}
/**
* t4_get_tx_sched - get the configuration of a Tx HW traffic scheduler
* @adap: the adapter
* @sched: the scheduler index
* @kbps: the byte rate in Kbps
* @ipg: the interpacket delay in tenths of nanoseconds
* @sleep_ok: if true we may sleep while awaiting command completion
*
* Return the current configuration of a HW Tx scheduler.
*/
void t4_get_tx_sched(struct adapter *adap, unsigned int sched,
unsigned int *kbps, unsigned int *ipg, bool sleep_ok)
{
unsigned int v, addr, bpt, cpt;
if (kbps) {
addr = TP_TX_MOD_Q1_Q0_RATE_LIMIT_A - sched / 2;
t4_tp_tm_pio_read(adap, &v, 1, addr, sleep_ok);
if (sched & 1)
v >>= 16;
bpt = (v >> 8) & 0xff;
cpt = v & 0xff;
if (!cpt) {
*kbps = 0; /* scheduler disabled */
} else {
v = (adap->params.vpd.cclk * 1000) / cpt; /* ticks/s */
*kbps = (v * bpt) / 125;
}
}
if (ipg) {
addr = TP_TX_MOD_Q1_Q0_TIMER_SEPARATOR_A - sched / 2;
t4_tp_tm_pio_read(adap, &v, 1, addr, sleep_ok);
if (sched & 1)
v >>= 16;
v &= 0xffff;
*ipg = (10000 * v) / core_ticks_per_usec(adap);
}
}
/* t4_sge_ctxt_rd - read an SGE context through FW
* @adap: the adapter
* @mbox: mailbox to use for the FW command
* @cid: the context id
* @ctype: the context type
* @data: where to store the context data
*
* Issues a FW command through the given mailbox to read an SGE context.
*/
int t4_sge_ctxt_rd(struct adapter *adap, unsigned int mbox, unsigned int cid,
enum ctxt_type ctype, u32 *data)
{
struct fw_ldst_cmd c;
int ret;
if (ctype == CTXT_FLM)
ret = FW_LDST_ADDRSPC_SGE_FLMC;
else
ret = FW_LDST_ADDRSPC_SGE_CONMC;
/**
* t4_sge_ctxt_rd_bd - read an SGE context bypassing FW
* @adap: the adapter
* @cid: the context id
* @ctype: the context type
* @data: where to store the context data
*
* Reads an SGE context directly, bypassing FW. This is only for
* debugging when FW is unavailable.
*/
int t4_sge_ctxt_rd_bd(struct adapter *adap, unsigned int cid,
enum ctxt_type ctype, u32 *data)
{
int i, ret;
t4_write_reg(adap, SGE_CTXT_CMD_A, CTXTQID_V(cid) | CTXTTYPE_V(ctype));
ret = t4_wait_op_done(adap, SGE_CTXT_CMD_A, BUSY_F, 0, 3, 1);
if (!ret)
for (i = SGE_CTXT_DATA0_A; i <= SGE_CTXT_DATA5_A; i += 4)
*data++ = t4_read_reg(adap, i);
return ret;
}
/**
* t4_i2c_rd - read I2C data from adapter
* @adap: the adapter
* @mbox: mailbox to use for the FW command
* @port: Port number if per-port device; <0 if not
* @devid: per-port device ID or absolute device ID
* @offset: byte offset into device I2C space
* @len: byte length of I2C space data
* @buf: buffer in which to return I2C data
*
* Reads the I2C data from the indicated device and location.
*/
int t4_i2c_rd(struct adapter *adap, unsigned int mbox, int port,
unsigned int devid, unsigned int offset,
unsigned int len, u8 *buf)
{
struct fw_ldst_cmd ldst_cmd, ldst_rpl;
unsigned int i2c_max = sizeof(ldst_cmd.u.i2c.data);
int ret = 0;
if (len > I2C_PAGE_SIZE)
return -EINVAL;
/* Dont allow reads that spans multiple pages */
if (offset < I2C_PAGE_SIZE && offset + len > I2C_PAGE_SIZE)
return -EINVAL;
/**
* t4_set_vlan_acl - Set a VLAN id for the specified VF
* @adap: the adapter
* @mbox: mailbox to use for the FW command
* @vf: one of the VFs instantiated by the specified PF
* @vlan: The vlanid to be set
*/
int t4_set_vlan_acl(struct adapter *adap, unsigned int mbox, unsigned int vf,
u16 vlan)
{
struct fw_acl_vlan_cmd vlan_cmd;
unsigned int enable;
enable = (vlan ? FW_ACL_VLAN_CMD_EN_F : 0);
memset(&vlan_cmd, 0, sizeof(vlan_cmd));
vlan_cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_ACL_VLAN_CMD) |
FW_CMD_REQUEST_F |
FW_CMD_WRITE_F |
FW_CMD_EXEC_F |
FW_ACL_VLAN_CMD_PFN_V(adap->pf) |
FW_ACL_VLAN_CMD_VFN_V(vf));
vlan_cmd.en_to_len16 = cpu_to_be32(enable | FW_LEN16(vlan_cmd));
/* Drop all packets that donot match vlan id */
vlan_cmd.dropnovlan_fm = (enable
? (FW_ACL_VLAN_CMD_DROPNOVLAN_F |
FW_ACL_VLAN_CMD_FM_F) : 0);
if (enable != 0) {
vlan_cmd.nvlan = 1;
vlan_cmd.vlanid[0] = cpu_to_be16(vlan);
}
/**
* modify_device_id - Modifies the device ID of the Boot BIOS image
* @device_id: the device ID to write.
* @boot_data: the boot image to modify.
*
* Write the supplied device ID to the boot BIOS image.
*/
static void modify_device_id(int device_id, u8 *boot_data)
{
struct cxgb4_pcir_data *pcir_header;
struct legacy_pci_rom_hdr *header;
u8 *cur_header = boot_data;
u16 pcir_offset;
/* Loop through all chained images and change the device ID's */
do {
header = (struct legacy_pci_rom_hdr *)cur_header;
pcir_offset = le16_to_cpu(header->pcir_offset);
pcir_header = (struct cxgb4_pcir_data *)(cur_header +
pcir_offset);
/**
* Only modify the Device ID if code type is Legacy or HP.
* 0x00: Okay to modify
* 0x01: FCODE. Do not modify
* 0x03: Okay to modify
* 0x04-0xFF: Do not modify
*/
if (pcir_header->code_type == CXGB4_HDR_CODE1) {
u8 csum = 0;
int i;
/**
* Modify Device ID to match current adatper
*/
pcir_header->device_id = cpu_to_le16(device_id);
/**
* Set checksum temporarily to 0.
* We will recalculate it later.
*/
header->cksum = 0x0;
/**
* Calculate and update checksum
*/
for (i = 0; i < (header->size512 * 512); i++)
csum += cur_header[i];
/**
* Invert summed value to create the checksum
* Writing new checksum value directly to the boot data
*/
cur_header[7] = -csum;
} else if (pcir_header->code_type == CXGB4_HDR_CODE2) {
/**
* Modify Device ID to match current adatper
*/
pcir_header->device_id = cpu_to_le16(device_id);
}
/**
* Move header pointer up to the next image in the ROM.
*/
cur_header += header->size512 * 512;
} while (!(pcir_header->indicator & CXGB4_HDR_INDI));
}
/**
* t4_load_boot - download boot flash
* @adap: the adapter
* @boot_data: the boot image to write
* @boot_addr: offset in flash to write boot_data
* @size: image size
*
* Write the supplied boot image to the card's serial flash.
* The boot image has the following sections: a 28-byte header and the
* boot image.
*/
int t4_load_boot(struct adapter *adap, u8 *boot_data,
unsigned int boot_addr, unsigned int size)
{
unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec;
unsigned int boot_sector = (boot_addr * 1024);
struct cxgb4_pci_exp_rom_header *header;
struct cxgb4_pcir_data *pcir_header;
int pcir_offset;
unsigned int i;
u16 device_id;
int ret, addr;
/**
* Make sure the boot image does not encroach on the firmware region
*/
if ((boot_sector + size) >> 16 > FLASH_FW_START_SEC) {
dev_err(adap->pdev_dev, "boot image encroaching on firmware region\n");
return -EFBIG;
}
/**
* Perform some primitive sanity testing to avoid accidentally
* writing garbage over the boot sectors. We ought to check for
* more but it's not worth it for now ...
*/
if (size < BOOT_MIN_SIZE || size > BOOT_MAX_SIZE) {
dev_err(adap->pdev_dev, "boot image too small/large\n");
return -EFBIG;
}
/* Check Vendor ID matches Chelsio ID*/
if (le16_to_cpu(pcir_header->vendor_id) != PCI_VENDOR_ID_CHELSIO) {
dev_err(adap->pdev_dev, "Vendor ID missing signature\n");
return -EINVAL;
}
/**
* The boot sector is comprised of the Expansion-ROM boot, iSCSI boot,
* and Boot configuration data sections. These 3 boot sections span
* sectors 0 to 7 in flash and live right before the FW image location.
*/
i = DIV_ROUND_UP(size ? size : FLASH_FW_START, sf_sec_size);
ret = t4_flash_erase_sectors(adap, boot_sector >> 16,
(boot_sector >> 16) + i - 1);
/**
* If size == 0 then we're simply erasing the FLASH sectors associated
* with the on-adapter option ROM file
*/
if (ret || size == 0)
goto out;
/* Retrieve adapter's device ID */
pci_read_config_word(adap->pdev, PCI_DEVICE_ID, &device_id);
/* Want to deal with PF 0 so I strip off PF 4 indicator */
device_id = device_id & 0xf0ff;
/* Check PCIE Device ID */
if (le16_to_cpu(pcir_header->device_id) != device_id) {
/**
* Change the device ID in the Boot BIOS image to match
* the Device ID of the current adapter.
*/
modify_device_id(device_id, boot_data);
}
/**
* Skip over the first SF_PAGE_SIZE worth of data and write it after
* we finish copying the rest of the boot image. This will ensure
* that the BIOS boot header will only be written if the boot image
* was written in full.
*/
addr = boot_sector;
for (size -= SF_PAGE_SIZE; size; size -= SF_PAGE_SIZE) {
addr += SF_PAGE_SIZE;
boot_data += SF_PAGE_SIZE;
ret = t4_write_flash(adap, addr, SF_PAGE_SIZE, boot_data,
false);
if (ret)
goto out;
}
ret = t4_write_flash(adap, boot_sector, SF_PAGE_SIZE,
(const u8 *)header, false);
/**
* t4_flash_bootcfg_addr - return the address of the flash
* optionrom configuration
* @adapter: the adapter
*
* Return the address within the flash where the OptionROM Configuration
* is stored, or an error if the device FLASH is too small to contain
* a OptionROM Configuration.
*/
static int t4_flash_bootcfg_addr(struct adapter *adapter)
{
/**
* If the device FLASH isn't large enough to hold a Firmware
* Configuration File, return an error.
*/
if (adapter->params.sf_size <
FLASH_BOOTCFG_START + FLASH_BOOTCFG_MAX_SIZE)
return -ENOSPC;
return FLASH_BOOTCFG_START;
}
int t4_load_bootcfg(struct adapter *adap, const u8 *cfg_data, unsigned int size)
{
unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec;
struct cxgb4_bootcfg_data *header;
unsigned int flash_cfg_start_sec;
unsigned int addr, npad;
int ret, i, n, cfg_addr;
cfg_addr = t4_flash_bootcfg_addr(adap);
if (cfg_addr < 0)
return cfg_addr;
if (size > FLASH_BOOTCFG_MAX_SIZE) {
dev_err(adap->pdev_dev, "bootcfg file too large, max is %u bytes\n",
FLASH_BOOTCFG_MAX_SIZE);
return -EFBIG;
}
header = (struct cxgb4_bootcfg_data *)cfg_data;
if (le16_to_cpu(header->signature) != BOOT_CFG_SIG) {
dev_err(adap->pdev_dev, "Wrong bootcfg signature\n");
ret = -EINVAL;
goto out;
}
i = DIV_ROUND_UP(FLASH_BOOTCFG_MAX_SIZE,
sf_sec_size);
ret = t4_flash_erase_sectors(adap, flash_cfg_start_sec,
flash_cfg_start_sec + i - 1);
/**
* If size == 0 then we're simply erasing the FLASH sectors associated
* with the on-adapter OptionROM Configuration File.
*/
if (ret || size == 0)
goto out;
/* this will write to the flash up to SF_PAGE_SIZE at a time */
for (i = 0; i < size; i += SF_PAGE_SIZE) {
n = min_t(u32, size - i, SF_PAGE_SIZE);
ret = t4_write_flash(adap, addr, n, cfg_data, false);
if (ret)
goto out;
addr += SF_PAGE_SIZE;
cfg_data += SF_PAGE_SIZE;
}
npad = ((size + 4 - 1) & ~3) - size;
for (i = 0; i < npad; i++) {
u8 data = 0;
ret = t4_write_flash(adap, cfg_addr + size + i, 1, &data,
false);
if (ret)
goto out;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.