From 49d7d933316375665cea49473d563cb8447d8a06 Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Wed, 4 Jun 2014 08:45:15 +0000 Subject: i40e/i40evf: Do not free the dummy packet buffer synchronously The HW still needs to consume it and freeing it in the function that created it would mean we will be racing with the HW. The i40e_clean_tx_ring() routine will free up the buffer attached once the HW has consumed it. The clean_fdir_tx_irq function had to be fixed to handle the freeing correctly. Cases where we program more than one filter per flow (Ipv4), the code had to be changed to allocate dummy buffer multiple times since it will be freed by the clean routine. This also fixes an issue where the filter program routine was not checking if there were descriptors available for programming a filter. Change-ID: Idf72028fd873221934e319d021ef65a1e51acaf7 Signed-off-by: Anjali Singhai Jain Tested-by: Jim Young Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 31709b8..440b671 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -3087,16 +3087,33 @@ static bool i40e_clean_fdir_tx_irq(struct i40e_ring *tx_ring, int budget) /* clear next_to_watch to prevent false hangs */ tx_buf->next_to_watch = NULL; + tx_desc->buffer_addr = 0; + tx_desc->cmd_type_offset_bsz = 0; + /* move past filter desc */ + tx_buf++; + tx_desc++; + i++; + if (unlikely(!i)) { + i -= tx_ring->count; + tx_buf = tx_ring->tx_bi; + tx_desc = I40E_TX_DESC(tx_ring, 0); + } /* unmap skb header data */ dma_unmap_single(tx_ring->dev, dma_unmap_addr(tx_buf, dma), dma_unmap_len(tx_buf, len), DMA_TO_DEVICE); + if (tx_buf->tx_flags & I40E_TX_FLAGS_FD_SB) + kfree(tx_buf->raw_buf); + tx_buf->raw_buf = NULL; + tx_buf->tx_flags = 0; + tx_buf->next_to_watch = NULL; dma_unmap_len_set(tx_buf, len, 0); + tx_desc->buffer_addr = 0; + tx_desc->cmd_type_offset_bsz = 0; - - /* move to the next desc and buffer to clean */ + /* move us past the eop_desc for start of next FD desc */ tx_buf++; tx_desc++; i++; diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 051e213..2c686e2 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -39,6 +39,7 @@ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size, } #define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS) +#define I40E_FD_CLEAN_DELAY 10 /** * i40e_program_fdir_filter - Program a Flow Director filter * @fdir_data: Packet data that will be filter parameters @@ -50,7 +51,7 @@ int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, u8 *raw_packet, struct i40e_pf *pf, bool add) { struct i40e_filter_program_desc *fdir_desc; - struct i40e_tx_buffer *tx_buf; + struct i40e_tx_buffer *tx_buf, *first; struct i40e_tx_desc *tx_desc; struct i40e_ring *tx_ring; unsigned int fpt, dcc; @@ -58,6 +59,7 @@ int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, u8 *raw_packet, struct device *dev; dma_addr_t dma; u32 td_cmd = 0; + u16 delay = 0; u16 i; /* find existing FDIR VSI */ @@ -71,6 +73,17 @@ int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, u8 *raw_packet, tx_ring = vsi->tx_rings[0]; dev = tx_ring->dev; + /* we need two descriptors to add/del a filter and we can wait */ + do { + if (I40E_DESC_UNUSED(tx_ring) > 1) + break; + msleep_interruptible(1); + delay++; + } while (delay < I40E_FD_CLEAN_DELAY); + + if (!(I40E_DESC_UNUSED(tx_ring) > 1)) + return -EAGAIN; + dma = dma_map_single(dev, raw_packet, I40E_FDIR_MAX_RAW_PACKET_SIZE, DMA_TO_DEVICE); if (dma_mapping_error(dev, dma)) @@ -79,8 +92,10 @@ int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, u8 *raw_packet, /* grab the next descriptor */ i = tx_ring->next_to_use; fdir_desc = I40E_TX_FDIRDESC(tx_ring, i); + first = &tx_ring->tx_bi[i]; + memset(first, 0, sizeof(struct i40e_tx_buffer)); - tx_ring->next_to_use = (i + 1 < tx_ring->count) ? i + 1 : 0; + tx_ring->next_to_use = ((i + 1) < tx_ring->count) ? i + 1 : 0; fpt = (fdir_data->q_index << I40E_TXD_FLTR_QW0_QINDEX_SHIFT) & I40E_TXD_FLTR_QW0_QINDEX_MASK; @@ -132,7 +147,9 @@ int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, u8 *raw_packet, tx_desc = I40E_TX_DESC(tx_ring, i); tx_buf = &tx_ring->tx_bi[i]; - tx_ring->next_to_use = (i + 1 < tx_ring->count) ? i + 1 : 0; + tx_ring->next_to_use = ((i + 1) < tx_ring->count) ? i + 1 : 0; + + memset(tx_buf, 0, sizeof(struct i40e_tx_buffer)); /* record length, and DMA address */ dma_unmap_len_set(tx_buf, len, I40E_FDIR_MAX_RAW_PACKET_SIZE); @@ -141,6 +158,9 @@ int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, u8 *raw_packet, tx_desc->buffer_addr = cpu_to_le64(dma); td_cmd = I40E_TXD_CMD | I40E_TX_DESC_CMD_DUMMY; + tx_buf->tx_flags = I40E_TX_FLAGS_FD_SB; + tx_buf->raw_buf = (void *)raw_packet; + tx_desc->cmd_type_offset_bsz = build_ctob(td_cmd, 0, I40E_FDIR_MAX_RAW_PACKET_SIZE, 0); @@ -148,14 +168,12 @@ int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, u8 *raw_packet, tx_buf->time_stamp = jiffies; /* Force memory writes to complete before letting h/w - * know there are new descriptors to fetch. (Only - * applicable for weak-ordered memory model archs, - * such as IA-64). + * know there are new descriptors to fetch. */ wmb(); /* Mark the data descriptor to be watched */ - tx_buf->next_to_watch = tx_desc; + first->next_to_watch = tx_desc; writel(tx_ring->next_to_use, tx_ring->tail); return 0; @@ -170,24 +188,27 @@ dma_fail: * i40e_add_del_fdir_udpv4 - Add/Remove UDPv4 filters * @vsi: pointer to the targeted VSI * @fd_data: the flow director data required for the FDir descriptor - * @raw_packet: the pre-allocated packet buffer for FDir * @add: true adds a filter, false removes it * * Returns 0 if the filters were successfully added or removed **/ static int i40e_add_del_fdir_udpv4(struct i40e_vsi *vsi, struct i40e_fdir_filter *fd_data, - u8 *raw_packet, bool add) + bool add) { struct i40e_pf *pf = vsi->back; struct udphdr *udp; struct iphdr *ip; bool err = false; + u8 *raw_packet; int ret; static char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0, 0x45, 0, 0, 0x1c, 0, 0, 0x40, 0, 0x40, 0x11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE, GFP_KERNEL); + if (!raw_packet) + return -ENOMEM; memcpy(raw_packet, packet, I40E_UDPIP_DUMMY_PACKET_LEN); ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET); @@ -220,19 +241,19 @@ static int i40e_add_del_fdir_udpv4(struct i40e_vsi *vsi, * i40e_add_del_fdir_tcpv4 - Add/Remove TCPv4 filters * @vsi: pointer to the targeted VSI * @fd_data: the flow director data required for the FDir descriptor - * @raw_packet: the pre-allocated packet buffer for FDir * @add: true adds a filter, false removes it * * Returns 0 if the filters were successfully added or removed **/ static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi, struct i40e_fdir_filter *fd_data, - u8 *raw_packet, bool add) + bool add) { struct i40e_pf *pf = vsi->back; struct tcphdr *tcp; struct iphdr *ip; bool err = false; + u8 *raw_packet; int ret; /* Dummy packet */ static char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0, @@ -240,6 +261,9 @@ static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80, 0x11, 0x0, 0x72, 0, 0, 0, 0}; + raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE, GFP_KERNEL); + if (!raw_packet) + return -ENOMEM; memcpy(raw_packet, packet, I40E_TCPIP_DUMMY_PACKET_LEN); ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET); @@ -286,7 +310,7 @@ static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi, **/ static int i40e_add_del_fdir_sctpv4(struct i40e_vsi *vsi, struct i40e_fdir_filter *fd_data, - u8 *raw_packet, bool add) + bool add) { return -EOPNOTSUPP; } @@ -297,33 +321,36 @@ static int i40e_add_del_fdir_sctpv4(struct i40e_vsi *vsi, * a specific flow spec * @vsi: pointer to the targeted VSI * @fd_data: the flow director data required for the FDir descriptor - * @raw_packet: the pre-allocated packet buffer for FDir * @add: true adds a filter, false removes it * * Returns 0 if the filters were successfully added or removed **/ static int i40e_add_del_fdir_ipv4(struct i40e_vsi *vsi, struct i40e_fdir_filter *fd_data, - u8 *raw_packet, bool add) + bool add) { struct i40e_pf *pf = vsi->back; struct iphdr *ip; bool err = false; + u8 *raw_packet; int ret; int i; static char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0, 0x45, 0, 0, 0x14, 0, 0, 0x40, 0, 0x40, 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - memcpy(raw_packet, packet, I40E_IP_DUMMY_PACKET_LEN); - ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET); - - ip->saddr = fd_data->src_ip[0]; - ip->daddr = fd_data->dst_ip[0]; - ip->protocol = 0; - for (i = I40E_FILTER_PCTYPE_NONF_IPV4_OTHER; i <= I40E_FILTER_PCTYPE_FRAG_IPV4; i++) { + raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE, GFP_KERNEL); + if (!raw_packet) + return -ENOMEM; + memcpy(raw_packet, packet, I40E_IP_DUMMY_PACKET_LEN); + ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET); + + ip->saddr = fd_data->src_ip[0]; + ip->daddr = fd_data->dst_ip[0]; + ip->protocol = 0; + fd_data->pctype = i; ret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add); @@ -353,50 +380,34 @@ int i40e_add_del_fdir(struct i40e_vsi *vsi, struct i40e_fdir_filter *input, bool add) { struct i40e_pf *pf = vsi->back; - u8 *raw_packet; int ret; - /* Populate the Flow Director that we have at the moment - * and allocate the raw packet buffer for the calling functions - */ - raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE, GFP_KERNEL); - if (!raw_packet) - return -ENOMEM; - switch (input->flow_type & ~FLOW_EXT) { case TCP_V4_FLOW: - ret = i40e_add_del_fdir_tcpv4(vsi, input, raw_packet, - add); + ret = i40e_add_del_fdir_tcpv4(vsi, input, add); break; case UDP_V4_FLOW: - ret = i40e_add_del_fdir_udpv4(vsi, input, raw_packet, - add); + ret = i40e_add_del_fdir_udpv4(vsi, input, add); break; case SCTP_V4_FLOW: - ret = i40e_add_del_fdir_sctpv4(vsi, input, raw_packet, - add); + ret = i40e_add_del_fdir_sctpv4(vsi, input, add); break; case IPV4_FLOW: - ret = i40e_add_del_fdir_ipv4(vsi, input, raw_packet, - add); + ret = i40e_add_del_fdir_ipv4(vsi, input, add); break; case IP_USER_FLOW: switch (input->ip4_proto) { case IPPROTO_TCP: - ret = i40e_add_del_fdir_tcpv4(vsi, input, - raw_packet, add); + ret = i40e_add_del_fdir_tcpv4(vsi, input, add); break; case IPPROTO_UDP: - ret = i40e_add_del_fdir_udpv4(vsi, input, - raw_packet, add); + ret = i40e_add_del_fdir_udpv4(vsi, input, add); break; case IPPROTO_SCTP: - ret = i40e_add_del_fdir_sctpv4(vsi, input, - raw_packet, add); + ret = i40e_add_del_fdir_sctpv4(vsi, input, add); break; default: - ret = i40e_add_del_fdir_ipv4(vsi, input, - raw_packet, add); + ret = i40e_add_del_fdir_ipv4(vsi, input, add); break; } break; @@ -406,7 +417,7 @@ int i40e_add_del_fdir(struct i40e_vsi *vsi, ret = -EINVAL; } - kfree(raw_packet); + /* The buffer allocated here is freed by the i40e_clean_tx_ring() */ return ret; } @@ -480,7 +491,11 @@ static void i40e_unmap_and_free_tx_resource(struct i40e_ring *ring, struct i40e_tx_buffer *tx_buffer) { if (tx_buffer->skb) { - dev_kfree_skb_any(tx_buffer->skb); + if (tx_buffer->tx_flags & I40E_TX_FLAGS_FD_SB) + kfree(tx_buffer->raw_buf); + else + dev_kfree_skb_any(tx_buffer->skb); + if (dma_unmap_len(tx_buffer, len)) dma_unmap_single(ring->dev, dma_unmap_addr(tx_buffer, dma), diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h index f09fb3e..c1c3569 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h @@ -131,6 +131,7 @@ enum i40e_dyn_idx_t { #define I40E_TX_FLAGS_FCCRC (u32)(1 << 6) #define I40E_TX_FLAGS_FSO (u32)(1 << 7) #define I40E_TX_FLAGS_TSYN (u32)(1 << 8) +#define I40E_TX_FLAGS_FD_SB (u32)(1 << 9) #define I40E_TX_FLAGS_VLAN_MASK 0xffff0000 #define I40E_TX_FLAGS_VLAN_PRIO_MASK 0xe0000000 #define I40E_TX_FLAGS_VLAN_PRIO_SHIFT 29 @@ -139,7 +140,10 @@ enum i40e_dyn_idx_t { struct i40e_tx_buffer { struct i40e_tx_desc *next_to_watch; unsigned long time_stamp; - struct sk_buff *skb; + union { + struct sk_buff *skb; + void *raw_buf; + }; unsigned int bytecount; unsigned short gso_segs; DEFINE_DMA_UNMAP_ADDR(dma); diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index f2762f5..b342f21 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -50,7 +50,11 @@ static void i40e_unmap_and_free_tx_resource(struct i40e_ring *ring, struct i40e_tx_buffer *tx_buffer) { if (tx_buffer->skb) { - dev_kfree_skb_any(tx_buffer->skb); + if (tx_buffer->tx_flags & I40E_TX_FLAGS_FD_SB) + kfree(tx_buffer->raw_buf); + else + dev_kfree_skb_any(tx_buffer->skb); + if (dma_unmap_len(tx_buffer, len)) dma_unmap_single(ring->dev, dma_unmap_addr(tx_buffer, dma), diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h b/drivers/net/ethernet/intel/i40evf/i40e_txrx.h index acd3c12..8bc6858 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.h @@ -130,6 +130,7 @@ enum i40e_dyn_idx_t { #define I40E_TX_FLAGS_IPV6 (u32)(1 << 5) #define I40E_TX_FLAGS_FCCRC (u32)(1 << 6) #define I40E_TX_FLAGS_FSO (u32)(1 << 7) +#define I40E_TX_FLAGS_FD_SB (u32)(1 << 9) #define I40E_TX_FLAGS_VLAN_MASK 0xffff0000 #define I40E_TX_FLAGS_VLAN_PRIO_MASK 0xe0000000 #define I40E_TX_FLAGS_VLAN_PRIO_SHIFT 29 @@ -138,7 +139,10 @@ enum i40e_dyn_idx_t { struct i40e_tx_buffer { struct i40e_tx_desc *next_to_watch; unsigned long time_stamp; - struct sk_buff *skb; + union { + struct sk_buff *skb; + void *raw_buf; + }; unsigned int bytecount; unsigned short gso_segs; DEFINE_DMA_UNMAP_ADDR(dma); -- cgit v0.10.2 From 4334edf53a032f54403d1f367b501502a8c61e93 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Wed, 4 Jun 2014 08:45:16 +0000 Subject: i40evf: don't violate scope Move a declaration up one level so we don't dereference it out of scope. This didn't cause any panics, but the details->async field would mysteriously disappear, causing unnecessary delays when sending AQ commands. Also, the code is just plain wrong. Change-ID: I753f64f13c55e5d75ea4351e29b14fb53b2f0104 Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/intel/i40evf/i40e_common.c b/drivers/net/ethernet/intel/i40evf/i40e_common.c index a43155a..4ea90bf 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_common.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_common.c @@ -551,6 +551,7 @@ i40e_status i40e_aq_send_msg_to_pf(struct i40e_hw *hw, struct i40e_asq_cmd_details *cmd_details) { struct i40e_aq_desc desc; + struct i40e_asq_cmd_details details; i40e_status status; i40evf_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_send_msg_to_pf); @@ -565,7 +566,6 @@ i40e_status i40e_aq_send_msg_to_pf(struct i40e_hw *hw, desc.datalen = cpu_to_le16(msglen); } if (!cmd_details) { - struct i40e_asq_cmd_details details; memset(&details, 0, sizeof(details)); details.async = true; cmd_details = &details; -- cgit v0.10.2 From 30fe8ad3667c9060a572e48ca4ada8f3161e5d2e Mon Sep 17 00:00:00 2001 From: Paul M Stillwell Jr Date: Wed, 4 Jun 2014 08:45:17 +0000 Subject: i40e/i40evf: Force a shifted '1' to be unsigned Force a shifted '1' to be unsiged to avoid shifting a signed int Change-ID: I688cbd082af0f2e1df548fda25847a5ca04babcf Signed-off-by: Paul M Stillwell Jr Tested-by: Jim Young Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/intel/i40e/i40e_hmc.h b/drivers/net/ethernet/intel/i40e/i40e_hmc.h index b45d8fe..732a026 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_hmc.h +++ b/drivers/net/ethernet/intel/i40e/i40e_hmc.h @@ -127,7 +127,7 @@ struct i40e_hmc_info { ((((type) == I40E_SD_TYPE_PAGED) ? 0 : 1) << \ I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT) | \ (1 << I40E_PFHMC_SDDATALOW_PMSDVALID_SHIFT); \ - val3 = (sd_index) | (1 << I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \ + val3 = (sd_index) | (1u << I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \ wr32((hw), I40E_PFHMC_SDDATAHIGH, val1); \ wr32((hw), I40E_PFHMC_SDDATALOW, val2); \ wr32((hw), I40E_PFHMC_SDCMD, val3); \ @@ -146,7 +146,7 @@ struct i40e_hmc_info { I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT) | \ ((((type) == I40E_SD_TYPE_PAGED) ? 0 : 1) << \ I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT); \ - val3 = (sd_index) | (1 << I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \ + val3 = (sd_index) | (1u << I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \ wr32((hw), I40E_PFHMC_SDDATAHIGH, 0); \ wr32((hw), I40E_PFHMC_SDDATALOW, val2); \ wr32((hw), I40E_PFHMC_SDCMD, val3); \ diff --git a/drivers/net/ethernet/intel/i40evf/i40e_hmc.h b/drivers/net/ethernet/intel/i40evf/i40e_hmc.h index a2ad9a4..931c880 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_hmc.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_hmc.h @@ -127,7 +127,7 @@ struct i40e_hmc_info { ((((type) == I40E_SD_TYPE_PAGED) ? 0 : 1) << \ I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT) | \ (1 << I40E_PFHMC_SDDATALOW_PMSDVALID_SHIFT); \ - val3 = (sd_index) | (1 << I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \ + val3 = (sd_index) | (1u << I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \ wr32((hw), I40E_PFHMC_SDDATAHIGH, val1); \ wr32((hw), I40E_PFHMC_SDDATALOW, val2); \ wr32((hw), I40E_PFHMC_SDCMD, val3); \ @@ -146,7 +146,7 @@ struct i40e_hmc_info { I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT) | \ ((((type) == I40E_SD_TYPE_PAGED) ? 0 : 1) << \ I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT); \ - val3 = (sd_index) | (1 << I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \ + val3 = (sd_index) | (1u << I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \ wr32((hw), I40E_PFHMC_SDDATAHIGH, 0); \ wr32((hw), I40E_PFHMC_SDDATALOW, val2); \ wr32((hw), I40E_PFHMC_SDCMD, val3); \ -- cgit v0.10.2 From 56497978bcbcde7a310ebaf2b67a936c66397593 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Wed, 4 Jun 2014 08:45:18 +0000 Subject: i40e: tolerate lost interrupts If the AQ interrupt gets lost for some reason, VF communications will stall as the VFs have no way of reaching the PF, which is essentially deaf. The VFs end up waiting forever for a reply that will never come. To alleviate this condition, go ahead and check the ARQ every time we run the service task. Remove the check for a pending event, and get rid of a chatty error message that is now meaningless. Change-ID: I0fc9d18169cd45c98f60188aef872cd6cee9a027 Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 440b671..88704c0 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -5314,9 +5314,6 @@ static void i40e_clean_adminq_subtask(struct i40e_pf *pf) u32 oldval; u32 val; - if (!test_bit(__I40E_ADMINQ_EVENT_PENDING, &pf->state)) - return; - /* check for error indications */ val = rd32(&pf->hw, pf->hw.aq.arq.len); oldval = val; @@ -5360,10 +5357,9 @@ static void i40e_clean_adminq_subtask(struct i40e_pf *pf) do { event.msg_size = I40E_MAX_AQ_BUF_SIZE; /* reinit each time */ ret = i40e_clean_arq_element(hw, &event, &pending); - if (ret == I40E_ERR_ADMIN_QUEUE_NO_WORK) { - dev_info(&pf->pdev->dev, "No ARQ event found\n"); + if (ret == I40E_ERR_ADMIN_QUEUE_NO_WORK) break; - } else if (ret) { + else if (ret) { dev_info(&pf->pdev->dev, "ARQ event error %d\n", ret); break; } -- cgit v0.10.2 From 164ec1bfa13d34834a72b2ace3ecb521234f444f Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Wed, 4 Jun 2014 08:45:19 +0000 Subject: i40evf: invite vector 0 to the interrupt party The i40evf_irq_enable and i40evf_fire_sw_interrupt functions were unfairly discriminating against MSI-X vector 0, just because it doesn't handle traffic. That doesn't mean it's not essential to the operation of the driver. This change allows the watchdog to fire vector 0 via software, which makes the driver tolerant of dropped interrupts on that vector. Buck up, vector 0! You can be part of our gang! Change-ID: I37131d955018a6b3e711e1732d21428acd0d767e Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 5f29e58..6186149 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -260,6 +260,12 @@ static void i40evf_fire_sw_int(struct i40evf_adapter *adapter, int i; uint32_t dyn_ctl; + if (mask & 1) { + dyn_ctl = rd32(hw, I40E_VFINT_DYN_CTL01); + dyn_ctl |= I40E_VFINT_DYN_CTLN_SWINT_TRIG_MASK | + I40E_VFINT_DYN_CTLN_CLEARPBA_MASK; + wr32(hw, I40E_VFINT_DYN_CTL01, dyn_ctl); + } for (i = 1; i < adapter->num_msix_vectors; i++) { if (mask & (1 << i)) { dyn_ctl = rd32(hw, I40E_VFINT_DYN_CTLN1(i - 1)); @@ -278,6 +284,7 @@ void i40evf_irq_enable(struct i40evf_adapter *adapter, bool flush) { struct i40e_hw *hw = &adapter->hw; + i40evf_misc_irq_enable(adapter); i40evf_irq_enable_queues(adapter, ~0); if (flush) -- cgit v0.10.2 From 8a4f34fbef029771f686ee93311fb2b488247b16 Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Wed, 4 Jun 2014 08:45:20 +0000 Subject: i40e: Fix a boundary condition and turning off of ntuple When turning off ntuple with a FD table full situation, the driver would have auto disabled FD filter additions. Clear the auto disable flag for FD_SB so that when the feature is turned on again using "ethtool -K ethx ntuple on" we can start adding filters once again. Change-ID: I036a32e7331bcae765b657c8abb4fa070940b163 Signed-off-by: Anjali Singhai Jain Tested-by: Jim Young Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 88704c0..d9dcb8c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -6885,9 +6885,11 @@ bool i40e_set_ntuple(struct i40e_pf *pf, netdev_features_t features) i40e_fdir_filter_exit(pf); } pf->flags &= ~I40E_FLAG_FD_SB_ENABLED; - /* if ATR was disabled it can be re-enabled. */ - if (!(pf->flags & I40E_FLAG_FD_ATR_ENABLED)) - pf->flags |= I40E_FLAG_FD_ATR_ENABLED; + pf->auto_disable_flags &= ~I40E_FLAG_FD_SB_ENABLED; + /* if ATR was auto disabled it can be re-enabled. */ + if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) && + (pf->auto_disable_flags & I40E_FLAG_FD_ATR_ENABLED)) + pf->auto_disable_flags &= ~I40E_FLAG_FD_ATR_ENABLED; } return need_reset; } -- cgit v0.10.2 From f846c1a038641de7eb2542b8537b211bdd30dd1a Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Wed, 4 Jun 2014 08:45:21 +0000 Subject: i40e: disable TPH TPH is not currently enabled in this product, make sure it isn't enabled by default. Change-ID: Ibb1a10799c33c4c76dec06fcd53b1d6efa13c1f5 Signed-off-by: Jesse Brandeburg Tested-by: Jim Young Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index d9dcb8c..ac90d5f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -2401,10 +2401,6 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring) rx_ctx.rxmax = min_t(u16, vsi->max_frame, (chain_len * ring->rx_buf_len)); - rx_ctx.tphrdesc_ena = 1; - rx_ctx.tphwdesc_ena = 1; - rx_ctx.tphdata_ena = 1; - rx_ctx.tphhead_ena = 1; if (hw->revision_id == 0) rx_ctx.lrxqthresh = 0; else diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index d2dabae..cafda0c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -347,10 +347,6 @@ static int i40e_config_vsi_rx_queue(struct i40e_vf *vf, u16 vsi_idx, rx_ctx.dsize = 1; /* default values */ - rx_ctx.tphrdesc_ena = 1; - rx_ctx.tphwdesc_ena = 1; - rx_ctx.tphdata_ena = 1; - rx_ctx.tphhead_ena = 1; rx_ctx.lrxqthresh = 2; rx_ctx.crcstrip = 1; rx_ctx.prefena = 1; -- cgit v0.10.2 From 4e91bcd5d47a92aa52a0520cb2b0c6f93c80dd6b Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Wed, 4 Jun 2014 08:45:23 +0000 Subject: i40e: Finish implementation of ethtool get settings Finish the i40e implementation of get_settings for ethtool. Change-ID: Iec81835aa9380723ae9288bcb79b30a6a1ecd498 Signed-off-by: Jesse Brandeburg Signed-off-by: Catherine Sullivan Tested-by: Jim Young Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index df89b6c..b105e6f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -215,52 +215,135 @@ static int i40e_get_settings(struct net_device *netdev, /* hardware is either in 40G mode or 10G mode * NOTE: this section initializes supported and advertising */ + if (!link_up) { + /* link is down and the driver needs to fall back on + * device ID to determine what kinds of info to display, + * it's mostly a guess that may change when link is up + */ + switch (hw->device_id) { + case I40E_DEV_ID_QSFP_A: + case I40E_DEV_ID_QSFP_B: + case I40E_DEV_ID_QSFP_C: + /* pluggable QSFP */ + ecmd->supported = SUPPORTED_40000baseSR4_Full | + SUPPORTED_40000baseCR4_Full | + SUPPORTED_40000baseLR4_Full; + ecmd->advertising = ADVERTISED_40000baseSR4_Full | + ADVERTISED_40000baseCR4_Full | + ADVERTISED_40000baseLR4_Full; + break; + case I40E_DEV_ID_KX_B: + /* backplane 40G */ + ecmd->supported = SUPPORTED_40000baseKR4_Full; + ecmd->advertising = ADVERTISED_40000baseKR4_Full; + break; + case I40E_DEV_ID_KX_C: + /* backplane 10G */ + ecmd->supported = SUPPORTED_10000baseKR_Full; + ecmd->advertising = ADVERTISED_10000baseKR_Full; + break; + default: + /* all the rest are 10G/1G */ + ecmd->supported = SUPPORTED_10000baseT_Full | + SUPPORTED_1000baseT_Full; + ecmd->advertising = ADVERTISED_10000baseT_Full | + ADVERTISED_1000baseT_Full; + break; + } + + /* skip phy_type use as it is zero when link is down */ + goto no_valid_phy_type; + } + switch (hw_link_info->phy_type) { case I40E_PHY_TYPE_40GBASE_CR4: case I40E_PHY_TYPE_40GBASE_CR4_CU: - ecmd->supported = SUPPORTED_40000baseCR4_Full; - ecmd->advertising = ADVERTISED_40000baseCR4_Full; + ecmd->supported = SUPPORTED_Autoneg | + SUPPORTED_40000baseCR4_Full; + ecmd->advertising = ADVERTISED_Autoneg | + ADVERTISED_40000baseCR4_Full; break; case I40E_PHY_TYPE_40GBASE_KR4: - ecmd->supported = SUPPORTED_40000baseKR4_Full; - ecmd->advertising = ADVERTISED_40000baseKR4_Full; + ecmd->supported = SUPPORTED_Autoneg | + SUPPORTED_40000baseKR4_Full; + ecmd->advertising = ADVERTISED_Autoneg | + ADVERTISED_40000baseKR4_Full; break; case I40E_PHY_TYPE_40GBASE_SR4: + case I40E_PHY_TYPE_XLPPI: + case I40E_PHY_TYPE_XLAUI: ecmd->supported = SUPPORTED_40000baseSR4_Full; - ecmd->advertising = ADVERTISED_40000baseSR4_Full; break; case I40E_PHY_TYPE_40GBASE_LR4: ecmd->supported = SUPPORTED_40000baseLR4_Full; - ecmd->advertising = ADVERTISED_40000baseLR4_Full; break; case I40E_PHY_TYPE_10GBASE_KX4: - ecmd->supported = SUPPORTED_10000baseKX4_Full; - ecmd->advertising = ADVERTISED_10000baseKX4_Full; + ecmd->supported = SUPPORTED_Autoneg | + SUPPORTED_10000baseKX4_Full; + ecmd->advertising = ADVERTISED_Autoneg | + ADVERTISED_10000baseKX4_Full; break; case I40E_PHY_TYPE_10GBASE_KR: - ecmd->supported = SUPPORTED_10000baseKR_Full; - ecmd->advertising = ADVERTISED_10000baseKR_Full; + ecmd->supported = SUPPORTED_Autoneg | + SUPPORTED_10000baseKR_Full; + ecmd->advertising = ADVERTISED_Autoneg | + ADVERTISED_10000baseKR_Full; break; - default: - if (i40e_is_40G_device(hw->device_id)) { - ecmd->supported = SUPPORTED_40000baseSR4_Full; - ecmd->advertising = ADVERTISED_40000baseSR4_Full; - } else { - ecmd->supported = SUPPORTED_10000baseT_Full; - ecmd->advertising = ADVERTISED_10000baseT_Full; - } + case I40E_PHY_TYPE_10GBASE_SR: + case I40E_PHY_TYPE_10GBASE_LR: + ecmd->supported = SUPPORTED_10000baseT_Full; + break; + case I40E_PHY_TYPE_10GBASE_CR1_CU: + case I40E_PHY_TYPE_10GBASE_CR1: + case I40E_PHY_TYPE_10GBASE_T: + ecmd->supported = SUPPORTED_Autoneg | + SUPPORTED_10000baseT_Full; + ecmd->advertising = ADVERTISED_Autoneg | + ADVERTISED_10000baseT_Full; + break; + case I40E_PHY_TYPE_XAUI: + case I40E_PHY_TYPE_XFI: + case I40E_PHY_TYPE_SFI: + case I40E_PHY_TYPE_10GBASE_SFPP_CU: + ecmd->supported = SUPPORTED_10000baseT_Full; break; + case I40E_PHY_TYPE_1000BASE_KX: + case I40E_PHY_TYPE_1000BASE_T: + ecmd->supported = SUPPORTED_Autoneg | + SUPPORTED_1000baseT_Full; + ecmd->advertising = ADVERTISED_Autoneg | + ADVERTISED_1000baseT_Full; + break; + case I40E_PHY_TYPE_100BASE_TX: + ecmd->supported = SUPPORTED_Autoneg | + SUPPORTED_100baseT_Full; + ecmd->advertising = ADVERTISED_Autoneg | + ADVERTISED_100baseT_Full; + break; + case I40E_PHY_TYPE_SGMII: + ecmd->supported = SUPPORTED_Autoneg | + SUPPORTED_1000baseT_Full | + SUPPORTED_100baseT_Full; + ecmd->advertising = ADVERTISED_Autoneg | + ADVERTISED_1000baseT_Full | + ADVERTISED_100baseT_Full; + break; + default: + /* if we got here and link is up something bad is afoot */ + WARN_ON(link_up); } - ecmd->supported |= SUPPORTED_Autoneg; - ecmd->advertising |= ADVERTISED_Autoneg; +no_valid_phy_type: + /* this is if autoneg is enabled or disabled */ ecmd->autoneg = ((hw_link_info->an_info & I40E_AQ_AN_COMPLETED) ? AUTONEG_ENABLE : AUTONEG_DISABLE); switch (hw->phy.media_type) { case I40E_MEDIA_TYPE_BACKPLANE: - ecmd->supported |= SUPPORTED_Backplane; - ecmd->advertising |= ADVERTISED_Backplane; + ecmd->supported |= SUPPORTED_Autoneg | + SUPPORTED_Backplane; + ecmd->advertising |= ADVERTISED_Autoneg | + ADVERTISED_Backplane; ecmd->port = PORT_NONE; break; case I40E_MEDIA_TYPE_BASET: @@ -276,7 +359,6 @@ static int i40e_get_settings(struct net_device *netdev, break; case I40E_MEDIA_TYPE_FIBER: ecmd->supported |= SUPPORTED_FIBRE; - ecmd->advertising |= ADVERTISED_FIBRE; ecmd->port = PORT_FIBRE; break; case I40E_MEDIA_TYPE_UNKNOWN: @@ -287,6 +369,25 @@ static int i40e_get_settings(struct net_device *netdev, ecmd->transceiver = XCVR_EXTERNAL; + ecmd->supported |= SUPPORTED_Pause; + + switch (hw->fc.current_mode) { + case I40E_FC_FULL: + ecmd->advertising |= ADVERTISED_Pause; + break; + case I40E_FC_TX_PAUSE: + ecmd->advertising |= ADVERTISED_Asym_Pause; + break; + case I40E_FC_RX_PAUSE: + ecmd->advertising |= (ADVERTISED_Pause | + ADVERTISED_Asym_Pause); + break; + default: + ecmd->advertising &= ~(ADVERTISED_Pause | + ADVERTISED_Asym_Pause); + break; + } + if (link_up) { switch (link_speed) { case I40E_LINK_SPEED_40GB: @@ -296,6 +397,9 @@ static int i40e_get_settings(struct net_device *netdev, case I40E_LINK_SPEED_10GB: ethtool_cmd_speed_set(ecmd, SPEED_10000); break; + case I40E_LINK_SPEED_1GB: + ethtool_cmd_speed_set(ecmd, SPEED_1000); + break; default: break; } -- cgit v0.10.2 From 8109e1232b3e5322415a9b5e09951617c5fae277 Mon Sep 17 00:00:00 2001 From: Catherine Sullivan Date: Wed, 4 Jun 2014 08:45:24 +0000 Subject: i40e/i40evf: Add new HW link info variable an_enabled and function update_link_info Add a new variable, hw.phy.link_info.an_enabled, to track whether autoneg is enabled. Also add a new function update_link_info that will update that variable as well as calling get_link_info to update the rest of the link info. Also add get_phy_capabilities to support this. Change-ID: I5157ef03492b6dd8ec5e608ba0cf9b0db9c01710 Signed-off-by: Catherine Sullivan Tested-by: Jim Young Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index 9d09ab3..debca01 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -1037,6 +1037,52 @@ void i40e_led_set(struct i40e_hw *hw, u32 mode, bool blink) /* Admin command wrappers */ /** + * i40e_aq_get_phy_capabilities + * @hw: pointer to the hw struct + * @abilities: structure for PHY capabilities to be filled + * @qualified_modules: report Qualified Modules + * @report_init: report init capabilities (active are default) + * @cmd_details: pointer to command details structure or NULL + * + * Returns the various PHY abilities supported on the Port. + **/ +i40e_status i40e_aq_get_phy_capabilities(struct i40e_hw *hw, + bool qualified_modules, bool report_init, + struct i40e_aq_get_phy_abilities_resp *abilities, + struct i40e_asq_cmd_details *cmd_details) +{ + struct i40e_aq_desc desc; + i40e_status status; + u16 abilities_size = sizeof(struct i40e_aq_get_phy_abilities_resp); + + if (!abilities) + return I40E_ERR_PARAM; + + i40e_fill_default_direct_cmd_desc(&desc, + i40e_aqc_opc_get_phy_abilities); + + desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_BUF); + if (abilities_size > I40E_AQ_LARGE_BUF) + desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB); + + if (qualified_modules) + desc.params.external.param0 |= + cpu_to_le32(I40E_AQ_PHY_REPORT_QUALIFIED_MODULES); + + if (report_init) + desc.params.external.param0 |= + cpu_to_le32(I40E_AQ_PHY_REPORT_INITIAL_VALUES); + + status = i40e_asq_send_command(hw, &desc, abilities, abilities_size, + cmd_details); + + if (hw->aq.asq_last_status == I40E_AQ_RC_EIO) + status = I40E_ERR_UNKNOWN_PHY; + + return status; +} + +/** * i40e_aq_clear_pxe_mode * @hw: pointer to the hw struct * @cmd_details: pointer to command details structure or NULL @@ -1163,6 +1209,35 @@ aq_get_link_info_exit: } /** + * i40e_update_link_info + * @hw: pointer to the hw struct + * @enable_lse: enable/disable LinkStatusEvent reporting + * + * Returns the link status of the adapter + **/ +i40e_status i40e_update_link_info(struct i40e_hw *hw, bool enable_lse) +{ + struct i40e_aq_get_phy_abilities_resp abilities; + i40e_status status; + + status = i40e_aq_get_link_info(hw, enable_lse, NULL, NULL); + if (status) + return status; + + status = i40e_aq_get_phy_capabilities(hw, false, false, + &abilities, NULL); + if (status) + return status; + + if (abilities.abilities & I40E_AQ_PHY_AN_ENABLED) + hw->phy.link_info.an_enabled = true; + else + hw->phy.link_info.an_enabled = false; + + return status; +} + +/** * i40e_aq_add_vsi * @hw: pointer to the hw struct * @vsi_ctx: pointer to a vsi context struct diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index ac90d5f..71eff16 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -5292,7 +5292,7 @@ static void i40e_handle_link_event(struct i40e_pf *pf, * then see if the status changed while processing the * initial event. */ - i40e_aq_get_link_info(&pf->hw, true, NULL, NULL); + i40e_update_link_info(&pf->hw, true); i40e_link_event(pf); } @@ -8337,7 +8337,7 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit) i40e_config_rss(pf); /* fill in link information and enable LSE reporting */ - i40e_aq_get_link_info(&pf->hw, true, NULL, NULL); + i40e_update_link_info(&pf->hw, true); i40e_link_event(pf); /* Initialize user-specific link properties */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h index 77c515d..6790878 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h @@ -82,6 +82,7 @@ i40e_status i40e_aq_set_link_restart_an(struct i40e_hw *hw, i40e_status i40e_aq_get_link_info(struct i40e_hw *hw, bool enable_lse, struct i40e_link_status *link, struct i40e_asq_cmd_details *cmd_details); +i40e_status i40e_update_link_info(struct i40e_hw *hw, bool enable_lse); i40e_status i40e_aq_set_local_advt_reg(struct i40e_hw *hw, u64 advt_reg, struct i40e_asq_cmd_details *cmd_details); diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 11dd2dc..f1c58ab 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -166,6 +166,7 @@ struct i40e_link_status { u8 an_info; u8 ext_info; u8 loopback; + bool an_enabled; /* is Link Status Event notification to SW enabled */ bool lse_enable; u16 max_frame_size; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h index 23cd18b..5b6e955 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h @@ -166,6 +166,7 @@ struct i40e_link_status { u8 an_info; u8 ext_info; u8 loopback; + bool an_enabled; /* is Link Status Event notification to SW enabled */ bool lse_enable; u16 max_frame_size; -- cgit v0.10.2 From a65997215be9f54dbc927b05fc8eb2fe55912d11 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Wed, 4 Jun 2014 08:45:25 +0000 Subject: i40e: move nway reset Just move nway reset up, will be used in the next patch. Change-ID: Ice3b631fa2044debc5c4541b42872a48163f8452 Signed-off-by: Jesse Brandeburg Tested-by: Jim Young Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index b105e6f..6508a1b 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -412,6 +412,25 @@ no_valid_phy_type: return 0; } +static int i40e_nway_reset(struct net_device *netdev) +{ + /* restart autonegotiation */ + struct i40e_netdev_priv *np = netdev_priv(netdev); + struct i40e_pf *pf = np->vsi->back; + struct i40e_hw *hw = &pf->hw; + bool link_up = hw->phy.link_info.link_info & I40E_AQ_LINK_UP; + i40e_status ret = 0; + + ret = i40e_aq_set_link_restart_an(hw, link_up, NULL); + if (ret) { + netdev_info(netdev, "link restart failed, aq_err=%d\n", + pf->hw.aq.asq_last_status); + return -EIO; + } + + return 0; +} + /** * i40e_get_pauseparam - Get Flow Control status * Return tx/rx-pause status @@ -1125,25 +1144,6 @@ static int i40e_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) return 0; } -static int i40e_nway_reset(struct net_device *netdev) -{ - /* restart autonegotiation */ - struct i40e_netdev_priv *np = netdev_priv(netdev); - struct i40e_pf *pf = np->vsi->back; - struct i40e_hw *hw = &pf->hw; - bool link_up = hw->phy.link_info.link_info & I40E_AQ_LINK_UP; - i40e_status ret = 0; - - ret = i40e_aq_set_link_restart_an(hw, link_up, NULL); - if (ret) { - netdev_info(netdev, "link restart failed, aq_err=%d\n", - pf->hw.aq.asq_last_status); - return -EIO; - } - - return 0; -} - static int i40e_set_phys_id(struct net_device *netdev, enum ethtool_phys_id_state state) { -- cgit v0.10.2 From c56999f94876b21cf18301076b9687ecdafdc9e5 Mon Sep 17 00:00:00 2001 From: Catherine Sullivan Date: Wed, 4 Jun 2014 08:45:26 +0000 Subject: i40e/i40evf: Add set_fc and init of FC settings Add function set_fc to set the requested FC mode. This patch also adds the init of FC setting to get_link_info and replaces the init code to set FC off by default in main. Also adds i40e_set_phy_config to support this. Change-ID: I7b25bbaec81f15777137ab324a095f916e44351d Signed-off-by: Catherine Sullivan Tested-by: Jim Young Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index debca01..bf808d4 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -1083,6 +1083,118 @@ i40e_status i40e_aq_get_phy_capabilities(struct i40e_hw *hw, } /** + * i40e_aq_set_phy_config + * @hw: pointer to the hw struct + * @config: structure with PHY configuration to be set + * @cmd_details: pointer to command details structure or NULL + * + * Set the various PHY configuration parameters + * supported on the Port.One or more of the Set PHY config parameters may be + * ignored in an MFP mode as the PF may not have the privilege to set some + * of the PHY Config parameters. This status will be indicated by the + * command response. + **/ +enum i40e_status_code i40e_aq_set_phy_config(struct i40e_hw *hw, + struct i40e_aq_set_phy_config *config, + struct i40e_asq_cmd_details *cmd_details) +{ + struct i40e_aq_desc desc; + struct i40e_aq_set_phy_config *cmd = + (struct i40e_aq_set_phy_config *)&desc.params.raw; + enum i40e_status_code status; + + if (!config) + return I40E_ERR_PARAM; + + i40e_fill_default_direct_cmd_desc(&desc, + i40e_aqc_opc_set_phy_config); + + *cmd = *config; + + status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details); + + return status; +} + +/** + * i40e_set_fc + * @hw: pointer to the hw struct + * + * Set the requested flow control mode using set_phy_config. + **/ +enum i40e_status_code i40e_set_fc(struct i40e_hw *hw, u8 *aq_failures, + bool atomic_restart) +{ + enum i40e_fc_mode fc_mode = hw->fc.requested_mode; + struct i40e_aq_get_phy_abilities_resp abilities; + struct i40e_aq_set_phy_config config; + enum i40e_status_code status; + u8 pause_mask = 0x0; + + *aq_failures = 0x0; + + switch (fc_mode) { + case I40E_FC_FULL: + pause_mask |= I40E_AQ_PHY_FLAG_PAUSE_TX; + pause_mask |= I40E_AQ_PHY_FLAG_PAUSE_RX; + break; + case I40E_FC_RX_PAUSE: + pause_mask |= I40E_AQ_PHY_FLAG_PAUSE_RX; + break; + case I40E_FC_TX_PAUSE: + pause_mask |= I40E_AQ_PHY_FLAG_PAUSE_TX; + break; + default: + break; + } + + /* Get the current phy config */ + status = i40e_aq_get_phy_capabilities(hw, false, false, &abilities, + NULL); + if (status) { + *aq_failures |= I40E_SET_FC_AQ_FAIL_GET; + return status; + } + + memset(&config, 0, sizeof(struct i40e_aq_set_phy_config)); + /* clear the old pause settings */ + config.abilities = abilities.abilities & ~(I40E_AQ_PHY_FLAG_PAUSE_TX) & + ~(I40E_AQ_PHY_FLAG_PAUSE_RX); + /* set the new abilities */ + config.abilities |= pause_mask; + /* If the abilities have changed, then set the new config */ + if (config.abilities != abilities.abilities) { + /* Auto restart link so settings take effect */ + if (atomic_restart) + config.abilities |= I40E_AQ_PHY_ENABLE_ATOMIC_LINK; + /* Copy over all the old settings */ + config.phy_type = abilities.phy_type; + config.link_speed = abilities.link_speed; + config.eee_capability = abilities.eee_capability; + config.eeer = abilities.eeer_val; + config.low_power_ctrl = abilities.d3_lpan; + status = i40e_aq_set_phy_config(hw, &config, NULL); + + if (status) + *aq_failures |= I40E_SET_FC_AQ_FAIL_SET; + } + /* Update the link info */ + status = i40e_update_link_info(hw, true); + if (status) { + /* Wait a little bit (on 40G cards it sometimes takes a really + * long time for link to come back from the atomic reset) + * and try once more + */ + msleep(1000); + status = i40e_update_link_info(hw, true); + } + if (status) + *aq_failures |= I40E_SET_FC_AQ_FAIL_UPDATE; + + return status; +} + +/** * i40e_aq_clear_pxe_mode * @hw: pointer to the hw struct * @cmd_details: pointer to command details structure or NULL @@ -1158,6 +1270,7 @@ i40e_status i40e_aq_get_link_info(struct i40e_hw *hw, (struct i40e_aqc_get_link_status *)&desc.params.raw; struct i40e_link_status *hw_link_info = &hw->phy.link_info; i40e_status status; + bool tx_pause, rx_pause; u16 command_flags; i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_get_link_status); @@ -1187,6 +1300,18 @@ i40e_status i40e_aq_get_link_info(struct i40e_hw *hw, hw_link_info->max_frame_size = le16_to_cpu(resp->max_frame_size); hw_link_info->pacing = resp->config & I40E_AQ_CONFIG_PACING_MASK; + /* update fc info */ + tx_pause = !!(resp->an_info & I40E_AQ_LINK_PAUSE_TX); + rx_pause = !!(resp->an_info & I40E_AQ_LINK_PAUSE_RX); + if (tx_pause & rx_pause) + hw->fc.current_mode = I40E_FC_FULL; + else if (tx_pause) + hw->fc.current_mode = I40E_FC_TX_PAUSE; + else if (rx_pause) + hw->fc.current_mode = I40E_FC_RX_PAUSE; + else + hw->fc.current_mode = I40E_FC_NONE; + if (resp->config & I40E_AQ_CONFIG_CRC_ENA) hw_link_info->crc_enable = true; else diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 71eff16..44cea6a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -4326,8 +4326,12 @@ static void i40e_print_link_message(struct i40e_vsi *vsi, bool isup) static int i40e_up_complete(struct i40e_vsi *vsi) { struct i40e_pf *pf = vsi->back; + u8 set_fc_aq_fail = 0; int err; + /* force flow control off */ + i40e_set_fc(&pf->hw, &set_fc_aq_fail, true); + if (pf->flags & I40E_FLAG_MSIX_ENABLED) i40e_vsi_configure_msix(vsi); else @@ -8277,7 +8281,6 @@ int i40e_fetch_switch_configuration(struct i40e_pf *pf, bool printconfig) **/ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit) { - u32 rxfc = 0, txfc = 0, rxfc_reg; int ret; /* find out what's out there already */ @@ -8343,62 +8346,7 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit) /* Initialize user-specific link properties */ pf->fc_autoneg_status = ((pf->hw.phy.link_info.an_info & I40E_AQ_AN_COMPLETED) ? true : false); - /* requested_mode is set in probe or by ethtool */ - if (!pf->fc_autoneg_status) - goto no_autoneg; - - if ((pf->hw.phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX) && - (pf->hw.phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX)) - pf->hw.fc.current_mode = I40E_FC_FULL; - else if (pf->hw.phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX) - pf->hw.fc.current_mode = I40E_FC_TX_PAUSE; - else if (pf->hw.phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX) - pf->hw.fc.current_mode = I40E_FC_RX_PAUSE; - else - pf->hw.fc.current_mode = I40E_FC_NONE; - - /* sync the flow control settings with the auto-neg values */ - switch (pf->hw.fc.current_mode) { - case I40E_FC_FULL: - txfc = 1; - rxfc = 1; - break; - case I40E_FC_TX_PAUSE: - txfc = 1; - rxfc = 0; - break; - case I40E_FC_RX_PAUSE: - txfc = 0; - rxfc = 1; - break; - case I40E_FC_NONE: - case I40E_FC_DEFAULT: - txfc = 0; - rxfc = 0; - break; - case I40E_FC_PFC: - /* TBD */ - break; - /* no default case, we have to handle all possibilities here */ - } - - wr32(&pf->hw, I40E_PRTDCB_FCCFG, txfc << I40E_PRTDCB_FCCFG_TFCE_SHIFT); - - rxfc_reg = rd32(&pf->hw, I40E_PRTDCB_MFLCN) & - ~I40E_PRTDCB_MFLCN_RFCE_MASK; - rxfc_reg |= (rxfc << I40E_PRTDCB_MFLCN_RFCE_SHIFT); - - wr32(&pf->hw, I40E_PRTDCB_MFLCN, rxfc_reg); - - goto fc_complete; - -no_autoneg: - /* disable L2 flow control, user can turn it on if they wish */ - wr32(&pf->hw, I40E_PRTDCB_FCCFG, 0); - wr32(&pf->hw, I40E_PRTDCB_MFLCN, rd32(&pf->hw, I40E_PRTDCB_MFLCN) & - ~I40E_PRTDCB_MFLCN_RFCE_MASK); -fc_complete: i40e_ptp_init(pf); return ret; diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h index 6790878..b6849fb 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h @@ -74,6 +74,15 @@ i40e_status i40e_aq_set_phy_debug(struct i40e_hw *hw, u8 cmd_flags, struct i40e_asq_cmd_details *cmd_details); i40e_status i40e_aq_set_default_vsi(struct i40e_hw *hw, u16 vsi_id, struct i40e_asq_cmd_details *cmd_details); +enum i40e_status_code i40e_aq_get_phy_capabilities(struct i40e_hw *hw, + bool qualified_modules, bool report_init, + struct i40e_aq_get_phy_abilities_resp *abilities, + struct i40e_asq_cmd_details *cmd_details); +enum i40e_status_code i40e_aq_set_phy_config(struct i40e_hw *hw, + struct i40e_aq_set_phy_config *config, + struct i40e_asq_cmd_details *cmd_details); +enum i40e_status_code i40e_set_fc(struct i40e_hw *hw, u8 *aq_failures, + bool atomic_reset); i40e_status i40e_aq_clear_pxe_mode(struct i40e_hw *hw, struct i40e_asq_cmd_details *cmd_details); i40e_status i40e_aq_set_link_restart_an(struct i40e_hw *hw, diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index f1c58ab..380eb53 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -140,6 +140,14 @@ enum i40e_fc_mode { I40E_FC_DEFAULT }; +enum i40e_set_fc_aq_failures { + I40E_SET_FC_AQ_FAIL_NONE = 0, + I40E_SET_FC_AQ_FAIL_GET = 1, + I40E_SET_FC_AQ_FAIL_SET = 2, + I40E_SET_FC_AQ_FAIL_UPDATE = 4, + I40E_SET_FC_AQ_FAIL_SET_UPDATE = 6 +}; + enum i40e_vsi_type { I40E_VSI_MAIN = 0, I40E_VSI_VMDQ1, diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h index 5b6e955..6dd72ad 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h @@ -140,6 +140,14 @@ enum i40e_fc_mode { I40E_FC_DEFAULT }; +enum i40e_set_fc_aq_failures { + I40E_SET_FC_AQ_FAIL_NONE = 0, + I40E_SET_FC_AQ_FAIL_GET = 1, + I40E_SET_FC_AQ_FAIL_SET = 2, + I40E_SET_FC_AQ_FAIL_UPDATE = 4, + I40E_SET_FC_AQ_FAIL_SET_UPDATE = 6 +}; + enum i40e_vsi_type { I40E_VSI_MAIN = 0, I40E_VSI_VMDQ1, -- cgit v0.10.2 From 2becc35aa74cbaf9c84e6ae166faab7a321d25ca Mon Sep 17 00:00:00 2001 From: Catherine Sullivan Date: Wed, 4 Jun 2014 08:45:27 +0000 Subject: i40e: Add set_pauseparam to ethtool Add i40e implementation of setpauseparam to ethtool. Change-ID: Ie7766b2091ec8f934737573c9ffd426081966718 Signed-off-by: Catherine Sullivan Tested-by: Jim Young Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 6508a1b..fc86761 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -457,6 +457,81 @@ static void i40e_get_pauseparam(struct net_device *netdev, } } +/** + * i40e_set_pauseparam - Set Flow Control parameter + * @netdev: network interface device structure + * @pause: return tx/rx flow control status + **/ +static int i40e_set_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct i40e_netdev_priv *np = netdev_priv(netdev); + struct i40e_pf *pf = np->vsi->back; + struct i40e_vsi *vsi = np->vsi; + struct i40e_hw *hw = &pf->hw; + struct i40e_link_status *hw_link_info = &hw->phy.link_info; + bool link_up = hw_link_info->link_info & I40E_AQ_LINK_UP; + i40e_status status; + u8 aq_failures; + int err; + + if (vsi != pf->vsi[pf->lan_vsi]) + return -EOPNOTSUPP; + + if (pause->autoneg != ((hw_link_info->an_info & I40E_AQ_AN_COMPLETED) ? + AUTONEG_ENABLE : AUTONEG_DISABLE)) { + netdev_info(netdev, "To change autoneg please use: ethtool -s autoneg \n"); + return -EOPNOTSUPP; + } + + /* If we have link and don't have autoneg */ + if (!test_bit(__I40E_DOWN, &pf->state) && + !(hw_link_info->an_info & I40E_AQ_AN_COMPLETED)) { + /* Send message that it might not necessarily work*/ + netdev_info(netdev, "Autoneg did not complete so changing settings may not result in an actual change.\n"); + } + + if (hw->fc.current_mode == I40E_FC_PFC) { + netdev_info(netdev, "Priority flow control enabled. Cannot set link flow control.\n"); + return -EOPNOTSUPP; + } + + if (pause->rx_pause && pause->tx_pause) + hw->fc.requested_mode = I40E_FC_FULL; + else if (pause->rx_pause && !pause->tx_pause) + hw->fc.requested_mode = I40E_FC_RX_PAUSE; + else if (!pause->rx_pause && pause->tx_pause) + hw->fc.requested_mode = I40E_FC_TX_PAUSE; + else if (!pause->rx_pause && !pause->tx_pause) + hw->fc.requested_mode = I40E_FC_NONE; + else + return -EINVAL; + + /* Set the fc mode and only restart an if link is up*/ + status = i40e_set_fc(hw, &aq_failures, link_up); + + if (aq_failures & I40E_SET_FC_AQ_FAIL_GET) { + netdev_info(netdev, "Set fc failed on the get_phy_capabilities call with error %d and status %d\n", + status, hw->aq.asq_last_status); + err = -EAGAIN; + } + if (aq_failures & I40E_SET_FC_AQ_FAIL_SET) { + netdev_info(netdev, "Set fc failed on the set_phy_config call with error %d and status %d\n", + status, hw->aq.asq_last_status); + err = -EAGAIN; + } + if (aq_failures & I40E_SET_FC_AQ_FAIL_UPDATE) { + netdev_info(netdev, "Set fc failed on the update_link_info call with error %d and status %d\n", + status, hw->aq.asq_last_status); + err = -EAGAIN; + } + + if (!test_bit(__I40E_DOWN, &pf->state)) + return i40e_nway_reset(netdev); + + return err; +} + static u32 i40e_get_msglevel(struct net_device *netdev) { struct i40e_netdev_priv *np = netdev_priv(netdev); @@ -1866,6 +1941,7 @@ static const struct ethtool_ops i40e_ethtool_ops = { .get_ringparam = i40e_get_ringparam, .set_ringparam = i40e_set_ringparam, .get_pauseparam = i40e_get_pauseparam, + .set_pauseparam = i40e_set_pauseparam, .get_msglevel = i40e_get_msglevel, .set_msglevel = i40e_set_msglevel, .get_rxnfc = i40e_get_rxnfc, -- cgit v0.10.2 From bf9c71417f721abf6853d0ae56be8cf228f92888 Mon Sep 17 00:00:00 2001 From: Catherine Sullivan Date: Wed, 4 Jun 2014 08:45:28 +0000 Subject: i40e: Implement set_settings for ethtool Implement set_settings for ethtool in i40e. Change-ID: Ie3c3fe18e8ff86c3f25b842844b3d9aabc9bba57 Signed-off-by: Catherine Sullivan Tested-by: Jim Young Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index fc86761..3abd3cb 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -412,6 +412,163 @@ no_valid_phy_type: return 0; } +/** + * i40e_set_settings - Set Speed and Duplex + * @netdev: network interface device structure + * @ecmd: ethtool command + * + * Set speed/duplex per media_types advertised/forced + **/ +static int i40e_set_settings(struct net_device *netdev, + struct ethtool_cmd *ecmd) +{ + struct i40e_netdev_priv *np = netdev_priv(netdev); + struct i40e_aq_get_phy_abilities_resp abilities; + struct i40e_aq_set_phy_config config; + struct i40e_pf *pf = np->vsi->back; + struct i40e_vsi *vsi = np->vsi; + struct i40e_hw *hw = &pf->hw; + struct ethtool_cmd safe_ecmd; + i40e_status status = 0; + bool change = false; + int err = 0; + u8 autoneg; + u32 advertise; + + if (vsi != pf->vsi[pf->lan_vsi]) + return -EOPNOTSUPP; + + if (hw->phy.media_type != I40E_MEDIA_TYPE_BASET && + hw->phy.media_type != I40E_MEDIA_TYPE_FIBER && + hw->phy.media_type != I40E_MEDIA_TYPE_BACKPLANE) + return -EOPNOTSUPP; + + /* get our own copy of the bits to check against */ + memset(&safe_ecmd, 0, sizeof(struct ethtool_cmd)); + i40e_get_settings(netdev, &safe_ecmd); + + /* save autoneg and speed out of ecmd */ + autoneg = ecmd->autoneg; + advertise = ecmd->advertising; + + /* set autoneg and speed back to what they currently are */ + ecmd->autoneg = safe_ecmd.autoneg; + ecmd->advertising = safe_ecmd.advertising; + + ecmd->cmd = safe_ecmd.cmd; + /* If ecmd and safe_ecmd are not the same now, then they are + * trying to set something that we do not support + */ + if (memcmp(ecmd, &safe_ecmd, sizeof(struct ethtool_cmd))) + return -EOPNOTSUPP; + + while (test_bit(__I40E_CONFIG_BUSY, &vsi->state)) + usleep_range(1000, 2000); + + /* Get the current phy config */ + status = i40e_aq_get_phy_capabilities(hw, false, false, &abilities, + NULL); + if (status) + return -EAGAIN; + + /* Copy link_speed and abilities to config in case they are not + * set below + */ + memset(&config, 0, sizeof(struct i40e_aq_set_phy_config)); + config.link_speed = abilities.link_speed; + config.abilities = abilities.abilities; + + /* Check autoneg */ + if (autoneg == AUTONEG_ENABLE) { + /* If autoneg is not supported, return error */ + if (!(safe_ecmd.supported & SUPPORTED_Autoneg)) { + netdev_info(netdev, "Autoneg not supported on this phy\n"); + return -EINVAL; + } + /* If autoneg was not already enabled */ + if (!(hw->phy.link_info.an_info & I40E_AQ_AN_COMPLETED)) { + config.abilities = abilities.abilities | + I40E_AQ_PHY_ENABLE_AN; + change = true; + } + } else { + /* If autoneg is supported 10GBASE_T is the only phy that + * can disable it, so otherwise return error + */ + if (safe_ecmd.supported & SUPPORTED_Autoneg && + hw->phy.link_info.phy_type != I40E_PHY_TYPE_10GBASE_T) { + netdev_info(netdev, "Autoneg cannot be disabled on this phy\n"); + return -EINVAL; + } + /* If autoneg is currently enabled */ + if (hw->phy.link_info.an_info & I40E_AQ_AN_COMPLETED) { + config.abilities = abilities.abilities | + ~I40E_AQ_PHY_ENABLE_AN; + change = true; + } + } + + if (advertise & ~safe_ecmd.supported) + return -EINVAL; + + if (advertise & ADVERTISED_100baseT_Full) + if (!(abilities.link_speed & I40E_LINK_SPEED_100MB)) { + config.link_speed |= I40E_LINK_SPEED_100MB; + change = true; + } + if (advertise & ADVERTISED_1000baseT_Full || + advertise & ADVERTISED_1000baseKX_Full) + if (!(abilities.link_speed & I40E_LINK_SPEED_1GB)) { + config.link_speed |= I40E_LINK_SPEED_1GB; + change = true; + } + if (advertise & ADVERTISED_10000baseT_Full || + advertise & ADVERTISED_10000baseKX4_Full || + advertise & ADVERTISED_10000baseKR_Full) + if (!(abilities.link_speed & I40E_LINK_SPEED_10GB)) { + config.link_speed |= I40E_LINK_SPEED_10GB; + change = true; + } + if (advertise & ADVERTISED_40000baseKR4_Full || + advertise & ADVERTISED_40000baseCR4_Full || + advertise & ADVERTISED_40000baseSR4_Full || + advertise & ADVERTISED_40000baseLR4_Full) + if (!(abilities.link_speed & I40E_LINK_SPEED_40GB)) { + config.link_speed |= I40E_LINK_SPEED_40GB; + change = true; + } + + if (change) { + /* copy over the rest of the abilities */ + config.phy_type = abilities.phy_type; + config.eee_capability = abilities.eee_capability; + config.eeer = abilities.eeer_val; + config.low_power_ctrl = abilities.d3_lpan; + + /* If link is up set link and an so changes take effect */ + if (hw->phy.link_info.link_info & I40E_AQ_LINK_UP) + config.abilities |= I40E_AQ_PHY_ENABLE_ATOMIC_LINK; + + /* make the aq call */ + status = i40e_aq_set_phy_config(hw, &config, NULL); + if (status) { + netdev_info(netdev, "Set phy config failed with error %d.\n", + status); + return -EAGAIN; + } + + status = i40e_update_link_info(hw, true); + if (status) + netdev_info(netdev, "Updating link info failed with error %d\n", + status); + + } else { + netdev_info(netdev, "Nothing changed, exiting without setting anything.\n"); + } + + return err; +} + static int i40e_nway_reset(struct net_device *netdev) { /* restart autonegotiation */ @@ -1929,6 +2086,7 @@ static int i40e_set_channels(struct net_device *dev, static const struct ethtool_ops i40e_ethtool_ops = { .get_settings = i40e_get_settings, + .set_settings = i40e_set_settings, .get_drvinfo = i40e_get_drvinfo, .get_regs_len = i40e_get_regs_len, .get_regs = i40e_get_regs, -- cgit v0.10.2 From 4e776381e0ea81500129ebaa213048e257d79e69 Mon Sep 17 00:00:00 2001 From: Catherine Sullivan Date: Wed, 4 Jun 2014 08:45:29 +0000 Subject: i40e/i40evf: Bump i40e to 0.4.21 and i40evf to 0.9.40 Bump. Change-ID: Ie0c36583ffd9997679f46bdf89bc462d3e992995 Signed-off-by: Catherine Sullivan Tested-by: Jim Young Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 44cea6a..e49352d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -39,7 +39,7 @@ static const char i40e_driver_string[] = #define DRV_VERSION_MAJOR 0 #define DRV_VERSION_MINOR 4 -#define DRV_VERSION_BUILD 19 +#define DRV_VERSION_BUILD 21 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \ __stringify(DRV_VERSION_MINOR) "." \ __stringify(DRV_VERSION_BUILD) DRV_KERN diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 6186149..1b980fb 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -36,7 +36,7 @@ char i40evf_driver_name[] = "i40evf"; static const char i40evf_driver_string[] = "Intel(R) XL710/X710 Virtual Function Network Driver"; -#define DRV_VERSION "0.9.38" +#define DRV_VERSION "0.9.40" const char i40evf_driver_version[] = DRV_VERSION; static const char i40evf_copyright[] = "Copyright (c) 2013 - 2014 Intel Corporation."; -- cgit v0.10.2