Skip to content

Commit

Permalink
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/gi…
Browse files Browse the repository at this point in the history
…t/jkirsher/net-next

Jeff Kirsher says:

====================
Intel Wired LAN Driver Updates 2014-06-26

This series contains updates to i40e and i40evf.

Kamil provides a cleanup patch to i40e where we do not need to acquire the
NVM for shadow RAM checksum calculation, since we only read the shadow RAM
through SRCTL register.

Paul provides a fix for handling HMC for big endian architectures for i40e
and i40evf.

Mitch provides four cleanup and fixes for i40evf.  Fix an issue where if
the VF driver fails to complete early init, then rmmod can cause a softlock
when the driver tries to stop a watchdog timer that never got initialized.
So add a check to see if the timer is actually initialized before stopping
it.  Make the function i40evf_send_api_ver() return more useful information,
instead of just returning -EIO by propagating firmware errors back to the
caller and log a message if the PF sends an invalid reply.  Fix up a log
message that was missing a word, which makes the log message more readable.
Fix an initialization failure if many VFs are instantiated at the same time
and the VF module is autoloaded by simply resending firmware request if
there is no response the first time.

Jacob does a rename of the function i40e_ptp_enable() to
i40e_ptp_feature_enable(), like he did for ixgbe, to reduce possible
confusion and ambugity in the purpose of the function.  Does follow on
PTP work on i40e, like he did for ixgbe, by breaking the PTP hardware
control from the ioctl command for timestamping mode.  By doing this,
we can maintain state about the 1588 timestamping mode and properly
re-enable to the last known mode during a re-initialization of 1588 bits.

Anjali cleans up the i40e driver where TCP-IPv4 filters were being added
twice, which seems to be left over from when we had to add two PTYPEs for
one filter.  Fixes the flow director sideband logic to detect when there
is a full flow director table.  Also fixes the programming of FDIR where
a couple of fields in the descriptor setup that were not being
programmed, which left the opportunity for stale data to be pushed as
part of the descriptor next time it was used.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jun 27, 2014
2 parents 0ff9275 + 99753ea commit c1c27fb
Show file tree
Hide file tree
Showing 11 changed files with 373 additions and 134 deletions.
3 changes: 2 additions & 1 deletion drivers/net/ethernet/intel/i40e/i40e.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
4 changes: 4 additions & 0 deletions drivers/net/ethernet/intel/i40e/i40e_debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -1962,6 +1965,7 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
dev_info(&pf->pdev->dev, " rem fd_filter <dest q_index> <flex_off> <pctype> <dest_vsi> <dest_ctl> <fd_status> <cnt_index> <fd_id> <packet_len> <packet>\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");
Expand Down
247 changes: 196 additions & 51 deletions drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
Expand Down
28 changes: 20 additions & 8 deletions drivers/net/ethernet/intel/i40e/i40e_lan_hmc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand Down
Loading

0 comments on commit c1c27fb

Please sign in to comment.