/* In T6, mailbox size is changed to 128 bytes to avoid *invalidatingtheentireprefetchbuffer.
*/ if (CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5)
mbox_data = T4VF_MBDATA_BASE_ADDR; else
mbox_data = T6VF_MBDATA_BASE_ADDR;
/* Queue ourselves onto the mailbox access list. When our entry is at *thefrontofthelist,wehaverightstoaccessthemailbox.Sowe *wait[forawhile]tillwe'reatthefront[orbailoutwithan *EBUSY]...
*/
spin_lock(&adapter->mbox_lock);
list_add_tail(&entry.list, &adapter->mlist.list);
spin_unlock(&adapter->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.Weveryrearely *contendonaccesstothemailbox...
*/ if (i > FW_CMD_MAX_TIMEOUT) {
spin_lock(&adapter->mbox_lock);
list_del(&entry.list);
spin_unlock(&adapter->mbox_lock);
ret = -EBUSY;
t4vf_record_mbox(adapter, cmd, size, access, ret); return ret;
}
/* If we're at the head, break out and start the mailbox *protocol.
*/ if (list_first_entry(&adapter->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);
}
}
/* *Looptryingtogetownershipofthemailbox.Returnanerror *ifwecan'tgainownership.
*/
v = MBOWNER_G(t4_read_reg(adapter, mbox_ctl)); for (i = 0; v == MBOX_OWNER_NONE && i < 3; i++)
v = MBOWNER_G(t4_read_reg(adapter, mbox_ctl)); if (v != MBOX_OWNER_DRV) {
spin_lock(&adapter->mbox_lock);
list_del(&entry.list);
spin_unlock(&adapter->mbox_lock);
ret = (v == MBOX_OWNER_FW) ? -EBUSY : -ETIMEDOUT;
t4vf_record_mbox(adapter, cmd, size, access, ret); return ret;
}
/* *WritethecommandarrayintotheMailboxDataregisterarrayand *transferownershipofthemailboxtothefirmware. * *FortheVFs,theMailboxData"registers"areactuallybackedby *T4's"MA"interfaceratherthanPLRegisters(asisthecasefor *thePFs).Becausetheseareindifferentcoherencydomains,the *writetotheVF'sPL-register-backedMailboxControlcanracein *frontofthewritestotheMA-backedVFMailboxData"registers". *Soweneedtodoaread-backonatleastonebyteoftheVFMailbox *DataregistersbeforedoingthewritetotheVFMailboxControl *register.
*/ if (cmd_op != FW_VI_STATS_CMD)
t4vf_record_mbox(adapter, cmd, size, access, 0); for (i = 0, p = cmd; i < size; i += 8)
t4_write_reg64(adapter, mbox_data + i, be64_to_cpu(*p++));
t4_read_reg(adapter, mbox_data); /* flush write */
/* *Spinwaitingforfirmwaretoacknowledgeprocessingourcommand.
*/
delay_idx = 0;
ms = delay[0];
for (i = 0; i < FW_CMD_MAX_TIMEOUT; i += ms) { if (sleep_ok) {
ms = delay[delay_idx]; if (delay_idx < ARRAY_SIZE(delay) - 1)
delay_idx++;
msleep(ms);
} else
mdelay(ms);
/* *Ifwe'retheowner,seeifthisisthereplywewanted.
*/
v = t4_read_reg(adapter, mbox_ctl); if (MBOWNER_G(v) == MBOX_OWNER_DRV) { /* *IftheMessageValidbitisn'ton,revokeownership *ofthemailboxandcontinuewaitingforourreply.
*/ if ((v & MBMSGVALID_F) == 0) {
t4_write_reg(adapter, mbox_ctl,
MBOWNER_V(MBOX_OWNER_NONE)); continue;
}
/* return value in low-order little-endian word */
v = be64_to_cpu(cmd_rpl[0]);
if (rpl) { /* request bit in high-order BE word */
WARN_ON((be32_to_cpu(*(const __be32 *)cmd)
& FW_CMD_REQUEST_F) == 0);
memcpy(rpl, cmd_rpl, size);
WARN_ON((be32_to_cpu(*(__be32 *)rpl)
& FW_CMD_REQUEST_F) != 0);
}
t4_write_reg(adapter, mbox_ctl,
MBOWNER_V(MBOX_OWNER_NONE));
execute = i + ms; if (cmd_op != FW_VI_STATS_CMD)
t4vf_record_mbox(adapter, cmd_rpl, size, access,
execute);
spin_lock(&adapter->mbox_lock);
list_del(&entry.list);
spin_unlock(&adapter->mbox_lock); return -FW_CMD_RETVAL_G(v);
}
}
/* We timed out. Return the error ... */
ret = -ETIMEDOUT;
t4vf_record_mbox(adapter, cmd, size, access, ret);
spin_lock(&adapter->mbox_lock);
list_del(&entry.list);
spin_unlock(&adapter->mbox_lock); return ret;
}
/* In the Physical Function Driver Common Code, the ADVERT_MASK is used to *maskoutbitsintheAdvertisedPortCapabilitieswhicharemanagedvia *separatecontrols,likePauseFramesandForwardErrorCorrection.Inthe *VirtualFunctionCommonCode,sinceweneverperformL1Configurationon *theLink,theonlythingswereallyneedtofilteroutarethingswhich *wedecodeandreportseparatelylikeSpeed.
*/ #define ADVERT_MASK (FW_PORT_CAP32_SPEED_V(FW_PORT_CAP32_SPEED_M) | \
FW_PORT_CAP32_802_3_PAUSE | \
FW_PORT_CAP32_802_3_ASM_DIR | \
FW_PORT_CAP32_FEC_V(FW_PORT_CAP32_FEC_M) | \
FW_PORT_CAP32_ANEG)
if (fw_fec & FW_PORT_CAP32_FEC_RS)
cc_fec |= FEC_RS; if (fw_fec & FW_PORT_CAP32_FEC_BASER_RS)
cc_fec |= FEC_BASER_RS;
return cc_fec;
}
/* 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)
/* Extract the various fields from the Port Information message. */ if (fw_caps == FW_CAPS16) {
u32 lstatus = be32_to_cpu(port_rpl.u.info.lstatus_to_modtype);
memset(&cmd, 0, sizeof(cmd));
cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_PARAMS_CMD) |
FW_CMD_REQUEST_F |
FW_CMD_READ_F);
len16 = DIV_ROUND_UP(offsetof(struct fw_params_cmd,
param[nparams].mnem), 16);
cmd.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(len16)); for (i = 0, p = &cmd.param[0]; i < nparams; i++, p++)
p->mnem = htonl(*params++);
ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl); if (ret == 0) for (i = 0, p = &rpl.param[0]; i < nparams; i++, p++)
*vals++ = be32_to_cpu(p->val); 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(adapter->params.chip) <= CHELSIO_T5)
ingpad_shift = INGPADBOUNDARY_SHIFT_X; else
ingpad_shift = T6_INGPADBOUNDARY_SHIFT_X;
fl_align = ingpadboundary; if (!is_t4(adapter->params.chip)) { /* T5 has a different interpretation of one of the PCIe Packing *Boundaryvalues.
*/
sge_control2 = adapter->params.sge.sge_control2;
ingpackboundary = INGPACKBOUNDARY_G(sge_control2); if (ingpackboundary == INGPACKBOUNDARY_16B_X)
ingpackboundary = 16; else
ingpackboundary = 1 << (ingpackboundary +
INGPACKBOUNDARY_SHIFT_X);
/* If the BAR2 Queue ID Offset is less than the Page Size, then the *hardwarewillinfertheAbsoluteQueueIDsimplyfromthewritesto *theBAR2QueueIDOffsetwithintheBAR2Page(andweneedtousea *BAR2QueueIDof0forthosewrites).Otherwise,we'llsimply *writetothefirstBAR2SGEQueueAreawithintheBAR2Pagewith *theBAR2QueueIDandthehardwarewillinfertheAbsoluteQueueID *fromtheBAR2PageandBAR2QueueID. * *OneimportantcensequenceofthisisthatsomeBAR2SGEregisters *havea"QueueID"fieldandwecanwritetheBAR2SGEQueueID *there.ButotherregisterssynthesizetheSGEQueueIDpurely *fromthewritestotheregisters--theWriteCombinedDoorbell *Bufferisagoodexample.TheseBAR2SGERegistersareonly *availableforthoseBAR2SGERegisterareaswheretheSGEAbsolute *QueueIDcanbeinferredfromsimplewrites.
*/
bar2_qoffset = bar2_page_offset;
bar2_qinferred = (bar2_qid_offset < page_size); if (bar2_qinferred) {
bar2_qoffset += bar2_qid_offset;
bar2_qid = 0;
}
/* T4 uses a single control field to specify both the PCIe Padding and *PackingBoundary.T5introducedtheabilitytospecifythese *separatelywiththePaddingBoundaryinSGE_CONTROLandPacking *BoundaryinSGE_CONTROL2.SoforT5andlaterweneedtograb *SGE_CONTROLinordertodeterminehowingresspacketdatawillbe *laidoutinPackedBufferMode.Unfortunately,olderversionsof *thefirmwarewon'tletusretrieveSGE_CONTROL2soifwegeta *failuregrabbingitwethrowanerrorsincewecan'tfigureoutthe *rightvalue.
*/ if (!is_t4(adapter->params.chip)) {
params[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) |
FW_PARAMS_PARAM_XYZ_V(SGE_CONTROL2_A));
v = t4vf_query_params(adapter, 1, params, vals); if (v != FW_SUCCESS) {
dev_err(adapter->pdev_dev, "Unable to get SGE Control2; " "probably old firmware.\n"); return v;
}
sge_params->sge_control2 = vals[0];
}
/* For T5 and later we want to use the new BAR2 Doorbells. *Unfortunately,olderfirmwaredidn'tallowthethisregistertobe *read.
*/ if (!is_t4(adapter->params.chip)) { unsignedint pf, s_hps, s_qpp;
params[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) |
FW_PARAMS_PARAM_XYZ_V(
SGE_EGRESS_QUEUES_PER_PAGE_VF_A));
params[1] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) |
FW_PARAMS_PARAM_XYZ_V(
SGE_INGRESS_QUEUES_PER_PAGE_VF_A));
v = t4vf_query_params(adapter, 2, params, vals); if (v != FW_SUCCESS) {
dev_warn(adapter->pdev_dev, "Unable to get VF SGE Queues/Page; " "probably old firmware.\n"); return v;
}
sge_params->sge_egress_queues_per_page = vals[0];
sge_params->sge_ingress_queues_per_page = vals[1];
/* We need the Queues/Page for our VF. This is based on the *PFfromwhichwe'reinstantiatedandisindexedinthe *registerwejustread.Doitonceheresoothercodein *thedrivercanjustuseit.
*/
pf = t4vf_get_pf_from_vf(adapter);
s_hps = (HOSTPAGESIZEPF0_S +
(HOSTPAGESIZEPF1_S - HOSTPAGESIZEPF0_S) * pf);
sge_params->sge_vf_hps =
((sge_params->sge_host_page_size >> s_hps)
& HOSTPAGESIZEPF0_M);
if (config->basicvirtual.ip6fourtupen)
word |= FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN_F; if (config->basicvirtual.ip6twotupen)
word |= FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN_F; if (config->basicvirtual.ip4fourtupen)
word |= FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN_F; if (config->basicvirtual.ip4twotupen)
word |= FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN_F; if (config->basicvirtual.udpen)
word |= FW_RSS_VI_CONFIG_CMD_UDPEN_F;
word |= FW_RSS_VI_CONFIG_CMD_DEFAULTQ_V(
config->basicvirtual.defaultq);
cmd.u.basicvirtual.defaultq_to_udpen = cpu_to_be32(word); break;
}
for (i = 0, p = cmd.u.exact; i < (int)fw_naddr; i++, p++) {
p->valid_to_idx = cpu_to_be16(
FW_VI_MAC_CMD_VALID_F |
FW_VI_MAC_CMD_IDX_V(FW_VI_MAC_MAC_BASED_FREE));
memcpy(p->macaddr, addr[offset+i], sizeof(p->macaddr));
}
ret = t4vf_wr_mbox_core(adapter, &cmd, sizeof(cmd), &cmd,
sleep_ok);
if (ret)
break;
for (i = 0, p = cmd.u.exact; i < fw_naddr; i++, p++) {
u16 index = FW_VI_MAC_CMD_IDX_G(
be16_to_cpu(p->valid_to_idx));
if (index < max_naddr)
nfilters++;
}
offset += fw_naddr;
rem -= fw_naddr;
}
if (ret == 0)
ret = nfilters;
return ret;
}
/**
* t4vf_change_mac - modifies the exact-match filter for a MAC address
* @adapter: the adapter
* @viid: the Virtual Interface ID
* @idx: index of existing filter for old value of MAC address, or -1
* @addr: the new MAC address value
* @persist: if idx < 0, the new MAC allocation should be persistent
*
* Modifies an exact-match filter and sets it to the new MAC address.
* Note that in general it is not possible to modify the value of a given
* filter so the generic way to modify an address filter is to free the
* one being used by the old address value and allocate a new filter for
* the new address value. @idx can be -1 if the address is a new
* addition.
*
* Returns a negative error number or the index of the filter with the new
* MAC value.
*/
int t4vf_change_mac(struct adapter *adapter, unsigned int viid,
int idx, const u8 *addr, bool persist)
{
int ret;
struct fw_vi_mac_cmd cmd, rpl;
struct fw_vi_mac_exact *p = &cmd.u.exact[0];
size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd,
u.exact[1]), 16);
unsigned int max_mac_addr = adapter->params.arch.mps_tcam_size;
/*
* If this is a new allocation, determine whether it should be
* persistent (across a "freemacs" operation) or not.
*/
if (idx < 0)
idx = persist ? FW_VI_MAC_ADD_PERSIST_MAC : FW_VI_MAC_ADD_MAC;
ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl);
if (ret == 0) {
p = &rpl.u.exact[0];
ret = FW_VI_MAC_CMD_IDX_G(be16_to_cpu(p->valid_to_idx));
if (ret >= max_mac_addr)
ret = -ENOMEM;
}
return ret;
}
/**
* t4vf_set_addr_hash - program the MAC inexact-match hash filter
* @adapter: the adapter
* @viid: the Virtual Interface Identifier
* @ucast: whether the hash filter should also match unicast addresses
* @vec: the value to be written to the hash filter
* @sleep_ok: call is allowed to sleep
*
* Sets the 64-bit inexact-match hash filter for a virtual interface.
*/
int t4vf_set_addr_hash(struct adapter *adapter, unsigned int viid,
bool ucast, u64 vec, bool sleep_ok)
{
struct fw_vi_mac_cmd cmd;
size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd,
u.exact[0]), 16);
/**
* t4vf_get_port_stats - collect "port" statistics
* @adapter: the adapter
* @pidx: the port index
* @s: the stats structure to fill
*
* Collect statistics for the "port"'s Virtual Interface.
*/
int t4vf_get_port_stats(struct adapter *adapter, int pidx,
struct t4vf_port_stats *s)
{
struct port_info *pi = adap2pinfo(adapter, pidx);
struct fw_vi_stats_vf fwstats;
unsigned int rem = VI_VF_NUM_STATS;
__be64 *fwsp = (__be64 *)&fwstats;
/*
* Grab the Virtual Interface statistics a chunk at a time via mailbox
* commands. We could use a Work Request and get all of them at once
* but that's an asynchronous interface which is awkward to use.
*/
while (rem) {
unsigned int ix = VI_VF_NUM_STATS - rem;
unsigned int nstats = min(6U, rem);
struct fw_vi_stats_cmd cmd, rpl;
size_t len = (offsetof(struct fw_vi_stats_cmd, u) +
sizeof(struct fw_vi_stats_ctl));
size_t len16 = DIV_ROUND_UP(len, 16);
int ret;
/**
* t4vf_iq_free - free an ingress queue and its free lists
* @adapter: the adapter
* @iqtype: the ingress queue type (FW_IQ_TYPE_FL_INT_CAP, etc.)
* @iqid: ingress queue ID
* @fl0id: FL0 queue ID or 0xffff if no attached FL0
* @fl1id: FL1 queue ID or 0xffff if no attached FL1
*
* Frees an ingress queue and its associated free lists, if any.
*/
int t4vf_iq_free(struct adapter *adapter, unsigned int iqtype,
unsigned int iqid, unsigned int fl0id, unsigned int fl1id)
{
struct fw_iq_cmd cmd;
/**
* t4vf_link_down_rc_str - return a string for a Link Down Reason Code
* @link_down_rc: Link Down Reason Code
*
* Returns a string representation of the Link Down Reason Code.
*/
static const char *t4vf_link_down_rc_str(unsigned char link_down_rc)
{
static const char * const reason[] = {
"Link Down",
"Remote Fault",
"Auto-negotiation Failure",
"Reserved",
"Insufficient Airflow",
"Unable To Determine Reason",
"No RX Signal Detected",
"Reserved",
};
if (link_down_rc >= ARRAY_SIZE(reason))
return "Bad Reason Code";
return reason[link_down_rc];
}
/**
* t4vf_handle_get_port_info - process a FW reply message
* @pi: the port info
* @cmd: start of the FW message
*
* Processes a GET_PORT_INFO FW reply message.
*/
static void t4vf_handle_get_port_info(struct port_info *pi,
const struct fw_port_cmd *cmd)
{
fw_port_cap32_t pcaps, acaps, lpacaps, linkattr;
struct link_config *lc = &pi->link_cfg;
struct adapter *adapter = pi->adapter;
unsigned int speed, fc, fec, adv_fc;
enum fw_port_module_type mod_type;
int action, link_ok, linkdnrc;
enum fw_port_type port_type;
/* Extract the various fields from the Port Information message. */
action = FW_PORT_CMD_ACTION_G(be32_to_cpu(cmd->action_to_len16));
switch (action) {
case FW_PORT_ACTION_GET_PORT_INFO: {
u32 lstatus = be32_to_cpu(cmd->u.info.lstatus_to_modtype);
/* Unfortunately the format of the Link Status in the old
* 16-bit Port Information message isn't the same as the
* 16-bit Port Capabilities bitfield used everywhere else ...
*/
linkattr = 0;
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;
break;
}
case FW_PORT_ACTION_GET_PORT_INFO32: {
u32 lstatus32;
if (mod_type != pi->mod_type) {
/* When a new Transceiver Module is inserted, the Firmware
* will examine any Forward Error Correction parameters
* present in the Transceiver Module i2c EPROM and determine
* the supported and recommended FEC settings from those
* based on IEEE 802.3 standards. We always record the
* IEEE 802.3 recommended "automatic" settings.
*/
lc->auto_fec = fec;
/* Some versions of the early T6 Firmware "cheated" when
* handling different Transceiver Modules by changing the
* underlaying Port Type reported to the Host Drivers. As
* such we need to capture whatever Port Type the Firmware
* sends us and record it in case it's different from what we
* were told earlier. Unfortunately, since Firmware is
* forever, we'll need to keep this code here forever, but in
* later T6 Firmware it should just be an assignment of the
* same value already recorded.
*/
pi->port_type = port_type;
/* If we're not physically capable of Auto-Negotiation, note
* this as Auto-Negotiation disabled. Otherwise, we track
* what Auto-Negotiation settings we have. Note parallel
* structure in init_link_config().
*/
if (!(lc->pcaps & FW_PORT_CAP32_ANEG)) {
lc->autoneg = AUTONEG_DISABLE;
} else if (lc->acaps & FW_PORT_CAP32_ANEG) {
lc->autoneg = AUTONEG_ENABLE;
} else {
/* When Autoneg is disabled, user needs to set
* single speed.
* Similar to cxgb4_ethtool.c: set_link_ksettings
*/
lc->acaps = 0;
lc->speed_caps = fwcap_to_speed(acaps);
lc->autoneg = AUTONEG_DISABLE;
}
/**
* t4vf_update_port_info - retrieve and update port information if changed
* @pi: the port_info
*
* We issue a Get Port Information Command to the Firmware and, if
* successful, we check to see if anything is different from what we
* last recorded and update things accordingly.
*/
int t4vf_update_port_info(struct port_info *pi)
{
unsigned int fw_caps = pi->adapter->params.fw_caps_support;
struct fw_port_cmd port_cmd;
int ret;
/**
* t4vf_handle_fw_rpl - process a firmware reply message
* @adapter: the adapter
* @rpl: start of the firmware message
*
* Processes a firmware message, such as link state change messages.
*/
int t4vf_handle_fw_rpl(struct adapter *adapter, const __be64 *rpl)
{
const struct fw_cmd_hdr *cmd_hdr = (const struct fw_cmd_hdr *)rpl;
u8 opcode = FW_CMD_OP_G(be32_to_cpu(cmd_hdr->hi));
switch (opcode) {
case FW_PORT_CMD: {
/*
* Link/module state change message.
*/
const struct fw_port_cmd *port_cmd =
(const struct fw_port_cmd *)rpl;
int action = FW_PORT_CMD_ACTION_G(
be32_to_cpu(port_cmd->action_to_len16));
int port_id, pidx;
if (action != FW_PORT_ACTION_GET_PORT_INFO &&
action != FW_PORT_ACTION_GET_PORT_INFO32) {
dev_err(adapter->pdev_dev,
"Unknown firmware PORT reply action %x\n",
action);
break;
}
int t4vf_prep_adapter(struct adapter *adapter)
{
int err;
unsigned int chipid;
/* Wait for the device to become ready before proceeding ...
*/
err = t4vf_wait_dev_ready(adapter);
if (err)
return err;
/* Default port and clock for debugging in case we can't reach
* firmware.
*/
adapter->params.nports = 1;
adapter->params.vfres.pmask = 1;
adapter->params.vpd.cclk = 50000;
/**
* t4vf_get_vf_mac_acl - Get the MAC address to be set to
* the VI of this VF.
* @adapter: The adapter
* @port: The port associated with vf
* @naddr: the number of ACL MAC addresses returned in addr
* @addr: Placeholder for MAC addresses
*
* Find the MAC address to be set to the VF's VI. The requested MAC address
* is from the host OS via callback in the PF driver.
*/
int t4vf_get_vf_mac_acl(struct adapter *adapter, unsigned int port,
unsigned int *naddr, u8 *addr)
{
struct fw_acl_mac_cmd cmd;
int ret;
switch (port) {
case 3:
memcpy(addr, cmd.macaddr3, sizeof(cmd.macaddr3));
break;
case 2:
memcpy(addr, cmd.macaddr2, sizeof(cmd.macaddr2));
break;
case 1:
memcpy(addr, cmd.macaddr1, sizeof(cmd.macaddr1));
break;
case 0:
memcpy(addr, cmd.macaddr0, sizeof(cmd.macaddr0));
break;
}
return ret;
}
/**
* t4vf_get_vf_vlan_acl - Get the VLAN ID to be set to
* the VI of this VF.
* @adapter: The adapter
*
* Find the VLAN ID to be set to the VF's VI. The requested VLAN ID
* is from the host OS via callback in the PF driver.
*/
int t4vf_get_vf_vlan_acl(struct adapter *adapter)
{
struct fw_acl_vlan_cmd cmd;
int vlan = 0;
int ret = 0;
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.