diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 2ec6e8a11ee1..0fbb32a8ad42 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -154,7 +154,7 @@ struct i40e_lump_tracking { #define I40E_DEFAULT_ATR_SAMPLE_RATE 20 #define I40E_FDIR_MAX_RAW_PACKET_SIZE 512 #define I40E_FDIR_BUFFER_FULL_MARGIN 10 -#define I40E_FDIR_BUFFER_HEAD_ROOM 200 +#define I40E_FDIR_BUFFER_HEAD_ROOM 32 enum i40e_fd_stat_idx { I40E_FD_STAT_ATR, @@ -582,6 +582,7 @@ int i40e_add_del_fdir(struct i40e_vsi *vsi, struct i40e_fdir_filter *input, bool add); void i40e_fdir_check_and_reenable(struct i40e_pf *pf); int i40e_get_current_fd_count(struct i40e_pf *pf); +int i40e_get_cur_guaranteed_fd_count(struct i40e_pf *pf); bool i40e_set_ntuple(struct i40e_pf *pf, netdev_features_t features); void i40e_set_ethtool_ops(struct net_device *netdev); struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi, diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c index 910b01b90cdc..ec07332e109e 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c +++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c @@ -1743,6 +1743,9 @@ static ssize_t i40e_dbg_command_write(struct file *filp, i40e_dbg_cmd_fd_ctrl(pf, I40E_FLAG_FD_ATR_ENABLED, false); } else if (strncmp(cmd_buf, "fd-atr on", 9) == 0) { i40e_dbg_cmd_fd_ctrl(pf, I40E_FLAG_FD_ATR_ENABLED, true); + } else if (strncmp(cmd_buf, "fd current cnt", 14) == 0) { + dev_info(&pf->pdev->dev, "FD current total filter count for this interface: %d\n", + i40e_get_current_fd_count(pf)); } else if (strncmp(cmd_buf, "lldp", 4) == 0) { if (strncmp(&cmd_buf[5], "stop", 4) == 0) { int ret; @@ -1962,6 +1965,7 @@ static ssize_t i40e_dbg_command_write(struct file *filp, dev_info(&pf->pdev->dev, " rem fd_filter \n"); dev_info(&pf->pdev->dev, " fd-atr off\n"); dev_info(&pf->pdev->dev, " fd-atr on\n"); + dev_info(&pf->pdev->dev, " fd current cnt"); dev_info(&pf->pdev->dev, " lldp start\n"); dev_info(&pf->pdev->dev, " lldp stop\n"); dev_info(&pf->pdev->dev, " lldp get local\n"); diff --git a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c index 870ab1ee072c..5a603a5e9aa8 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c +++ b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c @@ -746,6 +746,194 @@ static struct i40e_context_ele i40e_hmc_rxq_ce_info[] = { { 0 } }; +/** + * i40e_write_byte - replace HMC context byte + * @hmc_bits: pointer to the HMC memory + * @ce_info: a description of the struct to be read from + * @src: the struct to be read from + **/ +static void i40e_write_byte(u8 *hmc_bits, + struct i40e_context_ele *ce_info, + u8 *src) +{ + u8 src_byte, dest_byte, mask; + u8 *from, *dest; + u16 shift_width; + + /* copy from the next struct field */ + from = src + ce_info->offset; + + /* prepare the bits and mask */ + shift_width = ce_info->lsb % 8; + mask = ((u8)1 << ce_info->width) - 1; + + src_byte = *from; + src_byte &= mask; + + /* shift to correct alignment */ + mask <<= shift_width; + src_byte <<= shift_width; + + /* get the current bits from the target bit string */ + dest = hmc_bits + (ce_info->lsb / 8); + + memcpy(&dest_byte, dest, sizeof(dest_byte)); + + dest_byte &= ~mask; /* get the bits not changing */ + dest_byte |= src_byte; /* add in the new bits */ + + /* put it all back */ + memcpy(dest, &dest_byte, sizeof(dest_byte)); +} + +/** + * i40e_write_word - replace HMC context word + * @hmc_bits: pointer to the HMC memory + * @ce_info: a description of the struct to be read from + * @src: the struct to be read from + **/ +static void i40e_write_word(u8 *hmc_bits, + struct i40e_context_ele *ce_info, + u8 *src) +{ + u16 src_word, mask; + u8 *from, *dest; + u16 shift_width; + __le16 dest_word; + + /* copy from the next struct field */ + from = src + ce_info->offset; + + /* prepare the bits and mask */ + shift_width = ce_info->lsb % 8; + mask = ((u16)1 << ce_info->width) - 1; + + /* don't swizzle the bits until after the mask because the mask bits + * will be in a different bit position on big endian machines + */ + src_word = *(u16 *)from; + src_word &= mask; + + /* shift to correct alignment */ + mask <<= shift_width; + src_word <<= shift_width; + + /* get the current bits from the target bit string */ + dest = hmc_bits + (ce_info->lsb / 8); + + memcpy(&dest_word, dest, sizeof(dest_word)); + + dest_word &= ~(cpu_to_le16(mask)); /* get the bits not changing */ + dest_word |= cpu_to_le16(src_word); /* add in the new bits */ + + /* put it all back */ + memcpy(dest, &dest_word, sizeof(dest_word)); +} + +/** + * i40e_write_dword - replace HMC context dword + * @hmc_bits: pointer to the HMC memory + * @ce_info: a description of the struct to be read from + * @src: the struct to be read from + **/ +static void i40e_write_dword(u8 *hmc_bits, + struct i40e_context_ele *ce_info, + u8 *src) +{ + u32 src_dword, mask; + u8 *from, *dest; + u16 shift_width; + __le32 dest_dword; + + /* copy from the next struct field */ + from = src + ce_info->offset; + + /* prepare the bits and mask */ + shift_width = ce_info->lsb % 8; + + /* if the field width is exactly 32 on an x86 machine, then the shift + * operation will not work because the SHL instructions count is masked + * to 5 bits so the shift will do nothing + */ + if (ce_info->width < 32) + mask = ((u32)1 << ce_info->width) - 1; + else + mask = -1; + + /* don't swizzle the bits until after the mask because the mask bits + * will be in a different bit position on big endian machines + */ + src_dword = *(u32 *)from; + src_dword &= mask; + + /* shift to correct alignment */ + mask <<= shift_width; + src_dword <<= shift_width; + + /* get the current bits from the target bit string */ + dest = hmc_bits + (ce_info->lsb / 8); + + memcpy(&dest_dword, dest, sizeof(dest_dword)); + + dest_dword &= ~(cpu_to_le32(mask)); /* get the bits not changing */ + dest_dword |= cpu_to_le32(src_dword); /* add in the new bits */ + + /* put it all back */ + memcpy(dest, &dest_dword, sizeof(dest_dword)); +} + +/** + * i40e_write_qword - replace HMC context qword + * @hmc_bits: pointer to the HMC memory + * @ce_info: a description of the struct to be read from + * @src: the struct to be read from + **/ +static void i40e_write_qword(u8 *hmc_bits, + struct i40e_context_ele *ce_info, + u8 *src) +{ + u64 src_qword, mask; + u8 *from, *dest; + u16 shift_width; + __le64 dest_qword; + + /* copy from the next struct field */ + from = src + ce_info->offset; + + /* prepare the bits and mask */ + shift_width = ce_info->lsb % 8; + + /* if the field width is exactly 64 on an x86 machine, then the shift + * operation will not work because the SHL instructions count is masked + * to 6 bits so the shift will do nothing + */ + if (ce_info->width < 64) + mask = ((u64)1 << ce_info->width) - 1; + else + mask = -1; + + /* don't swizzle the bits until after the mask because the mask bits + * will be in a different bit position on big endian machines + */ + src_qword = *(u64 *)from; + src_qword &= mask; + + /* shift to correct alignment */ + mask <<= shift_width; + src_qword <<= shift_width; + + /* get the current bits from the target bit string */ + dest = hmc_bits + (ce_info->lsb / 8); + + memcpy(&dest_qword, dest, sizeof(dest_qword)); + + dest_qword &= ~(cpu_to_le64(mask)); /* get the bits not changing */ + dest_qword |= cpu_to_le64(src_qword); /* add in the new bits */ + + /* put it all back */ + memcpy(dest, &dest_qword, sizeof(dest_qword)); +} + /** * i40e_clear_hmc_context - zero out the HMC context bits * @hw: the hardware struct @@ -772,71 +960,28 @@ static i40e_status i40e_set_hmc_context(u8 *context_bytes, struct i40e_context_ele *ce_info, u8 *dest) { - u16 shift_width; - u64 bitfield; - u8 hi_byte; - u8 hi_mask; - u64 t_bits; - u64 mask; - u8 *p; int f; for (f = 0; ce_info[f].width != 0; f++) { - /* clear out the field */ - bitfield = 0; - /* copy from the next struct field */ - p = dest + ce_info[f].offset; + /* we have to deal with each element of the HMC using the + * correct size so that we are correct regardless of the + * endianness of the machine + */ switch (ce_info[f].size_of) { case 1: - bitfield = *p; + i40e_write_byte(context_bytes, &ce_info[f], dest); break; case 2: - bitfield = cpu_to_le16(*(u16 *)p); + i40e_write_word(context_bytes, &ce_info[f], dest); break; case 4: - bitfield = cpu_to_le32(*(u32 *)p); + i40e_write_dword(context_bytes, &ce_info[f], dest); break; case 8: - bitfield = cpu_to_le64(*(u64 *)p); + i40e_write_qword(context_bytes, &ce_info[f], dest); break; } - - /* prepare the bits and mask */ - shift_width = ce_info[f].lsb % 8; - mask = ((u64)1 << ce_info[f].width) - 1; - - /* save upper bytes for special case */ - hi_mask = (u8)((mask >> 56) & 0xff); - hi_byte = (u8)((bitfield >> 56) & 0xff); - - /* shift to correct alignment */ - mask <<= shift_width; - bitfield <<= shift_width; - - /* get the current bits from the target bit string */ - p = context_bytes + (ce_info[f].lsb / 8); - memcpy(&t_bits, p, sizeof(u64)); - - t_bits &= ~mask; /* get the bits not changing */ - t_bits |= bitfield; /* add in the new bits */ - - /* put it all back */ - memcpy(p, &t_bits, sizeof(u64)); - - /* deal with the special case if needed - * example: 62 bit field that starts in bit 5 of first byte - * will overlap 3 bits into byte 9 - */ - if ((shift_width + ce_info[f].width) > 64) { - u8 byte; - - hi_mask >>= (8 - shift_width); - hi_byte >>= (8 - shift_width); - byte = p[8] & ~hi_mask; /* get the bits not changing */ - byte |= hi_byte; /* add in the new bits */ - p[8] = byte; /* put it back */ - } } return 0; diff --git a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.h b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.h index eb65fe23c4a7..e74128db5be5 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.h +++ b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.h @@ -32,16 +32,22 @@ struct i40e_hw; /* HMC element context information */ -/* Rx queue context data */ +/* Rx queue context data + * + * The sizes of the variables may be larger than needed due to crossing byte + * boundaries. If we do not have the width of the variable set to the correct + * size then we could end up shifting bits off the top of the variable when the + * variable is at the top of a byte and crosses over into the next byte. + */ struct i40e_hmc_obj_rxq { u16 head; - u8 cpuid; + u16 cpuid; /* bigger than needed, see above for reason */ u64 base; u16 qlen; #define I40E_RXQ_CTX_DBUFF_SHIFT 7 - u8 dbuff; + u16 dbuff; /* bigger than needed, see above for reason */ #define I40E_RXQ_CTX_HBUFF_SHIFT 6 - u8 hbuff; + u16 hbuff; /* bigger than needed, see above for reason */ u8 dtype; u8 dsize; u8 crcstrip; @@ -50,16 +56,22 @@ struct i40e_hmc_obj_rxq { u8 hsplit_0; u8 hsplit_1; u8 showiv; - u16 rxmax; + u32 rxmax; /* bigger than needed, see above for reason */ u8 tphrdesc_ena; u8 tphwdesc_ena; u8 tphdata_ena; u8 tphhead_ena; - u8 lrxqthresh; + u16 lrxqthresh; /* bigger than needed, see above for reason */ u8 prefena; /* NOTE: normally must be set to 1 at init */ }; -/* Tx queue context data */ +/* Tx queue context data +* +* The sizes of the variables may be larger than needed due to crossing byte +* boundaries. If we do not have the width of the variable set to the correct +* size then we could end up shifting bits off the top of the variable when the +* variable is at the top of a byte and crosses over into the next byte. +*/ struct i40e_hmc_obj_txq { u16 head; u8 new_context; @@ -69,7 +81,7 @@ struct i40e_hmc_obj_txq { u8 fd_ena; u8 alt_vlan_ena; u16 thead_wb; - u16 cpuid; + u8 cpuid; u8 head_wb_ena; u16 qlen; u8 tphrdesc_ena; diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 5980d6b3fb1a..17b1295bf35a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -4944,7 +4944,20 @@ static void i40e_service_event_complete(struct i40e_pf *pf) } /** - * i40e_get_current_fd_count - Get the count of FD filters programmed in the HW + * i40e_get_cur_guaranteed_fd_count - Get the consumed guaranteed FD filters + * @pf: board private structure + **/ +int i40e_get_cur_guaranteed_fd_count(struct i40e_pf *pf) +{ + int val, fcnt_prog; + + val = rd32(&pf->hw, I40E_PFQF_FDSTAT); + fcnt_prog = (val & I40E_PFQF_FDSTAT_GUARANT_CNT_MASK); + return fcnt_prog; +} + +/** + * i40e_get_current_fd_count - Get the count of total FD filters programmed * @pf: board private structure **/ int i40e_get_current_fd_count(struct i40e_pf *pf) @@ -4956,7 +4969,6 @@ int i40e_get_current_fd_count(struct i40e_pf *pf) I40E_PFQF_FDSTAT_BEST_CNT_SHIFT); return fcnt_prog; } - /** * i40e_fdir_check_and_reenable - Function to reenabe FD ATR or SB if disabled * @pf: board private structure @@ -4971,8 +4983,8 @@ void i40e_fdir_check_and_reenable(struct i40e_pf *pf) if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) && (pf->flags & I40E_FLAG_FD_SB_ENABLED)) return; - fcnt_prog = i40e_get_current_fd_count(pf); - fcnt_avail = i40e_get_fd_cnt_all(pf); + fcnt_prog = i40e_get_cur_guaranteed_fd_count(pf); + fcnt_avail = pf->fdir_pf_filter_count; if (fcnt_prog < (fcnt_avail - I40E_FDIR_BUFFER_HEAD_ROOM)) { if ((pf->flags & I40E_FLAG_FD_SB_ENABLED) && (pf->auto_disable_flags & I40E_FLAG_FD_SB_ENABLED)) { diff --git a/drivers/net/ethernet/intel/i40e/i40e_nvm.c b/drivers/net/ethernet/intel/i40e/i40e_nvm.c index 81299189a47d..66bcb15422da 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_nvm.c +++ b/drivers/net/ethernet/intel/i40e/i40e_nvm.c @@ -324,13 +324,9 @@ i40e_status i40e_validate_nvm_checksum(struct i40e_hw *hw, u16 checksum_sr = 0; u16 checksum_local = 0; - ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ); - if (ret_code) - goto i40e_validate_nvm_checksum_exit; - ret_code = i40e_calc_nvm_checksum(hw, &checksum_local); if (ret_code) - goto i40e_validate_nvm_checksum_free; + goto i40e_validate_nvm_checksum_exit; /* Do not use i40e_read_nvm_word() because we do not want to take * the synchronization semaphores twice here. @@ -347,9 +343,6 @@ i40e_status i40e_validate_nvm_checksum(struct i40e_hw *hw, if (checksum) *checksum = checksum_local; -i40e_validate_nvm_checksum_free: - i40e_release_nvm(hw); - i40e_validate_nvm_checksum_exit: return ret_code; } diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c index 101f439acda6..0c935e8f3a6c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c @@ -216,7 +216,7 @@ static int i40e_ptp_settime(struct ptp_clock_info *ptp, } /** - * i40e_ptp_enable - Enable/disable ancillary features of the PHC subsystem + * i40e_ptp_feature_enable - Enable/disable ancillary features of the PHC subsystem * @ptp: The PTP clock structure * @rq: The requested feature to change * @on: Enable/disable flag @@ -224,8 +224,8 @@ static int i40e_ptp_settime(struct ptp_clock_info *ptp, * The XL710 does not support any of the ancillary features of the PHC * subsystem, so this function may just return. **/ -static int i40e_ptp_enable(struct ptp_clock_info *ptp, - struct ptp_clock_request *rq, int on) +static int i40e_ptp_feature_enable(struct ptp_clock_info *ptp, + struct ptp_clock_request *rq, int on) { return -EOPNOTSUPP; } @@ -423,28 +423,23 @@ int i40e_ptp_get_ts_config(struct i40e_pf *pf, struct ifreq *ifr) } /** - * i40e_ptp_set_ts_config - ioctl interface to control the HW timestamping + * i40e_ptp_set_timestamp_mode - setup hardware for requested timestamp mode * @pf: Board private structure - * @ifreq: ioctl data + * @config: hwtstamp settings requested or saved * - * Respond to the user filter requests and make the appropriate hardware - * changes here. The XL710 cannot support splitting of the Tx/Rx timestamping - * logic, so keep track in software of whether to indicate these timestamps - * or not. + * Control hardware registers to enter the specific mode requested by the + * user. Also used during reset path to ensure that timestamp settings are + * maintained. * - * It is permissible to "upgrade" the user request to a broader filter, as long - * as the user receives the timestamps they care about and the user is notified - * the filter has been broadened. + * Note: modifies config in place, and may update the requested mode to be + * more broad if the specific filter is not directly supported. **/ -int i40e_ptp_set_ts_config(struct i40e_pf *pf, struct ifreq *ifr) +static int i40e_ptp_set_timestamp_mode(struct i40e_pf *pf, + struct hwtstamp_config *config) { struct i40e_hw *hw = &pf->hw; - struct hwtstamp_config *config = &pf->tstamp_config; u32 pf_id, tsyntype, regval; - if (copy_from_user(config, ifr->ifr_data, sizeof(*config))) - return -EFAULT; - /* Reserved for future extensions. */ if (config->flags) return -EINVAL; @@ -535,23 +530,59 @@ int i40e_ptp_set_ts_config(struct i40e_pf *pf, struct ifreq *ifr) wr32(hw, I40E_PRTTSYN_CTL1, regval); } - return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ? + return 0; +} + +/** + * i40e_ptp_set_ts_config - ioctl interface to control the HW timestamping + * @pf: Board private structure + * @ifreq: ioctl data + * + * Respond to the user filter requests and make the appropriate hardware + * changes here. The XL710 cannot support splitting of the Tx/Rx timestamping + * logic, so keep track in software of whether to indicate these timestamps + * or not. + * + * It is permissible to "upgrade" the user request to a broader filter, as long + * as the user receives the timestamps they care about and the user is notified + * the filter has been broadened. + **/ +int i40e_ptp_set_ts_config(struct i40e_pf *pf, struct ifreq *ifr) +{ + struct hwtstamp_config config; + int err; + + if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) + return -EFAULT; + + err = i40e_ptp_set_timestamp_mode(pf, &config); + if (err) + return err; + + /* save these settings for future reference */ + pf->tstamp_config = config; + + return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? -EFAULT : 0; } /** - * i40e_ptp_init - Initialize the 1588 support and register the PHC + * i40e_ptp_create_clock - Create PTP clock device for userspace * @pf: Board private structure * - * This function registers the device clock as a PHC. If it is successful, it - * starts the clock in the hardware. + * This function creates a new PTP clock device. It only creates one if we + * don't already have one, so it is safe to call. Will return error if it + * can't create one, but success if we already have a device. Should be used + * by i40e_ptp_init to create clock initially, and prevent global resets from + * creating new clock devices. **/ -void i40e_ptp_init(struct i40e_pf *pf) +static long i40e_ptp_create_clock(struct i40e_pf *pf) { - struct i40e_hw *hw = &pf->hw; - struct net_device *netdev = pf->vsi[pf->lan_vsi]->netdev; + /* no need to create a clock device if we already have one */ + if (!IS_ERR_OR_NULL(pf->ptp_clock)) + return 0; - strncpy(pf->ptp_caps.name, "i40e", sizeof(pf->ptp_caps.name)); + strncpy(pf->ptp_caps.name, i40e_driver_name, sizeof(pf->ptp_caps.name)); pf->ptp_caps.owner = THIS_MODULE; pf->ptp_caps.max_adj = 999999999; pf->ptp_caps.n_ext_ts = 0; @@ -560,11 +591,46 @@ void i40e_ptp_init(struct i40e_pf *pf) pf->ptp_caps.adjtime = i40e_ptp_adjtime; pf->ptp_caps.gettime = i40e_ptp_gettime; pf->ptp_caps.settime = i40e_ptp_settime; - pf->ptp_caps.enable = i40e_ptp_enable; + pf->ptp_caps.enable = i40e_ptp_feature_enable; /* Attempt to register the clock before enabling the hardware. */ pf->ptp_clock = ptp_clock_register(&pf->ptp_caps, &pf->pdev->dev); if (IS_ERR(pf->ptp_clock)) { + return PTR_ERR(pf->ptp_clock); + } + + /* clear the hwtstamp settings here during clock create, instead of + * during regular init, so that we can maintain settings across a + * reset or suspend. + */ + pf->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE; + pf->tstamp_config.tx_type = HWTSTAMP_TX_OFF; + + return 0; +} + +/** + * i40e_ptp_init - Initialize the 1588 support after device probe or reset + * @pf: Board private structure + * + * This function sets device up for 1588 support. The first time it is run, it + * will create a PHC clock device. It does not create a clock device if one + * already exists. It also reconfigures the device after a reset. + **/ +void i40e_ptp_init(struct i40e_pf *pf) +{ + struct net_device *netdev = pf->vsi[pf->lan_vsi]->netdev; + struct i40e_hw *hw = &pf->hw; + long err; + + /* we have to initialize the lock first, since we can't control + * when the user will enter the PHC device entry points + */ + spin_lock_init(&pf->tmreg_lock); + + /* ensure we have a clock device */ + err = i40e_ptp_create_clock(pf); + if (err) { pf->ptp_clock = NULL; dev_err(&pf->pdev->dev, "%s: ptp_clock_register failed\n", __func__); @@ -572,8 +638,6 @@ void i40e_ptp_init(struct i40e_pf *pf) struct timespec ts; u32 regval; - spin_lock_init(&pf->tmreg_lock); - dev_info(&pf->pdev->dev, "%s: added PHC on %s\n", __func__, netdev->name); pf->flags |= I40E_FLAG_PTP; @@ -589,8 +653,8 @@ void i40e_ptp_init(struct i40e_pf *pf) /* Set the increment value per clock tick. */ i40e_ptp_set_increment(pf); - /* reset the tstamp_config */ - memset(&pf->tstamp_config, 0, sizeof(pf->tstamp_config)); + /* reset timestamping mode */ + i40e_ptp_set_timestamp_mode(pf, &pf->tstamp_config); /* Set the clock value. */ ts = ktime_to_timespec(ktime_get_real()); diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index e49f31dbd5d8..5cc27fba8ad5 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -100,8 +100,6 @@ int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, u8 *raw_packet, I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT) & I40E_TXD_FLTR_QW0_DEST_VSI_MASK; - fdir_desc->qindex_flex_ptype_vsi = cpu_to_le32(fpt); - dcc = I40E_TX_DESC_DTYPE_FILTER_PROG; if (add) @@ -124,6 +122,8 @@ int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, u8 *raw_packet, I40E_TXD_FLTR_QW1_CNTINDEX_MASK; } + fdir_desc->qindex_flex_ptype_vsi = cpu_to_le32(fpt); + fdir_desc->rsvd = cpu_to_le32(0); fdir_desc->dtype_cmd_cntindex = cpu_to_le32(dcc); fdir_desc->fd_id = cpu_to_le32(fdir_data->fd_id); @@ -271,19 +271,6 @@ static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi, fd_data->pctype, ret); } - fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP; - - ret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add); - if (ret) { - dev_info(&pf->pdev->dev, - "Filter command send failed for PCTYPE %d (ret = %d)\n", - fd_data->pctype, ret); - err = true; - } else { - dev_info(&pf->pdev->dev, "Filter OK for PCTYPE %d (ret = %d)\n", - fd_data->pctype, ret); - } - return err ? -EOPNOTSUPP : 0; } @@ -450,8 +437,8 @@ static void i40e_fd_handle_status(struct i40e_ring *rx_ring, rx_desc->wb.qword0.hi_dword.fd_id); /* filter programming failed most likely due to table full */ - fcnt_prog = i40e_get_current_fd_count(pf); - fcnt_avail = i40e_get_fd_cnt_all(pf); + fcnt_prog = i40e_get_cur_guaranteed_fd_count(pf); + fcnt_avail = pf->fdir_pf_filter_count; /* If ATR is running fcnt_prog can quickly change, * if we are very close to full, it makes sense to disable * FD ATR/SB and then re-enable it when there is room. @@ -1701,7 +1688,9 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb, I40E_TXD_FLTR_QW1_CNTINDEX_MASK; fdir_desc->qindex_flex_ptype_vsi = cpu_to_le32(flex_ptype); + fdir_desc->rsvd = cpu_to_le32(0); fdir_desc->dtype_cmd_cntindex = cpu_to_le32(dtype_cmd); + fdir_desc->fd_id = cpu_to_le32(0); } /** diff --git a/drivers/net/ethernet/intel/i40evf/i40e_lan_hmc.h b/drivers/net/ethernet/intel/i40evf/i40e_lan_hmc.h index d6f762241537..a5d79877354c 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_lan_hmc.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_lan_hmc.h @@ -32,16 +32,22 @@ struct i40e_hw; /* HMC element context information */ -/* Rx queue context data */ +/* Rx queue context data + * + * The sizes of the variables may be larger than needed due to crossing byte + * boundaries. If we do not have the width of the variable set to the correct + * size then we could end up shifting bits off the top of the variable when the + * variable is at the top of a byte and crosses over into the next byte. + */ struct i40e_hmc_obj_rxq { u16 head; - u8 cpuid; + u16 cpuid; /* bigger than needed, see above for reason */ u64 base; u16 qlen; #define I40E_RXQ_CTX_DBUFF_SHIFT 7 - u8 dbuff; + u16 dbuff; /* bigger than needed, see above for reason */ #define I40E_RXQ_CTX_HBUFF_SHIFT 6 - u8 hbuff; + u16 hbuff; /* bigger than needed, see above for reason */ u8 dtype; u8 dsize; u8 crcstrip; @@ -50,16 +56,22 @@ struct i40e_hmc_obj_rxq { u8 hsplit_0; u8 hsplit_1; u8 showiv; - u16 rxmax; + u32 rxmax; /* bigger than needed, see above for reason */ u8 tphrdesc_ena; u8 tphwdesc_ena; u8 tphdata_ena; u8 tphhead_ena; - u8 lrxqthresh; + u16 lrxqthresh; /* bigger than needed, see above for reason */ u8 prefena; /* NOTE: normally must be set to 1 at init */ }; -/* Tx queue context data */ +/* Tx queue context data +* +* The sizes of the variables may be larger than needed due to crossing byte +* boundaries. If we do not have the width of the variable set to the correct +* size then we could end up shifting bits off the top of the variable when the +* variable is at the top of a byte and crosses over into the next byte. +*/ struct i40e_hmc_obj_txq { u16 head; u8 new_context; @@ -69,7 +81,7 @@ struct i40e_hmc_obj_txq { u8 fd_ena; u8 alt_vlan_ena; u16 thead_wb; - u16 cpuid; + u8 cpuid; u8 head_wb_ena; u16 qlen; u8 tphrdesc_ena; diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index b473172708f5..8082a9fa5d10 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -2018,11 +2018,15 @@ static void i40evf_init_task(struct work_struct *work) if (err) { dev_info(&pdev->dev, "Unable to verify API version (%d), retrying\n", err); + if (err == I40E_ERR_ADMIN_QUEUE_NO_WORK) { + dev_info(&pdev->dev, "Resending request\n"); + err = i40evf_send_api_ver(adapter); + } goto err; } err = i40evf_send_vf_config_msg(adapter); if (err) { - dev_err(&pdev->dev, "Unable send config request (%d)\n", + dev_err(&pdev->dev, "Unable to send config request (%d)\n", err); goto err; } @@ -2408,7 +2412,9 @@ static void i40evf_remove(struct pci_dev *pdev) i40evf_reset_interrupt_capability(adapter); } - del_timer_sync(&adapter->watchdog_timer); + if (adapter->watchdog_timer.function) + del_timer_sync(&adapter->watchdog_timer); + flush_scheduled_work(); if (hw->aq.asq.count) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c index 2dc0bac76717..0ed2ad7e4eee 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c @@ -80,8 +80,9 @@ int i40evf_send_api_ver(struct i40evf_adapter *adapter) * @adapter: adapter structure * * Compare API versions with the PF. Must be called after admin queue is - * initialized. Returns 0 if API versions match, -EIO if - * they do not, or I40E_ERR_ADMIN_QUEUE_NO_WORK if the admin queue is empty. + * initialized. Returns 0 if API versions match, -EIO if they do not, + * I40E_ERR_ADMIN_QUEUE_NO_WORK if the admin queue is empty, and any errors + * from the firmware are propagated. **/ int i40evf_verify_api_ver(struct i40evf_adapter *adapter) { @@ -102,13 +103,13 @@ int i40evf_verify_api_ver(struct i40evf_adapter *adapter) goto out_alloc; err = (i40e_status)le32_to_cpu(event.desc.cookie_low); - if (err) { - err = -EIO; + if (err) goto out_alloc; - } if ((enum i40e_virtchnl_ops)le32_to_cpu(event.desc.cookie_high) != I40E_VIRTCHNL_OP_VERSION) { + dev_info(&adapter->pdev->dev, "Invalid reply type %d from PF\n", + le32_to_cpu(event.desc.cookie_high)); err = -EIO; goto out_alloc; }