X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fcxgbe%2Fbase%2Ft4_hw.c;h=7ebf4a9a703553600f3c0a6ca9e4438a926f98ba;hb=520e3f4888c508dad32da1d8c5486a7be9b0fbba;hp=e5ef73b674df877eee515955033088baf1d63a93;hpb=2aa5c722c64af2e810c10592edce339b0378f86f;p=dpdk.git diff --git a/drivers/net/cxgbe/base/t4_hw.c b/drivers/net/cxgbe/base/t4_hw.c index e5ef73b674..7ebf4a9a70 100644 --- a/drivers/net/cxgbe/base/t4_hw.c +++ b/drivers/net/cxgbe/base/t4_hw.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include @@ -246,7 +246,7 @@ static void get_mbox_rpl(struct adapter *adap, __be64 *rpl, int nflit, u32 mbox_addr) { for ( ; nflit; nflit--, mbox_addr += 8) - *rpl++ = htobe64(t4_read_reg64(adap, mbox_addr)); + *rpl++ = cpu_to_be64(t4_read_reg64(adap, mbox_addr)); } /* @@ -335,7 +335,7 @@ int t4_wr_mbox_meat_timeout(struct adapter *adap, int mbox, return -EINVAL; } - bzero(p, size); + memset(p, 0, size); memcpy(p, (const __be64 *)cmd, size); /* @@ -2480,6 +2480,50 @@ int t4_get_core_clock(struct adapter *adapter, struct vpd_params *p) return 0; } +/** + * t4_get_pfres - retrieve VF resource limits + * @adapter: the adapter + * + * Retrieves configured resource limits and capabilities for a physical + * function. The results are stored in @adapter->pfres. + */ +int t4_get_pfres(struct adapter *adapter) +{ + struct pf_resources *pfres = &adapter->params.pfres; + struct fw_pfvf_cmd cmd, rpl; + u32 word; + int v; + + /* + * Execute PFVF Read command to get VF resource limits; bail out early + * with error on command failure. + */ + memset(&cmd, 0, sizeof(cmd)); + cmd.op_to_vfn = cpu_to_be32(V_FW_CMD_OP(FW_PFVF_CMD) | + F_FW_CMD_REQUEST | + F_FW_CMD_READ | + V_FW_PFVF_CMD_PFN(adapter->pf) | + V_FW_PFVF_CMD_VFN(0)); + cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd)); + v = t4_wr_mbox(adapter, adapter->mbox, &cmd, sizeof(cmd), &rpl); + if (v != FW_SUCCESS) + return v; + + /* + * Extract PF resource limits and return success. + */ + word = be32_to_cpu(rpl.niqflint_niq); + pfres->niqflint = G_FW_PFVF_CMD_NIQFLINT(word); + + word = be32_to_cpu(rpl.type_to_neq); + pfres->neq = G_FW_PFVF_CMD_NEQ(word); + + word = be32_to_cpu(rpl.r_caps_to_nethctrl); + pfres->nethctrl = G_FW_PFVF_CMD_NETHCTRL(word); + + return 0; +} + /* serial flash and firmware constants and flash config file constants */ enum { SF_ATTEMPTS = 10, /* max retries for SF operations */ @@ -2765,142 +2809,11 @@ void t4_dump_version_info(struct adapter *adapter) G_FW_HDR_FW_VER_BUILD(adapter->params.er_vers)); } -#define ADVERT_MASK (V_FW_PORT_CAP32_SPEED(M_FW_PORT_CAP32_SPEED) | \ - FW_PORT_CAP32_ANEG) -/** - * fwcaps16_to_caps32 - convert 16-bit Port Capabilities to 32-bits - * @caps16: a 16-bit Port Capabilities value - * - * Returns the equivalent 32-bit Port Capabilities value. - */ -fw_port_cap32_t fwcaps16_to_caps32(fw_port_cap16_t caps16) -{ - fw_port_cap32_t caps32 = 0; - -#define CAP16_TO_CAP32(__cap) \ - do { \ - if (caps16 & FW_PORT_CAP_##__cap) \ - caps32 |= FW_PORT_CAP32_##__cap; \ - } while (0) - - CAP16_TO_CAP32(SPEED_100M); - CAP16_TO_CAP32(SPEED_1G); - CAP16_TO_CAP32(SPEED_25G); - CAP16_TO_CAP32(SPEED_10G); - CAP16_TO_CAP32(SPEED_40G); - CAP16_TO_CAP32(SPEED_100G); - CAP16_TO_CAP32(FC_RX); - CAP16_TO_CAP32(FC_TX); - CAP16_TO_CAP32(ANEG); - CAP16_TO_CAP32(MDIX); - CAP16_TO_CAP32(MDIAUTO); - CAP16_TO_CAP32(FEC_RS); - CAP16_TO_CAP32(FEC_BASER_RS); - CAP16_TO_CAP32(802_3_PAUSE); - CAP16_TO_CAP32(802_3_ASM_DIR); - -#undef CAP16_TO_CAP32 - - return caps32; -} - -/** - * fwcaps32_to_caps16 - convert 32-bit Port Capabilities to 16-bits - * @caps32: a 32-bit Port Capabilities value - * - * Returns the equivalent 16-bit Port Capabilities value. Note that - * not all 32-bit Port Capabilities can be represented in the 16-bit - * Port Capabilities and some fields/values may not make it. - */ -static fw_port_cap16_t fwcaps32_to_caps16(fw_port_cap32_t caps32) -{ - fw_port_cap16_t caps16 = 0; - -#define CAP32_TO_CAP16(__cap) \ - do { \ - if (caps32 & FW_PORT_CAP32_##__cap) \ - caps16 |= FW_PORT_CAP_##__cap; \ - } while (0) - - CAP32_TO_CAP16(SPEED_100M); - CAP32_TO_CAP16(SPEED_1G); - CAP32_TO_CAP16(SPEED_10G); - CAP32_TO_CAP16(SPEED_25G); - CAP32_TO_CAP16(SPEED_40G); - CAP32_TO_CAP16(SPEED_100G); - CAP32_TO_CAP16(FC_RX); - CAP32_TO_CAP16(FC_TX); - CAP32_TO_CAP16(802_3_PAUSE); - CAP32_TO_CAP16(802_3_ASM_DIR); - CAP32_TO_CAP16(ANEG); - CAP32_TO_CAP16(MDIX); - CAP32_TO_CAP16(MDIAUTO); - CAP32_TO_CAP16(FEC_RS); - CAP32_TO_CAP16(FEC_BASER_RS); - -#undef CAP32_TO_CAP16 - - return caps16; -} - -/* Translate Firmware Pause specification to Common Code */ -static inline enum cc_pause fwcap_to_cc_pause(fw_port_cap32_t fw_pause) -{ - enum cc_pause cc_pause = 0; - - if (fw_pause & FW_PORT_CAP32_FC_RX) - cc_pause |= PAUSE_RX; - if (fw_pause & FW_PORT_CAP32_FC_TX) - cc_pause |= PAUSE_TX; - - return cc_pause; -} - -/* Translate Common Code Pause Frame specification into Firmware */ -static inline fw_port_cap32_t cc_to_fwcap_pause(enum cc_pause cc_pause) -{ - fw_port_cap32_t fw_pause = 0; - - if (cc_pause & PAUSE_RX) - fw_pause |= FW_PORT_CAP32_FC_RX; - if (cc_pause & PAUSE_TX) - fw_pause |= FW_PORT_CAP32_FC_TX; - - return fw_pause; -} - -/* Translate Firmware Forward Error Correction specification to Common Code */ -static inline enum cc_fec fwcap_to_cc_fec(fw_port_cap32_t fw_fec) -{ - enum cc_fec cc_fec = 0; - - 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; -} - -/* Translate Common Code Forward Error Correction specification to Firmware */ -static inline fw_port_cap32_t cc_to_fwcap_fec(enum cc_fec cc_fec) -{ - fw_port_cap32_t fw_fec = 0; - - if (cc_fec & FEC_RS) - fw_fec |= FW_PORT_CAP32_FEC_RS; - if (cc_fec & FEC_BASER_RS) - fw_fec |= FW_PORT_CAP32_FEC_BASER_RS; - - return fw_fec; -} - /** - * t4_link_l1cfg - apply link configuration to MAC/PHY - * @adapter: the adapter - * @mbox: the Firmware Mailbox to use - * @port: the Port ID - * @lc: the Port's Link Configuration + * t4_link_l1cfg_core - apply link configuration to MAC/PHY + * @pi: the port info + * @caps: link capabilities to configure + * @sleep_ok: if true we may sleep while awaiting command completion * * Set up a port's MAC and PHY according to a desired link configuration. * - If the PHY can auto-negotiate first decide what to advertise, then @@ -2909,63 +2822,36 @@ static inline fw_port_cap32_t cc_to_fwcap_fec(enum cc_fec cc_fec) * - If auto-negotiation is off set the MAC to the proper speed/duplex/FC, * otherwise do it later based on the outcome of auto-negotiation. */ -int t4_link_l1cfg(struct adapter *adap, unsigned int mbox, unsigned int port, - struct link_config *lc) +int t4_link_l1cfg_core(struct port_info *pi, u32 caps, u8 sleep_ok) { - unsigned int fw_mdi = V_FW_PORT_CAP32_MDI(FW_PORT_CAP32_MDI_AUTO); - unsigned int fw_caps = adap->params.fw_caps_support; - fw_port_cap32_t fw_fc, cc_fec, fw_fec, rcap; + struct link_config *lc = &pi->link_cfg; + struct adapter *adap = pi->adapter; struct fw_port_cmd cmd; + int ret; - lc->link_ok = 0; - - fw_fc = cc_to_fwcap_pause(lc->requested_fc); - - /* Convert Common Code Forward Error Control settings into the - * Firmware's API. If the current Requested FEC has "Automatic" - * (IEEE 802.3) specified, then we use whatever the Firmware - * sent us as part of it's IEEE 802.3-based interpratation of - * the Transceiver Module EPROM FEC parameters. Otherwise we - * use whatever is in the current Requested FEC settings. - */ - if (lc->requested_fec & FEC_AUTO) - cc_fec = lc->auto_fec; - else - cc_fec = lc->requested_fec; - fw_fec = cc_to_fwcap_fec(cc_fec); - - /* Figure out what our Requested Port Capabilities are going to be. - */ - if (!(lc->pcaps & FW_PORT_CAP32_ANEG)) { - rcap = (lc->pcaps & ADVERT_MASK) | fw_fc | fw_fec; - lc->fc = lc->requested_fc & ~PAUSE_AUTONEG; - lc->fec = cc_fec; - } else if (lc->autoneg == AUTONEG_DISABLE) { - rcap = lc->requested_speed | fw_fc | fw_fec | fw_mdi; - lc->fc = lc->requested_fc & ~PAUSE_AUTONEG; - lc->fec = cc_fec; - } else { - rcap = lc->acaps | fw_fc | fw_fec | fw_mdi; - } - - /* And send that on to the Firmware ... - */ memset(&cmd, 0, sizeof(cmd)); cmd.op_to_portid = cpu_to_be32(V_FW_CMD_OP(FW_PORT_CMD) | F_FW_CMD_REQUEST | F_FW_CMD_EXEC | - V_FW_PORT_CMD_PORTID(port)); + V_FW_PORT_CMD_PORTID(pi->port_id)); cmd.action_to_len16 = - cpu_to_be32(V_FW_PORT_CMD_ACTION(fw_caps == FW_CAPS16 ? - FW_PORT_ACTION_L1_CFG : - FW_PORT_ACTION_L1_CFG32) | + cpu_to_be32(V_FW_PORT_CMD_ACTION(FW_PORT_ACTION_L1_CFG32) | FW_LEN16(cmd)); - if (fw_caps == FW_CAPS16) - cmd.u.l1cfg.rcap = cpu_to_be32(fwcaps32_to_caps16(rcap)); + cmd.u.l1cfg32.rcap32 = cpu_to_be32(caps); + + if (sleep_ok) + ret = t4_wr_mbox(adap, adap->mbox, &cmd, sizeof(cmd), NULL); + else + ret = t4_wr_mbox_ns(adap, adap->mbox, &cmd, sizeof(cmd), NULL); + + if (ret == FW_SUCCESS) + lc->link_caps = caps; else - cmd.u.l1cfg32.rcap32 = cpu_to_be32(rcap); + dev_err(adap, + "Requested Port Capabilities %#x rejected, error %d\n", + caps, ret); - return t4_wr_mbox(adap, mbox, &cmd, sizeof(cmd), NULL); + return ret; } /** @@ -3977,7 +3863,8 @@ int t4_set_params(struct adapter *adap, unsigned int mbox, unsigned int pf, int t4_alloc_vi_func(struct adapter *adap, unsigned int mbox, unsigned int port, unsigned int pf, unsigned int vf, unsigned int nmac, u8 *mac, unsigned int *rss_size, - unsigned int portfunc, unsigned int idstype) + unsigned int portfunc, unsigned int idstype, + u8 *vivld, u8 *vin) { int ret; struct fw_vi_cmd c; @@ -4015,6 +3902,10 @@ int t4_alloc_vi_func(struct adapter *adap, unsigned int mbox, } if (rss_size) *rss_size = G_FW_VI_CMD_RSSSIZE(be16_to_cpu(c.norss_rsssize)); + if (vivld) + *vivld = G_FW_VI_CMD_VFVLD(be32_to_cpu(c.alloc_to_len16)); + if (vin) + *vin = G_FW_VI_CMD_VIN(be32_to_cpu(c.alloc_to_len16)); return G_FW_VI_CMD_VIID(cpu_to_be16(c.type_to_viid)); } @@ -4035,10 +3926,10 @@ int t4_alloc_vi_func(struct adapter *adap, unsigned int mbox, */ int t4_alloc_vi(struct adapter *adap, unsigned int mbox, unsigned int port, unsigned int pf, unsigned int vf, unsigned int nmac, u8 *mac, - unsigned int *rss_size) + unsigned int *rss_size, u8 *vivld, u8 *vin) { return t4_alloc_vi_func(adap, mbox, port, pf, vf, nmac, mac, rss_size, - FW_VI_FUNC_ETH, 0); + FW_VI_FUNC_ETH, 0, vivld, vin); } /** @@ -4121,6 +4012,112 @@ int t4_set_rxmode(struct adapter *adap, unsigned int mbox, unsigned int viid, return t4vf_wr_mbox(adap, &c, sizeof(c), NULL); } +/** + * t4_alloc_raw_mac_filt - Adds a raw mac entry in mps tcam + * @adap: the adapter + * @viid: the VI id + * @mac: the MAC address + * @mask: the mask + * @idx: index at which to add this entry + * @port_id: the port index + * @lookup_type: MAC address for inner (1) or outer (0) header + * @sleep_ok: call is allowed to sleep + * + * Adds the mac entry at the specified index using raw mac interface. + * + * Returns a negative error number or the allocated index for this mac. + */ +int t4_alloc_raw_mac_filt(struct adapter *adap, unsigned int viid, + const u8 *addr, const u8 *mask, unsigned int idx, + u8 lookup_type, u8 port_id, bool sleep_ok) +{ + int ret = 0; + struct fw_vi_mac_cmd c; + struct fw_vi_mac_raw *p = &c.u.raw; + u32 val; + + memset(&c, 0, sizeof(c)); + c.op_to_viid = cpu_to_be32(V_FW_CMD_OP(FW_VI_MAC_CMD) | + F_FW_CMD_REQUEST | F_FW_CMD_WRITE | + V_FW_VI_MAC_CMD_VIID(viid)); + val = V_FW_CMD_LEN16(1) | + V_FW_VI_MAC_CMD_ENTRY_TYPE(FW_VI_MAC_TYPE_RAW); + c.freemacs_to_len16 = cpu_to_be32(val); + + /* Specify that this is an inner mac address */ + p->raw_idx_pkd = cpu_to_be32(V_FW_VI_MAC_CMD_RAW_IDX(idx)); + + /* Lookup Type. Outer header: 0, Inner header: 1 */ + p->data0_pkd = cpu_to_be32(V_DATALKPTYPE(lookup_type) | + V_DATAPORTNUM(port_id)); + /* Lookup mask and port mask */ + p->data0m_pkd = cpu_to_be64(V_DATALKPTYPE(M_DATALKPTYPE) | + V_DATAPORTNUM(M_DATAPORTNUM)); + + /* Copy the address and the mask */ + memcpy((u8 *)&p->data1[0] + 2, addr, ETHER_ADDR_LEN); + memcpy((u8 *)&p->data1m[0] + 2, mask, ETHER_ADDR_LEN); + + ret = t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, sleep_ok); + if (ret == 0) { + ret = G_FW_VI_MAC_CMD_RAW_IDX(be32_to_cpu(p->raw_idx_pkd)); + if (ret != (int)idx) + ret = -ENOMEM; + } + + return ret; +} + +/** + * t4_free_raw_mac_filt - Frees a raw mac entry in mps tcam + * @adap: the adapter + * @viid: the VI id + * @addr: the MAC address + * @mask: the mask + * @idx: index of the entry in mps tcam + * @lookup_type: MAC address for inner (1) or outer (0) header + * @port_id: the port index + * @sleep_ok: call is allowed to sleep + * + * Removes the mac entry at the specified index using raw mac interface. + * + * Returns a negative error number on failure. + */ +int t4_free_raw_mac_filt(struct adapter *adap, unsigned int viid, + const u8 *addr, const u8 *mask, unsigned int idx, + u8 lookup_type, u8 port_id, bool sleep_ok) +{ + struct fw_vi_mac_cmd c; + struct fw_vi_mac_raw *p = &c.u.raw; + u32 raw; + + memset(&c, 0, sizeof(c)); + c.op_to_viid = cpu_to_be32(V_FW_CMD_OP(FW_VI_MAC_CMD) | + F_FW_CMD_REQUEST | F_FW_CMD_WRITE | + V_FW_CMD_EXEC(0) | + V_FW_VI_MAC_CMD_VIID(viid)); + raw = V_FW_VI_MAC_CMD_ENTRY_TYPE(FW_VI_MAC_TYPE_RAW); + c.freemacs_to_len16 = cpu_to_be32(V_FW_VI_MAC_CMD_FREEMACS(0U) | + raw | + V_FW_CMD_LEN16(1)); + + p->raw_idx_pkd = cpu_to_be32(V_FW_VI_MAC_CMD_RAW_IDX(idx) | + FW_VI_MAC_ID_BASED_FREE); + + /* Lookup Type. Outer header: 0, Inner header: 1 */ + p->data0_pkd = cpu_to_be32(V_DATALKPTYPE(lookup_type) | + V_DATAPORTNUM(port_id)); + /* Lookup mask and port mask */ + p->data0m_pkd = cpu_to_be64(V_DATALKPTYPE(M_DATALKPTYPE) | + V_DATAPORTNUM(M_DATAPORTNUM)); + + /* Copy the address and the mask */ + memcpy((u8 *)&p->data1[0] + 2, addr, ETHER_ADDR_LEN); + memcpy((u8 *)&p->data1m[0] + 2, mask, ETHER_ADDR_LEN); + + return t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, sleep_ok); +} + /** * t4_change_mac - modifies the exact-match filter for a MAC address * @adap: the adapter @@ -4352,8 +4349,32 @@ static const char *t4_link_down_rc_str(unsigned char link_down_rc) return reason[link_down_rc]; } +static u32 t4_speed_to_fwcap(u32 speed) +{ + switch (speed) { + case 100000: + return FW_PORT_CAP32_SPEED_100G; + case 50000: + return FW_PORT_CAP32_SPEED_50G; + case 40000: + return FW_PORT_CAP32_SPEED_40G; + case 25000: + return FW_PORT_CAP32_SPEED_25G; + case 10000: + return FW_PORT_CAP32_SPEED_10G; + case 1000: + return FW_PORT_CAP32_SPEED_1G; + case 100: + return FW_PORT_CAP32_SPEED_100M; + default: + break; + } + + return 0; +} + /* Return the highest speed set in the port capabilities, in Mb/s. */ -static unsigned int fwcap_to_speed(fw_port_cap32_t caps) +unsigned int t4_fwcap_to_speed(u32 caps) { #define TEST_SPEED_RETURN(__caps_speed, __speed) \ do { \ @@ -4374,6 +4395,154 @@ static unsigned int fwcap_to_speed(fw_port_cap32_t caps) return 0; } +static void t4_set_link_autoneg_speed(struct port_info *pi, u32 *new_caps) +{ + struct link_config *lc = &pi->link_cfg; + u32 caps = *new_caps; + + caps &= ~V_FW_PORT_CAP32_SPEED(M_FW_PORT_CAP32_SPEED); + caps |= G_FW_PORT_CAP32_SPEED(lc->acaps); + + *new_caps = caps; +} + +int t4_set_link_speed(struct port_info *pi, u32 speed, u32 *new_caps) +{ + u32 fw_speed_cap = t4_speed_to_fwcap(speed); + struct link_config *lc = &pi->link_cfg; + u32 caps = *new_caps; + + if (!(lc->pcaps & fw_speed_cap)) + return -EOPNOTSUPP; + + caps &= ~V_FW_PORT_CAP32_SPEED(M_FW_PORT_CAP32_SPEED); + caps |= fw_speed_cap; + + *new_caps = caps; + + return 0; +} + +int t4_set_link_pause(struct port_info *pi, u8 autoneg, u8 pause_tx, + u8 pause_rx, u32 *new_caps) +{ + struct link_config *lc = &pi->link_cfg; + u32 caps = *new_caps; + u32 max_speed; + + max_speed = t4_fwcap_to_speed(lc->link_caps); + + if (autoneg) { + if (!(lc->pcaps & FW_PORT_CAP32_ANEG)) + return -EINVAL; + + caps |= FW_PORT_CAP32_ANEG; + t4_set_link_autoneg_speed(pi, &caps); + } else { + if (!max_speed) + max_speed = t4_fwcap_to_speed(lc->acaps); + + caps &= ~FW_PORT_CAP32_ANEG; + t4_set_link_speed(pi, max_speed, &caps); + } + + if (lc->pcaps & FW_PORT_CAP32_MDIAUTO) + caps |= V_FW_PORT_CAP32_MDI(FW_PORT_CAP32_MDI_AUTO); + + caps &= ~V_FW_PORT_CAP32_FC(M_FW_PORT_CAP32_FC); + caps &= ~V_FW_PORT_CAP32_802_3(M_FW_PORT_CAP32_802_3); + if (pause_tx && pause_rx) { + caps |= FW_PORT_CAP32_FC_TX | FW_PORT_CAP32_FC_RX; + if (lc->pcaps & FW_PORT_CAP32_802_3_PAUSE) + caps |= FW_PORT_CAP32_802_3_PAUSE; + } else if (pause_tx) { + caps |= FW_PORT_CAP32_FC_TX; + if (lc->pcaps & FW_PORT_CAP32_802_3_ASM_DIR) + caps |= FW_PORT_CAP32_802_3_ASM_DIR; + } else if (pause_rx) { + caps |= FW_PORT_CAP32_FC_RX; + if (lc->pcaps & FW_PORT_CAP32_802_3_PAUSE) + caps |= FW_PORT_CAP32_802_3_PAUSE; + + if (lc->pcaps & FW_PORT_CAP32_802_3_ASM_DIR) + caps |= FW_PORT_CAP32_802_3_ASM_DIR; + } + + *new_caps = caps; + + return 0; +} + +int t4_set_link_fec(struct port_info *pi, u8 fec_rs, u8 fec_baser, + u8 fec_none, u32 *new_caps) +{ + struct link_config *lc = &pi->link_cfg; + u32 max_speed, caps = *new_caps; + + if (!(lc->pcaps & V_FW_PORT_CAP32_FEC(M_FW_PORT_CAP32_FEC))) + return -EOPNOTSUPP; + + /* Link might be down. In that case consider the max + * speed advertised + */ + max_speed = t4_fwcap_to_speed(lc->link_caps); + if (!max_speed) + max_speed = t4_fwcap_to_speed(lc->acaps); + + caps &= ~V_FW_PORT_CAP32_FEC(M_FW_PORT_CAP32_FEC); + if (fec_rs) { + switch (max_speed) { + case 100000: + case 25000: + caps |= FW_PORT_CAP32_FEC_RS; + break; + default: + return -EOPNOTSUPP; + } + } + + if (fec_baser) { + switch (max_speed) { + case 50000: + case 25000: + caps |= FW_PORT_CAP32_FEC_BASER_RS; + break; + default: + return -EOPNOTSUPP; + } + } + + if (fec_none) + caps |= FW_PORT_CAP32_FEC_NO_FEC; + + if (!(caps & V_FW_PORT_CAP32_FEC(M_FW_PORT_CAP32_FEC))) { + /* No explicit encoding is requested. + * So, default back to AUTO. + */ + switch (max_speed) { + case 100000: + caps |= FW_PORT_CAP32_FEC_RS | + FW_PORT_CAP32_FEC_NO_FEC; + break; + case 50000: + caps |= FW_PORT_CAP32_FEC_BASER_RS | + FW_PORT_CAP32_FEC_NO_FEC; + break; + case 25000: + caps |= FW_PORT_CAP32_FEC_RS | + FW_PORT_CAP32_FEC_BASER_RS | + FW_PORT_CAP32_FEC_NO_FEC; + break; + default: + return -EOPNOTSUPP; + } + } + + *new_caps = caps; + + return 0; +} + /** * t4_handle_get_port_info - process a FW reply message * @pi: the port info @@ -4384,112 +4553,88 @@ static unsigned int fwcap_to_speed(fw_port_cap32_t caps) static void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl) { const struct fw_port_cmd *cmd = (const void *)rpl; - int action = G_FW_PORT_CMD_ACTION(be32_to_cpu(cmd->action_to_len16)); - fw_port_cap32_t pcaps, acaps, linkattr; + u8 link_ok, link_down_rc, mod_type, port_type; + u32 action, pcaps, acaps, link_caps, lstatus; struct link_config *lc = &pi->link_cfg; struct adapter *adapter = pi->adapter; - enum fw_port_module_type mod_type; - enum fw_port_type port_type; - unsigned int speed, fc, fec; - int link_ok, linkdnrc; + u8 mod_changed = 0; /* Extract the various fields from the Port Information message. */ - switch (action) { - case FW_PORT_ACTION_GET_PORT_INFO: { - u32 lstatus = be32_to_cpu(cmd->u.info.lstatus_to_modtype); - - link_ok = (lstatus & F_FW_PORT_CMD_LSTATUS) != 0; - linkdnrc = G_FW_PORT_CMD_LINKDNRC(lstatus); - port_type = G_FW_PORT_CMD_PTYPE(lstatus); - mod_type = G_FW_PORT_CMD_MODTYPE(lstatus); - pcaps = fwcaps16_to_caps32(be16_to_cpu(cmd->u.info.pcap)); - acaps = fwcaps16_to_caps32(be16_to_cpu(cmd->u.info.acap)); - - /* 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 & F_FW_PORT_CMD_RXPAUSE) - linkattr |= FW_PORT_CAP32_FC_RX; - if (lstatus & F_FW_PORT_CMD_TXPAUSE) - linkattr |= FW_PORT_CAP32_FC_TX; - if (lstatus & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_100M)) - linkattr |= FW_PORT_CAP32_SPEED_100M; - if (lstatus & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_1G)) - linkattr |= FW_PORT_CAP32_SPEED_1G; - if (lstatus & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_10G)) - linkattr |= FW_PORT_CAP32_SPEED_10G; - if (lstatus & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_25G)) - linkattr |= FW_PORT_CAP32_SPEED_25G; - if (lstatus & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_40G)) - linkattr |= FW_PORT_CAP32_SPEED_40G; - if (lstatus & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_100G)) - linkattr |= FW_PORT_CAP32_SPEED_100G; - - break; - } - - case FW_PORT_ACTION_GET_PORT_INFO32: { - u32 lstatus32 = - be32_to_cpu(cmd->u.info32.lstatus32_to_cbllen32); - - link_ok = (lstatus32 & F_FW_PORT_CMD_LSTATUS32) != 0; - linkdnrc = G_FW_PORT_CMD_LINKDNRC32(lstatus32); - port_type = G_FW_PORT_CMD_PORTTYPE32(lstatus32); - mod_type = G_FW_PORT_CMD_MODTYPE32(lstatus32); - pcaps = be32_to_cpu(cmd->u.info32.pcaps32); - acaps = be32_to_cpu(cmd->u.info32.acaps32); - linkattr = be32_to_cpu(cmd->u.info32.linkattr32); - break; - } - - default: + action = be32_to_cpu(cmd->action_to_len16); + if (G_FW_PORT_CMD_ACTION(action) != FW_PORT_ACTION_GET_PORT_INFO32) { dev_warn(adapter, "Handle Port Information: Bad Command/Action %#x\n", - be32_to_cpu(cmd->action_to_len16)); + action); return; } - fec = fwcap_to_cc_fec(acaps); + lstatus = be32_to_cpu(cmd->u.info32.lstatus32_to_cbllen32); + link_ok = (lstatus & F_FW_PORT_CMD_LSTATUS32) ? 1 : 0; + link_down_rc = G_FW_PORT_CMD_LINKDNRC32(lstatus); + port_type = G_FW_PORT_CMD_PORTTYPE32(lstatus); + mod_type = G_FW_PORT_CMD_MODTYPE32(lstatus); - fc = fwcap_to_cc_pause(linkattr); - speed = fwcap_to_speed(linkattr); + pcaps = be32_to_cpu(cmd->u.info32.pcaps32); + acaps = be32_to_cpu(cmd->u.info32.acaps32); + link_caps = be32_to_cpu(cmd->u.info32.linkattr32); - if (mod_type != pi->mod_type) { - lc->auto_fec = fec; - pi->port_type = port_type; - pi->mod_type = mod_type; + if (mod_type != lc->mod_type) { + t4_init_link_config(pi, pcaps, acaps, lc->mdio_addr, + port_type, mod_type); t4_os_portmod_changed(adapter, pi->pidx); + mod_changed = 1; } - if (link_ok != lc->link_ok || speed != lc->speed || - fc != lc->fc || fec != lc->fec) { /* something changed */ + if (link_ok != lc->link_ok || acaps != lc->acaps || + link_caps != lc->link_caps) { /* something changed */ if (!link_ok && lc->link_ok) { - lc->link_down_rc = linkdnrc; + lc->link_down_rc = link_down_rc; dev_warn(adap, "Port %d link down, reason: %s\n", - pi->tx_chan, t4_link_down_rc_str(linkdnrc)); + pi->port_id, + t4_link_down_rc_str(link_down_rc)); } lc->link_ok = link_ok; - lc->speed = speed; - lc->fc = fc; - lc->fec = fec; - lc->pcaps = pcaps; - lc->acaps = acaps & ADVERT_MASK; - - 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->requested_speed = fwcap_to_speed(acaps); - lc->autoneg = AUTONEG_DISABLE; - } + lc->acaps = acaps; + lc->link_caps = link_caps; + t4_os_link_changed(adapter, pi->pidx); + } + + if (mod_changed) { + u32 mod_caps = lc->admin_caps; + int ret; + + ret = t4_link_l1cfg_ns(pi, mod_caps); + if (ret != FW_SUCCESS) + dev_warn(adapter, + "Attempt to update new Transceiver Module settings %#x failed with error: %d\n", + mod_caps, ret); } } +/** + * t4_ctrl_eq_free - free a control egress queue + * @adap: the adapter + * @mbox: mailbox to use for the FW command + * @pf: the PF owning the queue + * @vf: the VF owning the queue + * @eqid: egress queue id + * + * Frees a control egress queue. + */ +int t4_ctrl_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, + unsigned int vf, unsigned int eqid) +{ + struct fw_eq_ctrl_cmd c; + + memset(&c, 0, sizeof(c)); + c.op_to_vfn = cpu_to_be32(V_FW_CMD_OP(FW_EQ_CTRL_CMD) | + F_FW_CMD_REQUEST | F_FW_CMD_EXEC | + V_FW_EQ_CTRL_CMD_PFN(pf) | + V_FW_EQ_CTRL_CMD_VFN(vf)); + c.alloc_to_len16 = cpu_to_be32(F_FW_EQ_CTRL_CMD_FREE | FW_LEN16(c)); + c.cmpliqid_eqid = cpu_to_be32(V_FW_EQ_CTRL_CMD_EQID(eqid)); + return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); +} + /** * t4_handle_fw_rpl - process a FW reply message * @adap: the adapter @@ -4511,9 +4656,7 @@ int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl) unsigned int action = G_FW_PORT_CMD_ACTION(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)) { + if (opcode == FW_PORT_CMD && action == FW_PORT_ACTION_GET_PORT_INFO32) { /* link/module state change message */ int chan = G_FW_PORT_CMD_PORTID(be32_to_cpu(p->op_to_portid)); struct port_info *pi = NULL; @@ -4539,45 +4682,67 @@ void t4_reset_link_config(struct adapter *adap, int idx) struct link_config *lc = &pi->link_cfg; lc->link_ok = 0; - lc->requested_speed = 0; - lc->requested_fc = 0; - lc->speed = 0; - lc->fc = 0; + lc->link_down_rc = 0; + lc->link_caps = 0; } /** - * init_link_config - initialize a link's SW state - * @lc: structure holding the link state + * t4_init_link_config - initialize a link's SW state + * @pi: the port info * @pcaps: link Port Capabilities * @acaps: link current Advertised Port Capabilities + * @mdio_addr : address of the PHY + * @port_type : firmware port type + * @mod_type : firmware module type * * Initializes the SW state maintained for each link, including the link's * capabilities and default speed/flow-control/autonegotiation settings. */ -void init_link_config(struct link_config *lc, fw_port_cap32_t pcaps, - fw_port_cap32_t acaps) +void t4_init_link_config(struct port_info *pi, u32 pcaps, u32 acaps, + u8 mdio_addr, u8 port_type, u8 mod_type) { + u8 fec_rs = 0, fec_baser = 0, fec_none = 0; + struct link_config *lc = &pi->link_cfg; + lc->pcaps = pcaps; - lc->requested_speed = 0; - lc->speed = 0; - lc->requested_fc = 0; - lc->fc = 0; + lc->acaps = acaps; + lc->admin_caps = acaps; + lc->link_caps = 0; - /** - * For Forward Error Control, we default to whatever the Firmware - * tells us the Link is currently advertising. - */ - lc->auto_fec = fwcap_to_cc_fec(acaps); - lc->requested_fec = FEC_AUTO; - lc->fec = lc->auto_fec; - - 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->mdio_addr = mdio_addr; + lc->port_type = port_type; + lc->mod_type = mod_type; + + lc->link_ok = 0; + lc->link_down_rc = 0; + + /* Turn Tx and Rx pause off by default */ + lc->admin_caps &= ~V_FW_PORT_CAP32_FC(M_FW_PORT_CAP32_FC); + lc->admin_caps &= ~V_FW_PORT_CAP32_802_3(M_FW_PORT_CAP32_802_3); + if (lc->pcaps & FW_PORT_CAP32_FORCE_PAUSE) + lc->admin_caps &= ~FW_PORT_CAP32_FORCE_PAUSE; + + /* Reset FEC caps to default values */ + if (lc->pcaps & V_FW_PORT_CAP32_FEC(M_FW_PORT_CAP32_FEC)) { + if (lc->acaps & FW_PORT_CAP32_FEC_RS) + fec_rs = 1; + else if (lc->acaps & FW_PORT_CAP32_FEC_BASER_RS) + fec_baser = 1; + else + fec_none = 1; + + lc->admin_caps &= ~V_FW_PORT_CAP32_FEC(M_FW_PORT_CAP32_FEC); + t4_set_link_fec(pi, fec_rs, fec_baser, fec_none, + &lc->admin_caps); + } + + if (lc->pcaps & FW_PORT_CAP32_FORCE_FEC) + lc->admin_caps &= ~FW_PORT_CAP32_FORCE_FEC; + + /* Reset MDI to AUTO */ + if (lc->pcaps & FW_PORT_CAP32_MDIAUTO) { + lc->admin_caps &= ~V_FW_PORT_CAP32_MDI(M_FW_PORT_CAP32_MDI); + lc->admin_caps |= V_FW_PORT_CAP32_MDI(FW_PORT_CAP32_MDI_AUTO); } } @@ -4616,9 +4781,8 @@ struct flash_desc { int t4_get_flash_params(struct adapter *adapter) { /* - * Table for non-Numonix supported flash parts. Numonix parts are left - * to the preexisting well-tested code. All flash parts have 64KB - * sectors. + * Table for non-standard supported Flash parts. Note, all Flash + * parts must have 64KB sectors. */ static struct flash_desc supported_flash[] = { { 0x00150201, 4 << 20 }, /* Spansion 4MB S25FL032P */ @@ -4627,7 +4791,7 @@ int t4_get_flash_params(struct adapter *adapter) int ret; u32 flashid = 0; unsigned int part, manufacturer; - unsigned int density, size; + unsigned int density, size = 0; /** * Issue a Read ID Command to the Flash part. We decode supported @@ -4642,6 +4806,9 @@ int t4_get_flash_params(struct adapter *adapter) if (ret < 0) 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) { adapter->params.sf_size = @@ -4652,6 +4819,15 @@ int t4_get_flash_params(struct adapter *adapter) } } + /** + * Decode Flash part size. The code below looks repetative with + * common encodings, but that's not guaranteed in the JEDEC + * specification for the Read JADEC ID command. The only thing that + * we're guaranteed by the JADEC 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 */ @@ -4688,21 +4864,81 @@ int t4_get_flash_params(struct adapter *adapter) case 0x22: size = 1 << 28; /* 256MB */ break; - default: - dev_err(adapter, "Micron Flash Part has bad size, ID = %#x, Density code = %#x\n", - flashid, density); - return -EINVAL; } + break; + } - adapter->params.sf_size = size; - adapter->params.sf_nsec = size / SF_SEC_SIZE; + 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: + size = 1 << 25; /* 32MB */ + break; + case 0x17: + size = 1 << 26; /* 64MB */ + break; + } break; } - default: - dev_err(adapter, "Unsupported Flash Part, ID = %#x\n", flashid); - return -EINVAL; + + case 0xc2: { /* Macronix */ + /** + * This Density -> Size decoding table is taken from Macronix + * Data Sheets. + */ + density = (flashid >> 16) & 0xff; + switch (density) { + case 0x17: + size = 1 << 23; /* 8MB */ + break; + case 0x18: + size = 1 << 24; /* 16MB */ + break; + } + break; + } + + case 0xef: { /* Winbond */ + /** + * This Density -> Size decoding table is taken from Winbond + * Data Sheets. + */ + density = (flashid >> 16) & 0xff; + switch (density) { + case 0x17: + size = 1 << 23; /* 8MB */ + break; + case 0x18: + size = 1 << 24; /* 16MB */ + 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(adapter, + "Unknown Flash Part, ID = %#x, assuming 4MB\n", + flashid); + size = 1 << 22; } + /** + * Store decoded Flash size and fall through into vetting code. + */ + adapter->params.sf_size = size; + adapter->params.sf_nsec = size / SF_SEC_SIZE; + found: /* * We should reject adapters with FLASHes which are too small. So, emit @@ -4793,6 +5029,10 @@ int t4_prep_adapter(struct adapter *adapter) adapter->params.arch.mps_rplc_size = 128; adapter->params.arch.nchan = NCHAN; adapter->params.arch.vfcount = 128; + /* Congestion map is for 4 channels so that + * MPS can have 4 priority per port. + */ + adapter->params.arch.cng_ch_bits_log = 2; break; case CHELSIO_T6: adapter->params.chip |= CHELSIO_CHIP_CODE(CHELSIO_T6, pl_rev); @@ -4802,6 +5042,10 @@ int t4_prep_adapter(struct adapter *adapter) adapter->params.arch.mps_rplc_size = 256; adapter->params.arch.nchan = 2; adapter->params.arch.vfcount = 256; + /* Congestion map is for 2 channels so that + * MPS can have 8 priority per port. + */ + adapter->params.arch.cng_ch_bits_log = 3; break; default: dev_err(adapter, "%s: Device %d is not supported\n", @@ -4968,8 +5212,8 @@ int t4_init_sge_params(struct adapter *adapter) */ int t4_init_tp_params(struct adapter *adap) { - int chan; - u32 v; + int chan, ret; + u32 param, v; v = t4_read_reg(adap, A_TP_TIMER_RESOLUTION); adap->params.tp.tre = G_TIMERRESOLUTION(v); @@ -4980,11 +5224,47 @@ int t4_init_tp_params(struct adapter *adap) adap->params.tp.tx_modq[chan] = chan; /* - * Cache the adapter's Compressed Filter Mode and global Incress + * Cache the adapter's Compressed Filter Mode/Mask and global Ingress * Configuration. */ - t4_read_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, - &adap->params.tp.vlan_pri_map, 1, A_TP_VLAN_PRI_MAP); + param = (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | + V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_FILTER) | + V_FW_PARAMS_PARAM_Y(FW_PARAM_DEV_FILTER_MODE_MASK)); + + /* Read current value */ + ret = t4_query_params(adap, adap->mbox, adap->pf, 0, + 1, ¶m, &v); + if (!ret) { + dev_info(adap, "Current filter mode/mask 0x%x:0x%x\n", + G_FW_PARAMS_PARAM_FILTER_MODE(v), + G_FW_PARAMS_PARAM_FILTER_MASK(v)); + adap->params.tp.vlan_pri_map = + G_FW_PARAMS_PARAM_FILTER_MODE(v); + adap->params.tp.filter_mask = + G_FW_PARAMS_PARAM_FILTER_MASK(v); + } else { + dev_info(adap, + "Failed to read filter mode/mask via fw api, using indirect-reg-read\n"); + + /* In case 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_read_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, + &adap->params.tp.vlan_pri_map, 1, + A_TP_VLAN_PRI_MAP); + + /* 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; + } + t4_read_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, &adap->params.tp.ingress_config, 1, A_TP_INGRESS_CONFIG); @@ -5007,13 +5287,16 @@ int t4_init_tp_params(struct adapter *adap) adap->params.tp.port_shift = t4_filter_field_shift(adap, F_PORT); adap->params.tp.protocol_shift = t4_filter_field_shift(adap, F_PROTOCOL); + adap->params.tp.ethertype_shift = t4_filter_field_shift(adap, + F_ETHERTYPE); + adap->params.tp.macmatch_shift = t4_filter_field_shift(adap, + F_MACMATCH); + adap->params.tp.tos_shift = t4_filter_field_shift(adap, F_TOS); - /* - * If TP_INGRESS_CONFIG.VNID == 0, then TP_VLAN_PRI_MAP.VNIC_ID - * represents the presense of an Outer VLAN instead of a VNIC ID. - */ - if ((adap->params.tp.ingress_config & F_VNIC) == 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; } @@ -5097,82 +5380,56 @@ int t4_init_rss_mode(struct adapter *adap, int mbox) int t4_port_init(struct adapter *adap, int mbox, int pf, int vf) { - unsigned int fw_caps = adap->params.fw_caps_support; - fw_port_cap32_t pcaps, acaps; + u32 param, val, pcaps, acaps; enum fw_port_type port_type; struct fw_port_cmd cmd; + u8 vivld = 0, vin = 0; int ret, i, j = 0; int mdio_addr; - u32 action; u8 addr[6]; + param = (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | + V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_PORT_CAPS32)); + val = 1; + ret = t4_set_params(adap, mbox, pf, vf, 1, ¶m, &val); + if (ret < 0) + return ret; + memset(&cmd, 0, sizeof(cmd)); for_each_port(adap, i) { struct port_info *pi = adap2pinfo(adap, i); unsigned int rss_size = 0; + u32 lstatus32; while ((adap->params.portvec & (1 << j)) == 0) j++; - /* 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, caps; - - caps = FW_PARAMS_PARAM_PFVF_PORT_CAPS32; - param = (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | - V_FW_PARAMS_PARAM_X(caps)); - val = 1; - ret = t4_set_params(adap, mbox, pf, vf, 1, ¶m, - &val); - fw_caps = ret == 0 ? FW_CAPS32 : FW_CAPS16; - adap->params.fw_caps_support = fw_caps; - } - memset(&cmd, 0, sizeof(cmd)); cmd.op_to_portid = cpu_to_be32(V_FW_CMD_OP(FW_PORT_CMD) | F_FW_CMD_REQUEST | F_FW_CMD_READ | V_FW_PORT_CMD_PORTID(j)); - action = fw_caps == FW_CAPS16 ? FW_PORT_ACTION_GET_PORT_INFO : - FW_PORT_ACTION_GET_PORT_INFO32; - cmd.action_to_len16 = cpu_to_be32(V_FW_PORT_CMD_ACTION(action) | + val = FW_PORT_ACTION_GET_PORT_INFO32; + cmd.action_to_len16 = cpu_to_be32(V_FW_PORT_CMD_ACTION(val) | FW_LEN16(cmd)); ret = t4_wr_mbox(pi->adapter, mbox, &cmd, sizeof(cmd), &cmd); if (ret) return ret; - /* Extract the various fields from the Port Information message. + /* 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); - - port_type = G_FW_PORT_CMD_PTYPE(lstatus); - mdio_addr = (lstatus & F_FW_PORT_CMD_MDIOCAP) ? - (int)G_FW_PORT_CMD_MDIOADDR(lstatus) : -1; - pcaps = be16_to_cpu(cmd.u.info.pcap); - acaps = be16_to_cpu(cmd.u.info.acap); - pcaps = fwcaps16_to_caps32(pcaps); - acaps = fwcaps16_to_caps32(acaps); - } else { - u32 lstatus32 = - be32_to_cpu(cmd.u.info32.lstatus32_to_cbllen32); - - port_type = G_FW_PORT_CMD_PORTTYPE32(lstatus32); - mdio_addr = (lstatus32 & F_FW_PORT_CMD_MDIOCAP32) ? - (int)G_FW_PORT_CMD_MDIOADDR32(lstatus32) : - -1; - pcaps = be32_to_cpu(cmd.u.info32.pcaps32); - acaps = be32_to_cpu(cmd.u.info32.acaps32); - } + lstatus32 = be32_to_cpu(cmd.u.info32.lstatus32_to_cbllen32); - ret = t4_alloc_vi(adap, mbox, j, pf, vf, 1, addr, &rss_size); + port_type = G_FW_PORT_CMD_PORTTYPE32(lstatus32); + mdio_addr = (lstatus32 & F_FW_PORT_CMD_MDIOCAP32) ? + (int)G_FW_PORT_CMD_MDIOADDR32(lstatus32) : -1; + pcaps = be32_to_cpu(cmd.u.info32.pcaps32); + acaps = be32_to_cpu(cmd.u.info32.acaps32); + + ret = t4_alloc_vi(adap, mbox, j, pf, vf, 1, addr, &rss_size, + &vivld, &vin); if (ret < 0) return ret; @@ -5181,12 +5438,230 @@ int t4_port_init(struct adapter *adap, int mbox, int pf, int vf) pi->rss_size = rss_size; t4_os_set_hw_addr(adap, i, addr); - pi->port_type = port_type; - pi->mdio_addr = mdio_addr; - pi->mod_type = FW_PORT_MOD_TYPE_NA; + /* If fw supports returning the VIN as part of FW_VI_CMD, + * save the returned values. + */ + if (adap->params.viid_smt_extn_support) { + pi->vivld = vivld; + pi->vin = vin; + } else { + /* Retrieve the values from VIID */ + pi->vivld = G_FW_VIID_VIVLD(pi->viid); + pi->vin = G_FW_VIID_VIN(pi->viid); + } - init_link_config(&pi->link_cfg, pcaps, acaps); + t4_init_link_config(pi, pcaps, acaps, mdio_addr, port_type, + FW_PORT_MOD_TYPE_NA); j++; } return 0; } + +/** + * t4_memory_rw_addr - read/write adapter memory via PCIE memory window + * @adap: the adapter + * @win: PCI-E Memory Window to use + * @addr: address within adapter memory + * @len: amount of memory to transfer + * @hbuf: host memory buffer + * @dir: direction of transfer T4_MEMORY_READ (1) or T4_MEMORY_WRITE (0) + * + * Reads/writes an [almost] arbitrary memory region in the firmware: the + * firmware memory address and host buffer must be aligned on 32-bit + * boudaries; the length may be arbitrary. + * + * NOTES: + * 1. The memory is transferred as a raw byte sequence from/to the + * firmware's memory. If this memory contains data structures which + * contain multi-byte integers, it's the caller's responsibility to + * perform appropriate byte order conversions. + * + * 2. It is the Caller's responsibility to ensure that no other code + * uses the specified PCI-E Memory Window while this routine is + * using it. This is typically done via the use of OS-specific + * locks, etc. + */ +int t4_memory_rw_addr(struct adapter *adap, int win, u32 addr, + u32 len, void *hbuf, int dir) +{ + u32 pos, offset, resid; + u32 win_pf, mem_reg, mem_aperture, mem_base; + u32 *buf; + + /* Argument sanity checks ...*/ + if (addr & 0x3 || (uintptr_t)hbuf & 0x3) + return -EINVAL; + buf = (u32 *)hbuf; + + /* It's convenient to be able to handle lengths which aren't a + * multiple of 32-bits because we often end up transferring files to + * the firmware. So we'll handle that by normalizing the length here + * and then handling any residual transfer at the end. + */ + resid = len & 0x3; + len -= resid; + + /* Each PCI-E Memory Window is programmed with a window size -- or + * "aperture" -- which controls the granularity of its mapping onto + * adapter memory. We need to grab that aperture in order to know + * how to use the specified window. The window is also programmed + * with the base address of the Memory Window in BAR0's address + * space. For T4 this is an absolute PCI-E Bus Address. For T5 + * the address is relative to BAR0. + */ + mem_reg = t4_read_reg(adap, + PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, + win)); + mem_aperture = 1 << (G_WINDOW(mem_reg) + X_WINDOW_SHIFT); + mem_base = G_PCIEOFST(mem_reg) << X_PCIEOFST_SHIFT; + + win_pf = is_t4(adap->params.chip) ? 0 : V_PFNUM(adap->pf); + + /* Calculate our initial PCI-E Memory Window Position and Offset into + * that Window. + */ + pos = addr & ~(mem_aperture - 1); + offset = addr - pos; + + /* Set up initial PCI-E Memory Window to cover the start of our + * transfer. (Read it back to ensure that changes propagate before we + * attempt to use the new value.) + */ + t4_write_reg(adap, + PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, win), + pos | win_pf); + t4_read_reg(adap, + PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, win)); + + /* Transfer data to/from the adapter as long as there's an integral + * number of 32-bit transfers to complete. + * + * A note on Endianness issues: + * + * The "register" reads and writes below from/to the PCI-E Memory + * Window invoke the standard adapter Big-Endian to PCI-E Link + * Little-Endian "swizzel." As a result, if we have the following + * data in adapter memory: + * + * Memory: ... | b0 | b1 | b2 | b3 | ... + * Address: i+0 i+1 i+2 i+3 + * + * Then a read of the adapter memory via the PCI-E Memory Window + * will yield: + * + * x = readl(i) + * 31 0 + * [ b3 | b2 | b1 | b0 ] + * + * If this value is stored into local memory on a Little-Endian system + * it will show up correctly in local memory as: + * + * ( ..., b0, b1, b2, b3, ... ) + * + * But on a Big-Endian system, the store will show up in memory + * incorrectly swizzled as: + * + * ( ..., b3, b2, b1, b0, ... ) + * + * So we need to account for this in the reads and writes to the + * PCI-E Memory Window below by undoing the register read/write + * swizzels. + */ + while (len > 0) { + if (dir == T4_MEMORY_READ) + *buf++ = le32_to_cpu((__le32)t4_read_reg(adap, + mem_base + + offset)); + else + t4_write_reg(adap, mem_base + offset, + (u32)cpu_to_le32(*buf++)); + offset += sizeof(__be32); + len -= sizeof(__be32); + + /* If we've reached the end of our current window aperture, + * move the PCI-E Memory Window on to the next. Note that + * doing this here after "len" may be 0 allows us to set up + * the PCI-E Memory Window for a possible final residual + * transfer below ... + */ + if (offset == mem_aperture) { + pos += mem_aperture; + offset = 0; + t4_write_reg(adap, + PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, + win), pos | win_pf); + t4_read_reg(adap, + PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, + win)); + } + } + + /* If the original transfer had a length which wasn't a multiple of + * 32-bits, now's where we need to finish off the transfer of the + * residual amount. The PCI-E Memory Window has already been moved + * above (if necessary) to cover this final transfer. + */ + if (resid) { + union { + u32 word; + char byte[4]; + } last; + unsigned char *bp; + int i; + + if (dir == T4_MEMORY_READ) { + last.word = le32_to_cpu((__le32)t4_read_reg(adap, + mem_base + + offset)); + for (bp = (unsigned char *)buf, i = resid; i < 4; i++) + bp[i] = last.byte[i]; + } else { + last.word = *buf; + for (i = resid; i < 4; i++) + last.byte[i] = 0; + t4_write_reg(adap, mem_base + offset, + (u32)cpu_to_le32(last.word)); + } + } + + return 0; +} + +/** + * t4_memory_rw_mtype -read/write EDC 0, EDC 1 or MC via PCIE memory window + * @adap: the adapter + * @win: PCI-E Memory Window to use + * @mtype: memory type: MEM_EDC0, MEM_EDC1 or MEM_MC + * @maddr: address within indicated memory type + * @len: amount of memory to transfer + * @hbuf: host memory buffer + * @dir: direction of transfer T4_MEMORY_READ (1) or T4_MEMORY_WRITE (0) + * + * Reads/writes adapter memory using t4_memory_rw_addr(). This routine + * provides an (memory type, address within memory type) interface. + */ +int t4_memory_rw_mtype(struct adapter *adap, int win, int mtype, u32 maddr, + u32 len, void *hbuf, int dir) +{ + u32 mtype_offset; + u32 edc_size, mc_size; + + /* Offset into the region of memory which is being accessed + * MEM_EDC0 = 0 + * MEM_EDC1 = 1 + * MEM_MC = 2 -- MEM_MC for chips with only 1 memory controller + * MEM_MC1 = 3 -- for chips with 2 memory controllers (e.g. T5) + */ + edc_size = G_EDRAM0_SIZE(t4_read_reg(adap, A_MA_EDRAM0_BAR)); + if (mtype != MEM_MC1) { + mtype_offset = (mtype * (edc_size * 1024 * 1024)); + } else { + mc_size = G_EXT_MEM0_SIZE(t4_read_reg(adap, + A_MA_EXT_MEMORY0_BAR)); + mtype_offset = (MEM_MC0 * edc_size + mc_size) * 1024 * 1024; + } + + return t4_memory_rw_addr(adap, win, + mtype_offset + maddr, len, + hbuf, dir); +}