diff options
Diffstat (limited to 'drivers/net/ethernet/qlogic')
36 files changed, 3834 insertions, 1991 deletions
diff --git a/drivers/net/ethernet/qlogic/Kconfig b/drivers/net/ethernet/qlogic/Kconfig index f59e6be4a66..d49cba12908 100644 --- a/drivers/net/ethernet/qlogic/Kconfig +++ b/drivers/net/ethernet/qlogic/Kconfig @@ -56,6 +56,27 @@ config QLCNIC_DCB  	  mode of DCB is supported. PG and PFC values are related only  	  to Tx. +config QLCNIC_VXLAN +	bool "Virtual eXtensible Local Area Network (VXLAN) offload support" +	default n +	depends on QLCNIC && VXLAN && !(QLCNIC=y && VXLAN=m) +	---help--- +	  This enables hardware offload support for VXLAN protocol over QLogic's +	  84XX series adapters. +	  Say Y here if you want to enable hardware offload support for +	  Virtual eXtensible Local Area Network (VXLAN) in the driver. + +config QLCNIC_HWMON +	bool "QLOGIC QLCNIC 82XX and 83XX family HWMON support" +	depends on QLCNIC && HWMON && !(QLCNIC=y && HWMON=m) +	default y +	---help--- +	  This configuration parameter can be used to read the +	  board temperature in Converged Ethernet devices +	  supported by qlcnic. + +	  This data is available via the hwmon sysfs interface. +  config QLGE  	tristate "QLogic QLGE 10Gb Ethernet Driver Support"  	depends on PCI diff --git a/drivers/net/ethernet/qlogic/netxen/Makefile b/drivers/net/ethernet/qlogic/netxen/Makefile index 861a0590b1f..e14e60c8838 100644 --- a/drivers/net/ethernet/qlogic/netxen/Makefile +++ b/drivers/net/ethernet/qlogic/netxen/Makefile @@ -13,9 +13,7 @@  # GNU General Public License for more details.  #                                     # You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, -# MA  02111-1307, USA. +# along with this program; if not, see <http://www.gnu.org/licenses/>.  #   # The full GNU General Public License is included in this distribution  # in the file called "COPYING". diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic.h b/drivers/net/ethernet/qlogic/netxen/netxen_nic.h index 32675e16021..6e426ae9469 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic.h +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic.h @@ -14,9 +14,7 @@   * GNU General Public License for more details.   *   * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, - * MA  02111-1307, USA. + * along with this program; if not, see <http://www.gnu.org/licenses/>.   *   * The full GNU General Public License is included in this distribution   * in the file called "COPYING". @@ -53,8 +51,8 @@  #define _NETXEN_NIC_LINUX_MAJOR 4  #define _NETXEN_NIC_LINUX_MINOR 0 -#define _NETXEN_NIC_LINUX_SUBVERSION 81 -#define NETXEN_NIC_LINUX_VERSIONID  "4.0.81" +#define _NETXEN_NIC_LINUX_SUBVERSION 82 +#define NETXEN_NIC_LINUX_VERSIONID  "4.0.82"  #define NETXEN_VERSION_CODE(a, b, c)	(((a) << 24) + ((b) << 16) + (c))  #define _major(v)	(((v) >> 24) & 0xff) @@ -1883,9 +1881,8 @@ static inline u32 netxen_tx_avail(struct nx_host_tx_ring *tx_ring)  int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, u64 *mac);  int netxen_p3_get_mac_addr(struct netxen_adapter *adapter, u64 *mac); -extern void netxen_change_ringparam(struct netxen_adapter *adapter); -extern int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, -				int *valp); +void netxen_change_ringparam(struct netxen_adapter *adapter); +int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp);  extern const struct ethtool_ops netxen_nic_ethtool_ops; diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c index 1bcaf45aa86..6f6be57f469 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c @@ -14,9 +14,7 @@   * GNU General Public License for more details.   *   * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, - * MA  02111-1307, USA. + * along with this program; if not, see <http://www.gnu.org/licenses/>.   *   * The full GNU General Public License is included in this distribution   * in the file called "COPYING". diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c index 4ca2c196c98..87e073c6e29 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c @@ -14,9 +14,7 @@   * GNU General Public License for more details.   *   * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, - * MA  02111-1307, USA. + * along with this program; if not, see <http://www.gnu.org/licenses/>.   *   * The full GNU General Public License is included in this distribution   * in the file called "COPYING". diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_hdr.h b/drivers/net/ethernet/qlogic/netxen/netxen_nic_hdr.h index 32c790659f9..a310c2f6502 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_hdr.h +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_hdr.h @@ -14,9 +14,7 @@   * GNU General Public License for more details.   *   * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, - * MA  02111-1307, USA. + * along with this program; if not, see <http://www.gnu.org/licenses/>.   *   * The full GNU General Public License is included in this distribution   * in the file called "COPYING". @@ -958,6 +956,7 @@ enum {  #define NETXEN_PEG_HALT_STATUS2 	(NETXEN_CAM_RAM(0xac))  #define NX_CRB_DEV_REF_COUNT		(NETXEN_CAM_RAM(0x138))  #define NX_CRB_DEV_STATE		(NETXEN_CAM_RAM(0x140)) +#define NETXEN_ULA_KEY			(NETXEN_CAM_RAM(0x178))  /* MiniDIMM related macros */  #define NETXEN_DIMM_CAPABILITY		(NETXEN_CAM_RAM(0x258)) diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c index 8375cbde996..db4280ce9c0 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c @@ -14,9 +14,7 @@   * GNU General Public License for more details.   *   * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, - * MA  02111-1307, USA. + * along with this program; if not, see <http://www.gnu.org/licenses/>.   *   * The full GNU General Public License is included in this distribution   * in the file called "COPYING". @@ -648,7 +646,7 @@ nx_p3_sre_macaddr_change(struct netxen_adapter *adapter, u8 *addr, unsigned op)  	mac_req = (nx_mac_req_t *)&req.words[0];  	mac_req->op = op; -	memcpy(mac_req->mac_addr, addr, 6); +	memcpy(mac_req->mac_addr, addr, ETH_ALEN);  	return netxen_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);  } @@ -663,7 +661,7 @@ static int nx_p3_nic_add_mac(struct netxen_adapter *adapter,  	list_for_each(head, del_list) {  		cur = list_entry(head, nx_mac_list_t, list); -		if (memcmp(addr, cur->mac_addr, ETH_ALEN) == 0) { +		if (ether_addr_equal(addr, cur->mac_addr)) {  			list_move_tail(head, &adapter->mac_list);  			return 0;  		} diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.h b/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.h index e2c5b6f2df0..7433c4d2160 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.h +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.h @@ -14,9 +14,7 @@   * GNU General Public License for more details.   *   * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, - * MA  02111-1307, USA. + * along with this program; if not, see <http://www.gnu.org/licenses/>.   *   * The full GNU General Public License is included in this distribution   * in the file called "COPYING". diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c index 7692dfd4f26..32058614151 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c @@ -14,9 +14,7 @@   * GNU General Public License for more details.   *   * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, - * MA  02111-1307, USA. + * along with this program; if not, see <http://www.gnu.org/licenses/>.   *   * The full GNU General Public License is included in this distribution   * in the file called "COPYING". @@ -1604,13 +1602,13 @@ netxen_process_lro(struct netxen_adapter *adapter,  	u32 seq_number;  	u8 vhdr_len = 0; -	if (unlikely(ring > adapter->max_rds_rings)) +	if (unlikely(ring >= adapter->max_rds_rings))  		return NULL;  	rds_ring = &recv_ctx->rds_rings[ring];  	index = netxen_get_lro_sts_refhandle(sts_data0); -	if (unlikely(index > rds_ring->num_desc)) +	if (unlikely(index >= rds_ring->num_desc))  		return NULL;  	buffer = &rds_ring->rx_buf_arr[index]; diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c index cbd75f97ffb..5bf05818a12 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c @@ -14,9 +14,7 @@   * GNU General Public License for more details.   *   * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, - * MA  02111-1307, USA. + * along with this program; if not, see <http://www.gnu.org/licenses/>.   *   * The full GNU General Public License is included in this distribution   * in the file called "COPYING". @@ -645,8 +643,9 @@ static int netxen_setup_msi_interrupts(struct netxen_adapter *adapter,  	if (adapter->msix_supported) {  		netxen_init_msix_entries(adapter, num_msix); -		err = pci_enable_msix(pdev, adapter->msix_entries, num_msix); -		if (err == 0) { +		err = pci_enable_msix_range(pdev, adapter->msix_entries, +					    num_msix, num_msix); +		if (err > 0) {  			adapter->flags |= NETXEN_NIC_MSIX_ENABLED;  			netxen_set_msix_bit(pdev, 1); @@ -1374,7 +1373,7 @@ netxen_setup_netdev(struct netxen_adapter *adapter,  	netxen_nic_change_mtu(netdev, netdev->mtu); -	SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops); +	netdev->ethtool_ops = &netxen_nic_ethtool_ops;  	netdev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |  	                      NETIF_F_RXCSUM; @@ -1415,6 +1414,32 @@ netxen_setup_netdev(struct netxen_adapter *adapter,  	return 0;  } +#define NETXEN_ULA_ADAPTER_KEY		(0xdaddad01) +#define NETXEN_NON_ULA_ADAPTER_KEY	(0xdaddad00) + +static void netxen_read_ula_info(struct netxen_adapter *adapter) +{ +	u32 temp; + +	/* Print ULA info only once for an adapter */ +	if (adapter->portnum != 0) +		return; + +	temp = NXRD32(adapter, NETXEN_ULA_KEY); +	switch (temp) { +	case NETXEN_ULA_ADAPTER_KEY: +		dev_info(&adapter->pdev->dev, "ULA adapter"); +		break; +	case NETXEN_NON_ULA_ADAPTER_KEY: +		dev_info(&adapter->pdev->dev, "non ULA adapter"); +		break; +	default: +		break; +	} + +	return; +} +  #ifdef CONFIG_PCIEAER  static void netxen_mask_aer_correctable(struct netxen_adapter *adapter)  { @@ -1561,6 +1586,8 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  		goto err_out_disable_msi;  	} +	netxen_read_ula_info(adapter); +  	err = netxen_setup_netdev(adapter, netdev);  	if (err)  		goto err_out_disable_msi; @@ -1602,7 +1629,6 @@ err_out_free_res:  	pci_release_regions(pdev);  err_out_disable_pdev: -	pci_set_drvdata(pdev, NULL);  	pci_disable_device(pdev);  	return err;  } @@ -1661,7 +1687,6 @@ static void netxen_nic_remove(struct pci_dev *pdev)  	pci_release_regions(pdev);  	pci_disable_device(pdev); -	pci_set_drvdata(pdev, NULL);  	free_netdev(netdev);  } diff --git a/drivers/net/ethernet/qlogic/qla3xxx.c b/drivers/net/ethernet/qlogic/qla3xxx.c index 91a8fcd6c24..b5d6bc1a8b0 100644 --- a/drivers/net/ethernet/qlogic/qla3xxx.c +++ b/drivers/net/ethernet/qlogic/qla3xxx.c @@ -8,7 +8,6 @@  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/types.h>  #include <linux/module.h>  #include <linux/list.h> @@ -3839,7 +3838,7 @@ static int ql3xxx_probe(struct pci_dev *pdev,  	/* Set driver entry points */  	ndev->netdev_ops = &ql3xxx_netdev_ops; -	SET_ETHTOOL_OPS(ndev, &ql3xxx_ethtool_ops); +	ndev->ethtool_ops = &ql3xxx_ethtool_ops;  	ndev->watchdog_timeo = 5 * HZ;  	netif_napi_add(ndev, &qdev->napi, ql_poll, 64); @@ -3916,7 +3915,6 @@ err_out_free_regions:  	pci_release_regions(pdev);  err_out_disable_pdev:  	pci_disable_device(pdev); -	pci_set_drvdata(pdev, NULL);  err_out:  	return err;  } @@ -3939,7 +3937,6 @@ static void ql3xxx_remove(struct pci_dev *pdev)  	iounmap(qdev->mem_map_registers);  	pci_release_regions(pdev); -	pci_set_drvdata(pdev, NULL);  	free_netdev(ndev);  } diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index 81bf83604c4..be618b9e874 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h @@ -23,6 +23,7 @@  #include <linux/ethtool.h>  #include <linux/mii.h>  #include <linux/timer.h> +#include <linux/irq.h>  #include <linux/vmalloc.h> @@ -38,8 +39,8 @@  #define _QLCNIC_LINUX_MAJOR 5  #define _QLCNIC_LINUX_MINOR 3 -#define _QLCNIC_LINUX_SUBVERSION 50 -#define QLCNIC_LINUX_VERSIONID  "5.3.50" +#define _QLCNIC_LINUX_SUBVERSION 60 +#define QLCNIC_LINUX_VERSIONID  "5.3.60"  #define QLCNIC_DRV_IDC_VER  0x01  #define QLCNIC_DRIVER_VERSION  ((_QLCNIC_LINUX_MAJOR << 16) |\  		 (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION)) @@ -98,8 +99,28 @@  #define TX_STOP_THRESH		((MAX_SKB_FRAGS >> 2) + MAX_TSO_HEADER_DESC \  							+ MGMT_CMD_DESC_RESV)  #define QLCNIC_MAX_TX_TIMEOUTS	2 -#define QLCNIC_MAX_TX_RINGS	8 -#define QLCNIC_MAX_SDS_RINGS	8 + +/* Driver will use 1 Tx ring in INT-x/MSI/SRIOV mode. */ +#define QLCNIC_SINGLE_RING		1 +#define QLCNIC_DEF_SDS_RINGS		4 +#define QLCNIC_DEF_TX_RINGS		4 +#define QLCNIC_MAX_VNIC_TX_RINGS	4 +#define QLCNIC_MAX_VNIC_SDS_RINGS	4 +#define QLCNIC_83XX_MINIMUM_VECTOR	3 +#define QLCNIC_82XX_MINIMUM_VECTOR	2 + +enum qlcnic_queue_type { +	QLCNIC_TX_QUEUE = 1, +	QLCNIC_RX_QUEUE, +}; + +/* Operational mode for driver */ +#define QLCNIC_VNIC_MODE	0xFF +#define QLCNIC_DEFAULT_MODE	0x0 + +/* Virtual NIC function count */ +#define QLC_DEFAULT_VNIC_COUNT	8 +#define QLC_84XX_VNIC_COUNT	16  /*   * Following are the states of the Phantom. Phantom will set them and @@ -149,11 +170,20 @@ struct cmd_desc_type0 {  	__le64 addr_buffer2; -	__le16 reference_handle; +	__le16 encap_descr;	/* 15:10 offset of outer L3 header, +				 * 9:6 number of 32bit words in outer L3 header, +				 * 5 offload outer L4 checksum, +				 * 4 offload outer L3 checksum, +				 * 3 Inner L4 type, TCP=0, UDP=1, +				 * 2 Inner L3 type, IPv4=0, IPv6=1, +				 * 1 Outer L3 type,IPv4=0, IPv6=1, +				 * 0 type of encapsulation, GRE=0, VXLAN=1 +				 */  	__le16 mss;  	u8 port_ctxid;		/* 7:4 ctxid 3:0 port */ -	u8 total_hdr_length;	/* LSO only : MAC+IP+TCP Hdr size */ -	__le16 conn_id;		/* IPSec offoad only */ +	u8 hdr_length;		/* LSO only : MAC+IP+TCP Hdr size */ +	u8 outer_hdr_length;	/* Encapsulation only */ +	u8 rsvd1;  	__le64 addr_buffer3;  	__le64 addr_buffer1; @@ -163,7 +193,9 @@ struct cmd_desc_type0 {  	__le64 addr_buffer4;  	u8 eth_addr[ETH_ALEN]; -	__le16 vlan_TCI; +	__le16 vlan_TCI;	/* In case of  encapsulation, +				 * this is for outer VLAN +				 */  } __attribute__ ((aligned(64))); @@ -351,6 +383,7 @@ struct qlcnic_rx_buffer {   */  #define QLCNIC_INTR_COAL_TYPE_RX		1  #define QLCNIC_INTR_COAL_TYPE_TX		2 +#define QLCNIC_INTR_COAL_TYPE_RX_TX		3  #define QLCNIC_DEF_INTR_COALESCE_RX_TIME_US	3  #define QLCNIC_DEF_INTR_COALESCE_RX_PACKETS	256 @@ -360,7 +393,7 @@ struct qlcnic_rx_buffer {  #define QLCNIC_INTR_DEFAULT			0x04  #define QLCNIC_CONFIG_INTR_COALESCE		3 -#define QLCNIC_DEV_INFO_SIZE			1 +#define QLCNIC_DEV_INFO_SIZE			2  struct qlcnic_nic_intr_coalesce {  	u8	type; @@ -373,7 +406,7 @@ struct qlcnic_nic_intr_coalesce {  	u32	timer_out;  }; -struct qlcnic_dump_template_hdr { +struct qlcnic_83xx_dump_template_hdr {  	u32	type;  	u32	offset;  	u32	size; @@ -390,15 +423,44 @@ struct qlcnic_dump_template_hdr {  	u32	rsvd[0];  }; +struct qlcnic_82xx_dump_template_hdr { +	u32	type; +	u32	offset; +	u32	size; +	u32	cap_mask; +	u32	num_entries; +	u32	version; +	u32	timestamp; +	u32	checksum; +	u32	drv_cap_mask; +	u32	sys_info[3]; +	u32	saved_state[16]; +	u32	cap_sizes[8]; +	u32	rsvd[7]; +	u32	capabilities; +	u32	rsvd1[0]; +}; + +#define QLC_PEX_DMA_READ_SIZE	(PAGE_SIZE * 16) +  struct qlcnic_fw_dump {  	u8	clr;	/* flag to indicate if dump is cleared */  	bool	enable; /* enable/disable dump */  	u32	size;	/* total size of the dump */ +	u32	cap_mask; /* Current capture mask */  	void	*data;	/* dump data area */ -	struct	qlcnic_dump_template_hdr *tmpl_hdr; +	void	*tmpl_hdr;  	dma_addr_t phys_addr;  	void	*dma_buffer;  	bool	use_pex_dma; +	/* Read only elements which are common between 82xx and 83xx +	 * template header. Update these values immediately after we read +	 * template header from Firmware +	 */ +	u32	tmpl_hdr_size; +	u32	version; +	u32	num_entries; +	u32	offset;  };  /* @@ -448,8 +510,10 @@ struct qlcnic_hardware_context {  	u16 max_rx_ques;  	u16 max_mtu;  	u32 msg_enable; -	u16 act_pci_func; +	u16 total_nic_func;  	u16 max_pci_func; +	u32 max_vnic_func; +	u32 total_pci_func;  	u32 capabilities;  	u32 extra_capability[3]; @@ -473,6 +537,9 @@ struct qlcnic_hardware_context {  	struct qlcnic_mailbox *mailbox;  	u8 extend_lb_time;  	u8 phys_port_id[ETH_ALEN]; +	u8 lb_mode; +	u16 vxlan_port; +	struct device *hwmon_dev;  };  struct qlcnic_adapter_stats { @@ -487,6 +554,9 @@ struct qlcnic_adapter_stats {  	u64  txbytes;  	u64  lrobytes;  	u64  lso_frames; +	u64  encap_lso_frames; +	u64  encap_tx_csummed; +	u64  encap_rx_csummed;  	u64  xmit_on;  	u64  xmit_off;  	u64  skb_alloc_failure; @@ -533,6 +603,14 @@ struct qlcnic_host_sds_ring {  	char name[IFNAMSIZ + 12];  } ____cacheline_internodealigned_in_smp; +struct qlcnic_tx_queue_stats { +	u64 xmit_on; +	u64 xmit_off; +	u64 xmit_called; +	u64 xmit_finished; +	u64 tx_bytes; +}; +  struct qlcnic_host_tx_ring {  	int irq;  	void __iomem *crb_intr_mask; @@ -544,10 +622,7 @@ struct qlcnic_host_tx_ring {  	u32 sw_consumer;  	u32 num_desc; -	u64 xmit_on; -	u64 xmit_off; -	u64 xmit_called; -	u64 xmit_finished; +	struct qlcnic_tx_queue_stats tx_stats;  	void __iomem *crb_cmd_producer;  	struct cmd_desc_type0 *desc_head; @@ -559,6 +634,8 @@ struct qlcnic_host_tx_ring {  	dma_addr_t phys_addr;  	dma_addr_t hw_cons_phys_addr;  	struct netdev_queue *txq; +	/* Lock to protect Tx descriptors cleanup */ +	spinlock_t tx_clean_lock;  } ____cacheline_internodealigned_in_smp;  /* @@ -769,9 +846,10 @@ struct qlcnic_cardrsp_tx_ctx {  #define QLCNIC_MAC_VLAN_ADD	3  #define QLCNIC_MAC_VLAN_DEL	4 -struct qlcnic_mac_list_s { +struct qlcnic_mac_vlan_list {  	struct list_head list;  	uint8_t mac_addr[ETH_ALEN+2]; +	u16 vlan_id;  };  /* MAC Learn */ @@ -789,6 +867,7 @@ struct qlcnic_mac_list_s {  #define QLCNIC_ILB_MODE		0x1  #define QLCNIC_ELB_MODE		0x2 +#define QLCNIC_LB_MODE_MASK	0x3  #define QLCNIC_LINKEVENT	0x1  #define QLCNIC_LB_RESPONSE	0x2 @@ -837,7 +916,11 @@ struct qlcnic_mac_list_s {  #define QLCNIC_FW_CAP2_HW_LRO_IPV6		BIT_3  #define QLCNIC_FW_CAPABILITY_SET_DRV_VER	BIT_5  #define QLCNIC_FW_CAPABILITY_2_BEACON		BIT_7 -#define QLCNIC_FW_CAPABILITY_2_PER_PORT_ESWITCH_CFG	BIT_8 +#define QLCNIC_FW_CAPABILITY_2_PER_PORT_ESWITCH_CFG	BIT_9 + +#define QLCNIC_83XX_FW_CAPAB_ENCAP_RX_OFFLOAD	BIT_0 +#define QLCNIC_83XX_FW_CAPAB_ENCAP_TX_OFFLOAD	BIT_1 +#define QLCNIC_83XX_FW_CAPAB_ENCAP_CKO_OFFLOAD	BIT_4  /* module types */  #define LINKEVENT_MODULE_NOT_PRESENT			1 @@ -931,6 +1014,14 @@ struct qlcnic_ipaddr {  #define QLCNIC_TX_INTR_SHARED		0x10000  #define QLCNIC_APP_CHANGED_FLAGS	0x20000  #define QLCNIC_HAS_PHYS_PORT_ID		0x40000 +#define QLCNIC_TSS_RSS			0x80000 + +#ifdef CONFIG_QLCNIC_VXLAN +#define QLCNIC_ADD_VXLAN_PORT		0x100000 +#define QLCNIC_DEL_VXLAN_PORT		0x200000 +#endif + +#define QLCNIC_VLAN_FILTERING		0x800000  #define QLCNIC_IS_MSI_FAMILY(adapter) \  	((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED)) @@ -940,8 +1031,9 @@ struct qlcnic_ipaddr {  #define QLCNIC_BEACON_EANBLE		0xC  #define QLCNIC_BEACON_DISABLE		0xD -#define QLCNIC_DEF_NUM_STS_DESC_RINGS	4 -#define QLCNIC_DEF_NUM_TX_RINGS		4 +#define QLCNIC_BEACON_ON		2 +#define QLCNIC_BEACON_OFF		0 +  #define QLCNIC_MSIX_TBL_SPACE		8192  #define QLCNIC_PCI_REG_MSIX_TBL 	0x44  #define QLCNIC_MSIX_TBL_PGSIZE		4096 @@ -961,8 +1053,7 @@ struct qlcnic_ipaddr {  #define __QLCNIC_SRIOV_CAPABLE		11  #define __QLCNIC_MBX_POLL_ENABLE	12  #define __QLCNIC_DIAG_MODE		13 -#define __QLCNIC_DCB_STATE		14 -#define __QLCNIC_DCB_IN_AEN		15 +#define __QLCNIC_MAINTENANCE_MODE	16  #define QLCNIC_INTERRUPT_TEST		1  #define QLCNIC_LOOPBACK_TEST		2 @@ -1013,7 +1104,6 @@ struct qlcnic_adapter {  	unsigned long state;  	u32 flags; -	int max_drv_tx_rings;  	u16 num_txd;  	u16 num_rxd;  	u16 num_jumbo_rxd; @@ -1021,7 +1111,16 @@ struct qlcnic_adapter {  	u16 max_jumbo_rxd;  	u8 max_rds_rings; -	u8 max_sds_rings; + +	u8 max_sds_rings; /* max sds rings supported by adapter */ +	u8 max_tx_rings;  /* max tx rings supported by adapter */ + +	u8 drv_tx_rings;  /* max tx rings supported by driver */ +	u8 drv_sds_rings; /* max sds rings supported by driver */ + +	u8 drv_tss_rings; /* tss ring input */ +	u8 drv_rss_rings; /* rss ring input */ +  	u8 rx_csum;  	u8 portnum; @@ -1047,6 +1146,7 @@ struct qlcnic_adapter {  	u64 dev_rst_time;  	bool drv_mac_learn;  	bool fdb_mac_learn; +	bool rx_mac_learn;  	unsigned long vlans[BITS_TO_LONGS(VLAN_N_VID)];  	u8 flash_mfg_id;  	struct qlcnic_npar_info *npars; @@ -1072,7 +1172,6 @@ struct qlcnic_adapter {  	struct qlcnic_filter_hash rx_fhash;  	struct list_head vf_mc_list; -	spinlock_t tx_clean_lock;  	spinlock_t mac_learn_lock;  	/* spinlock for catching rcv filters for eswitch traffic */  	spinlock_t rx_mac_learn_lock; @@ -1199,6 +1298,7 @@ struct qlcnic_npar_info {  	u8	promisc_mode;  	u8	offload_flags;  	u8      pci_func; +	u8      mac[ETH_ALEN];  };  struct qlcnic_eswitch { @@ -1221,6 +1321,7 @@ struct qlcnic_eswitch {  #define QL_STATUS_INVALID_PARAM	-1  #define MAX_BW			100	/* % of link speed */ +#define MIN_BW			1	/* % of link speed */  #define MAX_VLAN_ID		4095  #define MIN_VLAN_ID		2  #define DEFAULT_MAC_LEARN	1 @@ -1235,7 +1336,7 @@ struct qlcnic_pci_func_cfg {  	u16	port_num;  	u8	pci_func;  	u8	func_state; -	u8	def_mac_addr[6]; +	u8	def_mac_addr[ETH_ALEN];  };  struct qlcnic_npar_func_cfg { @@ -1437,8 +1538,6 @@ int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter);  int qlcnic_fw_cmd_set_port(struct qlcnic_adapter *adapter, u32 config);  int qlcnic_pci_mem_write_2M(struct qlcnic_adapter *, u64 off, u64 data);  int qlcnic_pci_mem_read_2M(struct qlcnic_adapter *, u64 off, u64 *data); -void qlcnic_pci_camqm_read_2M(struct qlcnic_adapter *, u64, u64 *); -void qlcnic_pci_camqm_write_2M(struct qlcnic_adapter *, u64, u64);  #define ADDR_IN_RANGE(addr, low, high)	\  	(((addr) < (high)) && ((addr) >= (low))) @@ -1474,16 +1573,11 @@ void qlcnic_pcie_sem_unlock(struct qlcnic_adapter *, int);  #define MAX_CTL_CHECK 1000 -int qlcnic_wol_supported(struct qlcnic_adapter *adapter);  void qlcnic_prune_lb_filters(struct qlcnic_adapter *adapter);  void qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter);  int qlcnic_dump_fw(struct qlcnic_adapter *);  int qlcnic_enable_fw_dump_state(struct qlcnic_adapter *);  bool qlcnic_check_fw_dump_state(struct qlcnic_adapter *); -pci_ers_result_t qlcnic_82xx_io_error_detected(struct pci_dev *, -					       pci_channel_state_t); -pci_ers_result_t qlcnic_82xx_io_slot_reset(struct pci_dev *); -void qlcnic_82xx_io_resume(struct pci_dev *);  /* Functions from qlcnic_init.c */  void qlcnic_schedule_work(struct qlcnic_adapter *, work_func_t, int); @@ -1518,9 +1612,7 @@ int qlcnic_check_fw_status(struct qlcnic_adapter *adapter);  void qlcnic_watchdog_task(struct work_struct *work);  void qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter,  		struct qlcnic_host_rds_ring *rds_ring, u8 ring_id); -int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max);  void qlcnic_set_multi(struct net_device *netdev); -void __qlcnic_set_multi(struct net_device *, u16);  int qlcnic_nic_add_mac(struct qlcnic_adapter *, const u8 *, u16);  int qlcnic_nic_del_mac(struct qlcnic_adapter *, const u8 *);  void qlcnic_82xx_free_mac_list(struct qlcnic_adapter *adapter); @@ -1533,24 +1625,22 @@ netdev_features_t qlcnic_fix_features(struct net_device *netdev,  	netdev_features_t features);  int qlcnic_set_features(struct net_device *netdev, netdev_features_t features);  int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable); -int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter);  void qlcnic_update_cmd_producer(struct qlcnic_host_tx_ring *);  /* Functions from qlcnic_ethtool.c */  int qlcnic_check_loopback_buff(unsigned char *, u8 []);  int qlcnic_do_lb_test(struct qlcnic_adapter *, u8); -int qlcnic_loopback_test(struct net_device *, u8);  /* Functions from qlcnic_main.c */  int qlcnic_reset_context(struct qlcnic_adapter *); -void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings); -int qlcnic_diag_alloc_res(struct net_device *netdev, int test); -netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev); -int qlcnic_set_max_rss(struct qlcnic_adapter *, u8, int); -int qlcnic_validate_max_rss(struct qlcnic_adapter *, __u32); -int qlcnic_validate_max_tx_rings(struct qlcnic_adapter *, u32 txq); +void qlcnic_diag_free_res(struct net_device *netdev, int); +int qlcnic_diag_alloc_res(struct net_device *netdev, int); +netdev_tx_t qlcnic_xmit_frame(struct sk_buff *, struct net_device *); +void qlcnic_set_tx_ring_count(struct qlcnic_adapter *, u8); +void qlcnic_set_sds_ring_count(struct qlcnic_adapter *, u8); +int qlcnic_setup_rings(struct qlcnic_adapter *); +int qlcnic_validate_rings(struct qlcnic_adapter *, __u32, int);  void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter); -void qlcnic_82xx_set_mac_filter_count(struct qlcnic_adapter *);  int qlcnic_enable_msix(struct qlcnic_adapter *, u32);  void qlcnic_set_drv_version(struct qlcnic_adapter *); @@ -1579,11 +1669,8 @@ void qlcnic_dump_mbx(struct qlcnic_adapter *, struct qlcnic_cmd_args *);  void qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter);  void qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter); -void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter); -void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter);  void qlcnic_82xx_add_sysfs(struct qlcnic_adapter *adapter);  void qlcnic_82xx_remove_sysfs(struct qlcnic_adapter *adapter); -int qlcnic_82xx_get_settings(struct qlcnic_adapter *, struct ethtool_cmd *);  int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *, u32);  int qlcnicvf_config_led(struct qlcnic_adapter *, u32, u32); @@ -1591,7 +1678,7 @@ void qlcnic_set_vlan_config(struct qlcnic_adapter *,  			    struct qlcnic_esw_func_cfg *);  void qlcnic_set_eswitch_port_features(struct qlcnic_adapter *,  				      struct qlcnic_esw_func_cfg *); - +int qlcnic_setup_tss_rss_intr(struct qlcnic_adapter  *);  void qlcnic_down(struct qlcnic_adapter *, struct net_device *);  int qlcnic_up(struct qlcnic_adapter *, struct net_device *);  void __qlcnic_down(struct qlcnic_adapter *, struct net_device *); @@ -1606,15 +1693,15 @@ int qlcnic_init_pci_info(struct qlcnic_adapter *);  int qlcnic_set_default_offload_settings(struct qlcnic_adapter *);  int qlcnic_reset_npar_config(struct qlcnic_adapter *);  int qlcnic_set_eswitch_port_config(struct qlcnic_adapter *); -void qlcnic_add_lb_filter(struct qlcnic_adapter *, struct sk_buff *, int, u16); -int qlcnic_get_beacon_state(struct qlcnic_adapter *, u8 *);  int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter);  int qlcnic_read_mac_addr(struct qlcnic_adapter *);  int qlcnic_setup_netdev(struct qlcnic_adapter *, struct net_device *, int);  void qlcnic_set_netdev_features(struct qlcnic_adapter *,  				struct qlcnic_esw_func_cfg *); -void qlcnic_sriov_vf_schedule_multi(struct net_device *); -void qlcnic_vf_add_mc_list(struct net_device *, u16); +void qlcnic_sriov_vf_set_multi(struct net_device *); +int qlcnic_is_valid_nic_func(struct qlcnic_adapter *, u8); +int qlcnic_get_pci_func_type(struct qlcnic_adapter *, u16, u16 *, u16 *, +			     u16 *);  /*   * QLOGIC Board information @@ -1638,26 +1725,6 @@ static inline u32 qlcnic_tx_avail(struct qlcnic_host_tx_ring *tx_ring)  				tx_ring->producer;  } -static inline int qlcnic_set_real_num_queues(struct qlcnic_adapter *adapter, -					     struct net_device *netdev) -{ -	int err, tx_q; - -	tx_q = adapter->max_drv_tx_rings; - -	netdev->num_tx_queues = tx_q; -	netdev->real_num_tx_queues = tx_q; - -	err = netif_set_real_num_tx_queues(netdev, tx_q); -	if (err) -		dev_err(&adapter->pdev->dev, "failed to set %d Tx queues\n", -			tx_q); -	else -		dev_info(&adapter->pdev->dev, "set %d Tx queues\n", tx_q); - -	return err; -} -  struct qlcnic_nic_template {  	int (*config_bridged_mode) (struct qlcnic_adapter *, u32);  	int (*config_led) (struct qlcnic_adapter *, u32, u32); @@ -1686,6 +1753,7 @@ int qlcnic_83xx_init_mailbox_work(struct qlcnic_adapter *);  void qlcnic_83xx_detach_mailbox_work(struct qlcnic_adapter *);  void qlcnic_83xx_reinit_mbx_work(struct qlcnic_mailbox *mbx);  void qlcnic_83xx_free_mailbox(struct qlcnic_mailbox *mbx); +void qlcnic_update_stats(struct qlcnic_adapter *);  /* Adapter hardware abstraction */  struct qlcnic_hardware_ops { @@ -1695,7 +1763,7 @@ struct qlcnic_hardware_ops {  	int (*write_reg) (struct qlcnic_adapter *, ulong, u32);  	void (*get_ocm_win) (struct qlcnic_hardware_context *);  	int (*get_mac_address) (struct qlcnic_adapter *, u8 *, u8); -	int (*setup_intr) (struct qlcnic_adapter *, u8, int); +	int (*setup_intr) (struct qlcnic_adapter *);  	int (*alloc_mbx_args)(struct qlcnic_cmd_args *,  			      struct qlcnic_adapter *, u32);  	int (*mbx_cmd) (struct qlcnic_adapter *, struct qlcnic_cmd_args *); @@ -1718,7 +1786,8 @@ struct qlcnic_hardware_ops {  	int (*change_macvlan) (struct qlcnic_adapter *, u8*, u16, u8);  	void (*napi_enable) (struct qlcnic_adapter *);  	void (*napi_disable) (struct qlcnic_adapter *); -	void (*config_intr_coal) (struct qlcnic_adapter *); +	int (*config_intr_coal) (struct qlcnic_adapter *, +				 struct ethtool_coalesce *);  	int (*config_rss) (struct qlcnic_adapter *, int);  	int (*config_hw_lro) (struct qlcnic_adapter *, int);  	int (*config_loopback) (struct qlcnic_adapter *, u8); @@ -1733,10 +1802,37 @@ struct qlcnic_hardware_ops {  					       pci_channel_state_t);  	pci_ers_result_t (*io_slot_reset) (struct pci_dev *);  	void (*io_resume) (struct pci_dev *); +	void (*get_beacon_state)(struct qlcnic_adapter *); +	void (*enable_sds_intr) (struct qlcnic_adapter *, +				 struct qlcnic_host_sds_ring *); +	void (*disable_sds_intr) (struct qlcnic_adapter *, +				  struct qlcnic_host_sds_ring *); +	void (*enable_tx_intr) (struct qlcnic_adapter *, +				struct qlcnic_host_tx_ring *); +	void (*disable_tx_intr) (struct qlcnic_adapter *, +				 struct qlcnic_host_tx_ring *); +	u32 (*get_saved_state)(void *, u32); +	void (*set_saved_state)(void *, u32, u32); +	void (*cache_tmpl_hdr_values)(struct qlcnic_fw_dump *); +	u32 (*get_cap_size)(void *, int); +	void (*set_sys_info)(void *, int, u32); +	void (*store_cap_mask)(void *, u32);  };  extern struct qlcnic_nic_template qlcnic_vf_ops; +static inline bool qlcnic_encap_tx_offload(struct qlcnic_adapter *adapter) +{ +	return adapter->ahw->extra_capability[0] & +	       QLCNIC_83XX_FW_CAPAB_ENCAP_TX_OFFLOAD; +} + +static inline bool qlcnic_encap_rx_offload(struct qlcnic_adapter *adapter) +{ +	return adapter->ahw->extra_capability[0] & +	       QLCNIC_83XX_FW_CAPAB_ENCAP_RX_OFFLOAD; +} +  static inline int qlcnic_start_firmware(struct qlcnic_adapter *adapter)  {  	return adapter->nic_ops->start_firmware(adapter); @@ -1766,10 +1862,9 @@ static inline int qlcnic_get_mac_address(struct qlcnic_adapter *adapter,  	return adapter->ahw->hw_ops->get_mac_address(adapter, mac, function);  } -static inline int qlcnic_setup_intr(struct qlcnic_adapter *adapter, -				    u8 num_intr, int txq) +static inline int qlcnic_setup_intr(struct qlcnic_adapter *adapter)  { -	return adapter->ahw->hw_ops->setup_intr(adapter, num_intr, txq); +	return adapter->ahw->hw_ops->setup_intr(adapter);  }  static inline int qlcnic_alloc_mbx_args(struct qlcnic_cmd_args *mbx, @@ -1906,9 +2001,10 @@ static inline void qlcnic_napi_disable(struct qlcnic_adapter *adapter)  	adapter->ahw->hw_ops->napi_disable(adapter);  } -static inline void qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter) +static inline int qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter, +					      struct ethtool_coalesce *ethcoal)  { -	adapter->ahw->hw_ops->config_intr_coal(adapter); +	return adapter->ahw->hw_ops->config_intr_coal(adapter, ethcoal);  }  static inline int qlcnic_config_rss(struct qlcnic_adapter *adapter, int enable) @@ -1960,12 +2056,53 @@ static inline void qlcnic_set_mac_filter_count(struct qlcnic_adapter *adapter)  		adapter->ahw->hw_ops->set_mac_filter_count(adapter);  } +static inline void qlcnic_get_beacon_state(struct qlcnic_adapter *adapter) +{ +	adapter->ahw->hw_ops->get_beacon_state(adapter); +} +  static inline void qlcnic_read_phys_port_id(struct qlcnic_adapter *adapter)  {  	if (adapter->ahw->hw_ops->read_phys_port_id)  		adapter->ahw->hw_ops->read_phys_port_id(adapter);  } +static inline u32 qlcnic_get_saved_state(struct qlcnic_adapter *adapter, +					 void *t_hdr, u32 index) +{ +	return adapter->ahw->hw_ops->get_saved_state(t_hdr, index); +} + +static inline void qlcnic_set_saved_state(struct qlcnic_adapter *adapter, +					  void *t_hdr, u32 index, u32 value) +{ +	adapter->ahw->hw_ops->set_saved_state(t_hdr, index, value); +} + +static inline void qlcnic_cache_tmpl_hdr_values(struct qlcnic_adapter *adapter, +						struct qlcnic_fw_dump *fw_dump) +{ +	adapter->ahw->hw_ops->cache_tmpl_hdr_values(fw_dump); +} + +static inline u32 qlcnic_get_cap_size(struct qlcnic_adapter *adapter, +				      void *tmpl_hdr, int index) +{ +	return adapter->ahw->hw_ops->get_cap_size(tmpl_hdr, index); +} + +static inline void qlcnic_set_sys_info(struct qlcnic_adapter *adapter, +				       void *tmpl_hdr, int idx, u32 value) +{ +	adapter->ahw->hw_ops->set_sys_info(tmpl_hdr, idx, value); +} + +static inline void qlcnic_store_cap_mask(struct qlcnic_adapter *adapter, +					 void *tmpl_hdr, u32 mask) +{ +	adapter->ahw->hw_ops->store_cap_mask(tmpl_hdr, mask); +} +  static inline void qlcnic_dev_request_reset(struct qlcnic_adapter *adapter,  					    u32 key)  { @@ -2002,19 +2139,67 @@ static inline bool qlcnic_check_multi_tx(struct qlcnic_adapter *adapter)  	return test_bit(__QLCNIC_MULTI_TX_UNIQUE, &adapter->state);  } +static inline void +qlcnic_82xx_enable_tx_intr(struct qlcnic_adapter *adapter, +			   struct qlcnic_host_tx_ring *tx_ring) +{ +	if (qlcnic_check_multi_tx(adapter) && +	    !adapter->ahw->diag_test) +		writel(0x0, tx_ring->crb_intr_mask); +} + +static inline void +qlcnic_82xx_disable_tx_intr(struct qlcnic_adapter *adapter, +			    struct qlcnic_host_tx_ring *tx_ring) +{ +	if (qlcnic_check_multi_tx(adapter) && +	    !adapter->ahw->diag_test) +		writel(1, tx_ring->crb_intr_mask); +} + +static inline void +qlcnic_83xx_enable_tx_intr(struct qlcnic_adapter *adapter, +			   struct qlcnic_host_tx_ring *tx_ring) +{ +	writel(0, tx_ring->crb_intr_mask); +} + +static inline void +qlcnic_83xx_disable_tx_intr(struct qlcnic_adapter *adapter, +			    struct qlcnic_host_tx_ring *tx_ring) +{ +	writel(1, tx_ring->crb_intr_mask); +} + +/* Enable MSI-x and INT-x interrupts */ +static inline void +qlcnic_83xx_enable_sds_intr(struct qlcnic_adapter *adapter, +			    struct qlcnic_host_sds_ring *sds_ring) +{ +	writel(0, sds_ring->crb_intr_mask); +} + +/* Disable MSI-x and INT-x interrupts */ +static inline void +qlcnic_83xx_disable_sds_intr(struct qlcnic_adapter *adapter, +			     struct qlcnic_host_sds_ring *sds_ring) +{ +	writel(1, sds_ring->crb_intr_mask); +} +  static inline void qlcnic_disable_multi_tx(struct qlcnic_adapter *adapter)  {  	test_and_clear_bit(__QLCNIC_MULTI_TX_UNIQUE, &adapter->state); -	adapter->max_drv_tx_rings = 1; +	adapter->drv_tx_rings = QLCNIC_SINGLE_RING;  }  /* When operating in a muti tx mode, driver needs to write 0x1   * to src register, instead of 0x0 to disable receiving interrupt.   */ -static inline void qlcnic_disable_int(struct qlcnic_host_sds_ring *sds_ring) +static inline void +qlcnic_82xx_disable_sds_intr(struct qlcnic_adapter *adapter, +			     struct qlcnic_host_sds_ring *sds_ring)  { -	struct qlcnic_adapter *adapter = sds_ring->adapter; -  	if (qlcnic_check_multi_tx(adapter) &&  	    !adapter->ahw->diag_test &&  	    (adapter->flags & QLCNIC_MSIX_ENABLED)) @@ -2023,13 +2208,42 @@ static inline void qlcnic_disable_int(struct qlcnic_host_sds_ring *sds_ring)  		writel(0, sds_ring->crb_intr_mask);  } +static inline void qlcnic_enable_sds_intr(struct qlcnic_adapter *adapter, +					  struct qlcnic_host_sds_ring *sds_ring) +{ +	if (adapter->ahw->hw_ops->enable_sds_intr) +		adapter->ahw->hw_ops->enable_sds_intr(adapter, sds_ring); +} + +static inline void +qlcnic_disable_sds_intr(struct qlcnic_adapter *adapter, +			struct qlcnic_host_sds_ring *sds_ring) +{ +	if (adapter->ahw->hw_ops->disable_sds_intr) +		adapter->ahw->hw_ops->disable_sds_intr(adapter, sds_ring); +} + +static inline void qlcnic_enable_tx_intr(struct qlcnic_adapter *adapter, +					 struct qlcnic_host_tx_ring *tx_ring) +{ +	if (adapter->ahw->hw_ops->enable_tx_intr) +		adapter->ahw->hw_ops->enable_tx_intr(adapter, tx_ring); +} + +static inline void qlcnic_disable_tx_intr(struct qlcnic_adapter *adapter, +					  struct qlcnic_host_tx_ring *tx_ring) +{ +	if (adapter->ahw->hw_ops->disable_tx_intr) +		adapter->ahw->hw_ops->disable_tx_intr(adapter, tx_ring); +} +  /* When operating in a muti tx mode, driver needs to write 0x0   * to src register, instead of 0x1 to enable receiving interrupts.   */ -static inline void qlcnic_enable_int(struct qlcnic_host_sds_ring *sds_ring) +static inline void +qlcnic_82xx_enable_sds_intr(struct qlcnic_adapter *adapter, +			    struct qlcnic_host_sds_ring *sds_ring)  { -	struct qlcnic_adapter *adapter = sds_ring->adapter; -  	if (qlcnic_check_multi_tx(adapter) &&  	    !adapter->ahw->diag_test &&  	    (adapter->flags & QLCNIC_MSIX_ENABLED)) @@ -2116,97 +2330,49 @@ static inline bool qlcnic_sriov_vf_check(struct qlcnic_adapter *adapter)  	return status;  } -static inline int qlcnic_dcb_get_hw_capability(struct qlcnic_adapter *adapter) -{ -	struct qlcnic_dcb *dcb = adapter->dcb; - -	if (dcb && dcb->ops->get_hw_capability) -		return dcb->ops->get_hw_capability(adapter); - -	return 0; -} - -static inline void qlcnic_dcb_free(struct qlcnic_adapter *adapter) -{ -	struct qlcnic_dcb *dcb = adapter->dcb; - -	if (dcb && dcb->ops->free) -		dcb->ops->free(adapter); -} - -static inline int qlcnic_dcb_attach(struct qlcnic_adapter *adapter) -{ -	struct qlcnic_dcb *dcb = adapter->dcb; - -	if (dcb && dcb->ops->attach) -		return dcb->ops->attach(adapter); - -	return 0; -} - -static inline int -qlcnic_dcb_query_hw_capability(struct qlcnic_adapter *adapter, char *buf) -{ -	struct qlcnic_dcb *dcb = adapter->dcb; - -	if (dcb && dcb->ops->query_hw_capability) -		return dcb->ops->query_hw_capability(adapter, buf); - -	return 0; -} - -static inline void qlcnic_dcb_get_info(struct qlcnic_adapter *adapter) +static inline bool qlcnic_83xx_pf_check(struct qlcnic_adapter *adapter)  { -	struct qlcnic_dcb *dcb = adapter->dcb; +	unsigned short device = adapter->pdev->device; -	if (dcb && dcb->ops->get_info) -		dcb->ops->get_info(adapter); +	return (device == PCI_DEVICE_ID_QLOGIC_QLE834X) ? true : false;  } -static inline int -qlcnic_dcb_query_cee_param(struct qlcnic_adapter *adapter, char *buf, u8 type) +static inline bool qlcnic_83xx_vf_check(struct qlcnic_adapter *adapter)  { -	struct qlcnic_dcb *dcb = adapter->dcb; - -	if (dcb && dcb->ops->query_cee_param) -		return dcb->ops->query_cee_param(adapter, buf, type); +	unsigned short device = adapter->pdev->device; -	return 0; +	return (device == PCI_DEVICE_ID_QLOGIC_VF_QLE834X) ? true : false;  } -static inline int qlcnic_dcb_get_cee_cfg(struct qlcnic_adapter *adapter) +static inline bool qlcnic_sriov_check(struct qlcnic_adapter *adapter)  { -	struct qlcnic_dcb *dcb = adapter->dcb; +	bool status; -	if (dcb && dcb->ops->get_cee_cfg) -		return dcb->ops->get_cee_cfg(adapter); +	status = (qlcnic_sriov_pf_check(adapter) || +		  qlcnic_sriov_vf_check(adapter)) ? true : false; -	return 0; +	return status;  } -static inline void -qlcnic_dcb_register_aen(struct qlcnic_adapter *adapter, u8 flag) +static inline u32 qlcnic_get_vnic_func_count(struct qlcnic_adapter *adapter)  { -	struct qlcnic_dcb *dcb = adapter->dcb; - -	if (dcb && dcb->ops->register_aen) -		dcb->ops->register_aen(adapter, flag); +	if (qlcnic_84xx_check(adapter)) +		return QLC_84XX_VNIC_COUNT; +	else +		return QLC_DEFAULT_VNIC_COUNT;  } -static inline void qlcnic_dcb_handle_aen(struct qlcnic_adapter *adapter, -					 void *msg) +#ifdef CONFIG_QLCNIC_HWMON +void qlcnic_register_hwmon_dev(struct qlcnic_adapter *); +void qlcnic_unregister_hwmon_dev(struct qlcnic_adapter *); +#else +static inline void qlcnic_register_hwmon_dev(struct qlcnic_adapter *adapter)  { -	struct qlcnic_dcb *dcb = adapter->dcb; - -	if (dcb && dcb->ops->handle_aen) -		dcb->ops->handle_aen(adapter, msg); +	return;  } - -static inline void qlcnic_dcb_init_dcbnl_ops(struct qlcnic_adapter *adapter) +static inline void qlcnic_unregister_hwmon_dev(struct qlcnic_adapter *adapter)  { -	struct qlcnic_dcb *dcb = adapter->dcb; - -	if (dcb && dcb->ops->init_dcbnl_ops) -		dcb->ops->init_dcbnl_ops(adapter); +	return;  } +#endif  #endif				/* __QLCNIC_H_ */ diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index 3ca00e05f23..a4a4ec0b68f 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c @@ -13,9 +13,27 @@  #include <linux/interrupt.h>  #include <linux/aer.h> -#define QLCNIC_MAX_TX_QUEUES		1 +static void __qlcnic_83xx_process_aen(struct qlcnic_adapter *); +static int qlcnic_83xx_clear_lb_mode(struct qlcnic_adapter *, u8); +static void qlcnic_83xx_configure_mac(struct qlcnic_adapter *, u8 *, u8, +				      struct qlcnic_cmd_args *); +static int qlcnic_83xx_get_port_config(struct qlcnic_adapter *); +static irqreturn_t qlcnic_83xx_handle_aen(int, void *); +static pci_ers_result_t qlcnic_83xx_io_error_detected(struct pci_dev *, +						      pci_channel_state_t); +static int qlcnic_83xx_set_port_config(struct qlcnic_adapter *); +static pci_ers_result_t qlcnic_83xx_io_slot_reset(struct pci_dev *); +static void qlcnic_83xx_io_resume(struct pci_dev *); +static int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *, u8); +static void qlcnic_83xx_set_mac_filter_count(struct qlcnic_adapter *); +static int qlcnic_83xx_resume(struct qlcnic_adapter *); +static int qlcnic_83xx_shutdown(struct pci_dev *); +static void qlcnic_83xx_get_beacon_state(struct qlcnic_adapter *); +  #define RSS_HASHTYPE_IP_TCP		0x3  #define QLC_83XX_FW_MBX_CMD		0 +#define QLC_SKIP_INACTIVE_PCI_REGS	7 +#define QLC_MAX_LEGACY_FUNC_SUPP	8  static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = {  	{QLCNIC_CMD_CONFIGURE_IP_ADDR, 6, 1}, @@ -35,7 +53,7 @@ static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = {  	{QLCNIC_CMD_READ_MAX_MTU, 4, 2},  	{QLCNIC_CMD_READ_MAX_LRO, 4, 2},  	{QLCNIC_CMD_MAC_ADDRESS, 4, 3}, -	{QLCNIC_CMD_GET_PCI_INFO, 1, 66}, +	{QLCNIC_CMD_GET_PCI_INFO, 1, 129},  	{QLCNIC_CMD_GET_NIC_INFO, 2, 19},  	{QLCNIC_CMD_SET_NIC_INFO, 32, 1},  	{QLCNIC_CMD_GET_ESWITCH_CAPABILITY, 4, 3}, @@ -60,7 +78,7 @@ static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = {  	{QLCNIC_CMD_GET_PORT_CONFIG, 2, 2},  	{QLCNIC_CMD_GET_LINK_STATUS, 2, 4},  	{QLCNIC_CMD_IDC_ACK, 5, 1}, -	{QLCNIC_CMD_INIT_NIC_FUNC, 2, 1}, +	{QLCNIC_CMD_INIT_NIC_FUNC, 3, 1},  	{QLCNIC_CMD_STOP_NIC_FUNC, 2, 1},  	{QLCNIC_CMD_SET_LED_CONFIG, 5, 1},  	{QLCNIC_CMD_GET_LED_CONFIG, 1, 5}, @@ -69,7 +87,8 @@ static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = {  	{QLCNIC_CMD_CONFIG_VPORT, 4, 4},  	{QLCNIC_CMD_BC_EVENT_SETUP, 2, 1},  	{QLCNIC_CMD_DCB_QUERY_CAP, 1, 2}, -	{QLCNIC_CMD_DCB_QUERY_PARAM, 2, 50}, +	{QLCNIC_CMD_DCB_QUERY_PARAM, 1, 50}, +	{QLCNIC_CMD_SET_INGRESS_ENCAP, 2, 1},  };  const u32 qlcnic_83xx_ext_reg_tbl[] = { @@ -181,7 +200,17 @@ static struct qlcnic_hardware_ops qlcnic_83xx_hw_ops = {  	.io_error_detected		= qlcnic_83xx_io_error_detected,  	.io_slot_reset			= qlcnic_83xx_io_slot_reset,  	.io_resume			= qlcnic_83xx_io_resume, - +	.get_beacon_state		= qlcnic_83xx_get_beacon_state, +	.enable_sds_intr		= qlcnic_83xx_enable_sds_intr, +	.disable_sds_intr		= qlcnic_83xx_disable_sds_intr, +	.enable_tx_intr			= qlcnic_83xx_enable_tx_intr, +	.disable_tx_intr		= qlcnic_83xx_disable_tx_intr, +	.get_saved_state		= qlcnic_83xx_get_saved_state, +	.set_saved_state		= qlcnic_83xx_set_saved_state, +	.cache_tmpl_hdr_values		= qlcnic_83xx_cache_tmpl_hdr_values, +	.get_cap_size			= qlcnic_83xx_get_cap_size, +	.set_sys_info			= qlcnic_83xx_set_sys_info, +	.store_cap_mask			= qlcnic_83xx_store_cap_mask,  };  static struct qlcnic_nic_template qlcnic_83xx_ops = { @@ -268,43 +297,75 @@ int qlcnic_83xx_wrt_reg_indirect(struct qlcnic_adapter *adapter, ulong addr,  	}  } -int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr, int txq) +static void qlcnic_83xx_enable_legacy(struct qlcnic_adapter *adapter)  { -	int err, i, num_msix;  	struct qlcnic_hardware_context *ahw = adapter->ahw; -	if (!num_intr) -		num_intr = QLCNIC_DEF_NUM_STS_DESC_RINGS; -	num_msix = rounddown_pow_of_two(min_t(int, num_online_cpus(), -					      num_intr)); +	/* MSI-X enablement failed, use legacy interrupt */ +	adapter->tgt_status_reg = ahw->pci_base0 + QLC_83XX_INTX_PTR; +	adapter->tgt_mask_reg = ahw->pci_base0 + QLC_83XX_INTX_MASK; +	adapter->isr_int_vec = ahw->pci_base0 + QLC_83XX_INTX_TRGR; +	adapter->msix_entries[0].vector = adapter->pdev->irq; +	dev_info(&adapter->pdev->dev, "using legacy interrupt\n"); +} + +static int qlcnic_83xx_calculate_msix_vector(struct qlcnic_adapter *adapter) +{ +	int num_msix; + +	num_msix = adapter->drv_sds_rings; +  	/* account for AEN interrupt MSI-X based interrupts */  	num_msix += 1;  	if (!(adapter->flags & QLCNIC_TX_INTR_SHARED)) -		num_msix += adapter->max_drv_tx_rings; +		num_msix += adapter->drv_tx_rings; -	err = qlcnic_enable_msix(adapter, num_msix); -	if (err == -ENOMEM) -		return err; -	if (adapter->flags & QLCNIC_MSIX_ENABLED) -		num_msix = adapter->ahw->num_msix; -	else { -		if (qlcnic_sriov_vf_check(adapter)) -			return -EINVAL; -		num_msix = 1; +	return num_msix; +} + +int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter) +{ +	struct qlcnic_hardware_context *ahw = adapter->ahw; +	int err, i, num_msix; + +	if (adapter->flags & QLCNIC_TSS_RSS) { +		err = qlcnic_setup_tss_rss_intr(adapter); +		if (err < 0) +			return err; +		num_msix = ahw->num_msix; +	} else { +		num_msix = qlcnic_83xx_calculate_msix_vector(adapter); + +		err = qlcnic_enable_msix(adapter, num_msix); +		if (err == -ENOMEM) +			return err; + +		if (adapter->flags & QLCNIC_MSIX_ENABLED) { +			num_msix = ahw->num_msix; +		} else { +			if (qlcnic_sriov_vf_check(adapter)) +				return -EINVAL; +			num_msix = 1; +			adapter->drv_sds_rings = QLCNIC_SINGLE_RING; +			adapter->drv_tx_rings = QLCNIC_SINGLE_RING; +		}  	} +  	/* setup interrupt mapping table for fw */  	ahw->intr_tbl = vzalloc(num_msix *  				sizeof(struct qlcnic_intrpt_config));  	if (!ahw->intr_tbl)  		return -ENOMEM; +  	if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) { -		/* MSI-X enablement failed, use legacy interrupt */ -		adapter->tgt_status_reg = ahw->pci_base0 + QLC_83XX_INTX_PTR; -		adapter->tgt_mask_reg = ahw->pci_base0 + QLC_83XX_INTX_MASK; -		adapter->isr_int_vec = ahw->pci_base0 + QLC_83XX_INTX_TRGR; -		adapter->msix_entries[0].vector = adapter->pdev->irq; -		dev_info(&adapter->pdev->dev, "using legacy interrupt\n"); +		if (adapter->ahw->pci_func >= QLC_MAX_LEGACY_FUNC_SUPP) { +			dev_err(&adapter->pdev->dev, "PCI function number 8 and higher are not supported with legacy interrupt, func 0x%x\n", +				ahw->pci_func); +			return -EOPNOTSUPP; +		} + +		qlcnic_83xx_enable_legacy(adapter);  	}  	for (i = 0; i < num_msix; i++) { @@ -315,34 +376,22 @@ int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr, int txq)  		ahw->intr_tbl[i].id = i;  		ahw->intr_tbl[i].src = 0;  	} +  	return 0;  } -inline void qlcnic_83xx_clear_legacy_intr_mask(struct qlcnic_adapter *adapter) +static inline void qlcnic_83xx_clear_legacy_intr_mask(struct qlcnic_adapter *adapter)  {  	writel(0, adapter->tgt_mask_reg);  } -inline void qlcnic_83xx_set_legacy_intr_mask(struct qlcnic_adapter *adapter) -{ -	writel(1, adapter->tgt_mask_reg); -} - -/* Enable MSI-x and INT-x interrupts */ -void qlcnic_83xx_enable_intr(struct qlcnic_adapter *adapter, -			     struct qlcnic_host_sds_ring *sds_ring) -{ -	writel(0, sds_ring->crb_intr_mask); -} - -/* Disable MSI-x and INT-x interrupts */ -void qlcnic_83xx_disable_intr(struct qlcnic_adapter *adapter, -			      struct qlcnic_host_sds_ring *sds_ring) +static inline void qlcnic_83xx_set_legacy_intr_mask(struct qlcnic_adapter *adapter)  { -	writel(1, sds_ring->crb_intr_mask); +	if (adapter->tgt_mask_reg) +		writel(1, adapter->tgt_mask_reg);  } -inline void qlcnic_83xx_enable_legacy_msix_mbx_intr(struct qlcnic_adapter +static inline void qlcnic_83xx_enable_legacy_msix_mbx_intr(struct qlcnic_adapter  						    *adapter)  {  	u32 mask; @@ -449,8 +498,9 @@ irqreturn_t qlcnic_83xx_intr(int irq, void *data)  	qlcnic_83xx_poll_process_aen(adapter); -	if (ahw->diag_test == QLCNIC_INTERRUPT_TEST) { -		ahw->diag_cnt++; +	if (ahw->diag_test) { +		if (ahw->diag_test == QLCNIC_INTERRUPT_TEST) +			ahw->diag_cnt++;  		qlcnic_83xx_enable_legacy_msix_mbx_intr(adapter);  		return IRQ_HANDLED;  	} @@ -478,7 +528,7 @@ irqreturn_t qlcnic_83xx_tmp_intr(int irq, void *data)  done:  	adapter->ahw->diag_cnt++; -	qlcnic_83xx_enable_intr(adapter, sds_ring); +	qlcnic_enable_sds_intr(adapter, sds_ring);  	return IRQ_HANDLED;  } @@ -498,8 +548,11 @@ void qlcnic_83xx_free_mbx_intr(struct qlcnic_adapter *adapter)  		num_msix = 0;  	msleep(20); -	synchronize_irq(adapter->msix_entries[num_msix].vector); -	free_irq(adapter->msix_entries[num_msix].vector, adapter); + +	if (adapter->msix_entries) { +		synchronize_irq(adapter->msix_entries[num_msix].vector); +		free_irq(adapter->msix_entries[num_msix].vector, adapter); +	}  }  int qlcnic_83xx_setup_mbx_intr(struct qlcnic_adapter *adapter) @@ -632,10 +685,10 @@ int qlcnic_83xx_get_port_info(struct qlcnic_adapter *adapter)  	return status;  } -void qlcnic_83xx_set_mac_filter_count(struct qlcnic_adapter *adapter) +static void qlcnic_83xx_set_mac_filter_count(struct qlcnic_adapter *adapter)  {  	struct qlcnic_hardware_context *ahw = adapter->ahw; -	u16 act_pci_fn = ahw->act_pci_func; +	u16 act_pci_fn = ahw->total_nic_func;  	u16 count;  	ahw->max_mc_count = QLC_83XX_MAX_MC_COUNT; @@ -760,6 +813,9 @@ int qlcnic_83xx_issue_cmd(struct qlcnic_adapter *adapter,  	int cmd_type, err, opcode;  	unsigned long timeout; +	if (!mbx) +		return -EIO; +  	opcode = LSW(cmd->req.arg[0]);  	cmd_type = cmd->type;  	err = mbx->ops->enqueue_cmd(adapter, cmd, &timeout); @@ -831,6 +887,9 @@ int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx,  			return 0;  		}  	} + +	dev_err(&adapter->pdev->dev, "%s: Invalid mailbox command opcode 0x%x\n", +		__func__, type);  	return -EINVAL;  } @@ -864,7 +923,7 @@ static void qlcnic_83xx_handle_idc_comp_aen(struct qlcnic_adapter *adapter,  	return;  } -void __qlcnic_83xx_process_aen(struct qlcnic_adapter *adapter) +static void __qlcnic_83xx_process_aen(struct qlcnic_adapter *adapter)  {  	struct qlcnic_hardware_context *ahw = adapter->ahw;  	u32 event[QLC_83XX_MBX_AEN_CNT]; @@ -902,7 +961,7 @@ void __qlcnic_83xx_process_aen(struct qlcnic_adapter *adapter)  			 QLCNIC_MBX_RSP(event[0]));  		break;  	case QLCNIC_MBX_DCBX_CONFIG_CHANGE_EVENT: -		qlcnic_dcb_handle_aen(adapter, (void *)&event[1]); +		qlcnic_dcb_aen_handler(adapter->dcb, (void *)&event[1]);  		break;  	default:  		dev_dbg(&adapter->pdev->dev, "Unsupported AEN:0x%x.\n", @@ -979,14 +1038,14 @@ static int qlcnic_83xx_add_rings(struct qlcnic_adapter *adapter)  	sds_mbx_size = sizeof(struct qlcnic_sds_mbx);  	context_id = recv_ctx->context_id; -	num_sds = (adapter->max_sds_rings - QLCNIC_MAX_RING_SETS); +	num_sds = adapter->drv_sds_rings - QLCNIC_MAX_SDS_RINGS;  	ahw->hw_ops->alloc_mbx_args(&cmd, adapter,  				    QLCNIC_CMD_ADD_RCV_RINGS);  	cmd.req.arg[1] = 0 | (num_sds << 8) | (context_id << 16);  	/* set up status rings, mbx 2-81 */  	index = 2; -	for (i = 8; i < adapter->max_sds_rings; i++) { +	for (i = 8; i < adapter->drv_sds_rings; i++) {  		memset(&sds_mbx, 0, sds_mbx_size);  		sds = &recv_ctx->sds_rings[i];  		sds->consumer = 0; @@ -1021,7 +1080,7 @@ static int qlcnic_83xx_add_rings(struct qlcnic_adapter *adapter)  	mbx_out = (struct qlcnic_add_rings_mbx_out *)&cmd.rsp.arg[1];  	index = 0;  	/* status descriptor ring */ -	for (i = 8; i < adapter->max_sds_rings; i++) { +	for (i = 8; i < adapter->drv_sds_rings; i++) {  		sds = &recv_ctx->sds_rings[i];  		sds->crb_sts_consumer = ahw->pci_base0 +  					mbx_out->host_csmr[index]; @@ -1079,10 +1138,10 @@ int qlcnic_83xx_create_rx_ctx(struct qlcnic_adapter *adapter)  	struct qlcnic_hardware_context *ahw = adapter->ahw;  	num_rds = adapter->max_rds_rings; -	if (adapter->max_sds_rings <= QLCNIC_MAX_RING_SETS) -		num_sds = adapter->max_sds_rings; +	if (adapter->drv_sds_rings <= QLCNIC_MAX_SDS_RINGS) +		num_sds = adapter->drv_sds_rings;  	else -		num_sds = QLCNIC_MAX_RING_SETS; +		num_sds = QLCNIC_MAX_SDS_RINGS;  	sds_mbx_size = sizeof(struct qlcnic_sds_mbx);  	rds_mbx_size = sizeof(struct qlcnic_rds_mbx); @@ -1183,7 +1242,7 @@ int qlcnic_83xx_create_rx_ctx(struct qlcnic_adapter *adapter)  		sds->crb_intr_mask = ahw->pci_base0 + intr_mask;  	} -	if (adapter->max_sds_rings > QLCNIC_MAX_RING_SETS) +	if (adapter->drv_sds_rings > QLCNIC_MAX_SDS_RINGS)  		err = qlcnic_83xx_add_rings(adapter);  out:  	qlcnic_free_mbx_args(&cmd); @@ -1239,9 +1298,9 @@ int qlcnic_83xx_create_tx_ctx(struct qlcnic_adapter *adapter,  	mbx.size = tx->num_desc;  	if (adapter->flags & QLCNIC_MSIX_ENABLED) {  		if (!(adapter->flags & QLCNIC_TX_INTR_SHARED)) -			msix_vector = adapter->max_sds_rings + ring; +			msix_vector = adapter->drv_sds_rings + ring;  		else -			msix_vector = adapter->max_sds_rings - 1; +			msix_vector = adapter->drv_sds_rings - 1;  		msix_id = ahw->intr_tbl[msix_vector].id;  	} else {  		msix_id = QLCRDX(ahw, QLCNIC_DEF_INT_ID); @@ -1264,14 +1323,15 @@ int qlcnic_83xx_create_tx_ctx(struct qlcnic_adapter *adapter,  		qlcnic_pf_set_interface_id_create_tx_ctx(adapter, &temp);  	cmd.req.arg[1] = QLCNIC_CAP0_LEGACY_CONTEXT; -	cmd.req.arg[5] = QLCNIC_MAX_TX_QUEUES | temp; +	cmd.req.arg[5] = QLCNIC_SINGLE_RING | temp; +  	buf = &cmd.req.arg[6];  	memcpy(buf, &mbx, sizeof(struct qlcnic_tx_mbx));  	/* send the mailbox command*/  	err = qlcnic_issue_cmd(adapter, &cmd);  	if (err) { -		dev_err(&adapter->pdev->dev, -			"Failed to create Tx ctx in firmware 0x%x\n", err); +		netdev_err(adapter->netdev, +			   "Failed to create Tx ctx in firmware 0x%x\n", err);  		goto out;  	}  	mbx_out = (struct qlcnic_tx_mbx_out *)&cmd.rsp.arg[2]; @@ -1279,18 +1339,19 @@ int qlcnic_83xx_create_tx_ctx(struct qlcnic_adapter *adapter,  	tx->ctx_id = mbx_out->ctx_id;  	if ((adapter->flags & QLCNIC_MSIX_ENABLED) &&  	    !(adapter->flags & QLCNIC_TX_INTR_SHARED)) { -		intr_mask = ahw->intr_tbl[adapter->max_sds_rings + ring].src; +		intr_mask = ahw->intr_tbl[adapter->drv_sds_rings + ring].src;  		tx->crb_intr_mask = ahw->pci_base0 + intr_mask;  	} -	dev_info(&adapter->pdev->dev, "Tx Context[0x%x] Created, state:0x%x\n", -		 tx->ctx_id, mbx_out->state); +	netdev_info(adapter->netdev, +		    "Tx Context[0x%x] Created, state:0x%x\n", +		    tx->ctx_id, mbx_out->state);  out:  	qlcnic_free_mbx_args(&cmd);  	return err;  }  static int qlcnic_83xx_diag_alloc_res(struct net_device *netdev, int test, -				      int num_sds_ring) +				      u8 num_sds_ring)  {  	struct qlcnic_adapter *adapter = netdev_priv(netdev);  	struct qlcnic_host_sds_ring *sds_ring; @@ -1306,7 +1367,7 @@ static int qlcnic_83xx_diag_alloc_res(struct net_device *netdev, int test,  	qlcnic_detach(adapter); -	adapter->max_sds_rings = 1; +	adapter->drv_sds_rings = QLCNIC_SINGLE_RING;  	adapter->ahw->diag_test = test;  	adapter->ahw->linkup = 0; @@ -1320,7 +1381,7 @@ static int qlcnic_83xx_diag_alloc_res(struct net_device *netdev, int test,  	if (ret) {  		qlcnic_detach(adapter);  		if (adapter_state == QLCNIC_ADAPTER_UP_MAGIC) { -			adapter->max_sds_rings = num_sds_ring; +			adapter->drv_sds_rings = num_sds_ring;  			qlcnic_attach(adapter);  		}  		netif_device_attach(netdev); @@ -1333,18 +1394,13 @@ static int qlcnic_83xx_diag_alloc_res(struct net_device *netdev, int test,  	}  	if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) { -		for (ring = 0; ring < adapter->max_sds_rings; ring++) { +		for (ring = 0; ring < adapter->drv_sds_rings; ring++) {  			sds_ring = &adapter->recv_ctx->sds_rings[ring]; -			qlcnic_83xx_enable_intr(adapter, sds_ring); +			qlcnic_enable_sds_intr(adapter, sds_ring);  		}  	}  	if (adapter->ahw->diag_test == QLCNIC_LOOPBACK_TEST) { -		/* disable and free mailbox interrupt */ -		if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) { -			qlcnic_83xx_enable_mbx_poll(adapter); -			qlcnic_83xx_free_mbx_intr(adapter); -		}  		adapter->ahw->loopback_state = 0;  		adapter->ahw->hw_ops->setup_link_event(adapter, 1);  	} @@ -1354,39 +1410,26 @@ static int qlcnic_83xx_diag_alloc_res(struct net_device *netdev, int test,  }  static void qlcnic_83xx_diag_free_res(struct net_device *netdev, -					int max_sds_rings) +				      u8 drv_sds_rings)  {  	struct qlcnic_adapter *adapter = netdev_priv(netdev);  	struct qlcnic_host_sds_ring *sds_ring; -	int ring, err; +	int ring;  	clear_bit(__QLCNIC_DEV_UP, &adapter->state);  	if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) { -		for (ring = 0; ring < adapter->max_sds_rings; ring++) { +		for (ring = 0; ring < adapter->drv_sds_rings; ring++) {  			sds_ring = &adapter->recv_ctx->sds_rings[ring]; -			qlcnic_83xx_disable_intr(adapter, sds_ring); -			if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) -				qlcnic_83xx_enable_mbx_poll(adapter); +			if (adapter->flags & QLCNIC_MSIX_ENABLED) +				qlcnic_disable_sds_intr(adapter, sds_ring);  		}  	}  	qlcnic_fw_destroy_ctx(adapter);  	qlcnic_detach(adapter); -	if (adapter->ahw->diag_test == QLCNIC_LOOPBACK_TEST) { -		if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) { -			err = qlcnic_83xx_setup_mbx_intr(adapter); -			qlcnic_83xx_disable_mbx_poll(adapter); -			if (err) { -				dev_err(&adapter->pdev->dev, -					"%s: failed to setup mbx interrupt\n", -					__func__); -				goto out; -			} -		} -	}  	adapter->ahw->diag_test = 0; -	adapter->max_sds_rings = max_sds_rings; +	adapter->drv_sds_rings = drv_sds_rings;  	if (qlcnic_attach(adapter))  		goto out; @@ -1394,13 +1437,37 @@ static void qlcnic_83xx_diag_free_res(struct net_device *netdev,  	if (netif_running(netdev))  		__qlcnic_up(adapter, netdev); -	if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST && -	    !(adapter->flags & QLCNIC_MSIX_ENABLED)) -		qlcnic_83xx_disable_mbx_poll(adapter);  out:  	netif_device_attach(netdev);  } +static void qlcnic_83xx_get_beacon_state(struct qlcnic_adapter *adapter) +{ +	struct qlcnic_hardware_context *ahw = adapter->ahw; +	struct qlcnic_cmd_args cmd; +	u8 beacon_state; +	int err = 0; + +	err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_LED_CONFIG); +	if (!err) { +		err = qlcnic_issue_cmd(adapter, &cmd); +		if (!err) { +			beacon_state = cmd.rsp.arg[4]; +			if (beacon_state == QLCNIC_BEACON_DISABLE) +				ahw->beacon_state = QLC_83XX_BEACON_OFF; +			else if (beacon_state == QLC_83XX_ENABLE_BEACON) +				ahw->beacon_state = QLC_83XX_BEACON_ON; +		} +	} else { +		netdev_err(adapter->netdev, "Get beacon state failed, err=%d\n", +			   err); +	} + +	qlcnic_free_mbx_args(&cmd); + +	return; +} +  int qlcnic_83xx_config_led(struct qlcnic_adapter *adapter, u32 state,  			   u32 beacon)  { @@ -1513,8 +1580,7 @@ int  qlcnic_83xx_set_led(struct net_device *netdev,  	return err;  } -void qlcnic_83xx_register_nic_idc_func(struct qlcnic_adapter *adapter, -				       int enable) +void qlcnic_83xx_initialize_nic(struct qlcnic_adapter *adapter, int enable)  {  	struct qlcnic_cmd_args cmd;  	int status; @@ -1522,21 +1588,21 @@ void qlcnic_83xx_register_nic_idc_func(struct qlcnic_adapter *adapter,  	if (qlcnic_sriov_vf_check(adapter))  		return; -	if (enable) { +	if (enable)  		status = qlcnic_alloc_mbx_args(&cmd, adapter,  					       QLCNIC_CMD_INIT_NIC_FUNC); -		if (status) -			return; - -		cmd.req.arg[1] = BIT_0 | BIT_31; -	} else { +	else  		status = qlcnic_alloc_mbx_args(&cmd, adapter,  					       QLCNIC_CMD_STOP_NIC_FUNC); -		if (status) -			return; -		cmd.req.arg[1] = BIT_0 | BIT_31; -	} +	if (status) +		return; + +	cmd.req.arg[1] = QLC_REGISTER_LB_IDC | QLC_INIT_FW_RESOURCES; + +	if (adapter->dcb) +		cmd.req.arg[1] |= QLC_REGISTER_DCB_AEN; +  	status = qlcnic_issue_cmd(adapter, &cmd);  	if (status)  		dev_err(&adapter->pdev->dev, @@ -1546,7 +1612,7 @@ void qlcnic_83xx_register_nic_idc_func(struct qlcnic_adapter *adapter,  	qlcnic_free_mbx_args(&cmd);  } -int qlcnic_83xx_set_port_config(struct qlcnic_adapter *adapter) +static int qlcnic_83xx_set_port_config(struct qlcnic_adapter *adapter)  {  	struct qlcnic_cmd_args cmd;  	int err; @@ -1563,7 +1629,7 @@ int qlcnic_83xx_set_port_config(struct qlcnic_adapter *adapter)  	return err;  } -int qlcnic_83xx_get_port_config(struct qlcnic_adapter *adapter) +static int qlcnic_83xx_get_port_config(struct qlcnic_adapter *adapter)  {  	struct qlcnic_cmd_args cmd;  	int err; @@ -1605,7 +1671,9 @@ static void qlcnic_83xx_set_interface_id_promisc(struct qlcnic_adapter *adapter,  						 u32 *interface_id)  {  	if (qlcnic_sriov_pf_check(adapter)) { +		qlcnic_alloc_lb_filters_mem(adapter);  		qlcnic_pf_set_interface_id_promisc(adapter, interface_id); +		adapter->rx_mac_learn = true;  	} else {  		if (!qlcnic_sriov_vf_check(adapter))  			*interface_id = adapter->recv_ctx->context_id << 16; @@ -1632,7 +1700,11 @@ int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode)  	cmd->type = QLC_83XX_MBX_CMD_NO_WAIT;  	qlcnic_83xx_set_interface_id_promisc(adapter, &temp); -	cmd->req.arg[1] = (mode ? 1 : 0) | temp; + +	if (qlcnic_84xx_check(adapter) && qlcnic_sriov_pf_check(adapter)) +		mode = VPORT_MISS_MODE_ACCEPT_ALL; + +	cmd->req.arg[1] = mode | temp;  	err = qlcnic_issue_cmd(adapter, cmd);  	if (!err)  		return err; @@ -1648,7 +1720,9 @@ int qlcnic_83xx_loopback_test(struct net_device *netdev, u8 mode)  {  	struct qlcnic_adapter *adapter = netdev_priv(netdev);  	struct qlcnic_hardware_context *ahw = adapter->ahw; -	int ret = 0, loop = 0, max_sds_rings = adapter->max_sds_rings; +	u8 drv_sds_rings = adapter->drv_sds_rings; +	u8 drv_tx_rings = adapter->drv_tx_rings; +	int ret = 0, loop = 0;  	if (ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {  		netdev_warn(netdev, @@ -1670,7 +1744,7 @@ int qlcnic_83xx_loopback_test(struct net_device *netdev, u8 mode)  		    mode == QLCNIC_ILB_MODE ? "internal" : "external");  	ret = qlcnic_83xx_diag_alloc_res(netdev, QLCNIC_LOOPBACK_TEST, -					 max_sds_rings); +					 drv_sds_rings);  	if (ret)  		goto fail_diag_alloc; @@ -1697,21 +1771,16 @@ int qlcnic_83xx_loopback_test(struct net_device *netdev, u8 mode)  		}  	} while ((adapter->ahw->linkup && ahw->has_link_events) != 1); -	/* Make sure carrier is off and queue is stopped during loopback */ -	if (netif_running(netdev)) { -		netif_carrier_off(netdev); -		netif_tx_stop_all_queues(netdev); -	} -  	ret = qlcnic_do_lb_test(adapter, mode);  	qlcnic_83xx_clear_lb_mode(adapter, mode);  free_diag_res: -	qlcnic_83xx_diag_free_res(netdev, max_sds_rings); +	qlcnic_83xx_diag_free_res(netdev, drv_sds_rings);  fail_diag_alloc: -	adapter->max_sds_rings = max_sds_rings; +	adapter->drv_sds_rings = drv_sds_rings; +	adapter->drv_tx_rings = drv_tx_rings;  	qlcnic_release_diag_lock(adapter);  	return ret;  } @@ -1722,14 +1791,14 @@ static void qlcnic_extend_lb_idc_cmpltn_wait(struct qlcnic_adapter *adapter,  	struct qlcnic_hardware_context *ahw = adapter->ahw;  	int temp; -	netdev_info(adapter->netdev, "Recieved loopback IDC time extend event for 0x%x seconds\n", +	netdev_info(adapter->netdev, "Received loopback IDC time extend event for 0x%x seconds\n",  		    ahw->extend_lb_time);  	temp = ahw->extend_lb_time * 1000;  	*max_wait_count += temp / QLC_83XX_LB_MSLEEP_COUNT;  	ahw->extend_lb_time = 0;  } -int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode) +static int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode)  {  	struct qlcnic_hardware_context *ahw = adapter->ahw;  	struct net_device *netdev = adapter->netdev; @@ -1798,7 +1867,7 @@ int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode)  	return status;  } -int qlcnic_83xx_clear_lb_mode(struct qlcnic_adapter *adapter, u8 mode) +static int qlcnic_83xx_clear_lb_mode(struct qlcnic_adapter *adapter, u8 mode)  {  	struct qlcnic_hardware_context *ahw = adapter->ahw;  	u32 config = ahw->port_config, max_wait_count; @@ -2033,8 +2102,8 @@ void qlcnic_83xx_change_l2_filter(struct qlcnic_adapter *adapter, u64 *addr,  	qlcnic_83xx_sre_macaddr_change(adapter, mac, vlan_id, QLCNIC_MAC_ADD);  } -void qlcnic_83xx_configure_mac(struct qlcnic_adapter *adapter, u8 *mac, -			       u8 type, struct qlcnic_cmd_args *cmd) +static void qlcnic_83xx_configure_mac(struct qlcnic_adapter *adapter, u8 *mac, +				      u8 type, struct qlcnic_cmd_args *cmd)  {  	switch (type) {  	case QLCNIC_SET_STATION_MAC: @@ -2078,37 +2147,130 @@ int qlcnic_83xx_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac,  	return err;  } -void qlcnic_83xx_config_intr_coal(struct qlcnic_adapter *adapter) +static int qlcnic_83xx_set_rx_intr_coal(struct qlcnic_adapter *adapter)  { -	int err; -	u16 temp; -	struct qlcnic_cmd_args cmd;  	struct qlcnic_nic_intr_coalesce *coal = &adapter->ahw->coal; +	struct qlcnic_cmd_args cmd; +	u16 temp; +	int err; -	if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED) -		return; +	err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_INTR_COAL); +	if (err) +		return err; + +	temp = adapter->recv_ctx->context_id; +	cmd.req.arg[1] = QLCNIC_INTR_COAL_TYPE_RX | temp << 16; +	temp = coal->rx_time_us; +	cmd.req.arg[2] = coal->rx_packets | temp << 16; +	cmd.req.arg[3] = coal->flag; + +	err = qlcnic_issue_cmd(adapter, &cmd); +	if (err != QLCNIC_RCODE_SUCCESS) +		netdev_err(adapter->netdev, +			   "failed to set interrupt coalescing parameters\n"); + +	qlcnic_free_mbx_args(&cmd); + +	return err; +} + +static int qlcnic_83xx_set_tx_intr_coal(struct qlcnic_adapter *adapter) +{ +	struct qlcnic_nic_intr_coalesce *coal = &adapter->ahw->coal; +	struct qlcnic_cmd_args cmd; +	u16 temp; +	int err;  	err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_INTR_COAL);  	if (err) -		return; +		return err; -	if (coal->type == QLCNIC_INTR_COAL_TYPE_RX) { -		temp = adapter->recv_ctx->context_id; -		cmd.req.arg[1] = QLCNIC_INTR_COAL_TYPE_RX | temp << 16; -		temp = coal->rx_time_us; -		cmd.req.arg[2] = coal->rx_packets | temp << 16; -	} else if (coal->type == QLCNIC_INTR_COAL_TYPE_TX) { -		temp = adapter->tx_ring->ctx_id; -		cmd.req.arg[1] = QLCNIC_INTR_COAL_TYPE_TX | temp << 16; -		temp = coal->tx_time_us; -		cmd.req.arg[2] = coal->tx_packets | temp << 16; -	} +	temp = adapter->tx_ring->ctx_id; +	cmd.req.arg[1] = QLCNIC_INTR_COAL_TYPE_TX | temp << 16; +	temp = coal->tx_time_us; +	cmd.req.arg[2] = coal->tx_packets | temp << 16;  	cmd.req.arg[3] = coal->flag; +  	err = qlcnic_issue_cmd(adapter, &cmd);  	if (err != QLCNIC_RCODE_SUCCESS) -		dev_info(&adapter->pdev->dev, -			 "Failed to send interrupt coalescence parameters\n"); +		netdev_err(adapter->netdev, +			   "failed to set interrupt coalescing  parameters\n"); +  	qlcnic_free_mbx_args(&cmd); + +	return err; +} + +int qlcnic_83xx_set_rx_tx_intr_coal(struct qlcnic_adapter *adapter) +{ +	int err = 0; + +	err = qlcnic_83xx_set_rx_intr_coal(adapter); +	if (err) +		netdev_err(adapter->netdev, +			   "failed to set Rx coalescing parameters\n"); + +	err = qlcnic_83xx_set_tx_intr_coal(adapter); +	if (err) +		netdev_err(adapter->netdev, +			   "failed to set Tx coalescing parameters\n"); + +	return err; +} + +int qlcnic_83xx_config_intr_coal(struct qlcnic_adapter *adapter, +				 struct ethtool_coalesce *ethcoal) +{ +	struct qlcnic_nic_intr_coalesce *coal = &adapter->ahw->coal; +	u32 rx_coalesce_usecs, rx_max_frames; +	u32 tx_coalesce_usecs, tx_max_frames; +	int err; + +	if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED) +		return -EIO; + +	tx_coalesce_usecs = ethcoal->tx_coalesce_usecs; +	tx_max_frames = ethcoal->tx_max_coalesced_frames; +	rx_coalesce_usecs = ethcoal->rx_coalesce_usecs; +	rx_max_frames = ethcoal->rx_max_coalesced_frames; +	coal->flag = QLCNIC_INTR_DEFAULT; + +	if ((coal->rx_time_us == rx_coalesce_usecs) && +	    (coal->rx_packets == rx_max_frames)) { +		coal->type = QLCNIC_INTR_COAL_TYPE_TX; +		coal->tx_time_us = tx_coalesce_usecs; +		coal->tx_packets = tx_max_frames; +	} else if ((coal->tx_time_us == tx_coalesce_usecs) && +		   (coal->tx_packets == tx_max_frames)) { +		coal->type = QLCNIC_INTR_COAL_TYPE_RX; +		coal->rx_time_us = rx_coalesce_usecs; +		coal->rx_packets = rx_max_frames; +	} else { +		coal->type = QLCNIC_INTR_COAL_TYPE_RX_TX; +		coal->rx_time_us = rx_coalesce_usecs; +		coal->rx_packets = rx_max_frames; +		coal->tx_time_us = tx_coalesce_usecs; +		coal->tx_packets = tx_max_frames; +	} + +	switch (coal->type) { +	case QLCNIC_INTR_COAL_TYPE_RX: +		err = qlcnic_83xx_set_rx_intr_coal(adapter); +		break; +	case QLCNIC_INTR_COAL_TYPE_TX: +		err = qlcnic_83xx_set_tx_intr_coal(adapter); +		break; +	case QLCNIC_INTR_COAL_TYPE_RX_TX: +		err = qlcnic_83xx_set_rx_tx_intr_coal(adapter); +		break; +	default: +		err = -EINVAL; +		netdev_err(adapter->netdev, +			   "Invalid Interrupt coalescing type\n"); +		break; +	} + +	return err;  }  static void qlcnic_83xx_handle_link_aen(struct qlcnic_adapter *adapter, @@ -2133,10 +2295,11 @@ static void qlcnic_83xx_handle_link_aen(struct qlcnic_adapter *adapter,  	ahw->link_autoneg = MSB(MSW(data[3]));  	ahw->module_type = MSB(LSW(data[3]));  	ahw->has_link_events = 1; +	ahw->lb_mode = data[4] & QLCNIC_LB_MODE_MASK;  	qlcnic_advert_link_change(adapter, link_status);  } -irqreturn_t qlcnic_83xx_handle_aen(int irq, void *data) +static irqreturn_t qlcnic_83xx_handle_aen(int irq, void *data)  {  	struct qlcnic_adapter *adapter = data;  	struct qlcnic_mailbox *mbx; @@ -2162,36 +2325,6 @@ out:  	return IRQ_HANDLED;  } -int qlcnic_enable_eswitch(struct qlcnic_adapter *adapter, u8 port, u8 enable) -{ -	int err = -EIO; -	struct qlcnic_cmd_args cmd; - -	if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) { -		dev_err(&adapter->pdev->dev, -			"%s: Error, invoked by non management func\n", -			__func__); -		return err; -	} - -	err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_TOGGLE_ESWITCH); -	if (err) -		return err; - -	cmd.req.arg[1] = (port & 0xf) | BIT_4; -	err = qlcnic_issue_cmd(adapter, &cmd); - -	if (err != QLCNIC_RCODE_SUCCESS) { -		dev_err(&adapter->pdev->dev, "Failed to enable eswitch%d\n", -			err); -		err = -EIO; -	} -	qlcnic_free_mbx_args(&cmd); - -	return err; - -} -  int qlcnic_83xx_set_nic_info(struct qlcnic_adapter *adapter,  			     struct qlcnic_info *nic)  { @@ -2276,20 +2409,46 @@ int qlcnic_83xx_get_nic_info(struct qlcnic_adapter *adapter,  		temp = (cmd.rsp.arg[8] & 0x7FFE0000) >> 17;  		npar_info->max_linkspeed_reg_offset = temp;  	} -	if (npar_info->capabilities & QLCNIC_FW_CAPABILITY_MORE_CAPS) -		memcpy(ahw->extra_capability, &cmd.rsp.arg[16], -		       sizeof(ahw->extra_capability)); + +	memcpy(ahw->extra_capability, &cmd.rsp.arg[16], +	       sizeof(ahw->extra_capability));  out:  	qlcnic_free_mbx_args(&cmd);  	return err;  } +int qlcnic_get_pci_func_type(struct qlcnic_adapter *adapter, u16 type, +			     u16 *nic, u16 *fcoe, u16 *iscsi) +{ +	struct device *dev = &adapter->pdev->dev; +	int err = 0; + +	switch (type) { +	case QLCNIC_TYPE_NIC: +		(*nic)++; +		break; +	case QLCNIC_TYPE_FCOE: +		(*fcoe)++; +		break; +	case QLCNIC_TYPE_ISCSI: +		(*iscsi)++; +		break; +	default: +		dev_err(dev, "%s: Unknown PCI type[%x]\n", +			__func__, type); +		err = -EIO; +	} + +	return err; +} +  int qlcnic_83xx_get_pci_info(struct qlcnic_adapter *adapter,  			     struct qlcnic_pci_info *pci_info)  {  	struct qlcnic_hardware_context *ahw = adapter->ahw;  	struct device *dev = &adapter->pdev->dev; +	u16 nic = 0, fcoe = 0, iscsi = 0;  	struct qlcnic_cmd_args cmd;  	int i, err = 0, j = 0;  	u32 temp; @@ -2300,16 +2459,20 @@ int qlcnic_83xx_get_pci_info(struct qlcnic_adapter *adapter,  	err = qlcnic_issue_cmd(adapter, &cmd); -	ahw->act_pci_func = 0; +	ahw->total_nic_func = 0;  	if (err == QLCNIC_RCODE_SUCCESS) {  		ahw->max_pci_func = cmd.rsp.arg[1] & 0xFF; -		for (i = 2, j = 0; j < QLCNIC_MAX_PCI_FUNC; j++, pci_info++) { +		for (i = 2, j = 0; j < ahw->max_vnic_func; j++, pci_info++) {  			pci_info->id = cmd.rsp.arg[i] & 0xFFFF;  			pci_info->active = (cmd.rsp.arg[i] & 0xFFFF0000) >> 16;  			i++; +			if (!pci_info->active) { +				i += QLC_SKIP_INACTIVE_PCI_REGS; +				continue; +			}  			pci_info->type = cmd.rsp.arg[i] & 0xFFFF; -			if (pci_info->type == QLCNIC_TYPE_NIC) -				ahw->act_pci_func++; +			err = qlcnic_get_pci_func_type(adapter, pci_info->type, +						       &nic, &fcoe, &iscsi);  			temp = (cmd.rsp.arg[i] & 0xFFFF0000) >> 16;  			pci_info->default_port = temp;  			i++; @@ -2321,24 +2484,19 @@ int qlcnic_83xx_get_pci_info(struct qlcnic_adapter *adapter,  			i++;  			memcpy(pci_info->mac + sizeof(u32), &cmd.rsp.arg[i], 2);  			i = i + 3; -			if (ahw->op_mode == QLCNIC_MGMT_FUNC) -				dev_info(dev, "id = %d active = %d type = %d\n" -					 "\tport = %d min bw = %d max bw = %d\n" -					 "\tmac_addr =  %pM\n", pci_info->id, -					 pci_info->active, pci_info->type, -					 pci_info->default_port, -					 pci_info->tx_min_bw, -					 pci_info->tx_max_bw, pci_info->mac);  		} -		if (ahw->op_mode == QLCNIC_MGMT_FUNC) -			dev_info(dev, "Max functions = %d, active functions = %d\n", -				 ahw->max_pci_func, ahw->act_pci_func); -  	} else {  		dev_err(dev, "Failed to get PCI Info, error = %d\n", err);  		err = -EIO;  	} +	ahw->total_nic_func = nic; +	ahw->total_pci_func = nic + fcoe + iscsi; +	if (ahw->total_nic_func == 0 || ahw->total_pci_func == 0) { +		dev_err(dev, "%s: Invalid function count: total nic func[%x], total pci func[%x]\n", +			__func__, ahw->total_nic_func, ahw->total_pci_func); +		err = -EIO; +	}  	qlcnic_free_mbx_args(&cmd);  	return err; @@ -2879,19 +3037,18 @@ void qlcnic_83xx_unlock_driver(struct qlcnic_adapter *adapter)  	QLCRDX(adapter->ahw, QLC_83XX_DRV_UNLOCK);  } -int qlcnic_83xx_ms_mem_write128(struct qlcnic_adapter *adapter, u64 addr, +int qlcnic_ms_mem_write128(struct qlcnic_adapter *adapter, u64 addr,  				u32 *data, u32 count)  {  	int i, j, ret = 0;  	u32 temp; -	int err = 0;  	/* Check alignment */  	if (addr & 0xF)  		return -EIO;  	mutex_lock(&adapter->ahw->mem_lock); -	qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_ADDR_HI, 0); +	qlcnic_ind_wr(adapter, QLCNIC_MS_ADDR_HI, 0);  	for (i = 0; i < count; i++, addr += 16) {  		if (!((ADDR_IN_RANGE(addr, QLCNIC_ADDR_QDR_NET, @@ -2902,26 +3059,16 @@ int qlcnic_83xx_ms_mem_write128(struct qlcnic_adapter *adapter, u64 addr,  			return -EIO;  		} -		qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_ADDR_LO, addr); -		qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_WRTDATA_LO, -					     *data++); -		qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_WRTDATA_HI, -					     *data++); -		qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_WRTDATA_ULO, -					     *data++); -		qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_WRTDATA_UHI, -					     *data++); -		qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_CTRL, -					     QLCNIC_TA_WRITE_ENABLE); -		qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_CTRL, -					     QLCNIC_TA_WRITE_START); +		qlcnic_ind_wr(adapter, QLCNIC_MS_ADDR_LO, addr); +		qlcnic_ind_wr(adapter, QLCNIC_MS_WRTDATA_LO, *data++); +		qlcnic_ind_wr(adapter, QLCNIC_MS_WRTDATA_HI, *data++); +		qlcnic_ind_wr(adapter, QLCNIC_MS_WRTDATA_ULO, *data++); +		qlcnic_ind_wr(adapter, QLCNIC_MS_WRTDATA_UHI, *data++); +		qlcnic_ind_wr(adapter, QLCNIC_MS_CTRL, QLCNIC_TA_WRITE_ENABLE); +		qlcnic_ind_wr(adapter, QLCNIC_MS_CTRL, QLCNIC_TA_WRITE_START);  		for (j = 0; j < MAX_CTL_CHECK; j++) { -			temp = QLCRD32(adapter, QLCNIC_MS_CTRL, &err); -			if (err == -EIO) { -				mutex_unlock(&adapter->ahw->mem_lock); -				return err; -			} +			temp = qlcnic_ind_rd(adapter, QLCNIC_MS_CTRL);  			if ((temp & TA_CTL_BUSY) == 0)  				break; @@ -3061,11 +3208,14 @@ int qlcnic_83xx_get_settings(struct qlcnic_adapter *adapter,  	int status = 0;  	struct qlcnic_hardware_context *ahw = adapter->ahw; -	/* Get port configuration info */ -	status = qlcnic_83xx_get_port_info(adapter); -	/* Get Link Status related info */ -	config = qlcnic_83xx_test_link(adapter); -	ahw->module_type = QLC_83XX_SFP_MODULE_TYPE(config); +	if (!test_bit(__QLCNIC_MAINTENANCE_MODE, &adapter->state)) { +		/* Get port configuration info */ +		status = qlcnic_83xx_get_port_info(adapter); +		/* Get Link Status related info */ +		config = qlcnic_83xx_test_link(adapter); +		ahw->module_type = QLC_83XX_SFP_MODULE_TYPE(config); +	} +  	/* hard code until there is a way to get it from flash */  	ahw->board_type = QLCNIC_BRDTYPE_83XX_10G; @@ -3279,12 +3429,12 @@ int qlcnic_83xx_reg_test(struct qlcnic_adapter *adapter)  	return 0;  } -int qlcnic_83xx_get_regs_len(struct qlcnic_adapter *adapter) +inline int qlcnic_83xx_get_regs_len(struct qlcnic_adapter *adapter)  {  	return (ARRAY_SIZE(qlcnic_83xx_ext_reg_tbl) * -		sizeof(adapter->ahw->ext_reg_tbl)) + -		(ARRAY_SIZE(qlcnic_83xx_reg_tbl) + -		sizeof(adapter->ahw->reg_tbl)); +		sizeof(*adapter->ahw->ext_reg_tbl)) + +		(ARRAY_SIZE(qlcnic_83xx_reg_tbl) * +		sizeof(*adapter->ahw->reg_tbl));  }  int qlcnic_83xx_get_registers(struct qlcnic_adapter *adapter, u32 *regs_buff) @@ -3305,10 +3455,11 @@ int qlcnic_83xx_interrupt_test(struct net_device *netdev)  	struct qlcnic_adapter *adapter = netdev_priv(netdev);  	struct qlcnic_hardware_context *ahw = adapter->ahw;  	struct qlcnic_cmd_args cmd; +	u8 val, drv_sds_rings = adapter->drv_sds_rings; +	u8 drv_tx_rings = adapter->drv_tx_rings;  	u32 data;  	u16 intrpt_id, id; -	u8 val; -	int ret, max_sds_rings = adapter->max_sds_rings; +	int ret;  	if (test_bit(__QLCNIC_RESETTING, &adapter->state)) {  		netdev_info(netdev, "Device is resetting\n"); @@ -3321,7 +3472,7 @@ int qlcnic_83xx_interrupt_test(struct net_device *netdev)  	}  	ret = qlcnic_83xx_diag_alloc_res(netdev, QLCNIC_INTERRUPT_TEST, -					 max_sds_rings); +					 drv_sds_rings);  	if (ret)  		goto fail_diag_irq; @@ -3358,10 +3509,11 @@ int qlcnic_83xx_interrupt_test(struct net_device *netdev)  done:  	qlcnic_free_mbx_args(&cmd); -	qlcnic_83xx_diag_free_res(netdev, max_sds_rings); +	qlcnic_83xx_diag_free_res(netdev, drv_sds_rings);  fail_diag_irq: -	adapter->max_sds_rings = max_sds_rings; +	adapter->drv_sds_rings = drv_sds_rings; +	adapter->drv_tx_rings = drv_tx_rings;  	qlcnic_release_diag_lock(adapter);  	return ret;  } @@ -3381,10 +3533,21 @@ void qlcnic_83xx_get_pauseparam(struct qlcnic_adapter *adapter,  	}  	config = ahw->port_config;  	if (config & QLC_83XX_CFG_STD_PAUSE) { -		if (config & QLC_83XX_CFG_STD_TX_PAUSE) +		switch (MSW(config)) { +		case QLC_83XX_TX_PAUSE: +			pause->tx_pause = 1; +			break; +		case QLC_83XX_RX_PAUSE: +			pause->rx_pause = 1; +			break; +		case QLC_83XX_TX_RX_PAUSE: +		default: +			/* Backward compatibility for existing +			 * flash definitions +			 */  			pause->tx_pause = 1; -		if (config & QLC_83XX_CFG_STD_RX_PAUSE)  			pause->rx_pause = 1; +		}  	}  	if (QLC_83XX_AUTONEG(config)) @@ -3427,7 +3590,8 @@ int qlcnic_83xx_set_pauseparam(struct qlcnic_adapter *adapter,  		ahw->port_config &= ~QLC_83XX_CFG_STD_RX_PAUSE;  		ahw->port_config |= QLC_83XX_CFG_STD_TX_PAUSE;  	} else if (!pause->rx_pause && !pause->tx_pause) { -		ahw->port_config &= ~QLC_83XX_CFG_STD_TX_RX_PAUSE; +		ahw->port_config &= ~(QLC_83XX_CFG_STD_TX_RX_PAUSE | +				      QLC_83XX_CFG_STD_PAUSE);  	}  	status = qlcnic_83xx_set_port_config(adapter);  	if (status) { @@ -3471,7 +3635,7 @@ int qlcnic_83xx_flash_test(struct qlcnic_adapter *adapter)  	return 0;  } -int qlcnic_83xx_shutdown(struct pci_dev *pdev) +static int qlcnic_83xx_shutdown(struct pci_dev *pdev)  {  	struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);  	struct net_device *netdev = adapter->netdev; @@ -3493,7 +3657,7 @@ int qlcnic_83xx_shutdown(struct pci_dev *pdev)  	return 0;  } -int qlcnic_83xx_resume(struct qlcnic_adapter *adapter) +static int qlcnic_83xx_resume(struct qlcnic_adapter *adapter)  {  	struct qlcnic_hardware_context *ahw = adapter->ahw;  	struct qlc_83xx_idc *idc = &ahw->idc; @@ -3503,7 +3667,7 @@ int qlcnic_83xx_resume(struct qlcnic_adapter *adapter)  	if (err)  		return err; -	if (ahw->nic_mode == QLC_83XX_VIRTUAL_NIC_MODE) { +	if (ahw->nic_mode == QLCNIC_VNIC_MODE) {  		if (ahw->op_mode == QLCNIC_MGMT_FUNC) {  			qlcnic_83xx_set_vnic_opmode(adapter);  		} else { @@ -3524,12 +3688,15 @@ int qlcnic_83xx_resume(struct qlcnic_adapter *adapter)  void qlcnic_83xx_reinit_mbx_work(struct qlcnic_mailbox *mbx)  { -	INIT_COMPLETION(mbx->completion); +	reinit_completion(&mbx->completion);  	set_bit(QLC_83XX_MBX_READY, &mbx->status);  }  void qlcnic_83xx_free_mailbox(struct qlcnic_mailbox *mbx)  { +	if (!mbx) +		return; +  	destroy_workqueue(mbx->work_q);  	kfree(mbx);  } @@ -3650,6 +3817,9 @@ void qlcnic_83xx_detach_mailbox_work(struct qlcnic_adapter *adapter)  {  	struct qlcnic_mailbox *mbx = adapter->ahw->mailbox; +	if (!mbx) +		return; +  	clear_bit(QLC_83XX_MBX_READY, &mbx->status);  	complete(&mbx->completion);  	cancel_work_sync(&mbx->work); @@ -3735,6 +3905,19 @@ static void qlcnic_83xx_decode_mbx_rsp(struct qlcnic_adapter *adapter,  	return;  } +static inline void qlcnic_dump_mailbox_registers(struct qlcnic_adapter *adapter) +{ +	struct qlcnic_hardware_context *ahw = adapter->ahw; +	u32 offset; + +	offset = QLCRDX(ahw, QLCNIC_DEF_INT_MASK); +	dev_info(&adapter->pdev->dev, "Mbx interrupt mask=0x%x, Mbx interrupt enable=0x%x, Host mbx control=0x%x, Fw mbx control=0x%x", +		 readl(ahw->pci_base0 + offset), +		 QLCRDX(ahw, QLCNIC_MBX_INTR_ENBL), +		 QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL), +		 QLCRDX(ahw, QLCNIC_FW_MBX_CTRL)); +} +  static void qlcnic_83xx_mailbox_worker(struct work_struct *work)  {  	struct qlcnic_mailbox *mbx = container_of(work, struct qlcnic_mailbox, @@ -3779,6 +3962,8 @@ static void qlcnic_83xx_mailbox_worker(struct work_struct *work)  				__func__, cmd->cmd_op, cmd->type, ahw->pci_func,  				ahw->op_mode);  			clear_bit(QLC_83XX_MBX_READY, &mbx->status); +			qlcnic_dump_mailbox_registers(adapter); +			qlcnic_83xx_get_mbx_data(adapter, cmd);  			qlcnic_dump_mbx(adapter, cmd);  			qlcnic_83xx_idc_request_reset(adapter,  						      QLCNIC_FORCE_FW_DUMP_KEY); @@ -3825,8 +4010,8 @@ int qlcnic_83xx_init_mailbox_work(struct qlcnic_adapter *adapter)  	return 0;  } -pci_ers_result_t qlcnic_83xx_io_error_detected(struct pci_dev *pdev, -					       pci_channel_state_t state) +static pci_ers_result_t qlcnic_83xx_io_error_detected(struct pci_dev *pdev, +						      pci_channel_state_t state)  {  	struct qlcnic_adapter *adapter = pci_get_drvdata(pdev); @@ -3847,7 +4032,7 @@ pci_ers_result_t qlcnic_83xx_io_error_detected(struct pci_dev *pdev,  	return PCI_ERS_RESULT_NEED_RESET;  } -pci_ers_result_t qlcnic_83xx_io_slot_reset(struct pci_dev *pdev) +static pci_ers_result_t qlcnic_83xx_io_slot_reset(struct pci_dev *pdev)  {  	struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);  	int err = 0; @@ -3870,7 +4055,7 @@ disconnect:  	return PCI_ERS_RESULT_DISCONNECT;  } -void qlcnic_83xx_io_resume(struct pci_dev *pdev) +static void qlcnic_83xx_io_resume(struct pci_dev *pdev)  {  	struct qlcnic_adapter *adapter = pci_get_drvdata(pdev); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h index 533e150503a..2bf101a47d0 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h @@ -61,7 +61,6 @@  #define QLC_83XX_HOST_SDS_MBX_IDX		8  #define QLCNIC_HOST_RDS_MBX_IDX			88 -#define QLCNIC_MAX_RING_SETS			8  /* Pause control registers */  #define QLC_83XX_SRE_SHIM_REG		0x0D200284 @@ -183,8 +182,8 @@ struct qlcnic_rcv_mbx_out {  	u8	num_pci_func;  	u8	state;  #endif -	u32	host_csmr[QLCNIC_MAX_RING_SETS]; -	struct __host_producer_mbx host_prod[QLCNIC_MAX_RING_SETS]; +	u32	host_csmr[QLCNIC_MAX_SDS_RINGS]; +	struct __host_producer_mbx host_prod[QLCNIC_MAX_SDS_RINGS];  } __packed;  struct qlcnic_add_rings_mbx_out { @@ -197,8 +196,8 @@ struct qlcnic_add_rings_mbx_out {  	u8	sts_num;  	u8	rcv_num;  #endif -	u32  host_csmr[QLCNIC_MAX_RING_SETS]; -	struct __host_producer_mbx host_prod[QLCNIC_MAX_RING_SETS]; +	u32  host_csmr[QLCNIC_MAX_SDS_RINGS]; +	struct __host_producer_mbx host_prod[QLCNIC_MAX_SDS_RINGS];  } __packed;  /* Transmit context mailbox inbox registers @@ -309,6 +308,8 @@ struct qlc_83xx_reset {  #define QLC_83XX_IDC_FLASH_PARAM_ADDR			0x3e8020  struct qlcnic_adapter; +struct qlcnic_fw_dump; +  struct qlc_83xx_idc {  	int (*state_entry) (struct qlcnic_adapter *);  	u64		sec_counter; @@ -325,6 +326,11 @@ struct qlc_83xx_idc {  	char		**name;  }; +enum qlcnic_vlan_operations { +	QLC_VLAN_ADD = 0, +	QLC_VLAN_DELETE +}; +  /* Device States */  enum qlcnic_83xx_states {  	QLC_83XX_IDC_DEV_UNKNOWN, @@ -363,6 +369,9 @@ enum qlcnic_83xx_states {  #define QLC_83XX_LINK_EEE(data)		((data) & BIT_13)  #define QLC_83XX_DCBX(data)			(((data) >> 28) & 7)  #define QLC_83XX_AUTONEG(data)			((data) & BIT_15) +#define QLC_83XX_TX_PAUSE			0x10 +#define QLC_83XX_RX_PAUSE			0x20 +#define QLC_83XX_TX_RX_PAUSE			0x30  #define QLC_83XX_CFG_STD_PAUSE			(1 << 5)  #define QLC_83XX_CFG_STD_TX_PAUSE		(1 << 20)  #define QLC_83XX_CFG_STD_RX_PAUSE		(2 << 20) @@ -374,6 +383,8 @@ enum qlcnic_83xx_states {  /* LED configuration settings */  #define QLC_83XX_ENABLE_BEACON		0xe +#define QLC_83XX_BEACON_ON		1 +#define QLC_83XX_BEACON_OFF		0  #define QLC_83XX_LED_RATE		0xff  #define QLC_83XX_LED_ACT		(1 << 10)  #define QLC_83XX_LED_MOD		(0 << 13) @@ -407,13 +418,10 @@ enum qlcnic_83xx_states {  #define QLC_83XX_GET_FUNC_MODE_FROM_NPAR_INFO(val)	(val & 0x80000000)  #define QLC_83XX_GET_LRO_CAPABILITY(val)		(val & 0x20)  #define QLC_83XX_GET_LSO_CAPABILITY(val)		(val & 0x40) -#define QLC_83XX_GET_LSO_CAPABILITY(val)		(val & 0x40)  #define QLC_83XX_GET_HW_LRO_CAPABILITY(val)		(val & 0x400)  #define QLC_83XX_GET_VLAN_ALIGN_CAPABILITY(val)	(val & 0x4000)  #define QLC_83XX_GET_FW_LRO_MSS_CAPABILITY(val)	(val & 0x20000)  #define QLC_83XX_ESWITCH_CAPABILITY			BIT_23 -#define QLC_83XX_VIRTUAL_NIC_MODE			0xFF -#define QLC_83XX_DEFAULT_MODE				0x0  #define QLC_83XX_SRIOV_MODE				0x1  #define QLCNIC_BRDTYPE_83XX_10G			0x0083 @@ -518,10 +526,16 @@ enum qlc_83xx_ext_regs {  	QLC_83XX_ASIC_TEMP,  }; +/* Initialize/Stop NIC command bit definitions */ +#define QLC_REGISTER_LB_IDC		BIT_0 +#define QLC_REGISTER_DCB_AEN		BIT_1 +#define QLC_83XX_MULTI_TENANCY_INFO	BIT_29 +#define QLC_INIT_FW_RESOURCES		BIT_31 +  /* 83xx funcitons */  int qlcnic_83xx_get_fw_version(struct qlcnic_adapter *);  int qlcnic_83xx_issue_cmd(struct qlcnic_adapter *, struct qlcnic_cmd_args *); -int qlcnic_83xx_setup_intr(struct qlcnic_adapter *, u8, int); +int qlcnic_83xx_setup_intr(struct qlcnic_adapter *);  void qlcnic_83xx_get_func_no(struct qlcnic_adapter *);  int qlcnic_83xx_cam_lock(struct qlcnic_adapter *);  void qlcnic_83xx_cam_unlock(struct qlcnic_adapter *); @@ -532,24 +546,20 @@ void qlcnic_83xx_write_crb(struct qlcnic_adapter *, char *, loff_t, size_t);  void qlcnic_83xx_read_crb(struct qlcnic_adapter *, char *, loff_t, size_t);  int qlcnic_83xx_rd_reg_indirect(struct qlcnic_adapter *, ulong, int *);  int qlcnic_83xx_wrt_reg_indirect(struct qlcnic_adapter *, ulong, u32); -void qlcnic_83xx_process_rcv_diag(struct qlcnic_adapter *, int, u64 []);  int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *, u32); -int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *, u8); -int qlcnic_83xx_clear_lb_mode(struct qlcnic_adapter *, u8);  int qlcnic_83xx_config_hw_lro(struct qlcnic_adapter *, int);  int qlcnic_83xx_config_rss(struct qlcnic_adapter *, int); -int qlcnic_83xx_config_intr_coalesce(struct qlcnic_adapter *);  void qlcnic_83xx_change_l2_filter(struct qlcnic_adapter *, u64 *, u16);  int qlcnic_83xx_get_pci_info(struct qlcnic_adapter *, struct qlcnic_pci_info *);  int qlcnic_83xx_set_nic_info(struct qlcnic_adapter *, struct qlcnic_info *); -void qlcnic_83xx_register_nic_idc_func(struct qlcnic_adapter *, int); +void qlcnic_83xx_initialize_nic(struct qlcnic_adapter *, int);  int qlcnic_83xx_napi_add(struct qlcnic_adapter *, struct net_device *);  void qlcnic_83xx_napi_del(struct qlcnic_adapter *);  void qlcnic_83xx_napi_enable(struct qlcnic_adapter *);  void qlcnic_83xx_napi_disable(struct qlcnic_adapter *);  int qlcnic_83xx_config_led(struct qlcnic_adapter *, u32, u32); -void qlcnic_ind_wr(struct qlcnic_adapter *, u32, u32); +int qlcnic_ind_wr(struct qlcnic_adapter *, u32, u32);  int qlcnic_ind_rd(struct qlcnic_adapter *, u32);  int qlcnic_83xx_create_rx_ctx(struct qlcnic_adapter *);  int qlcnic_83xx_create_tx_ctx(struct qlcnic_adapter *, @@ -563,32 +573,22 @@ void qlcnic_83xx_process_rcv_ring_diag(struct qlcnic_host_sds_ring *);  int qlcnic_83xx_config_intrpt(struct qlcnic_adapter *, bool);  int qlcnic_83xx_sre_macaddr_change(struct qlcnic_adapter *, u8 *, u16, u8);  int qlcnic_83xx_get_mac_address(struct qlcnic_adapter *, u8 *, u8); -void qlcnic_83xx_configure_mac(struct qlcnic_adapter *, u8 *, u8, -			       struct qlcnic_cmd_args *);  int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *,  			       struct qlcnic_adapter *, u32);  void qlcnic_free_mbx_args(struct qlcnic_cmd_args *);  void qlcnic_set_npar_data(struct qlcnic_adapter *, const struct qlcnic_info *,  			  struct qlcnic_info *); -void qlcnic_83xx_config_intr_coal(struct qlcnic_adapter *); -irqreturn_t qlcnic_83xx_handle_aen(int, void *); +int qlcnic_83xx_config_intr_coal(struct qlcnic_adapter *, +				 struct ethtool_coalesce *); +int qlcnic_83xx_set_rx_tx_intr_coal(struct qlcnic_adapter *);  int qlcnic_83xx_get_port_info(struct qlcnic_adapter *);  void qlcnic_83xx_enable_mbx_interrupt(struct qlcnic_adapter *);  void qlcnic_83xx_disable_mbx_intr(struct qlcnic_adapter *);  irqreturn_t qlcnic_83xx_clear_legacy_intr(struct qlcnic_adapter *);  irqreturn_t qlcnic_83xx_intr(int, void *);  irqreturn_t qlcnic_83xx_tmp_intr(int, void *); -void qlcnic_83xx_enable_intr(struct qlcnic_adapter *, -			     struct qlcnic_host_sds_ring *); -void qlcnic_83xx_disable_intr(struct qlcnic_adapter *, -			     struct qlcnic_host_sds_ring *);  void qlcnic_83xx_check_vf(struct qlcnic_adapter *,  			  const struct pci_device_id *); -void __qlcnic_83xx_process_aen(struct qlcnic_adapter *); -int qlcnic_83xx_get_port_config(struct qlcnic_adapter *); -int qlcnic_83xx_set_port_config(struct qlcnic_adapter *); -int qlcnic_enable_eswitch(struct qlcnic_adapter *, u8, u8); -int qlcnic_83xx_get_nic_configuration(struct qlcnic_adapter *);  int qlcnic_83xx_config_default_opmode(struct qlcnic_adapter *);  int qlcnic_83xx_setup_mbx_intr(struct qlcnic_adapter *);  void qlcnic_83xx_free_mbx_intr(struct qlcnic_adapter *); @@ -610,23 +610,19 @@ int qlcnic_83xx_lockless_flash_read32(struct qlcnic_adapter *,  				      u32, u8 *, int);  int qlcnic_83xx_init(struct qlcnic_adapter *, int);  int qlcnic_83xx_idc_ready_state_entry(struct qlcnic_adapter *); -int qlcnic_83xx_check_hw_status(struct qlcnic_adapter *p_dev);  void qlcnic_83xx_idc_poll_dev_state(struct work_struct *); -int qlcnic_83xx_get_reset_instruction_template(struct qlcnic_adapter *);  void qlcnic_83xx_idc_exit(struct qlcnic_adapter *);  void qlcnic_83xx_idc_request_reset(struct qlcnic_adapter *, u32);  int qlcnic_83xx_lock_driver(struct qlcnic_adapter *);  void qlcnic_83xx_unlock_driver(struct qlcnic_adapter *);  int qlcnic_83xx_set_default_offload_settings(struct qlcnic_adapter *); -int qlcnic_83xx_ms_mem_write128(struct qlcnic_adapter *, u64, u32 *, u32);  int qlcnic_83xx_idc_vnic_pf_entry(struct qlcnic_adapter *); -int qlcnic_83xx_enable_vnic_mode(struct qlcnic_adapter *, int);  int qlcnic_83xx_disable_vnic_mode(struct qlcnic_adapter *, int);  int qlcnic_83xx_config_vnic_opmode(struct qlcnic_adapter *);  int qlcnic_83xx_get_vnic_vport_info(struct qlcnic_adapter *,  				    struct qlcnic_info *, u8);  int qlcnic_83xx_get_vnic_pf_info(struct qlcnic_adapter *, struct qlcnic_info *); -int qlcnic_83xx_enable_port_eswitch(struct qlcnic_adapter *, int); +int qlcnic_83xx_set_port_eswitch_status(struct qlcnic_adapter *, int, int *);  void qlcnic_83xx_get_minidump_template(struct qlcnic_adapter *);  void qlcnic_83xx_get_stats(struct qlcnic_adapter *adapter, u64 *data); @@ -648,9 +644,6 @@ int qlcnic_83xx_enable_flash_write(struct qlcnic_adapter *);  int qlcnic_83xx_disable_flash_write(struct qlcnic_adapter *);  void qlcnic_83xx_enable_mbx_poll(struct qlcnic_adapter *);  void qlcnic_83xx_disable_mbx_poll(struct qlcnic_adapter *); -void qlcnic_83xx_set_mac_filter_count(struct qlcnic_adapter *); -int qlcnic_83xx_shutdown(struct pci_dev *); -int qlcnic_83xx_resume(struct qlcnic_adapter *);  int qlcnic_83xx_idc_init(struct qlcnic_adapter *);  int qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter *);  int qlcnic_83xx_set_vnic_opmode(struct qlcnic_adapter *); @@ -658,8 +651,11 @@ int qlcnic_83xx_check_vnic_state(struct qlcnic_adapter *);  void qlcnic_83xx_aer_stop_poll_work(struct qlcnic_adapter *);  int qlcnic_83xx_aer_reset(struct qlcnic_adapter *);  void qlcnic_83xx_aer_start_poll_work(struct qlcnic_adapter *); -pci_ers_result_t qlcnic_83xx_io_error_detected(struct pci_dev *, -					       pci_channel_state_t); -pci_ers_result_t qlcnic_83xx_io_slot_reset(struct pci_dev *); -void qlcnic_83xx_io_resume(struct pci_dev *); +u32 qlcnic_83xx_get_saved_state(void *, u32); +void qlcnic_83xx_set_saved_state(void *, u32, u32); +void qlcnic_83xx_cache_tmpl_hdr_values(struct qlcnic_fw_dump *); +u32 qlcnic_83xx_get_cap_size(void *, int); +void qlcnic_83xx_set_sys_info(void *, int, u32); +void qlcnic_83xx_store_cap_mask(void *, u32); +int qlcnic_ms_mem_write128(struct qlcnic_adapter *, u64, u32 *, u32);  #endif diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c index f09e787af0b..f33559b7252 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c @@ -39,6 +39,9 @@  static int qlcnic_83xx_init_default_driver(struct qlcnic_adapter *adapter);  static int qlcnic_83xx_check_heartbeat(struct qlcnic_adapter *p_dev);  static int qlcnic_83xx_restart_hw(struct qlcnic_adapter *adapter); +static int qlcnic_83xx_check_hw_status(struct qlcnic_adapter *p_dev); +static int qlcnic_83xx_get_reset_instruction_template(struct qlcnic_adapter *); +static void qlcnic_83xx_stop_hw(struct qlcnic_adapter *);  /* Template header */  struct qlc_83xx_reset_hdr { @@ -380,7 +383,7 @@ static int qlcnic_83xx_idc_tx_soft_reset(struct qlcnic_adapter *adapter)  	qlcnic_up(adapter, netdev);  	netif_device_attach(netdev);  	clear_bit(__QLCNIC_RESETTING, &adapter->state); -	dev_err(&adapter->pdev->dev, "%s:\n", __func__); +	netdev_info(adapter->netdev, "%s: soft reset complete.\n", __func__);  	return 0;  } @@ -614,8 +617,7 @@ int qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter *adapter)  	qlcnic_83xx_reinit_mbx_work(adapter->ahw->mailbox);  	qlcnic_83xx_enable_mbx_interrupt(adapter); -	/* register for NIC IDC AEN Events */ -	qlcnic_83xx_register_nic_idc_func(adapter, 1); +	qlcnic_83xx_initialize_nic(adapter, 1);  	err = qlcnic_sriov_pf_reinit(adapter);  	if (err) @@ -636,7 +638,7 @@ int qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter *adapter)  	if (adapter->portnum == 0)  		qlcnic_set_drv_version(adapter); -	qlcnic_dcb_get_info(adapter); +	qlcnic_dcb_get_info(adapter->dcb);  	qlcnic_83xx_idc_attach_driver(adapter);  	return 0; @@ -740,6 +742,7 @@ static int qlcnic_83xx_idc_unknown_state(struct qlcnic_adapter *adapter)  	adapter->ahw->idc.err_code = -EIO;  	dev_err(&adapter->pdev->dev,  		"%s: Device in unknown state\n", __func__); +	clear_bit(__QLCNIC_RESETTING, &adapter->state);  	return 0;  } @@ -846,6 +849,10 @@ static int qlcnic_83xx_idc_ready_state(struct qlcnic_adapter *adapter)  			clear_bit(QLC_83XX_MBX_READY, &mbx->status);  			set_bit(__QLCNIC_RESETTING, &adapter->state);  			qlcnic_83xx_idc_enter_need_reset_state(adapter, 1); +		}  else { +			netdev_info(adapter->netdev, "%s: Auto firmware recovery is disabled\n", +				    __func__); +			qlcnic_83xx_idc_enter_failed_state(adapter, 1);  		}  		return -EIO;  	} @@ -897,7 +904,7 @@ static int qlcnic_83xx_idc_need_reset_state(struct qlcnic_adapter *adapter)  		qlcnic_83xx_idc_update_audit_reg(adapter, 0, 1);  		set_bit(__QLCNIC_RESETTING, &adapter->state);  		clear_bit(QLC_83XX_MBX_READY, &mbx->status); -		if (adapter->ahw->nic_mode == QLC_83XX_VIRTUAL_NIC_MODE) +		if (adapter->ahw->nic_mode == QLCNIC_VNIC_MODE)  			qlcnic_83xx_disable_vnic_mode(adapter, 1);  		if (qlcnic_check_diag_status(adapter)) { @@ -943,13 +950,26 @@ static int qlcnic_83xx_idc_need_quiesce_state(struct qlcnic_adapter *adapter)  	return 0;  } -static int qlcnic_83xx_idc_failed_state(struct qlcnic_adapter *adapter) +static void qlcnic_83xx_idc_failed_state(struct qlcnic_adapter *adapter)  { -	dev_err(&adapter->pdev->dev, "%s: please restart!!\n", __func__); +	struct qlcnic_hardware_context *ahw = adapter->ahw; +	u32 val, owner; + +	val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL); +	if (val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY) { +		owner = qlcnic_83xx_idc_find_reset_owner_id(adapter); +		if (ahw->pci_func == owner) { +			qlcnic_83xx_stop_hw(adapter); +			qlcnic_dump_fw(adapter); +		} +	} + +	netdev_warn(adapter->netdev, "%s: Reboot will be required to recover the adapter!!\n", +		    __func__);  	clear_bit(__QLCNIC_RESETTING, &adapter->state); -	adapter->ahw->idc.err_code = -EIO; +	ahw->idc.err_code = -EIO; -	return 0; +	return;  }  static int qlcnic_83xx_idc_quiesce_state(struct qlcnic_adapter *adapter) @@ -1000,10 +1020,99 @@ static int qlcnic_83xx_idc_check_state_validity(struct qlcnic_adapter *adapter,  	return 0;  } +#ifdef CONFIG_QLCNIC_VXLAN +#define QLC_83XX_ENCAP_TYPE_VXLAN	BIT_1 +#define QLC_83XX_MATCH_ENCAP_ID		BIT_2 +#define QLC_83XX_SET_VXLAN_UDP_DPORT	BIT_3 +#define QLC_83XX_VXLAN_UDP_DPORT(PORT)	((PORT & 0xffff) << 16) + +#define QLCNIC_ENABLE_INGRESS_ENCAP_PARSING 1 +#define QLCNIC_DISABLE_INGRESS_ENCAP_PARSING 0 + +static int qlcnic_set_vxlan_port(struct qlcnic_adapter *adapter) +{ +	u16 port = adapter->ahw->vxlan_port; +	struct qlcnic_cmd_args cmd; +	int ret = 0; + +	memset(&cmd, 0, sizeof(cmd)); + +	ret = qlcnic_alloc_mbx_args(&cmd, adapter, +				    QLCNIC_CMD_INIT_NIC_FUNC); +	if (ret) +		return ret; + +	cmd.req.arg[1] = QLC_83XX_MULTI_TENANCY_INFO; +	cmd.req.arg[2] = QLC_83XX_ENCAP_TYPE_VXLAN | +			 QLC_83XX_SET_VXLAN_UDP_DPORT | +			 QLC_83XX_VXLAN_UDP_DPORT(port); + +	ret = qlcnic_issue_cmd(adapter, &cmd); +	if (ret) +		netdev_err(adapter->netdev, +			   "Failed to set VXLAN port %d in adapter\n", +			   port); + +	qlcnic_free_mbx_args(&cmd); + +	return ret; +} + +static int qlcnic_set_vxlan_parsing(struct qlcnic_adapter *adapter, +				    bool state) +{ +	u16 vxlan_port = adapter->ahw->vxlan_port; +	struct qlcnic_cmd_args cmd; +	int ret = 0; + +	memset(&cmd, 0, sizeof(cmd)); + +	ret = qlcnic_alloc_mbx_args(&cmd, adapter, +				    QLCNIC_CMD_SET_INGRESS_ENCAP); +	if (ret) +		return ret; + +	cmd.req.arg[1] = state ? QLCNIC_ENABLE_INGRESS_ENCAP_PARSING : +				 QLCNIC_DISABLE_INGRESS_ENCAP_PARSING; + +	ret = qlcnic_issue_cmd(adapter, &cmd); +	if (ret) +		netdev_err(adapter->netdev, +			   "Failed to %s VXLAN parsing for port %d\n", +			   state ? "enable" : "disable", vxlan_port); +	else +		netdev_info(adapter->netdev, +			    "%s VXLAN parsing for port %d\n", +			    state ? "Enabled" : "Disabled", vxlan_port); + +	qlcnic_free_mbx_args(&cmd); + +	return ret; +} +#endif +  static void qlcnic_83xx_periodic_tasks(struct qlcnic_adapter *adapter)  {  	if (adapter->fhash.fnum)  		qlcnic_prune_lb_filters(adapter); + +#ifdef CONFIG_QLCNIC_VXLAN +	if (adapter->flags & QLCNIC_ADD_VXLAN_PORT) { +		if (qlcnic_set_vxlan_port(adapter)) +			return; + +		if (qlcnic_set_vxlan_parsing(adapter, true)) +			return; + +		adapter->flags &= ~QLCNIC_ADD_VXLAN_PORT; +	} else if (adapter->flags & QLCNIC_DEL_VXLAN_PORT) { +		if (qlcnic_set_vxlan_parsing(adapter, false)) +			return; + +		adapter->ahw->vxlan_port = 0; +		adapter->flags &= ~QLCNIC_DEL_VXLAN_PORT; +	} +#endif  }  /** @@ -1208,10 +1317,10 @@ void qlcnic_83xx_idc_request_reset(struct qlcnic_adapter *adapter, u32 key)  	}  	val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL); -	if ((val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY) || -	    !qlcnic_auto_fw_reset) { -		dev_err(&adapter->pdev->dev, -			"%s:failed, device in non reset mode\n", __func__); +	if (val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY) { +		netdev_info(adapter->netdev, "%s: Auto firmware recovery is disabled\n", +			    __func__); +		qlcnic_83xx_idc_enter_failed_state(adapter, 0);  		qlcnic_83xx_unlock_driver(adapter);  		return;  	} @@ -1243,24 +1352,24 @@ static int qlcnic_83xx_copy_bootloader(struct qlcnic_adapter *adapter)  	if (size & 0xF)  		size = (size + 16) & ~0xF; -	p_cache = kzalloc(size, GFP_KERNEL); +	p_cache = vzalloc(size);  	if (p_cache == NULL)  		return -ENOMEM;  	ret = qlcnic_83xx_lockless_flash_read32(adapter, src, p_cache,  						size / sizeof(u32));  	if (ret) { -		kfree(p_cache); +		vfree(p_cache);  		return ret;  	}  	/* 16 byte write to MS memory */ -	ret = qlcnic_83xx_ms_mem_write128(adapter, dest, (u32 *)p_cache, -					  size / 16); +	ret = qlcnic_ms_mem_write128(adapter, dest, (u32 *)p_cache, +				     size / 16);  	if (ret) { -		kfree(p_cache); +		vfree(p_cache);  		return ret;  	} -	kfree(p_cache); +	vfree(p_cache);  	return ret;  } @@ -1280,8 +1389,8 @@ static int qlcnic_83xx_copy_fw_file(struct qlcnic_adapter *adapter)  	p_cache = (u32 *)fw->data;  	addr = (u64)dest; -	ret = qlcnic_83xx_ms_mem_write128(adapter, addr, -					  (u32 *)p_cache, size / 16); +	ret = qlcnic_ms_mem_write128(adapter, addr, +				     p_cache, size / 16);  	if (ret) {  		dev_err(&adapter->pdev->dev, "MS memory write failed\n");  		release_firmware(fw); @@ -1296,8 +1405,8 @@ static int qlcnic_83xx_copy_fw_file(struct qlcnic_adapter *adapter)  			data[i] = fw->data[size + i];  		for (; i < 16; i++)  			data[i] = 0; -		ret = qlcnic_83xx_ms_mem_write128(adapter, addr, -						  (u32 *)data, 1); +		ret = qlcnic_ms_mem_write128(adapter, addr, +					     (u32 *)data, 1);  		if (ret) {  			dev_err(&adapter->pdev->dev,  				"MS memory write failed\n"); @@ -1511,7 +1620,7 @@ static int qlcnic_83xx_check_cmd_peg_status(struct qlcnic_adapter *p_dev)  	return -EIO;  } -int qlcnic_83xx_check_hw_status(struct qlcnic_adapter *p_dev) +static int qlcnic_83xx_check_hw_status(struct qlcnic_adapter *p_dev)  {  	int err; @@ -1584,7 +1693,7 @@ static int qlcnic_83xx_reset_template_checksum(struct qlcnic_adapter *p_dev)  	}  } -int qlcnic_83xx_get_reset_instruction_template(struct qlcnic_adapter *p_dev) +static int qlcnic_83xx_get_reset_instruction_template(struct qlcnic_adapter *p_dev)  {  	struct qlcnic_hardware_context *ahw = p_dev->ahw;  	u32 addr, count, prev_ver, curr_ver; @@ -1983,6 +2092,14 @@ static int qlcnic_83xx_restart_hw(struct qlcnic_adapter *adapter)  	val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);  	if (!(val & QLC_83XX_IDC_GRACEFULL_RESET))  		qlcnic_dump_fw(adapter); + +	if (val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY) { +		netdev_info(adapter->netdev, "%s: Auto firmware recovery is disabled\n", +			    __func__); +		qlcnic_83xx_idc_enter_failed_state(adapter, 1); +		return err; +	} +  	qlcnic_83xx_init_hw(adapter);  	if (qlcnic_83xx_copy_bootloader(adapter)) @@ -2003,7 +2120,7 @@ static int qlcnic_83xx_restart_hw(struct qlcnic_adapter *adapter)  	return 0;  } -int qlcnic_83xx_get_nic_configuration(struct qlcnic_adapter *adapter) +static int qlcnic_83xx_get_nic_configuration(struct qlcnic_adapter *adapter)  {  	int err;  	struct qlcnic_info nic_info; @@ -2034,7 +2151,7 @@ int qlcnic_83xx_get_nic_configuration(struct qlcnic_adapter *adapter)  		return QLC_83XX_DEFAULT_OPMODE;  	if (ahw->capabilities & QLC_83XX_ESWITCH_CAPABILITY) -		return QLC_83XX_VIRTUAL_NIC_MODE; +		return QLCNIC_VNIC_MODE;  	return QLC_83XX_DEFAULT_OPMODE;  } @@ -2042,25 +2159,36 @@ int qlcnic_83xx_get_nic_configuration(struct qlcnic_adapter *adapter)  int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter)  {  	struct qlcnic_hardware_context *ahw = adapter->ahw; +	u16 max_sds_rings, max_tx_rings;  	int ret;  	ret = qlcnic_83xx_get_nic_configuration(adapter);  	if (ret == -EIO)  		return -EIO; -	if (ret == QLC_83XX_VIRTUAL_NIC_MODE) { -		ahw->nic_mode = QLC_83XX_VIRTUAL_NIC_MODE; +	if (ret == QLCNIC_VNIC_MODE) { +		ahw->nic_mode = QLCNIC_VNIC_MODE; +  		if (qlcnic_83xx_config_vnic_opmode(adapter))  			return -EIO; +		max_sds_rings = QLCNIC_MAX_VNIC_SDS_RINGS; +		max_tx_rings = QLCNIC_MAX_VNIC_TX_RINGS;  	} else if (ret == QLC_83XX_DEFAULT_OPMODE) { -		ahw->nic_mode = QLC_83XX_DEFAULT_MODE; +		ahw->nic_mode = QLCNIC_DEFAULT_MODE;  		adapter->nic_ops->init_driver = qlcnic_83xx_init_default_driver;  		ahw->idc.state_entry = qlcnic_83xx_idc_ready_state_entry; +		max_sds_rings = QLCNIC_MAX_SDS_RINGS; +		max_tx_rings = QLCNIC_MAX_TX_RINGS;  	} else { +		dev_err(&adapter->pdev->dev, "%s: Invalid opmode %d\n", +			__func__, ret);  		return -EIO;  	} +	adapter->max_sds_rings = min(ahw->max_rx_ques, max_sds_rings); +	adapter->max_tx_rings = min(ahw->max_tx_ques, max_tx_rings); +  	return 0;  } @@ -2159,13 +2287,34 @@ static int qlcnic_83xx_get_fw_info(struct qlcnic_adapter *adapter)  	return err;  } +static void qlcnic_83xx_init_rings(struct qlcnic_adapter *adapter) +{ +	u8 rx_cnt = QLCNIC_DEF_SDS_RINGS; +	u8 tx_cnt = QLCNIC_DEF_TX_RINGS; + +	adapter->max_tx_rings = QLCNIC_MAX_TX_RINGS; +	adapter->max_sds_rings = QLCNIC_MAX_SDS_RINGS; + +	if (!adapter->ahw->msix_supported) { +		rx_cnt = QLCNIC_SINGLE_RING; +		tx_cnt = QLCNIC_SINGLE_RING; +	} + +	/* compute and set drv sds rings */ +	qlcnic_set_tx_ring_count(adapter, tx_cnt); +	qlcnic_set_sds_ring_count(adapter, rx_cnt); +}  int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac)  {  	struct qlcnic_hardware_context *ahw = adapter->ahw;  	int err = 0; +	adapter->rx_mac_learn = false;  	ahw->msix_supported = !!qlcnic_use_msi_x; + +	qlcnic_83xx_init_rings(adapter); +  	err = qlcnic_83xx_init_mailbox_work(adapter);  	if (err)  		goto exit; @@ -2178,51 +2327,53 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac)  			return err;  	} +	if (qlcnic_83xx_read_flash_descriptor_table(adapter) || +	    qlcnic_83xx_read_flash_mfg_id(adapter)) { +		dev_err(&adapter->pdev->dev, "Failed reading flash mfg id\n"); +		err = -ENOTRECOVERABLE; +		goto detach_mbx; +	} +  	err = qlcnic_83xx_check_hw_status(adapter);  	if (err)  		goto detach_mbx; -	if (!qlcnic_83xx_read_flash_descriptor_table(adapter)) -		qlcnic_83xx_read_flash_mfg_id(adapter); -  	err = qlcnic_83xx_get_fw_info(adapter);  	if (err)  		goto detach_mbx;  	err = qlcnic_83xx_idc_init(adapter);  	if (err) -		goto clear_fw_info; +		goto detach_mbx; -	err = qlcnic_setup_intr(adapter, 0, 0); +	err = qlcnic_setup_intr(adapter);  	if (err) {  		dev_err(&adapter->pdev->dev, "Failed to setup interrupt\n");  		goto disable_intr;  	} +	INIT_DELAYED_WORK(&adapter->idc_aen_work, qlcnic_83xx_idc_aen_work); +  	err = qlcnic_83xx_setup_mbx_intr(adapter);  	if (err)  		goto disable_mbx_intr;  	qlcnic_83xx_clear_function_resources(adapter); - -	INIT_DELAYED_WORK(&adapter->idc_aen_work, qlcnic_83xx_idc_aen_work); - -	/* register for NIC IDC AEN Events */ -	qlcnic_83xx_register_nic_idc_func(adapter, 1); +	qlcnic_dcb_enable(adapter->dcb); +	qlcnic_83xx_initialize_nic(adapter, 1); +	qlcnic_dcb_get_info(adapter->dcb);  	/* Configure default, SR-IOV or Virtual NIC mode of operation */  	err = qlcnic_83xx_configure_opmode(adapter);  	if (err)  		goto disable_mbx_intr; +  	/* Perform operating mode specific initialization */  	err = adapter->nic_ops->init_driver(adapter);  	if (err)  		goto disable_mbx_intr; -	if (adapter->dcb && qlcnic_dcb_attach(adapter)) -		qlcnic_clear_dcb_ops(adapter); -  	/* Periodically monitor device status */  	qlcnic_83xx_idc_poll_dev_state(&adapter->fw_work.work);  	return 0; @@ -2233,12 +2384,10 @@ disable_mbx_intr:  disable_intr:  	qlcnic_teardown_intr(adapter); -clear_fw_info: -	kfree(ahw->fw_info); -  detach_mbx:  	qlcnic_83xx_detach_mailbox_work(adapter);  	qlcnic_83xx_free_mailbox(ahw->mailbox); +	ahw->mailbox = NULL;  exit:  	return err;  } @@ -2251,11 +2400,11 @@ void qlcnic_83xx_aer_stop_poll_work(struct qlcnic_adapter *adapter)  	clear_bit(QLC_83XX_MBX_READY, &idc->status);  	cancel_delayed_work_sync(&adapter->fw_work); -	if (ahw->nic_mode == QLC_83XX_VIRTUAL_NIC_MODE) +	if (ahw->nic_mode == QLCNIC_VNIC_MODE)  		qlcnic_83xx_disable_vnic_mode(adapter, 1);  	qlcnic_83xx_idc_detach_driver(adapter); -	qlcnic_83xx_register_nic_idc_func(adapter, 0); +	qlcnic_83xx_initialize_nic(adapter, 0);  	cancel_delayed_work_sync(&adapter->idc_aen_work);  } diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c index 0248a4c2f5d..be7d7a62cc0 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c @@ -8,7 +8,7 @@  #include "qlcnic.h"  #include "qlcnic_hw.h" -int qlcnic_83xx_enable_vnic_mode(struct qlcnic_adapter *adapter, int lock) +static int qlcnic_83xx_enable_vnic_mode(struct qlcnic_adapter *adapter, int lock)  {  	if (lock) {  		if (qlcnic_83xx_lock_driver(adapter)) @@ -94,13 +94,29 @@ qlcnic_83xx_config_vnic_buff_descriptors(struct qlcnic_adapter *adapter)   **/  static int qlcnic_83xx_init_mgmt_vnic(struct qlcnic_adapter *adapter)  { -	int err = -EIO; +	struct qlcnic_hardware_context *ahw = adapter->ahw; +	struct device *dev = &adapter->pdev->dev; +	struct qlcnic_npar_info *npar; +	int i, err = -EIO;  	qlcnic_83xx_get_minidump_template(adapter); +  	if (!(adapter->flags & QLCNIC_ADAPTER_INITIALIZED)) {  		if (qlcnic_init_pci_info(adapter))  			return err; +		npar = adapter->npars; + +		for (i = 0; i < ahw->total_nic_func; i++, npar++) { +			dev_info(dev, "id:%d active:%d type:%d port:%d min_bw:%d max_bw:%d mac_addr:%pM\n", +				 npar->pci_func, npar->active, npar->type, +				 npar->phy_port, npar->min_bw, npar->max_bw, +				 npar->mac); +		} + +		dev_info(dev, "Max functions = %d, active functions = %d\n", +			 ahw->max_pci_func, ahw->total_nic_func); +  		if (qlcnic_83xx_set_vnic_opmode(adapter))  			return err; @@ -115,12 +131,12 @@ static int qlcnic_83xx_init_mgmt_vnic(struct qlcnic_adapter *adapter)  		return err;  	qlcnic_83xx_config_vnic_buff_descriptors(adapter); -	adapter->ahw->msix_supported = !!qlcnic_use_msi_x; +	ahw->msix_supported = qlcnic_use_msi_x ? 1 : 0;  	adapter->flags |= QLCNIC_ADAPTER_INITIALIZED;  	qlcnic_83xx_enable_vnic_mode(adapter, 1); -	dev_info(&adapter->pdev->dev, "HAL Version: %d, Management function\n", -		 adapter->ahw->fw_hal_version); +	dev_info(dev, "HAL Version: %d, Management function\n", +		 ahw->fw_hal_version);  	return 0;  } @@ -208,10 +224,14 @@ int qlcnic_83xx_config_vnic_opmode(struct qlcnic_adapter *adapter)  		return -EIO;  	} -	if (ahw->capabilities & QLC_83XX_ESWITCH_CAPABILITY) +	if (ahw->capabilities & QLC_83XX_ESWITCH_CAPABILITY) {  		adapter->flags |= QLCNIC_ESWITCH_ENABLED; -	else +		if (adapter->drv_mac_learn) +			adapter->rx_mac_learn = true; +	} else {  		adapter->flags &= ~QLCNIC_ESWITCH_ENABLED; +		adapter->rx_mac_learn = false; +	}  	ahw->idc.vnic_state = QLCNIC_DEV_NPAR_NON_OPER;  	ahw->idc.vnic_wait_limit = QLCNIC_DEV_NPAR_OPER_TIMEO; @@ -240,8 +260,8 @@ int qlcnic_83xx_check_vnic_state(struct qlcnic_adapter *adapter)  	return 0;  } -static int qlcnic_83xx_get_eswitch_port_info(struct qlcnic_adapter *adapter, -					     int func, int *port_id) +int qlcnic_83xx_set_port_eswitch_status(struct qlcnic_adapter *adapter, +					int func, int *port_id)  {  	struct qlcnic_info nic_info;  	int err = 0; @@ -257,23 +277,8 @@ static int qlcnic_83xx_get_eswitch_port_info(struct qlcnic_adapter *adapter,  	else  		err = -EIO; -	return err; -} - -int qlcnic_83xx_enable_port_eswitch(struct qlcnic_adapter *adapter, int func) -{ -	int id, err = 0; - -	err = qlcnic_83xx_get_eswitch_port_info(adapter, func, &id); -	if (err) -		return err; - -	if (!(adapter->eswitch[id].flags & QLCNIC_SWITCH_ENABLE)) { -		if (!qlcnic_enable_eswitch(adapter, id, 1)) -			adapter->eswitch[id].flags |= QLCNIC_SWITCH_ENABLE; -		else -			err = -EIO; -	} +	if (!err) +		adapter->eswitch[*port_id].flags |= QLCNIC_SWITCH_ENABLE;  	return err;  } diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c index 86850dd633a..304e247bdf3 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c @@ -91,18 +91,6 @@ void qlcnic_free_mbx_args(struct qlcnic_cmd_args *cmd)  	cmd->rsp.arg = NULL;  } -static int qlcnic_is_valid_nic_func(struct qlcnic_adapter *adapter, u8 pci_func) -{ -	int i; - -	for (i = 0; i < adapter->ahw->act_pci_func; i++) { -		if (adapter->npars[i].pci_func == pci_func) -			return i; -	} - -	return -1; -} -  static u32  qlcnic_poll_rsp(struct qlcnic_adapter *adapter)  { @@ -270,7 +258,7 @@ int qlcnic_82xx_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)  	int err;  	nrds_rings = adapter->max_rds_rings; -	nsds_rings = adapter->max_sds_rings; +	nsds_rings = adapter->drv_sds_rings;  	rq_size = SIZEOF_HOSTRQ_RX(struct qlcnic_hostrq_rx_ctx, nrds_rings,  				   nsds_rings); @@ -475,7 +463,7 @@ int qlcnic_82xx_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter,  	if (qlcnic_check_multi_tx(adapter) &&  	    !adapter->ahw->diag_test) { -		temp_nsds_rings = adapter->max_sds_rings; +		temp_nsds_rings = adapter->drv_sds_rings;  		index = temp_nsds_rings + ring;  		msix_id = ahw->intr_tbl[index].id;  		prq->msi_index = cpu_to_le16(msix_id); @@ -512,7 +500,7 @@ int qlcnic_82xx_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter,  		if (qlcnic_check_multi_tx(adapter) &&  		    !adapter->ahw->diag_test &&  		    (adapter->flags & QLCNIC_MSIX_ENABLED)) { -			index = adapter->max_sds_rings + ring; +			index = adapter->drv_sds_rings + ring;  			intr_mask = ahw->intr_tbl[index].src;  			tx_ring->crb_intr_mask = ahw->pci_base0 + intr_mask;  		} @@ -582,7 +570,7 @@ int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter)  	recv_ctx = adapter->recv_ctx; -	for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) { +	for (ring = 0; ring < adapter->drv_tx_rings; ring++) {  		tx_ring = &adapter->tx_ring[ring];  		ptr = (__le32 *)dma_alloc_coherent(&pdev->dev, sizeof(u32),  						   &tx_ring->hw_cons_phys_addr, @@ -616,7 +604,7 @@ int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter)  	} -	for (ring = 0; ring < adapter->max_sds_rings; ring++) { +	for (ring = 0; ring < adapter->drv_sds_rings; ring++) {  		sds_ring = &recv_ctx->sds_rings[ring];  		addr = dma_alloc_coherent(&adapter->pdev->dev, @@ -664,7 +652,7 @@ int qlcnic_fw_create_ctx(struct qlcnic_adapter *dev)  	if (err)  		goto err_out; -	for (ring = 0; ring < dev->max_drv_tx_rings; ring++) { +	for (ring = 0; ring < dev->drv_tx_rings; ring++) {  		err = qlcnic_fw_cmd_create_tx_ctx(dev,  						  &dev->tx_ring[ring],  						  ring); @@ -703,7 +691,7 @@ void qlcnic_fw_destroy_ctx(struct qlcnic_adapter *adapter)  	if (test_and_clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) {  		qlcnic_fw_cmd_del_rx_ctx(adapter); -		for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) +		for (ring = 0; ring < adapter->drv_tx_rings; ring++)  			qlcnic_fw_cmd_del_tx_ctx(adapter,  						 &adapter->tx_ring[ring]); @@ -733,7 +721,7 @@ void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter)  	recv_ctx = adapter->recv_ctx; -	for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) { +	for (ring = 0; ring < adapter->drv_tx_rings; ring++) {  		tx_ring = &adapter->tx_ring[ring];  		if (tx_ring->hw_consumer != NULL) {  			dma_free_coherent(&adapter->pdev->dev, sizeof(u32), @@ -764,7 +752,7 @@ void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter)  		}  	} -	for (ring = 0; ring < adapter->max_sds_rings; ring++) { +	for (ring = 0; ring < adapter->drv_sds_rings; ring++) {  		sds_ring = &recv_ctx->sds_rings[ring];  		if (sds_ring->desc_head != NULL) { @@ -964,13 +952,15 @@ out_free_dma:  int qlcnic_82xx_get_pci_info(struct qlcnic_adapter *adapter,  			     struct qlcnic_pci_info *pci_info)  { -	int err = 0, i; +	struct qlcnic_hardware_context *ahw = adapter->ahw; +	size_t npar_size = sizeof(struct qlcnic_pci_info_le); +	size_t pci_size = npar_size * ahw->max_vnic_func; +	u16 nic = 0, fcoe = 0, iscsi = 0; +	struct qlcnic_pci_info_le *npar;  	struct qlcnic_cmd_args cmd;  	dma_addr_t pci_info_dma_t; -	struct qlcnic_pci_info_le *npar;  	void *pci_info_addr; -	size_t npar_size = sizeof(struct qlcnic_pci_info_le); -	size_t pci_size = npar_size * QLCNIC_MAX_PCI_FUNC; +	int err = 0, i;  	pci_info_addr = dma_zalloc_coherent(&adapter->pdev->dev, pci_size,  					    &pci_info_dma_t, GFP_KERNEL); @@ -987,14 +977,16 @@ int qlcnic_82xx_get_pci_info(struct qlcnic_adapter *adapter,  	cmd.req.arg[3] = pci_size;  	err = qlcnic_issue_cmd(adapter, &cmd); -	adapter->ahw->act_pci_func = 0; +	ahw->total_nic_func = 0;  	if (err == QLCNIC_RCODE_SUCCESS) { -		for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++, npar++, pci_info++) { +		for (i = 0; i < ahw->max_vnic_func; i++, npar++, pci_info++) {  			pci_info->id = le16_to_cpu(npar->id);  			pci_info->active = le16_to_cpu(npar->active); +			if (!pci_info->active) +				continue;  			pci_info->type = le16_to_cpu(npar->type); -			if (pci_info->type == QLCNIC_TYPE_NIC) -				adapter->ahw->act_pci_func++; +			err = qlcnic_get_pci_func_type(adapter, pci_info->type, +						       &nic, &fcoe, &iscsi);  			pci_info->default_port =  				le16_to_cpu(npar->default_port);  			pci_info->tx_min_bw = @@ -1009,6 +1001,14 @@ int qlcnic_82xx_get_pci_info(struct qlcnic_adapter *adapter,  		err = -EIO;  	} +	ahw->total_nic_func = nic; +	ahw->total_pci_func = nic + fcoe + iscsi; +	if (ahw->total_nic_func == 0 || ahw->total_pci_func == 0) { +		dev_err(&adapter->pdev->dev, +			"%s: Invalid function count: total nic func[%x], total pci func[%x]\n", +			__func__, ahw->total_nic_func, ahw->total_pci_func); +		err = -EIO; +	}  	qlcnic_free_mbx_args(&cmd);  out_free_dma:  	dma_free_coherent(&adapter->pdev->dev, pci_size, pci_info_addr, @@ -1027,8 +1027,11 @@ int qlcnic_config_port_mirroring(struct qlcnic_adapter *adapter, u8 id,  	u32 arg1;  	if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC || -	    !(adapter->eswitch[id].flags & QLCNIC_SWITCH_ENABLE)) +	    !(adapter->eswitch[id].flags & QLCNIC_SWITCH_ENABLE)) { +		dev_err(&adapter->pdev->dev, "%s: Not a management function\n", +			__func__);  		return err; +	}  	arg1 = id | (enable_mirroring ? BIT_4 : 0);  	arg1 |= pci_func << 8; @@ -1201,7 +1204,7 @@ int qlcnic_get_eswitch_stats(struct qlcnic_adapter *adapter, const u8 eswitch,  	esw_stats->numbytes = QLCNIC_STATS_NOT_AVAIL;  	esw_stats->context_id = eswitch; -	for (i = 0; i < adapter->ahw->act_pci_func; i++) { +	for (i = 0; i < adapter->ahw->total_nic_func; i++) {  		if (adapter->npars[i].phy_port != eswitch)  			continue; @@ -1234,15 +1237,16 @@ int qlcnic_get_eswitch_stats(struct qlcnic_adapter *adapter, const u8 eswitch,  int qlcnic_clear_esw_stats(struct qlcnic_adapter *adapter, const u8 func_esw,  		const u8 port, const u8 rx_tx)  { +	struct qlcnic_hardware_context *ahw = adapter->ahw; +	struct qlcnic_cmd_args cmd;  	int err;  	u32 arg1; -	struct qlcnic_cmd_args cmd; -	if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) +	if (ahw->op_mode != QLCNIC_MGMT_FUNC)  		return -EIO;  	if (func_esw == QLCNIC_STATS_PORT) { -		if (port >= QLCNIC_MAX_PCI_FUNC) +		if (port >= ahw->max_vnic_func)  			goto err_ret;  	} else if (func_esw == QLCNIC_STATS_ESWITCH) {  		if (port >= QLCNIC_NIU_MAX_XG_PORTS) @@ -1317,8 +1321,12 @@ int qlcnic_config_switch_port(struct qlcnic_adapter *adapter,  	u32 arg1, arg2 = 0;  	u8 pci_func; -	if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) +	if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) { +		dev_err(&adapter->pdev->dev, "%s: Not a management function\n", +			__func__);  		return err; +	} +  	pci_func = esw_cfg->pci_func;  	index = qlcnic_is_valid_nic_func(adapter, pci_func);  	if (index < 0) @@ -1353,6 +1361,7 @@ int qlcnic_config_switch_port(struct qlcnic_adapter *adapter,  			arg2 &= ~BIT_3;  		break;  	case QLCNIC_ADD_VLAN: +			arg1 &= ~(0x0ffff << 16);  			arg1 |= (BIT_2 | BIT_5);  			arg1 |= (esw_cfg->vlan_id << 16);  			break; @@ -1361,6 +1370,8 @@ int qlcnic_config_switch_port(struct qlcnic_adapter *adapter,  			arg1 &= ~(0x0ffff << 16);  			break;  	default: +		dev_err(&adapter->pdev->dev, "%s: Invalid opmode 0x%x\n", +			__func__, esw_cfg->op_mode);  		return err;  	} diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c index d62d5ce432e..561cb11ca58 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c @@ -15,7 +15,6 @@  #define QLC_DCB_GET_MAP(V)		(1 << V) -#define QLC_DCB_AEN_BIT			0x2  #define QLC_DCB_FW_VER			0x2  #define QLC_DCB_MAX_TC			0x8  #define QLC_DCB_MAX_APP			0x8 @@ -57,22 +56,21 @@ static const struct dcbnl_rtnl_ops qlcnic_dcbnl_ops;  static void qlcnic_dcb_aen_work(struct work_struct *);  static void qlcnic_dcb_data_cee_param_map(struct qlcnic_adapter *); -static inline void __qlcnic_init_dcbnl_ops(struct qlcnic_adapter *); -static void __qlcnic_dcb_free(struct qlcnic_adapter *); -static int __qlcnic_dcb_attach(struct qlcnic_adapter *); -static int __qlcnic_dcb_query_hw_capability(struct qlcnic_adapter *, char *); -static void __qlcnic_dcb_get_info(struct qlcnic_adapter *); +static inline void __qlcnic_init_dcbnl_ops(struct qlcnic_dcb *); +static void __qlcnic_dcb_free(struct qlcnic_dcb *); +static int __qlcnic_dcb_attach(struct qlcnic_dcb *); +static int __qlcnic_dcb_query_hw_capability(struct qlcnic_dcb *, char *); +static void __qlcnic_dcb_get_info(struct qlcnic_dcb *); -static int qlcnic_82xx_dcb_get_hw_capability(struct qlcnic_adapter *); -static int qlcnic_82xx_dcb_query_cee_param(struct qlcnic_adapter *, char *, u8); -static int qlcnic_82xx_dcb_get_cee_cfg(struct qlcnic_adapter *); -static void qlcnic_82xx_dcb_handle_aen(struct qlcnic_adapter *, void *); +static int qlcnic_82xx_dcb_get_hw_capability(struct qlcnic_dcb *); +static int qlcnic_82xx_dcb_query_cee_param(struct qlcnic_dcb *, char *, u8); +static int qlcnic_82xx_dcb_get_cee_cfg(struct qlcnic_dcb *); +static void qlcnic_82xx_dcb_aen_handler(struct qlcnic_dcb *, void *); -static int qlcnic_83xx_dcb_get_hw_capability(struct qlcnic_adapter *); -static int qlcnic_83xx_dcb_query_cee_param(struct qlcnic_adapter *, char *, u8); -static int qlcnic_83xx_dcb_get_cee_cfg(struct qlcnic_adapter *); -static int qlcnic_83xx_dcb_register_aen(struct qlcnic_adapter *, bool); -static void qlcnic_83xx_dcb_handle_aen(struct qlcnic_adapter *, void *); +static int qlcnic_83xx_dcb_get_hw_capability(struct qlcnic_dcb *); +static int qlcnic_83xx_dcb_query_cee_param(struct qlcnic_dcb *, char *, u8); +static int qlcnic_83xx_dcb_get_cee_cfg(struct qlcnic_dcb *); +static void qlcnic_83xx_dcb_aen_handler(struct qlcnic_dcb *, void *);  struct qlcnic_dcb_capability {  	bool	tsa_capability; @@ -179,8 +177,7 @@ static struct qlcnic_dcb_ops qlcnic_83xx_dcb_ops = {  	.get_hw_capability	= qlcnic_83xx_dcb_get_hw_capability,  	.query_cee_param	= qlcnic_83xx_dcb_query_cee_param,  	.get_cee_cfg		= qlcnic_83xx_dcb_get_cee_cfg, -	.register_aen		= qlcnic_83xx_dcb_register_aen, -	.handle_aen		= qlcnic_83xx_dcb_handle_aen, +	.aen_handler		= qlcnic_83xx_dcb_aen_handler,  };  static struct qlcnic_dcb_ops qlcnic_82xx_dcb_ops = { @@ -193,7 +190,7 @@ static struct qlcnic_dcb_ops qlcnic_82xx_dcb_ops = {  	.get_hw_capability	= qlcnic_82xx_dcb_get_hw_capability,  	.query_cee_param	= qlcnic_82xx_dcb_query_cee_param,  	.get_cee_cfg		= qlcnic_82xx_dcb_get_cee_cfg, -	.handle_aen		= qlcnic_82xx_dcb_handle_aen, +	.aen_handler		= qlcnic_82xx_dcb_aen_handler,  };  static u8 qlcnic_dcb_get_num_app(struct qlcnic_adapter *adapter, u32 val) @@ -242,10 +239,10 @@ static int qlcnic_dcb_prio_count(u8 up_tc_map)  	return j;  } -static inline void __qlcnic_init_dcbnl_ops(struct qlcnic_adapter *adapter) +static inline void __qlcnic_init_dcbnl_ops(struct qlcnic_dcb *dcb)  { -	if (test_bit(__QLCNIC_DCB_STATE, &adapter->state)) -		adapter->netdev->dcbnl_ops = &qlcnic_dcbnl_ops; +	if (test_bit(QLCNIC_DCB_STATE, &dcb->state)) +		dcb->adapter->netdev->dcbnl_ops = &qlcnic_dcbnl_ops;  }  static void qlcnic_set_dcb_ops(struct qlcnic_adapter *adapter) @@ -256,10 +253,13 @@ static void qlcnic_set_dcb_ops(struct qlcnic_adapter *adapter)  		adapter->dcb->ops = &qlcnic_83xx_dcb_ops;  } -int __qlcnic_register_dcb(struct qlcnic_adapter *adapter) +int qlcnic_register_dcb(struct qlcnic_adapter *adapter)  {  	struct qlcnic_dcb *dcb; +	if (qlcnic_sriov_vf_check(adapter)) +		return 0; +  	dcb = kzalloc(sizeof(struct qlcnic_dcb), GFP_ATOMIC);  	if (!dcb)  		return -ENOMEM; @@ -267,20 +267,21 @@ int __qlcnic_register_dcb(struct qlcnic_adapter *adapter)  	adapter->dcb = dcb;  	dcb->adapter = adapter;  	qlcnic_set_dcb_ops(adapter); +	dcb->state = 0;  	return 0;  } -static void __qlcnic_dcb_free(struct qlcnic_adapter *adapter) +static void __qlcnic_dcb_free(struct qlcnic_dcb *dcb)  { -	struct qlcnic_dcb *dcb = adapter->dcb; +	struct qlcnic_adapter *adapter;  	if (!dcb)  		return; -	qlcnic_dcb_register_aen(adapter, 0); +	adapter = dcb->adapter; -	while (test_bit(__QLCNIC_DCB_IN_AEN, &adapter->state)) +	while (test_bit(QLCNIC_DCB_AEN_MODE, &dcb->state))  		usleep_range(10000, 11000);  	cancel_delayed_work_sync(&dcb->aen_work); @@ -298,23 +299,21 @@ static void __qlcnic_dcb_free(struct qlcnic_adapter *adapter)  	adapter->dcb = NULL;  } -static void __qlcnic_dcb_get_info(struct qlcnic_adapter *adapter) +static void __qlcnic_dcb_get_info(struct qlcnic_dcb *dcb)  { -	qlcnic_dcb_get_hw_capability(adapter); -	qlcnic_dcb_get_cee_cfg(adapter); -	qlcnic_dcb_register_aen(adapter, 1); +	qlcnic_dcb_get_hw_capability(dcb); +	qlcnic_dcb_get_cee_cfg(dcb);  } -static int __qlcnic_dcb_attach(struct qlcnic_adapter *adapter) +static int __qlcnic_dcb_attach(struct qlcnic_dcb *dcb)  { -	struct qlcnic_dcb *dcb = adapter->dcb;  	int err = 0;  	INIT_DELAYED_WORK(&dcb->aen_work, qlcnic_dcb_aen_work);  	dcb->wq = create_singlethread_workqueue("qlcnic-dcb");  	if (!dcb->wq) { -		dev_err(&adapter->pdev->dev, +		dev_err(&dcb->adapter->pdev->dev,  			"DCB workqueue allocation failed. DCB will be disabled\n");  		return -1;  	} @@ -331,8 +330,6 @@ static int __qlcnic_dcb_attach(struct qlcnic_adapter *adapter)  		goto out_free_cfg;  	} -	qlcnic_dcb_get_info(adapter); -  	return 0;  out_free_cfg:  	kfree(dcb->cfg); @@ -345,9 +342,9 @@ out_free_wq:  	return err;  } -static int __qlcnic_dcb_query_hw_capability(struct qlcnic_adapter *adapter, -					    char *buf) +static int __qlcnic_dcb_query_hw_capability(struct qlcnic_dcb *dcb, char *buf)  { +	struct qlcnic_adapter *adapter = dcb->adapter;  	struct qlcnic_cmd_args cmd;  	u32 mbx_out;  	int err; @@ -371,15 +368,15 @@ static int __qlcnic_dcb_query_hw_capability(struct qlcnic_adapter *adapter,  	return err;  } -static int __qlcnic_dcb_get_capability(struct qlcnic_adapter *adapter, u32 *val) +static int __qlcnic_dcb_get_capability(struct qlcnic_dcb *dcb, u32 *val)  { -	struct qlcnic_dcb_capability *cap = &adapter->dcb->cfg->capability; +	struct qlcnic_dcb_capability *cap = &dcb->cfg->capability;  	u32 mbx_out;  	int err;  	memset(cap, 0, sizeof(struct qlcnic_dcb_capability)); -	err = qlcnic_dcb_query_hw_capability(adapter, (char *)val); +	err = qlcnic_dcb_query_hw_capability(dcb, (char *)val);  	if (err)  		return err; @@ -397,21 +394,21 @@ static int __qlcnic_dcb_get_capability(struct qlcnic_adapter *adapter, u32 *val)  	if (cap->max_num_tc > QLC_DCB_MAX_TC ||  	    cap->max_ets_tc > cap->max_num_tc ||  	    cap->max_pfc_tc > cap->max_num_tc) { -		dev_err(&adapter->pdev->dev, "Invalid DCB configuration\n"); +		dev_err(&dcb->adapter->pdev->dev, "Invalid DCB configuration\n");  		return -EINVAL;  	}  	return err;  } -static int qlcnic_82xx_dcb_get_hw_capability(struct qlcnic_adapter *adapter) +static int qlcnic_82xx_dcb_get_hw_capability(struct qlcnic_dcb *dcb)  { -	struct qlcnic_dcb_cfg *cfg = adapter->dcb->cfg; +	struct qlcnic_dcb_cfg *cfg = dcb->cfg;  	struct qlcnic_dcb_capability *cap;  	u32 mbx_out;  	int err; -	err = __qlcnic_dcb_get_capability(adapter, &mbx_out); +	err = __qlcnic_dcb_get_capability(dcb, &mbx_out);  	if (err)  		return err; @@ -419,15 +416,16 @@ static int qlcnic_82xx_dcb_get_hw_capability(struct qlcnic_adapter *adapter)  	cap->dcb_capability = DCB_CAP_DCBX_VER_CEE | DCB_CAP_DCBX_LLD_MANAGED;  	if (cap->dcb_capability && cap->tsa_capability && cap->ets_capability) -		set_bit(__QLCNIC_DCB_STATE, &adapter->state); +		set_bit(QLCNIC_DCB_STATE, &dcb->state);  	return err;  } -static int qlcnic_82xx_dcb_query_cee_param(struct qlcnic_adapter *adapter, +static int qlcnic_82xx_dcb_query_cee_param(struct qlcnic_dcb *dcb,  					   char *buf, u8 type)  {  	u16 size = sizeof(struct qlcnic_82xx_dcb_param_mbx_le); +	struct qlcnic_adapter *adapter = dcb->adapter;  	struct qlcnic_82xx_dcb_param_mbx_le *prsp_le;  	struct device *dev = &adapter->pdev->dev;  	dma_addr_t cardrsp_phys_addr; @@ -447,8 +445,7 @@ static int qlcnic_82xx_dcb_query_cee_param(struct qlcnic_adapter *adapter,  		return -EINVAL;  	} -	addr = dma_alloc_coherent(&adapter->pdev->dev, size, &cardrsp_phys_addr, -				  GFP_KERNEL); +	addr = dma_alloc_coherent(dev, size, &cardrsp_phys_addr, GFP_KERNEL);  	if (addr == NULL)  		return -ENOMEM; @@ -488,72 +485,67 @@ out:  	qlcnic_free_mbx_args(&cmd);  out_free_rsp: -	dma_free_coherent(&adapter->pdev->dev, size, addr, cardrsp_phys_addr); +	dma_free_coherent(dev, size, addr, cardrsp_phys_addr);  	return err;  } -static int qlcnic_82xx_dcb_get_cee_cfg(struct qlcnic_adapter *adapter) +static int qlcnic_82xx_dcb_get_cee_cfg(struct qlcnic_dcb *dcb)  {  	struct qlcnic_dcb_mbx_params *mbx;  	int err; -	mbx = adapter->dcb->param; +	mbx = dcb->param;  	if (!mbx)  		return 0; -	err = qlcnic_dcb_query_cee_param(adapter, (char *)&mbx->type[0], +	err = qlcnic_dcb_query_cee_param(dcb, (char *)&mbx->type[0],  					 QLC_DCB_LOCAL_PARAM_FWID);  	if (err)  		return err; -	err = qlcnic_dcb_query_cee_param(adapter, (char *)&mbx->type[1], +	err = qlcnic_dcb_query_cee_param(dcb, (char *)&mbx->type[1],  					 QLC_DCB_OPER_PARAM_FWID);  	if (err)  		return err; -	err = qlcnic_dcb_query_cee_param(adapter, (char *)&mbx->type[2], +	err = qlcnic_dcb_query_cee_param(dcb, (char *)&mbx->type[2],  					 QLC_DCB_PEER_PARAM_FWID);  	if (err)  		return err;  	mbx->prio_tc_map = QLC_82XX_DCB_PRIO_TC_MAP; -	qlcnic_dcb_data_cee_param_map(adapter); +	qlcnic_dcb_data_cee_param_map(dcb->adapter);  	return err;  }  static void qlcnic_dcb_aen_work(struct work_struct *work)  { -	struct qlcnic_adapter *adapter;  	struct qlcnic_dcb *dcb;  	dcb = container_of(work, struct qlcnic_dcb, aen_work.work); -	adapter = dcb->adapter; -	qlcnic_dcb_get_cee_cfg(adapter); -	clear_bit(__QLCNIC_DCB_IN_AEN, &adapter->state); +	qlcnic_dcb_get_cee_cfg(dcb); +	clear_bit(QLCNIC_DCB_AEN_MODE, &dcb->state);  } -static void qlcnic_82xx_dcb_handle_aen(struct qlcnic_adapter *adapter, -				       void *data) +static void qlcnic_82xx_dcb_aen_handler(struct qlcnic_dcb *dcb, void *data)  { -	struct qlcnic_dcb *dcb = adapter->dcb; - -	if (test_and_set_bit(__QLCNIC_DCB_IN_AEN, &adapter->state)) +	if (test_and_set_bit(QLCNIC_DCB_AEN_MODE, &dcb->state))  		return;  	queue_delayed_work(dcb->wq, &dcb->aen_work, 0);  } -static int qlcnic_83xx_dcb_get_hw_capability(struct qlcnic_adapter *adapter) +static int qlcnic_83xx_dcb_get_hw_capability(struct qlcnic_dcb *dcb)  { -	struct qlcnic_dcb_capability *cap = &adapter->dcb->cfg->capability; +	struct qlcnic_dcb_capability *cap = &dcb->cfg->capability;  	u32 mbx_out;  	int err; -	err = __qlcnic_dcb_get_capability(adapter, &mbx_out); +	err = __qlcnic_dcb_get_capability(dcb, &mbx_out);  	if (err)  		return err; @@ -565,14 +557,15 @@ static int qlcnic_83xx_dcb_get_hw_capability(struct qlcnic_adapter *adapter)  		cap->dcb_capability |= DCB_CAP_DCBX_LLD_MANAGED;  	if (cap->dcb_capability && cap->tsa_capability && cap->ets_capability) -		set_bit(__QLCNIC_DCB_STATE, &adapter->state); +		set_bit(QLCNIC_DCB_STATE, &dcb->state);  	return err;  } -static int qlcnic_83xx_dcb_query_cee_param(struct qlcnic_adapter *adapter, +static int qlcnic_83xx_dcb_query_cee_param(struct qlcnic_dcb *dcb,  					   char *buf, u8 idx)  { +	struct qlcnic_adapter *adapter = dcb->adapter;  	struct qlcnic_dcb_mbx_params mbx_out;  	int err, i, j, k, max_app, size;  	struct qlcnic_dcb_param *each; @@ -632,56 +625,30 @@ out:  	return err;  } -static int qlcnic_83xx_dcb_get_cee_cfg(struct qlcnic_adapter *adapter) +static int qlcnic_83xx_dcb_get_cee_cfg(struct qlcnic_dcb *dcb)  { -	struct qlcnic_dcb *dcb = adapter->dcb;  	int err; -	err = qlcnic_dcb_query_cee_param(adapter, (char *)dcb->param, 0); +	err = qlcnic_dcb_query_cee_param(dcb, (char *)dcb->param, 0);  	if (err)  		return err; -	qlcnic_dcb_data_cee_param_map(adapter); +	qlcnic_dcb_data_cee_param_map(dcb->adapter);  	return err;  } -static int qlcnic_83xx_dcb_register_aen(struct qlcnic_adapter *adapter, -					bool flag) +static void qlcnic_83xx_dcb_aen_handler(struct qlcnic_dcb *dcb, void *data)  { -	u8 val = (flag ? QLCNIC_CMD_INIT_NIC_FUNC : QLCNIC_CMD_STOP_NIC_FUNC); -	struct qlcnic_cmd_args cmd; -	int err; - -	err = qlcnic_alloc_mbx_args(&cmd, adapter, val); -	if (err) -		return err; - -	cmd.req.arg[1] = QLC_DCB_AEN_BIT; - -	err = qlcnic_issue_cmd(adapter, &cmd); -	if (err) -		dev_err(&adapter->pdev->dev, "Failed to %s DCBX AEN, err %d\n", -			(flag ? "register" : "unregister"), err); - -	qlcnic_free_mbx_args(&cmd); - -	return err; -} - -static void qlcnic_83xx_dcb_handle_aen(struct qlcnic_adapter *adapter, -				       void *data) -{ -	struct qlcnic_dcb *dcb = adapter->dcb;  	u32 *val = data; -	if (test_and_set_bit(__QLCNIC_DCB_IN_AEN, &adapter->state)) +	if (test_and_set_bit(QLCNIC_DCB_AEN_MODE, &dcb->state))  		return;  	if (*val & BIT_8) -		set_bit(__QLCNIC_DCB_STATE, &adapter->state); +		set_bit(QLCNIC_DCB_STATE, &dcb->state);  	else -		clear_bit(__QLCNIC_DCB_STATE, &adapter->state); +		clear_bit(QLCNIC_DCB_STATE, &dcb->state);  	queue_delayed_work(dcb->wq, &dcb->aen_work, 0);  } @@ -814,12 +781,12 @@ static u8 qlcnic_dcb_get_state(struct net_device *netdev)  {  	struct qlcnic_adapter *adapter = netdev_priv(netdev); -	return test_bit(__QLCNIC_DCB_STATE, &adapter->state); +	return test_bit(QLCNIC_DCB_STATE, &adapter->dcb->state);  }  static void qlcnic_dcb_get_perm_hw_addr(struct net_device *netdev, u8 *addr)  { -	memcpy(addr, netdev->dev_addr, netdev->addr_len); +	memcpy(addr, netdev->perm_addr, netdev->addr_len);  }  static void @@ -834,11 +801,11 @@ qlcnic_dcb_get_pg_tc_cfg_tx(struct net_device *netdev, int tc, u8 *prio,  	type = &adapter->dcb->cfg->type[QLC_DCB_OPER_IDX];  	*prio = *pgid = *bw_per = *up_tc_map = 0; -	if (!test_bit(__QLCNIC_DCB_STATE, &adapter->state) || +	if (!test_bit(QLCNIC_DCB_STATE, &adapter->dcb->state) ||  	    !type->tc_param_valid)  		return; -	if (tc < 0 || (tc > QLC_DCB_MAX_TC)) +	if (tc < 0 || (tc >= QLC_DCB_MAX_TC))  		return;  	tc_cfg = &type->tc_cfg[tc]; @@ -870,11 +837,11 @@ static void qlcnic_dcb_get_pg_bwg_cfg_tx(struct net_device *netdev, int pgid,  	*bw_pct = 0;  	type = &adapter->dcb->cfg->type[QLC_DCB_OPER_IDX]; -	if (!test_bit(__QLCNIC_DCB_STATE, &adapter->state) || +	if (!test_bit(QLCNIC_DCB_STATE, &adapter->dcb->state) ||  	    !type->tc_param_valid)  		return; -	if (pgid < 0 || pgid > QLC_DCB_MAX_PG) +	if (pgid < 0 || pgid >= QLC_DCB_MAX_PG)  		return;  	pgcfg = &type->pg_cfg[pgid]; @@ -896,7 +863,7 @@ static void qlcnic_dcb_get_pfc_cfg(struct net_device *netdev, int prio,  	*setting = 0;  	type = &adapter->dcb->cfg->type[QLC_DCB_OPER_IDX]; -	if (!test_bit(__QLCNIC_DCB_STATE, &adapter->state) || +	if (!test_bit(QLCNIC_DCB_STATE, &adapter->dcb->state) ||  	    !type->pfc_mode_enable)  		return; @@ -915,7 +882,7 @@ static u8 qlcnic_dcb_get_capability(struct net_device *netdev, int capid,  {  	struct qlcnic_adapter *adapter = netdev_priv(netdev); -	if (!test_bit(__QLCNIC_DCB_STATE, &adapter->state)) +	if (!test_bit(QLCNIC_DCB_STATE, &adapter->dcb->state))  		return 0;  	switch (capid) { @@ -944,7 +911,7 @@ static int qlcnic_dcb_get_num_tcs(struct net_device *netdev, int attr, u8 *num)  	struct qlcnic_adapter *adapter = netdev_priv(netdev);  	struct qlcnic_dcb_cfg *cfg = adapter->dcb->cfg; -	if (!test_bit(__QLCNIC_DCB_STATE, &adapter->state)) +	if (!test_bit(QLCNIC_DCB_STATE, &adapter->dcb->state))  		return -EINVAL;  	switch (attr) { @@ -967,7 +934,7 @@ static u8 qlcnic_dcb_get_app(struct net_device *netdev, u8 idtype, u16 id)  				.protocol = id,  			     }; -	if (!test_bit(__QLCNIC_DCB_STATE, &adapter->state)) +	if (!test_bit(QLCNIC_DCB_STATE, &adapter->dcb->state))  		return 0;  	return dcb_getapp(netdev, &app); @@ -978,7 +945,7 @@ static u8 qlcnic_dcb_get_pfc_state(struct net_device *netdev)  	struct qlcnic_adapter *adapter = netdev_priv(netdev);  	struct qlcnic_dcb *dcb = adapter->dcb; -	if (!test_bit(__QLCNIC_DCB_STATE, &adapter->state)) +	if (!test_bit(QLCNIC_DCB_STATE, &dcb->state))  		return 0;  	return dcb->cfg->type[QLC_DCB_OPER_IDX].pfc_mode_enable; @@ -989,7 +956,7 @@ static u8 qlcnic_dcb_get_dcbx(struct net_device *netdev)  	struct qlcnic_adapter *adapter = netdev_priv(netdev);  	struct qlcnic_dcb_cfg *cfg = adapter->dcb->cfg; -	if (!test_bit(__QLCNIC_DCB_STATE, &adapter->state)) +	if (!test_bit(QLCNIC_DCB_STATE, &adapter->dcb->state))  		return 0;  	return cfg->capability.dcb_capability; @@ -1000,7 +967,7 @@ static u8 qlcnic_dcb_get_feat_cfg(struct net_device *netdev, int fid, u8 *flag)  	struct qlcnic_adapter *adapter = netdev_priv(netdev);  	struct qlcnic_dcb_cee *type; -	if (!test_bit(__QLCNIC_DCB_STATE, &adapter->state)) +	if (!test_bit(QLCNIC_DCB_STATE, &adapter->dcb->state))  		return 1;  	type = &adapter->dcb->cfg->type[QLC_DCB_OPER_IDX]; @@ -1053,9 +1020,10 @@ static int qlcnic_dcb_peer_app_info(struct net_device *netdev,  	struct qlcnic_dcb_cee *peer;  	int i; +	memset(info, 0, sizeof(*info));  	*app_count = 0; -	if (!test_bit(__QLCNIC_DCB_STATE, &adapter->state)) +	if (!test_bit(QLCNIC_DCB_STATE, &adapter->dcb->state))  		return 0;  	peer = &adapter->dcb->cfg->type[QLC_DCB_PEER_IDX]; @@ -1076,7 +1044,7 @@ static int qlcnic_dcb_peer_app_table(struct net_device *netdev,  	struct qlcnic_dcb_app *app;  	int i, j; -	if (!test_bit(__QLCNIC_DCB_STATE, &adapter->state)) +	if (!test_bit(QLCNIC_DCB_STATE, &adapter->dcb->state))  		return 0;  	peer = &adapter->dcb->cfg->type[QLC_DCB_PEER_IDX]; @@ -1101,7 +1069,7 @@ static int qlcnic_dcb_cee_peer_get_pg(struct net_device *netdev,  	struct qlcnic_dcb_cee *peer;  	u8 i, j, k, map; -	if (!test_bit(__QLCNIC_DCB_STATE, &adapter->state)) +	if (!test_bit(QLCNIC_DCB_STATE, &adapter->dcb->state))  		return 0;  	peer = &adapter->dcb->cfg->type[QLC_DCB_PEER_IDX]; @@ -1136,7 +1104,7 @@ static int qlcnic_dcb_cee_peer_get_pfc(struct net_device *netdev,  	pfc->pfc_en = 0; -	if (!test_bit(__QLCNIC_DCB_STATE, &adapter->state)) +	if (!test_bit(QLCNIC_DCB_STATE, &adapter->dcb->state))  		return 0;  	peer = &cfg->type[QLC_DCB_PEER_IDX]; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h index b87ce9fb503..3cf4a10fbe1 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h @@ -8,26 +8,28 @@  #ifndef __QLCNIC_DCBX_H  #define __QLCNIC_DCBX_H -void qlcnic_clear_dcb_ops(struct qlcnic_adapter *); +#define QLCNIC_DCB_STATE	0 +#define QLCNIC_DCB_AEN_MODE	1  #ifdef CONFIG_QLCNIC_DCB -int __qlcnic_register_dcb(struct qlcnic_adapter *); +int qlcnic_register_dcb(struct qlcnic_adapter *);  #else -static inline int __qlcnic_register_dcb(struct qlcnic_adapter *adapter) +static inline int qlcnic_register_dcb(struct qlcnic_adapter *adapter)  { return 0; }  #endif +struct qlcnic_dcb; +  struct qlcnic_dcb_ops { -	void (*init_dcbnl_ops) (struct qlcnic_adapter *); -	void (*free) (struct qlcnic_adapter *); -	int (*attach) (struct qlcnic_adapter *); -	int (*query_hw_capability) (struct qlcnic_adapter *, char *); -	int (*get_hw_capability) (struct qlcnic_adapter *); -	void (*get_info) (struct qlcnic_adapter *); -	int (*query_cee_param) (struct qlcnic_adapter *, char *, u8); -	int (*get_cee_cfg) (struct qlcnic_adapter *); -	int (*register_aen) (struct qlcnic_adapter *, bool); -	void (*handle_aen) (struct qlcnic_adapter *, void *); +	int (*query_hw_capability) (struct qlcnic_dcb *, char *); +	int (*get_hw_capability) (struct qlcnic_dcb *); +	int (*query_cee_param) (struct qlcnic_dcb *, char *, u8); +	void (*init_dcbnl_ops) (struct qlcnic_dcb *); +	void (*aen_handler) (struct qlcnic_dcb *, void *); +	int (*get_cee_cfg) (struct qlcnic_dcb *); +	void (*get_info) (struct qlcnic_dcb *); +	int (*attach) (struct qlcnic_dcb *); +	void (*free) (struct qlcnic_dcb *);  };  struct qlcnic_dcb { @@ -37,5 +39,84 @@ struct qlcnic_dcb {  	struct workqueue_struct		*wq;  	struct qlcnic_dcb_ops		*ops;  	struct qlcnic_dcb_cfg		*cfg; +	unsigned long			state;  }; + +static inline void qlcnic_clear_dcb_ops(struct qlcnic_dcb *dcb) +{ +	kfree(dcb); +	dcb = NULL; +} + +static inline int qlcnic_dcb_get_hw_capability(struct qlcnic_dcb *dcb) +{ +	if (dcb && dcb->ops->get_hw_capability) +		return dcb->ops->get_hw_capability(dcb); + +	return 0; +} + +static inline void qlcnic_dcb_free(struct qlcnic_dcb *dcb) +{ +	if (dcb && dcb->ops->free) +		dcb->ops->free(dcb); +} + +static inline int qlcnic_dcb_attach(struct qlcnic_dcb *dcb) +{ +	if (dcb && dcb->ops->attach) +		return dcb->ops->attach(dcb); + +	return 0; +} + +static inline int +qlcnic_dcb_query_hw_capability(struct qlcnic_dcb *dcb, char *buf) +{ +	if (dcb && dcb->ops->query_hw_capability) +		return dcb->ops->query_hw_capability(dcb, buf); + +	return 0; +} + +static inline void qlcnic_dcb_get_info(struct qlcnic_dcb *dcb) +{ +	if (dcb && dcb->ops->get_info) +		dcb->ops->get_info(dcb); +} + +static inline int +qlcnic_dcb_query_cee_param(struct qlcnic_dcb *dcb, char *buf, u8 type) +{ +	if (dcb && dcb->ops->query_cee_param) +		return dcb->ops->query_cee_param(dcb, buf, type); + +	return 0; +} + +static inline int qlcnic_dcb_get_cee_cfg(struct qlcnic_dcb *dcb) +{ +	if (dcb && dcb->ops->get_cee_cfg) +		return dcb->ops->get_cee_cfg(dcb); + +	return 0; +} + +static inline void qlcnic_dcb_aen_handler(struct qlcnic_dcb *dcb, void *msg) +{ +	if (dcb && dcb->ops->aen_handler) +		dcb->ops->aen_handler(dcb, msg); +} + +static inline void qlcnic_dcb_init_dcbnl_ops(struct qlcnic_dcb *dcb) +{ +	if (dcb && dcb->ops->init_dcbnl_ops) +		dcb->ops->init_dcbnl_ops(dcb); +} + +static inline void qlcnic_dcb_enable(struct qlcnic_dcb *dcb) +{ +	if (dcb && qlcnic_dcb_attach(dcb)) +		qlcnic_clear_dcb_ops(dcb); +}  #endif diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c index 4d7ad0074d1..1b7f3dbae28 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c @@ -27,43 +27,42 @@ static const u32 qlcnic_fw_dump_level[] = {  };  static const struct qlcnic_stats qlcnic_gstrings_stats[] = { +	{"xmit_on", QLC_SIZEOF(stats.xmit_on), QLC_OFF(stats.xmit_on)}, +	{"xmit_off", QLC_SIZEOF(stats.xmit_off), QLC_OFF(stats.xmit_off)},  	{"xmit_called", QLC_SIZEOF(stats.xmitcalled), -		QLC_OFF(stats.xmitcalled)}, +	 QLC_OFF(stats.xmitcalled)},  	{"xmit_finished", QLC_SIZEOF(stats.xmitfinished), -		QLC_OFF(stats.xmitfinished)}, -	{"rx_dropped", QLC_SIZEOF(stats.rxdropped), QLC_OFF(stats.rxdropped)}, +	 QLC_OFF(stats.xmitfinished)}, +	{"tx dma map error", QLC_SIZEOF(stats.tx_dma_map_error), +	 QLC_OFF(stats.tx_dma_map_error)}, +	{"tx_bytes", QLC_SIZEOF(stats.txbytes), QLC_OFF(stats.txbytes)},  	{"tx_dropped", QLC_SIZEOF(stats.txdropped), QLC_OFF(stats.txdropped)}, -	{"csummed", QLC_SIZEOF(stats.csummed), QLC_OFF(stats.csummed)}, +	{"rx dma map error", QLC_SIZEOF(stats.rx_dma_map_error), +	 QLC_OFF(stats.rx_dma_map_error)},  	{"rx_pkts", QLC_SIZEOF(stats.rx_pkts), QLC_OFF(stats.rx_pkts)}, -	{"lro_pkts", QLC_SIZEOF(stats.lro_pkts), QLC_OFF(stats.lro_pkts)},  	{"rx_bytes", QLC_SIZEOF(stats.rxbytes), QLC_OFF(stats.rxbytes)}, -	{"tx_bytes", QLC_SIZEOF(stats.txbytes), QLC_OFF(stats.txbytes)}, +	{"rx_dropped", QLC_SIZEOF(stats.rxdropped), QLC_OFF(stats.rxdropped)}, +	{"null rxbuf", QLC_SIZEOF(stats.null_rxbuf), QLC_OFF(stats.null_rxbuf)}, +	{"csummed", QLC_SIZEOF(stats.csummed), QLC_OFF(stats.csummed)}, +	{"lro_pkts", QLC_SIZEOF(stats.lro_pkts), QLC_OFF(stats.lro_pkts)},  	{"lrobytes", QLC_SIZEOF(stats.lrobytes), QLC_OFF(stats.lrobytes)},  	{"lso_frames", QLC_SIZEOF(stats.lso_frames), QLC_OFF(stats.lso_frames)}, -	{"xmit_on", QLC_SIZEOF(stats.xmit_on), QLC_OFF(stats.xmit_on)}, -	{"xmit_off", QLC_SIZEOF(stats.xmit_off), QLC_OFF(stats.xmit_off)}, +	{"encap_lso_frames", QLC_SIZEOF(stats.encap_lso_frames), +	 QLC_OFF(stats.encap_lso_frames)}, +	{"encap_tx_csummed", QLC_SIZEOF(stats.encap_tx_csummed), +	 QLC_OFF(stats.encap_tx_csummed)}, +	{"encap_rx_csummed", QLC_SIZEOF(stats.encap_rx_csummed), +	 QLC_OFF(stats.encap_rx_csummed)},  	{"skb_alloc_failure", QLC_SIZEOF(stats.skb_alloc_failure),  	 QLC_OFF(stats.skb_alloc_failure)}, -	{"null rxbuf", QLC_SIZEOF(stats.null_rxbuf), QLC_OFF(stats.null_rxbuf)}, -	{"rx dma map error", QLC_SIZEOF(stats.rx_dma_map_error), -					 QLC_OFF(stats.rx_dma_map_error)}, -	{"tx dma map error", QLC_SIZEOF(stats.tx_dma_map_error), -					 QLC_OFF(stats.tx_dma_map_error)},  	{"mac_filter_limit_overrun", QLC_SIZEOF(stats.mac_filter_limit_overrun), -				QLC_OFF(stats.mac_filter_limit_overrun)}, +	 QLC_OFF(stats.mac_filter_limit_overrun)},  	{"spurious intr", QLC_SIZEOF(stats.spurious_intr),  	 QLC_OFF(stats.spurious_intr)},  };  static const char qlcnic_device_gstrings_stats[][ETH_GSTRING_LEN] = { -	"rx unicast frames", -	"rx multicast frames", -	"rx broadcast frames", -	"rx dropped frames", -	"rx errors", -	"rx local frames", -	"rx numbytes",  	"tx unicast frames",  	"tx multicast frames",  	"tx broadcast frames", @@ -71,6 +70,13 @@ static const char qlcnic_device_gstrings_stats[][ETH_GSTRING_LEN] = {  	"tx errors",  	"tx local frames",  	"tx numbytes", +	"rx unicast frames", +	"rx multicast frames", +	"rx broadcast frames", +	"rx dropped frames", +	"rx errors", +	"rx local frames", +	"rx numbytes",  };  static const char qlcnic_83xx_tx_stats_strings[][ETH_GSTRING_LEN] = { @@ -126,13 +132,16 @@ static const char qlcnic_83xx_mac_stats_strings[][ETH_GSTRING_LEN] = {  #define QLCNIC_STATS_LEN	ARRAY_SIZE(qlcnic_gstrings_stats) -static const char qlcnic_tx_ring_stats_strings[][ETH_GSTRING_LEN] = { +static const char qlcnic_tx_queue_stats_strings[][ETH_GSTRING_LEN] = {  	"xmit_on",  	"xmit_off",  	"xmit_called",  	"xmit_finished", +	"tx_bytes",  }; +#define QLCNIC_TX_STATS_LEN	ARRAY_SIZE(qlcnic_tx_queue_stats_strings) +  static const char qlcnic_83xx_rx_stats_strings[][ETH_GSTRING_LEN] = {  	"ctx_rx_bytes",  	"ctx_rx_pkts", @@ -164,31 +173,39 @@ static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = {  #define QLCNIC_TEST_LEN	ARRAY_SIZE(qlcnic_gstrings_test) -static inline int qlcnic_82xx_statistics(void) +static inline int qlcnic_82xx_statistics(struct qlcnic_adapter *adapter)  { -	return ARRAY_SIZE(qlcnic_device_gstrings_stats) + -	       ARRAY_SIZE(qlcnic_83xx_mac_stats_strings); +	return ARRAY_SIZE(qlcnic_gstrings_stats) + +	       ARRAY_SIZE(qlcnic_83xx_mac_stats_strings) + +	       QLCNIC_TX_STATS_LEN * adapter->drv_tx_rings;  } -static inline int qlcnic_83xx_statistics(void) +static inline int qlcnic_83xx_statistics(struct qlcnic_adapter *adapter)  { -	return ARRAY_SIZE(qlcnic_83xx_tx_stats_strings) + +	return ARRAY_SIZE(qlcnic_gstrings_stats) + +	       ARRAY_SIZE(qlcnic_83xx_tx_stats_strings) +  	       ARRAY_SIZE(qlcnic_83xx_mac_stats_strings) + -	       ARRAY_SIZE(qlcnic_83xx_rx_stats_strings); +	       ARRAY_SIZE(qlcnic_83xx_rx_stats_strings) + +	       QLCNIC_TX_STATS_LEN * adapter->drv_tx_rings;  }  static int qlcnic_dev_statistics_len(struct qlcnic_adapter *adapter)  { -	if (qlcnic_82xx_check(adapter)) -		return qlcnic_82xx_statistics(); -	else if (qlcnic_83xx_check(adapter)) -		return qlcnic_83xx_statistics(); -	else -		return -1; +	int len = -1; + +	if (qlcnic_82xx_check(adapter)) { +		len = qlcnic_82xx_statistics(adapter); +		if (adapter->flags & QLCNIC_ESWITCH_ENABLED) +			len += ARRAY_SIZE(qlcnic_device_gstrings_stats); +	} else if (qlcnic_83xx_check(adapter)) { +		len = qlcnic_83xx_statistics(adapter); +	} + +	return len;  } -#define QLCNIC_RING_REGS_COUNT	20 -#define QLCNIC_RING_REGS_LEN	(QLCNIC_RING_REGS_COUNT * sizeof(u32)) +#define	QLCNIC_TX_INTR_NOT_CONFIGURED	0X78563412 +  #define QLCNIC_MAX_EEPROM_LEN   1024  static const u32 diag_registers[] = { @@ -218,8 +235,16 @@ static const u32 ext_diag_registers[] = {  	-1  }; -#define QLCNIC_MGMT_API_VERSION	2 -#define QLCNIC_ETHTOOL_REGS_VER	3 +#define QLCNIC_MGMT_API_VERSION	3 +#define QLCNIC_ETHTOOL_REGS_VER	4 + +static inline int qlcnic_get_ring_regs_len(struct qlcnic_adapter *adapter) +{ +	int ring_regs_cnt = (adapter->drv_tx_rings * 5) + +			    (adapter->max_rds_rings * 2) + +			    (adapter->drv_sds_rings * 3) + 5; +	return ring_regs_cnt * sizeof(u32); +}  static int qlcnic_get_regs_len(struct net_device *dev)  { @@ -231,7 +256,9 @@ static int qlcnic_get_regs_len(struct net_device *dev)  	else  		len = sizeof(ext_diag_registers) + sizeof(diag_registers); -	return QLCNIC_RING_REGS_LEN + len + QLCNIC_DEV_INFO_SIZE + 1; +	len += ((QLCNIC_DEV_INFO_SIZE + 2) * sizeof(u32)); +	len += qlcnic_get_ring_regs_len(adapter); +	return len;  }  static int qlcnic_get_eeprom_len(struct net_device *dev) @@ -257,21 +284,8 @@ qlcnic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)  		sizeof(drvinfo->version));  } -static int -qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) -{ -	struct qlcnic_adapter *adapter = netdev_priv(dev); - -	if (qlcnic_82xx_check(adapter)) -		return qlcnic_82xx_get_settings(adapter, ecmd); -	else if (qlcnic_83xx_check(adapter)) -		return qlcnic_83xx_get_settings(adapter, ecmd); - -	return -EIO; -} - -int qlcnic_82xx_get_settings(struct qlcnic_adapter *adapter, -			     struct ethtool_cmd *ecmd) +static int qlcnic_82xx_get_settings(struct qlcnic_adapter *adapter, +				    struct ethtool_cmd *ecmd)  {  	struct qlcnic_hardware_context *ahw = adapter->ahw;  	u32 speed, reg; @@ -412,6 +426,20 @@ skip:  	return 0;  } +static int qlcnic_get_settings(struct net_device *dev, +			       struct ethtool_cmd *ecmd) +{ +	struct qlcnic_adapter *adapter = netdev_priv(dev); + +	if (qlcnic_82xx_check(adapter)) +		return qlcnic_82xx_get_settings(adapter, ecmd); +	else if (qlcnic_83xx_check(adapter)) +		return qlcnic_83xx_get_settings(adapter, ecmd); + +	return -EIO; +} + +  static int qlcnic_set_port_config(struct qlcnic_adapter *adapter,  				  struct ethtool_cmd *ecmd)  { @@ -493,6 +521,8 @@ qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)  	struct qlcnic_adapter *adapter = netdev_priv(dev);  	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;  	struct qlcnic_host_sds_ring *sds_ring; +	struct qlcnic_host_rds_ring *rds_rings; +	struct qlcnic_host_tx_ring *tx_ring;  	u32 *regs_buff = p;  	int ring, i = 0; @@ -504,6 +534,9 @@ qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)  	regs_buff[0] = (0xcafe0000 | (QLCNIC_DEV_INFO_SIZE & 0xffff));  	regs_buff[1] = QLCNIC_MGMT_API_VERSION; +	if (adapter->ahw->capabilities & QLC_83XX_ESWITCH_CAPABILITY) +		regs_buff[2] = adapter->ahw->max_vnic_func; +  	if (qlcnic_82xx_check(adapter))  		i = qlcnic_82xx_get_registers(adapter, regs_buff);  	else @@ -512,21 +545,35 @@ qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)  	if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))  		return; -	regs_buff[i++] = 0xFFEFCDAB; /* Marker btw regs and ring count*/ - -	regs_buff[i++] = 1; /* No. of tx ring */ -	regs_buff[i++] = le32_to_cpu(*(adapter->tx_ring->hw_consumer)); -	regs_buff[i++] = readl(adapter->tx_ring->crb_cmd_producer); - -	regs_buff[i++] = 2; /* No. of rx ring */ -	regs_buff[i++] = readl(recv_ctx->rds_rings[0].crb_rcv_producer); -	regs_buff[i++] = readl(recv_ctx->rds_rings[1].crb_rcv_producer); +	/* Marker btw regs and TX ring count */ +	regs_buff[i++] = 0xFFEFCDAB; + +	regs_buff[i++] = adapter->drv_tx_rings; /* No. of TX ring */ +	for (ring = 0; ring < adapter->drv_tx_rings; ring++) { +		tx_ring = &adapter->tx_ring[ring]; +		regs_buff[i++] = le32_to_cpu(*(tx_ring->hw_consumer)); +		regs_buff[i++] = tx_ring->sw_consumer; +		regs_buff[i++] = readl(tx_ring->crb_cmd_producer); +		regs_buff[i++] = tx_ring->producer; +		if (tx_ring->crb_intr_mask) +			regs_buff[i++] = readl(tx_ring->crb_intr_mask); +		else +			regs_buff[i++] = QLCNIC_TX_INTR_NOT_CONFIGURED; +	} -	regs_buff[i++] = adapter->max_sds_rings; +	regs_buff[i++] = adapter->max_rds_rings; /* No. of RX ring */ +	for (ring = 0; ring < adapter->max_rds_rings; ring++) { +		rds_rings = &recv_ctx->rds_rings[ring]; +		regs_buff[i++] = readl(rds_rings->crb_rcv_producer); +		regs_buff[i++] = rds_rings->producer; +	} -	for (ring = 0; ring < adapter->max_sds_rings; ring++) { +	regs_buff[i++] = adapter->drv_sds_rings; /* No. of SDS ring */ +	for (ring = 0; ring < adapter->drv_sds_rings; ring++) {  		sds_ring = &(recv_ctx->sds_rings[ring]);  		regs_buff[i++] = readl(sds_ring->crb_sts_consumer); +		regs_buff[i++] = sds_ring->consumer; +		regs_buff[i++] = readl(sds_ring->crb_intr_mask);  	}  } @@ -635,46 +682,91 @@ qlcnic_set_ringparam(struct net_device *dev,  	return qlcnic_reset_context(adapter);  } +static int qlcnic_validate_ring_count(struct qlcnic_adapter *adapter, +				      u8 rx_ring, u8 tx_ring) +{ +	if (rx_ring == 0 || tx_ring == 0) +		return -EINVAL; + +	if (rx_ring != 0) { +		if (rx_ring > adapter->max_sds_rings) { +			netdev_err(adapter->netdev, +				   "Invalid ring count, SDS ring count %d should not be greater than max %d driver sds rings.\n", +				   rx_ring, adapter->max_sds_rings); +			return -EINVAL; +		} +	} + +	 if (tx_ring != 0) { +		if (tx_ring > adapter->max_tx_rings) { +			netdev_err(adapter->netdev, +				   "Invalid ring count, Tx ring count %d should not be greater than max %d driver Tx rings.\n", +				   tx_ring, adapter->max_tx_rings); +			return -EINVAL; +		} +	} + +	return 0; +} +  static void qlcnic_get_channels(struct net_device *dev,  		struct ethtool_channels *channel)  {  	struct qlcnic_adapter *adapter = netdev_priv(dev); -	int min; - -	min = min_t(int, adapter->ahw->max_rx_ques, num_online_cpus()); -	channel->max_rx = rounddown_pow_of_two(min); -	channel->max_tx = min_t(int, QLCNIC_MAX_TX_RINGS, num_online_cpus()); -	channel->rx_count = adapter->max_sds_rings; -	channel->tx_count = adapter->max_drv_tx_rings; +	channel->max_rx = adapter->max_sds_rings; +	channel->max_tx = adapter->max_tx_rings; +	channel->rx_count = adapter->drv_sds_rings; +	channel->tx_count = adapter->drv_tx_rings;  }  static int qlcnic_set_channels(struct net_device *dev, -		struct ethtool_channels *channel) +			       struct ethtool_channels *channel)  {  	struct qlcnic_adapter *adapter = netdev_priv(dev);  	int err; -	int txq = 0; + +	if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) { +		netdev_err(dev, "No RSS/TSS support in non MSI-X mode\n"); +		return -EINVAL; +	}  	if (channel->other_count || channel->combined_count)  		return -EINVAL; -	if (channel->rx_count) { -		err = qlcnic_validate_max_rss(adapter, channel->rx_count); -		if (err) +	err = qlcnic_validate_ring_count(adapter, channel->rx_count, +					 channel->tx_count); +	if (err) +		return err; + +	if (adapter->drv_sds_rings != channel->rx_count) { +		err = qlcnic_validate_rings(adapter, channel->rx_count, +					    QLCNIC_RX_QUEUE); +		if (err) { +			netdev_err(dev, "Unable to configure %u SDS rings\n", +				   channel->rx_count);  			return err; +		} +		adapter->drv_rss_rings = channel->rx_count;  	} -	if (channel->tx_count) { -		err = qlcnic_validate_max_tx_rings(adapter, channel->tx_count); -		if (err) +	if (adapter->drv_tx_rings != channel->tx_count) { +		err = qlcnic_validate_rings(adapter, channel->tx_count, +					    QLCNIC_TX_QUEUE); +		if (err) { +			netdev_err(dev, "Unable to configure %u Tx rings\n", +				   channel->tx_count);  			return err; -		txq = channel->tx_count; +		} +		adapter->drv_tss_rings = channel->tx_count;  	} -	err = qlcnic_set_max_rss(adapter, channel->rx_count, txq); -	netdev_info(dev, "allocated 0x%x sds rings and  0x%x tx rings\n", -		    adapter->max_sds_rings, adapter->max_drv_tx_rings); +	adapter->flags |= QLCNIC_TSS_RSS; + +	err = qlcnic_setup_rings(adapter); +	netdev_info(dev, "Allocated %d SDS rings and %d Tx rings\n", +		    adapter->drv_sds_rings, adapter->drv_tx_rings); +  	return err;  } @@ -854,18 +946,13 @@ static int qlcnic_eeprom_test(struct net_device *dev)  static int qlcnic_get_sset_count(struct net_device *dev, int sset)  { -	int len;  	struct qlcnic_adapter *adapter = netdev_priv(dev);  	switch (sset) {  	case ETH_SS_TEST:  		return QLCNIC_TEST_LEN;  	case ETH_SS_STATS: -		len = qlcnic_dev_statistics_len(adapter) + QLCNIC_STATS_LEN; -		if ((adapter->flags & QLCNIC_ESWITCH_ENABLED) || -		    qlcnic_83xx_check(adapter)) -			return len; -		return qlcnic_82xx_statistics(); +		return qlcnic_dev_statistics_len(adapter);  	default:  		return -EOPNOTSUPP;  	} @@ -876,7 +963,8 @@ static int qlcnic_irq_test(struct net_device *netdev)  	struct qlcnic_adapter *adapter = netdev_priv(netdev);  	struct qlcnic_hardware_context *ahw = adapter->ahw;  	struct qlcnic_cmd_args cmd; -	int ret, max_sds_rings = adapter->max_sds_rings; +	int ret, drv_sds_rings = adapter->drv_sds_rings; +	int drv_tx_rings = adapter->drv_tx_rings;  	if (qlcnic_83xx_check(adapter))  		return qlcnic_83xx_interrupt_test(netdev); @@ -905,10 +993,11 @@ done:  	qlcnic_free_mbx_args(&cmd);  free_diag_res: -	qlcnic_diag_free_res(netdev, max_sds_rings); +	qlcnic_diag_free_res(netdev, drv_sds_rings);  clear_diag_irq: -	adapter->max_sds_rings = max_sds_rings; +	adapter->drv_sds_rings = drv_sds_rings; +	adapter->drv_tx_rings = drv_tx_rings;  	clear_bit(__QLCNIC_RESETTING, &adapter->state);  	return ret; @@ -981,11 +1070,11 @@ int qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode)  	return 0;  } -int qlcnic_loopback_test(struct net_device *netdev, u8 mode) +static int qlcnic_loopback_test(struct net_device *netdev, u8 mode)  {  	struct qlcnic_adapter *adapter = netdev_priv(netdev); -	int max_drv_tx_rings = adapter->max_drv_tx_rings; -	int max_sds_rings = adapter->max_sds_rings; +	int drv_tx_rings = adapter->drv_tx_rings; +	int drv_sds_rings = adapter->drv_sds_rings;  	struct qlcnic_host_sds_ring *sds_ring;  	struct qlcnic_hardware_context *ahw = adapter->ahw;  	int loop = 0; @@ -1040,11 +1129,11 @@ int qlcnic_loopback_test(struct net_device *netdev, u8 mode)  	qlcnic_clear_lb_mode(adapter, mode);   free_res: -	qlcnic_diag_free_res(netdev, max_sds_rings); +	qlcnic_diag_free_res(netdev, drv_sds_rings);   clear_it: -	adapter->max_sds_rings = max_sds_rings; -	adapter->max_drv_tx_rings = max_drv_tx_rings; +	adapter->drv_sds_rings = drv_sds_rings; +	adapter->drv_tx_rings = drv_tx_rings;  	clear_bit(__QLCNIC_RESETTING, &adapter->state);  	return ret;  } @@ -1097,11 +1186,11 @@ qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 *data)  		       QLCNIC_TEST_LEN * ETH_GSTRING_LEN);  		break;  	case ETH_SS_STATS: -		num_stats = ARRAY_SIZE(qlcnic_tx_ring_stats_strings); -		for (i = 0; i < adapter->max_drv_tx_rings; i++) { +		num_stats = ARRAY_SIZE(qlcnic_tx_queue_stats_strings); +		for (i = 0; i < adapter->drv_tx_rings; i++) {  			for (index = 0; index < num_stats; index++) { -				sprintf(data, "tx_ring_%d %s", i, -					qlcnic_tx_ring_stats_strings[index]); +				sprintf(data, "tx_queue_%d %s", i, +					qlcnic_tx_queue_stats_strings[index]);  				data += ETH_GSTRING_LEN;  			}  		} @@ -1199,6 +1288,36 @@ static u64 *qlcnic_fill_stats(u64 *data, void *stats, int type)  	return data;  } +void qlcnic_update_stats(struct qlcnic_adapter *adapter) +{ +	struct qlcnic_host_tx_ring *tx_ring; +	int ring; + +	for (ring = 0; ring < adapter->drv_tx_rings; ring++) { +		tx_ring = &adapter->tx_ring[ring]; +		adapter->stats.xmit_on += tx_ring->tx_stats.xmit_on; +		adapter->stats.xmit_off += tx_ring->tx_stats.xmit_off; +		adapter->stats.xmitcalled += tx_ring->tx_stats.xmit_called; +		adapter->stats.xmitfinished += tx_ring->tx_stats.xmit_finished; +		adapter->stats.txbytes += tx_ring->tx_stats.tx_bytes; +	} +} + +static u64 *qlcnic_fill_tx_queue_stats(u64 *data, void *stats) +{ +	struct qlcnic_host_tx_ring *tx_ring; + +	tx_ring = (struct qlcnic_host_tx_ring *)stats; + +	*data++ = QLCNIC_FILL_STATS(tx_ring->tx_stats.xmit_on); +	*data++ = QLCNIC_FILL_STATS(tx_ring->tx_stats.xmit_off); +	*data++ = QLCNIC_FILL_STATS(tx_ring->tx_stats.xmit_called); +	*data++ = QLCNIC_FILL_STATS(tx_ring->tx_stats.xmit_finished); +	*data++ = QLCNIC_FILL_STATS(tx_ring->tx_stats.tx_bytes); + +	return data; +} +  static void qlcnic_get_ethtool_stats(struct net_device *dev,  				     struct ethtool_stats *stats, u64 *data)  { @@ -1206,19 +1325,20 @@ static void qlcnic_get_ethtool_stats(struct net_device *dev,  	struct qlcnic_host_tx_ring *tx_ring;  	struct qlcnic_esw_statistics port_stats;  	struct qlcnic_mac_statistics mac_stats; -	int index, ret, length, size, ring; +	int index, ret, length, size, tx_size, ring;  	char *p; -	memset(data, 0, adapter->max_drv_tx_rings * 4 * sizeof(u64)); -	for (ring = 0, index = 0; ring < adapter->max_drv_tx_rings; ring++) { +	tx_size = adapter->drv_tx_rings * QLCNIC_TX_STATS_LEN; + +	memset(data, 0, tx_size * sizeof(u64)); +	for (ring = 0, index = 0; ring < adapter->drv_tx_rings; ring++) {  		if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) {  			tx_ring = &adapter->tx_ring[ring]; -			*data++ = tx_ring->xmit_on; -			*data++ = tx_ring->xmit_off; -			*data++ = tx_ring->xmit_called; -			*data++ = tx_ring->xmit_finished; +			data = qlcnic_fill_tx_queue_stats(data, tx_ring); +			qlcnic_update_stats(adapter);  		}  	} +  	memset(data, 0, stats->n_stats * sizeof(u64));  	length = QLCNIC_STATS_LEN;  	for (index = 0; index < length; index++) { @@ -1260,7 +1380,7 @@ static int qlcnic_set_led(struct net_device *dev,  			  enum ethtool_phys_id_state state)  {  	struct qlcnic_adapter *adapter = netdev_priv(dev); -	int max_sds_rings = adapter->max_sds_rings; +	int drv_sds_rings = adapter->drv_sds_rings;  	int err = -EIO, active = 1;  	if (qlcnic_83xx_check(adapter)) @@ -1318,7 +1438,7 @@ static int qlcnic_set_led(struct net_device *dev,  	}  	if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state)) -		qlcnic_diag_free_res(dev, max_sds_rings); +		qlcnic_diag_free_res(dev, drv_sds_rings);  	if (!active || err)  		clear_bit(__QLCNIC_LED_ENABLE, &adapter->state); @@ -1389,9 +1509,7 @@ static int qlcnic_set_intr_coalesce(struct net_device *netdev,  			struct ethtool_coalesce *ethcoal)  {  	struct qlcnic_adapter *adapter = netdev_priv(netdev); -	struct qlcnic_nic_intr_coalesce *coal; -	u32 rx_coalesce_usecs, rx_max_frames; -	u32 tx_coalesce_usecs, tx_max_frames; +	int err;  	if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))  		return -EINVAL; @@ -1401,82 +1519,31 @@ static int qlcnic_set_intr_coalesce(struct net_device *netdev,  	* unsupported parameters are set.  	*/  	if (ethcoal->rx_coalesce_usecs > 0xffff || -		ethcoal->rx_max_coalesced_frames > 0xffff || -		ethcoal->tx_coalesce_usecs > 0xffff || -		ethcoal->tx_max_coalesced_frames > 0xffff || -		ethcoal->rx_coalesce_usecs_irq || -		ethcoal->rx_max_coalesced_frames_irq || -		ethcoal->tx_coalesce_usecs_irq || -		ethcoal->tx_max_coalesced_frames_irq || -		ethcoal->stats_block_coalesce_usecs || -		ethcoal->use_adaptive_rx_coalesce || -		ethcoal->use_adaptive_tx_coalesce || -		ethcoal->pkt_rate_low || -		ethcoal->rx_coalesce_usecs_low || -		ethcoal->rx_max_coalesced_frames_low || -		ethcoal->tx_coalesce_usecs_low || -		ethcoal->tx_max_coalesced_frames_low || -		ethcoal->pkt_rate_high || -		ethcoal->rx_coalesce_usecs_high || -		ethcoal->rx_max_coalesced_frames_high || -		ethcoal->tx_coalesce_usecs_high || -		ethcoal->tx_max_coalesced_frames_high) +	    ethcoal->rx_max_coalesced_frames > 0xffff || +	    ethcoal->tx_coalesce_usecs > 0xffff || +	    ethcoal->tx_max_coalesced_frames > 0xffff || +	    ethcoal->rx_coalesce_usecs_irq || +	    ethcoal->rx_max_coalesced_frames_irq || +	    ethcoal->tx_coalesce_usecs_irq || +	    ethcoal->tx_max_coalesced_frames_irq || +	    ethcoal->stats_block_coalesce_usecs || +	    ethcoal->use_adaptive_rx_coalesce || +	    ethcoal->use_adaptive_tx_coalesce || +	    ethcoal->pkt_rate_low || +	    ethcoal->rx_coalesce_usecs_low || +	    ethcoal->rx_max_coalesced_frames_low || +	    ethcoal->tx_coalesce_usecs_low || +	    ethcoal->tx_max_coalesced_frames_low || +	    ethcoal->pkt_rate_high || +	    ethcoal->rx_coalesce_usecs_high || +	    ethcoal->rx_max_coalesced_frames_high || +	    ethcoal->tx_coalesce_usecs_high || +	    ethcoal->tx_max_coalesced_frames_high)  		return -EINVAL; -	coal = &adapter->ahw->coal; +	err = qlcnic_config_intr_coalesce(adapter, ethcoal); -	if (qlcnic_83xx_check(adapter)) { -		if (!ethcoal->tx_coalesce_usecs || -		    !ethcoal->tx_max_coalesced_frames || -		    !ethcoal->rx_coalesce_usecs || -		    !ethcoal->rx_max_coalesced_frames) { -			coal->flag = QLCNIC_INTR_DEFAULT; -			coal->type = QLCNIC_INTR_COAL_TYPE_RX; -			coal->rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US; -			coal->rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS; -			coal->tx_time_us = QLCNIC_DEF_INTR_COALESCE_TX_TIME_US; -			coal->tx_packets = QLCNIC_DEF_INTR_COALESCE_TX_PACKETS; -		} else { -			tx_coalesce_usecs = ethcoal->tx_coalesce_usecs; -			tx_max_frames = ethcoal->tx_max_coalesced_frames; -			rx_coalesce_usecs = ethcoal->rx_coalesce_usecs; -			rx_max_frames = ethcoal->rx_max_coalesced_frames; -			coal->flag = 0; - -			if ((coal->rx_time_us == rx_coalesce_usecs) && -			    (coal->rx_packets == rx_max_frames)) { -				coal->type = QLCNIC_INTR_COAL_TYPE_TX; -				coal->tx_time_us = tx_coalesce_usecs; -				coal->tx_packets = tx_max_frames; -			} else if ((coal->tx_time_us == tx_coalesce_usecs) && -				   (coal->tx_packets == tx_max_frames)) { -				coal->type = QLCNIC_INTR_COAL_TYPE_RX; -				coal->rx_time_us = rx_coalesce_usecs; -				coal->rx_packets = rx_max_frames; -			} else { -				coal->type = QLCNIC_INTR_COAL_TYPE_RX; -				coal->rx_time_us = rx_coalesce_usecs; -				coal->rx_packets = rx_max_frames; -				coal->tx_time_us = tx_coalesce_usecs; -				coal->tx_packets = tx_max_frames; -			} -		} -	} else { -		if (!ethcoal->rx_coalesce_usecs || -		    !ethcoal->rx_max_coalesced_frames) { -			coal->flag = QLCNIC_INTR_DEFAULT; -			coal->rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US; -			coal->rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS; -		} else { -			coal->flag = 0; -			coal->rx_time_us = ethcoal->rx_coalesce_usecs; -			coal->rx_packets = ethcoal->rx_max_coalesced_frames; -		} -	} - -	qlcnic_config_intr_coalesce(adapter); - -	return 0; +	return err;  }  static int qlcnic_get_intr_coalesce(struct net_device *netdev, @@ -1583,14 +1650,14 @@ qlcnic_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump)  	}  	if (fw_dump->clr) -		dump->len = fw_dump->tmpl_hdr->size + fw_dump->size; +		dump->len = fw_dump->tmpl_hdr_size + fw_dump->size;  	else  		dump->len = 0;  	if (!qlcnic_check_fw_dump_state(adapter))  		dump->flag = ETH_FW_DUMP_DISABLE;  	else -		dump->flag = fw_dump->tmpl_hdr->drv_cap_mask; +		dump->flag = fw_dump->cap_mask;  	dump->version = adapter->fw_version;  	return 0; @@ -1615,9 +1682,10 @@ qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,  		netdev_info(netdev, "Dump not available\n");  		return -EINVAL;  	} +  	/* Copy template header first */ -	copy_sz = fw_dump->tmpl_hdr->size; -	hdr_ptr = (u32 *) fw_dump->tmpl_hdr; +	copy_sz = fw_dump->tmpl_hdr_size; +	hdr_ptr = (u32 *)fw_dump->tmpl_hdr;  	data = buffer;  	for (i = 0; i < copy_sz/sizeof(u32); i++)  		*data++ = cpu_to_le32(*hdr_ptr++); @@ -1625,7 +1693,7 @@ qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,  	/* Copy captured dump data */  	memcpy(buffer + copy_sz, fw_dump->data, fw_dump->size);  	dump->len = copy_sz + fw_dump->size; -	dump->flag = fw_dump->tmpl_hdr->drv_cap_mask; +	dump->flag = fw_dump->cap_mask;  	/* Free dump area once data has been captured */  	vfree(fw_dump->data); @@ -1647,7 +1715,11 @@ static int qlcnic_set_dump_mask(struct qlcnic_adapter *adapter, u32 mask)  		return -EOPNOTSUPP;  	} -	fw_dump->tmpl_hdr->drv_cap_mask = mask; +	fw_dump->cap_mask = mask; + +	/* Store new capture mask in template header as well*/ +	qlcnic_store_cap_mask(adapter, fw_dump->tmpl_hdr, mask); +  	netdev_info(netdev, "Driver mask changed to: 0x%x\n", mask);  	return 0;  } @@ -1659,7 +1731,6 @@ qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)  	struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;  	bool valid_mask = false;  	int i, ret = 0; -	u32 state;  	switch (val->flag) {  	case QLCNIC_FORCE_FW_DUMP_KEY: @@ -1712,9 +1783,8 @@ qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)  	case QLCNIC_SET_QUIESCENT:  	case QLCNIC_RESET_QUIESCENT: -		state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE); -		if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD)) -			netdev_info(netdev, "Device in FAILED state\n"); +		if (test_bit(__QLCNIC_MAINTENANCE_MODE, &adapter->state)) +			netdev_info(netdev, "Device is in non-operational state\n");  		break;  	default: @@ -1794,3 +1864,11 @@ const struct ethtool_ops qlcnic_sriov_vf_ethtool_ops = {  	.set_msglevel		= qlcnic_set_msglevel,  	.get_msglevel		= qlcnic_get_msglevel,  }; + +const struct ethtool_ops qlcnic_ethtool_failed_ops = { +	.get_settings		= qlcnic_get_settings, +	.get_drvinfo		= qlcnic_get_drvinfo, +	.set_msglevel		= qlcnic_set_msglevel, +	.get_msglevel		= qlcnic_get_msglevel, +	.set_dump		= qlcnic_set_dump, +}; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h index d262211b03b..34e467b239a 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h @@ -698,7 +698,6 @@ struct qlcnic_legacy_intr_set {  };  #define QLCNIC_MSIX_BASE	0x132110 -#define QLCNIC_MAX_PCI_FUNC	8  #define QLCNIC_MAX_VLAN_FILTERS	64  #define FLASH_ROM_WINDOW	0x42110030 diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c index f8adc7b01f1..851cb4a80d5 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c @@ -317,9 +317,7 @@ static void qlcnic_write_window_reg(u32 addr, void __iomem *bar0, u32 data)  int  qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg)  { -	int timeout = 0; -	int err = 0; -	u32 done = 0; +	int timeout = 0, err = 0, done = 0;  	while (!done) {  		done = QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_LOCK(sem)), @@ -327,10 +325,20 @@ qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg)  		if (done == 1)  			break;  		if (++timeout >= QLCNIC_PCIE_SEM_TIMEOUT) { -			dev_err(&adapter->pdev->dev, -				"Failed to acquire sem=%d lock; holdby=%d\n", -				sem, -				id_reg ? QLCRD32(adapter, id_reg, &err) : -1); +			if (id_reg) { +				done = QLCRD32(adapter, id_reg, &err); +				if (done != -1) +					dev_err(&adapter->pdev->dev, +						"Failed to acquire sem=%d lock held by=%d\n", +						sem, done); +				else +					dev_err(&adapter->pdev->dev, +						"Failed to acquire sem=%d lock", +						sem); +			} else { +				dev_err(&adapter->pdev->dev, +					"Failed to acquire sem=%d lock", sem); +			}  			return -EIO;  		}  		msleep(1); @@ -365,12 +373,16 @@ int qlcnic_ind_rd(struct qlcnic_adapter *adapter, u32 addr)  	return data;  } -void qlcnic_ind_wr(struct qlcnic_adapter *adapter, u32 addr, u32 data) +int qlcnic_ind_wr(struct qlcnic_adapter *adapter, u32 addr, u32 data)  { +	int ret = 0; +  	if (qlcnic_82xx_check(adapter))  		qlcnic_write_window_reg(addr, adapter->ahw->pci_base0, data);  	else -		qlcnic_83xx_wrt_reg_indirect(adapter, addr, data); +		ret = qlcnic_83xx_wrt_reg_indirect(adapter, addr, data); + +	return ret;  }  static int @@ -445,7 +457,7 @@ int qlcnic_82xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,  	mac_req = (struct qlcnic_mac_req *)&req.words[0];  	mac_req->op = op; -	memcpy(mac_req->mac_addr, addr, 6); +	memcpy(mac_req->mac_addr, addr, ETH_ALEN);  	vlan_req = (struct qlcnic_vlan_req *)&req.words[1];  	vlan_req->vlan_id = cpu_to_le16(vlan_id); @@ -455,14 +467,14 @@ int qlcnic_82xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,  int qlcnic_nic_del_mac(struct qlcnic_adapter *adapter, const u8 *addr)  { +	struct qlcnic_mac_vlan_list *cur;  	struct list_head *head; -	struct qlcnic_mac_list_s *cur;  	int err = -EINVAL;  	/* Delete MAC from the existing list */  	list_for_each(head, &adapter->mac_list) { -		cur = list_entry(head, struct qlcnic_mac_list_s, list); -		if (memcmp(addr, cur->mac_addr, ETH_ALEN) == 0) { +		cur = list_entry(head, struct qlcnic_mac_vlan_list, list); +		if (ether_addr_equal(addr, cur->mac_addr)) {  			err = qlcnic_sre_macaddr_change(adapter, cur->mac_addr,  							0, QLCNIC_MAC_DEL);  			if (err) @@ -477,17 +489,18 @@ int qlcnic_nic_del_mac(struct qlcnic_adapter *adapter, const u8 *addr)  int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr, u16 vlan)  { +	struct qlcnic_mac_vlan_list *cur;  	struct list_head *head; -	struct qlcnic_mac_list_s *cur;  	/* look up if already exists */  	list_for_each(head, &adapter->mac_list) { -		cur = list_entry(head, struct qlcnic_mac_list_s, list); -		if (memcmp(addr, cur->mac_addr, ETH_ALEN) == 0) +		cur = list_entry(head, struct qlcnic_mac_vlan_list, list); +		if (ether_addr_equal(addr, cur->mac_addr) && +		    cur->vlan_id == vlan)  			return 0;  	} -	cur = kzalloc(sizeof(struct qlcnic_mac_list_s), GFP_ATOMIC); +	cur = kzalloc(sizeof(*cur), GFP_ATOMIC);  	if (cur == NULL)  		return -ENOMEM; @@ -499,11 +512,12 @@ int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr, u16 vlan)  		return -EIO;  	} +	cur->vlan_id = vlan;  	list_add_tail(&cur->list, &adapter->mac_list);  	return 0;  } -void __qlcnic_set_multi(struct net_device *netdev, u16 vlan) +static void __qlcnic_set_multi(struct net_device *netdev, u16 vlan)  {  	struct qlcnic_adapter *adapter = netdev_priv(netdev);  	struct qlcnic_hardware_context *ahw = adapter->ahw; @@ -516,8 +530,7 @@ void __qlcnic_set_multi(struct net_device *netdev, u16 vlan)  	if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))  		return; -	if (!qlcnic_sriov_vf_check(adapter)) -		qlcnic_nic_add_mac(adapter, adapter->mac_addr, vlan); +	qlcnic_nic_add_mac(adapter, adapter->mac_addr, vlan);  	qlcnic_nic_add_mac(adapter, bcast_addr, vlan);  	if (netdev->flags & IFF_PROMISC) { @@ -526,15 +539,11 @@ void __qlcnic_set_multi(struct net_device *netdev, u16 vlan)  	} else if ((netdev->flags & IFF_ALLMULTI) ||  		   (netdev_mc_count(netdev) > ahw->max_mc_count)) {  		mode = VPORT_MISS_MODE_ACCEPT_MULTI; -	} else if (!netdev_mc_empty(netdev) && -		   !qlcnic_sriov_vf_check(adapter)) { +	} else if (!netdev_mc_empty(netdev)) {  		netdev_for_each_mc_addr(ha, netdev)  			qlcnic_nic_add_mac(adapter, ha->addr, vlan);  	} -	if (qlcnic_sriov_vf_check(adapter)) -		qlcnic_vf_add_mc_list(netdev, vlan); -  	/* configure unicast MAC address, if there is not sufficient space  	 * to store all the unicast addresses then enable promiscuous mode  	 */ @@ -545,14 +554,15 @@ void __qlcnic_set_multi(struct net_device *netdev, u16 vlan)  			qlcnic_nic_add_mac(adapter, ha->addr, vlan);  	} -	if (!qlcnic_sriov_vf_check(adapter)) { -		if (mode == VPORT_MISS_MODE_ACCEPT_ALL && -		    !adapter->fdb_mac_learn) { -			qlcnic_alloc_lb_filters_mem(adapter); -			adapter->drv_mac_learn = true; -		} else { -			adapter->drv_mac_learn = false; -		} +	if (mode == VPORT_MISS_MODE_ACCEPT_ALL && +	    !adapter->fdb_mac_learn) { +		qlcnic_alloc_lb_filters_mem(adapter); +		adapter->drv_mac_learn = 1; +		if (adapter->flags & QLCNIC_ESWITCH_ENABLED) +			adapter->rx_mac_learn = true; +	} else { +		adapter->drv_mac_learn = 0; +		adapter->rx_mac_learn = false;  	}  	qlcnic_nic_set_promisc(adapter, mode); @@ -561,27 +571,14 @@ void __qlcnic_set_multi(struct net_device *netdev, u16 vlan)  void qlcnic_set_multi(struct net_device *netdev)  {  	struct qlcnic_adapter *adapter = netdev_priv(netdev); -	struct netdev_hw_addr *ha; -	struct qlcnic_mac_list_s *cur;  	if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))  		return; -	if (qlcnic_sriov_vf_check(adapter)) { -		if (!netdev_mc_empty(netdev)) { -			netdev_for_each_mc_addr(ha, netdev) { -				cur = kzalloc(sizeof(struct qlcnic_mac_list_s), -					      GFP_ATOMIC); -				if (cur == NULL) -					break; -				memcpy(cur->mac_addr, -				       ha->addr, ETH_ALEN); -				list_add_tail(&cur->list, &adapter->vf_mc_list); -			} -		} -		qlcnic_sriov_vf_schedule_multi(adapter->netdev); -		return; -	} -	__qlcnic_set_multi(netdev, 0); + +	if (qlcnic_sriov_vf_check(adapter)) +		qlcnic_sriov_vf_set_multi(netdev); +	else +		__qlcnic_set_multi(netdev, 0);  }  int qlcnic_82xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode) @@ -605,11 +602,11 @@ int qlcnic_82xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode)  void qlcnic_82xx_free_mac_list(struct qlcnic_adapter *adapter)  { -	struct qlcnic_mac_list_s *cur;  	struct list_head *head = &adapter->mac_list; +	struct qlcnic_mac_vlan_list *cur;  	while (!list_empty(head)) { -		cur = list_entry(head->next, struct qlcnic_mac_list_s, list); +		cur = list_entry(head->next, struct qlcnic_mac_vlan_list, list);  		qlcnic_sre_macaddr_change(adapter,  				cur->mac_addr, 0, QLCNIC_MAC_DEL);  		list_del(&cur->list); @@ -623,7 +620,7 @@ void qlcnic_prune_lb_filters(struct qlcnic_adapter *adapter)  	struct hlist_node *n;  	struct hlist_head *head;  	int i; -	unsigned long time; +	unsigned long expires;  	u8 cmd;  	for (i = 0; i < adapter->fhash.fbucket_size; i++) { @@ -631,8 +628,8 @@ void qlcnic_prune_lb_filters(struct qlcnic_adapter *adapter)  		hlist_for_each_entry_safe(tmp_fil, n, head, fnode) {  			cmd =  tmp_fil->vlan_id ? QLCNIC_MAC_VLAN_DEL :  						  QLCNIC_MAC_DEL; -			time = tmp_fil->ftime; -			if (jiffies > (QLCNIC_FILTER_AGE * HZ + time)) { +			expires = tmp_fil->ftime + QLCNIC_FILTER_AGE * HZ; +			if (time_before(expires, jiffies)) {  				qlcnic_sre_macaddr_change(adapter,  							  tmp_fil->faddr,  							  tmp_fil->vlan_id, @@ -650,8 +647,8 @@ void qlcnic_prune_lb_filters(struct qlcnic_adapter *adapter)  		hlist_for_each_entry_safe(tmp_fil, n, head, fnode)  		{ -			time = tmp_fil->ftime; -			if (jiffies > (QLCNIC_FILTER_AGE * HZ + time)) { +			expires = tmp_fil->ftime + QLCNIC_FILTER_AGE * HZ; +			if (time_before(expires, jiffies)) {  				spin_lock_bh(&adapter->rx_mac_learn_lock);  				adapter->rx_fhash.fnum--;  				hlist_del(&tmp_fil->fnode); @@ -756,10 +753,7 @@ int qlcnic_82xx_read_phys_port_id(struct qlcnic_adapter *adapter)  	return 0;  } -/* - * Send the interrupt coalescing parameter set by ethtool to the card. - */ -void qlcnic_82xx_config_intr_coalesce(struct qlcnic_adapter *adapter) +int qlcnic_82xx_set_rx_coalesce(struct qlcnic_adapter *adapter)  {  	struct qlcnic_nic_req req;  	int rv; @@ -781,12 +775,32 @@ void qlcnic_82xx_config_intr_coalesce(struct qlcnic_adapter *adapter)  	if (rv != 0)  		dev_err(&adapter->netdev->dev,  			"Could not send interrupt coalescing parameters\n"); + +	return rv;  } -#define QLCNIC_ENABLE_IPV4_LRO		1 -#define QLCNIC_ENABLE_IPV6_LRO		2 -#define QLCNIC_NO_DEST_IPV4_CHECK	(1 << 8) -#define QLCNIC_NO_DEST_IPV6_CHECK	(2 << 8) +/* Send the interrupt coalescing parameter set by ethtool to the card. */ +int qlcnic_82xx_config_intr_coalesce(struct qlcnic_adapter *adapter, +				     struct ethtool_coalesce *ethcoal) +{ +	struct qlcnic_nic_intr_coalesce *coal = &adapter->ahw->coal; +	int rv; + +	coal->flag = QLCNIC_INTR_DEFAULT; +	coal->rx_time_us = ethcoal->rx_coalesce_usecs; +	coal->rx_packets = ethcoal->rx_max_coalesced_frames; + +	rv = qlcnic_82xx_set_rx_coalesce(adapter); + +	if (rv) +		netdev_err(adapter->netdev, +			   "Failed to set Rx coalescing parametrs\n"); + +	return rv; +} + +#define QLCNIC_ENABLE_IPV4_LRO		BIT_0 +#define QLCNIC_ENABLE_IPV6_LRO		(BIT_1 | BIT_9)  int qlcnic_82xx_config_hw_lro(struct qlcnic_adapter *adapter, int enable)  { @@ -806,11 +820,10 @@ int qlcnic_82xx_config_hw_lro(struct qlcnic_adapter *adapter, int enable)  	word = 0;  	if (enable) { -		word = QLCNIC_ENABLE_IPV4_LRO | QLCNIC_NO_DEST_IPV4_CHECK; +		word = QLCNIC_ENABLE_IPV4_LRO;  		if (adapter->ahw->extra_capability[0] &  		    QLCNIC_FW_CAP2_HW_LRO_IPV6) -			word |= QLCNIC_ENABLE_IPV6_LRO | -				QLCNIC_NO_DEST_IPV6_CHECK; +			word |= QLCNIC_ENABLE_IPV6_LRO;  	}  	req.words[0] = cpu_to_le64(word); @@ -951,7 +964,7 @@ int qlcnic_82xx_linkevent_request(struct qlcnic_adapter *adapter, int enable)  	return rv;  } -int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter) +static int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter)  {  	struct qlcnic_nic_req req;  	u64 word; @@ -1250,7 +1263,7 @@ static int qlcnic_pci_mem_access_direct(struct qlcnic_adapter *adapter,  	return 0;  } -void +static void  qlcnic_pci_camqm_read_2M(struct qlcnic_adapter *adapter, u64 off, u64 *data)  {  	void __iomem *addr = adapter->ahw->pci_base0 + @@ -1261,7 +1274,7 @@ qlcnic_pci_camqm_read_2M(struct qlcnic_adapter *adapter, u64 off, u64 *data)  	mutex_unlock(&adapter->ahw->mem_lock);  } -void +static void  qlcnic_pci_camqm_write_2M(struct qlcnic_adapter *adapter, u64 off, u64 data)  {  	void __iomem *addr = adapter->ahw->pci_base0 + @@ -1497,7 +1510,7 @@ int qlcnic_82xx_get_board_info(struct qlcnic_adapter *adapter)  	return 0;  } -int +static int  qlcnic_wol_supported(struct qlcnic_adapter *adapter)  {  	u32 wol_cfg; @@ -1537,19 +1550,34 @@ int qlcnic_82xx_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)  	return rv;  } -int qlcnic_get_beacon_state(struct qlcnic_adapter *adapter, u8 *h_state) +void qlcnic_82xx_get_beacon_state(struct qlcnic_adapter *adapter)  { +	struct qlcnic_hardware_context *ahw = adapter->ahw;  	struct qlcnic_cmd_args cmd; -	int err; +	u8 beacon_state; +	int err = 0; -	err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_LED_STATUS); -	if (!err) { -		err = qlcnic_issue_cmd(adapter, &cmd); -		if (!err) -			*h_state = cmd.rsp.arg[1]; +	if (ahw->extra_capability[0] & QLCNIC_FW_CAPABILITY_2_BEACON) { +		err = qlcnic_alloc_mbx_args(&cmd, adapter, +					    QLCNIC_CMD_GET_LED_STATUS); +		if (!err) { +			err = qlcnic_issue_cmd(adapter, &cmd); +			if (err) { +				netdev_err(adapter->netdev, +					   "Failed to get current beacon state, err=%d\n", +					   err); +			} else { +				beacon_state = cmd.rsp.arg[1]; +				if (beacon_state == QLCNIC_BEACON_DISABLE) +					ahw->beacon_state = QLCNIC_BEACON_OFF; +				else if (beacon_state == QLCNIC_BEACON_EANBLE) +					ahw->beacon_state = QLCNIC_BEACON_ON; +			} +		} +		qlcnic_free_mbx_args(&cmd);  	} -	qlcnic_free_mbx_args(&cmd); -	return err; + +	return;  }  void qlcnic_82xx_get_func_no(struct qlcnic_adapter *adapter) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h index 272c356cf9b..cbe2399c30a 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h @@ -98,6 +98,7 @@ enum qlcnic_regs {  #define QLCNIC_CMD_GET_LINK_EVENT		0x48  #define QLCNIC_CMD_CONFIGURE_MAC_RX_MODE	0x49  #define QLCNIC_CMD_CONFIGURE_HW_LRO		0x4A +#define QLCNIC_CMD_SET_INGRESS_ENCAP		0x4E  #define QLCNIC_CMD_INIT_NIC_FUNC		0x60  #define QLCNIC_CMD_STOP_NIC_FUNC		0x61  #define QLCNIC_CMD_IDC_ACK			0x63 @@ -146,6 +147,12 @@ struct qlcnic_mailbox_metadata {  #define QLCNIC_MBX_PORT_RSP_OK	0x1a  #define QLCNIC_MBX_ASYNC_EVENT	BIT_15 +/* Set HW Tx ring limit for 82xx adapter. */ +#define QLCNIC_MAX_HW_TX_RINGS		8 +#define QLCNIC_MAX_HW_VNIC_TX_RINGS	4 +#define QLCNIC_MAX_TX_RINGS		8 +#define QLCNIC_MAX_SDS_RINGS		8 +  struct qlcnic_pci_info;  struct qlcnic_info;  struct qlcnic_cmd_args; @@ -155,17 +162,20 @@ struct qlcnic_host_sds_ring;  struct qlcnic_host_tx_ring;  struct qlcnic_hardware_context;  struct qlcnic_adapter; +struct qlcnic_fw_dump; -int qlcnic_82xx_start_firmware(struct qlcnic_adapter *);  int qlcnic_82xx_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong, int *);  int qlcnic_82xx_hw_write_wx_2M(struct qlcnic_adapter *, ulong, u32);  int qlcnic_82xx_config_hw_lro(struct qlcnic_adapter *adapter, int);  int qlcnic_82xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32);  int qlcnic_82xx_napi_add(struct qlcnic_adapter *adapter,  			 struct net_device *netdev); +void qlcnic_82xx_get_beacon_state(struct qlcnic_adapter *);  void qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter,  			       u64 *uaddr, u16 vlan_id); -void qlcnic_82xx_config_intr_coalesce(struct qlcnic_adapter *adapter); +int qlcnic_82xx_config_intr_coalesce(struct qlcnic_adapter *, +				     struct ethtool_coalesce *); +int qlcnic_82xx_set_rx_coalesce(struct qlcnic_adapter *);  int qlcnic_82xx_config_rss(struct qlcnic_adapter *adapter, int);  void qlcnic_82xx_config_ipaddr(struct qlcnic_adapter *adapter,  			       __be32, int); @@ -175,9 +185,6 @@ int qlcnic_82xx_clear_lb_mode(struct qlcnic_adapter *adapter, u8);  int qlcnic_82xx_set_lb_mode(struct qlcnic_adapter *, u8);  void qlcnic_82xx_write_crb(struct qlcnic_adapter *, char *, loff_t, size_t);  void qlcnic_82xx_read_crb(struct qlcnic_adapter *, char *, loff_t, size_t); -void qlcnic_82xx_dev_request_reset(struct qlcnic_adapter *, u32); -int qlcnic_82xx_setup_intr(struct qlcnic_adapter *, u8, int); -irqreturn_t qlcnic_82xx_clear_legacy_intr(struct qlcnic_adapter *);  int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter,  			  struct qlcnic_cmd_args *);  int qlcnic_82xx_mq_intrpt(struct qlcnic_adapter *, int); @@ -208,4 +215,11 @@ int qlcnic_82xx_shutdown(struct pci_dev *);  int qlcnic_82xx_resume(struct qlcnic_adapter *);  void qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter, u8 failed);  void qlcnic_fw_poll_work(struct work_struct *work); + +u32 qlcnic_82xx_get_saved_state(void *, u32); +void qlcnic_82xx_set_saved_state(void *, u32, u32); +void qlcnic_82xx_cache_tmpl_hdr_values(struct qlcnic_fw_dump *); +u32 qlcnic_82xx_get_cap_size(void *, int); +void qlcnic_82xx_set_sys_info(void *, int, u32); +void qlcnic_82xx_store_cap_mask(void *, u32);  #endif				/* __QLCNIC_HW_H_ */ diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c index 66c26cf7a2b..c4262c23ed7 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c @@ -134,6 +134,8 @@ void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter,  	struct qlcnic_skb_frag *buffrag;  	int i, j; +	spin_lock(&tx_ring->tx_clean_lock); +  	cmd_buf = tx_ring->cmd_buf_arr;  	for (i = 0; i < tx_ring->num_desc; i++) {  		buffrag = cmd_buf->frag_array; @@ -157,6 +159,8 @@ void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter,  		}  		cmd_buf++;  	} + +	spin_unlock(&tx_ring->tx_clean_lock);  }  void qlcnic_free_sw_resources(struct qlcnic_adapter *adapter) @@ -236,7 +240,7 @@ int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter)  		spin_lock_init(&rds_ring->lock);  	} -	for (ring = 0; ring < adapter->max_sds_rings; ring++) { +	for (ring = 0; ring < adapter->drv_sds_rings; ring++) {  		sds_ring = &recv_ctx->sds_rings[ring];  		sds_ring->irq = adapter->msix_entries[ring].vector;  		sds_ring->adapter = adapter; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c index 11b4bb83b93..e45bf09af0c 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c @@ -13,16 +13,19 @@  #include "qlcnic.h" -#define TX_ETHER_PKT	0x01 -#define TX_TCP_PKT	0x02 -#define TX_UDP_PKT	0x03 -#define TX_IP_PKT	0x04 -#define TX_TCP_LSO	0x05 -#define TX_TCP_LSO6	0x06 -#define TX_TCPV6_PKT	0x0b -#define TX_UDPV6_PKT	0x0c -#define FLAGS_VLAN_TAGGED	0x10 -#define FLAGS_VLAN_OOB		0x40 +#define QLCNIC_TX_ETHER_PKT		0x01 +#define QLCNIC_TX_TCP_PKT		0x02 +#define QLCNIC_TX_UDP_PKT		0x03 +#define QLCNIC_TX_IP_PKT		0x04 +#define QLCNIC_TX_TCP_LSO		0x05 +#define QLCNIC_TX_TCP_LSO6		0x06 +#define QLCNIC_TX_ENCAP_PKT		0x07 +#define QLCNIC_TX_ENCAP_LSO		0x08 +#define QLCNIC_TX_TCPV6_PKT		0x0b +#define QLCNIC_TX_UDPV6_PKT		0x0c + +#define QLCNIC_FLAGS_VLAN_TAGGED	0x10 +#define QLCNIC_FLAGS_VLAN_OOB		0x40  #define qlcnic_set_tx_vlan_tci(cmd_desc, v)	\  	(cmd_desc)->vlan_TCI = cpu_to_le16(v); @@ -124,41 +127,16 @@  #define qlcnic_83xx_is_ip_align(sts)	(((sts) >> 46) & 1)  #define qlcnic_83xx_has_vlan_tag(sts)	(((sts) >> 47) & 1) -struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *, -				     struct qlcnic_host_rds_ring *, u16, u16); +static int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, +				   int max); -inline void qlcnic_enable_tx_intr(struct qlcnic_adapter *adapter, -				  struct qlcnic_host_tx_ring *tx_ring) -{ -	if (qlcnic_check_multi_tx(adapter) && -	    !adapter->ahw->diag_test) -		writel(0x0, tx_ring->crb_intr_mask); -} - - -static inline void qlcnic_disable_tx_int(struct qlcnic_adapter *adapter, -					 struct qlcnic_host_tx_ring *tx_ring) -{ -	if (qlcnic_check_multi_tx(adapter) && -	    !adapter->ahw->diag_test) -		writel(1, tx_ring->crb_intr_mask); -} - -inline void qlcnic_83xx_enable_tx_intr(struct qlcnic_adapter *adapter, -				       struct qlcnic_host_tx_ring *tx_ring) -{ -	writel(0, tx_ring->crb_intr_mask); -} - -inline void qlcnic_83xx_disable_tx_intr(struct qlcnic_adapter *adapter, -					struct qlcnic_host_tx_ring *tx_ring) -{ -	writel(1, tx_ring->crb_intr_mask); -} +static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *, +					    struct qlcnic_host_rds_ring *, +					    u16, u16); -static inline u8 qlcnic_mac_hash(u64 mac) +static inline u8 qlcnic_mac_hash(u64 mac, u16 vlan)  { -	return (u8)((mac & 0xff) ^ ((mac >> 40) & 0xff)); +	return (u8)((mac & 0xff) ^ ((mac >> 40) & 0xff) ^ (vlan & 0xff));  }  static inline u32 qlcnic_get_ref_handle(struct qlcnic_adapter *adapter, @@ -202,7 +180,7 @@ static struct qlcnic_filter *qlcnic_find_mac_filter(struct hlist_head *head,  	struct hlist_node *n;  	hlist_for_each_entry_safe(tmp_fil, n, head, fnode) { -		if (!memcmp(tmp_fil->faddr, addr, ETH_ALEN) && +		if (ether_addr_equal(tmp_fil->faddr, addr) &&  		    tmp_fil->vlan_id == vlan_id)  			return tmp_fil;  	} @@ -210,8 +188,8 @@ static struct qlcnic_filter *qlcnic_find_mac_filter(struct hlist_head *head,  	return NULL;  } -void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, struct sk_buff *skb, -			  int loopback_pkt, u16 vlan_id) +static void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, +				 struct sk_buff *skb, int loopback_pkt, u16 vlan_id)  {  	struct ethhdr *phdr = (struct ethhdr *)(skb->data);  	struct qlcnic_filter *fil, *tmp_fil; @@ -221,8 +199,11 @@ void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, struct sk_buff *skb,  	u8 hindex, op;  	int ret; +	if (!qlcnic_sriov_pf_check(adapter) || (vlan_id == 0xffff)) +		vlan_id = 0; +  	memcpy(&src_addr, phdr->h_source, ETH_ALEN); -	hindex = qlcnic_mac_hash(src_addr) & +	hindex = qlcnic_mac_hash(src_addr, vlan_id) &  		 (adapter->fhash.fbucket_size - 1);  	if (loopback_pkt) { @@ -322,31 +303,35 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter,  			       struct cmd_desc_type0 *first_desc,  			       struct sk_buff *skb)  { +	struct vlan_ethhdr *vh = (struct vlan_ethhdr *)(skb->data); +	struct ethhdr *phdr = (struct ethhdr *)(skb->data); +	u16 protocol = ntohs(skb->protocol);  	struct qlcnic_filter *fil, *tmp_fil; -	struct hlist_node *n;  	struct hlist_head *head; -	struct net_device *netdev = adapter->netdev; -	struct ethhdr *phdr = (struct ethhdr *)(skb->data); +	struct hlist_node *n;  	u64 src_addr = 0;  	u16 vlan_id = 0; -	u8 hindex; +	u8 hindex, hval;  	if (ether_addr_equal(phdr->h_source, adapter->mac_addr))  		return; -	if (adapter->fhash.fnum >= adapter->fhash.fmax) { -		adapter->stats.mac_filter_limit_overrun++; -		netdev_info(netdev, "Can not add more than %d mac addresses\n", -			    adapter->fhash.fmax); -		return; +	if (adapter->flags & QLCNIC_VLAN_FILTERING) { +		if (protocol == ETH_P_8021Q) { +			vh = (struct vlan_ethhdr *)skb->data; +			vlan_id = ntohs(vh->h_vlan_TCI); +		} else if (vlan_tx_tag_present(skb)) { +			vlan_id = vlan_tx_tag_get(skb); +		}  	}  	memcpy(&src_addr, phdr->h_source, ETH_ALEN); -	hindex = qlcnic_mac_hash(src_addr) & (adapter->fhash.fbucket_size - 1); +	hval = qlcnic_mac_hash(src_addr, vlan_id); +	hindex = hval & (adapter->fhash.fbucket_size - 1);  	head = &(adapter->fhash.fhead[hindex]);  	hlist_for_each_entry_safe(tmp_fil, n, head, fnode) { -		if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN) && +		if (ether_addr_equal(tmp_fil->faddr, (u8 *)&src_addr) &&  		    tmp_fil->vlan_id == vlan_id) {  			if (jiffies > (QLCNIC_READD_AGE * HZ + tmp_fil->ftime))  				qlcnic_change_filter(adapter, &src_addr, @@ -356,6 +341,11 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter,  		}  	} +	if (unlikely(adapter->fhash.fnum >= adapter->fhash.fmax)) { +		adapter->stats.mac_filter_limit_overrun++; +		return; +	} +  	fil = kzalloc(sizeof(struct qlcnic_filter), GFP_ATOMIC);  	if (!fil)  		return; @@ -370,6 +360,101 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter,  	spin_unlock(&adapter->mac_learn_lock);  } +#define QLCNIC_ENCAP_VXLAN_PKT		BIT_0 +#define QLCNIC_ENCAP_OUTER_L3_IP6	BIT_1 +#define QLCNIC_ENCAP_INNER_L3_IP6	BIT_2 +#define QLCNIC_ENCAP_INNER_L4_UDP	BIT_3 +#define QLCNIC_ENCAP_DO_L3_CSUM		BIT_4 +#define QLCNIC_ENCAP_DO_L4_CSUM		BIT_5 + +static int qlcnic_tx_encap_pkt(struct qlcnic_adapter *adapter, +			       struct cmd_desc_type0 *first_desc, +			       struct sk_buff *skb, +			       struct qlcnic_host_tx_ring *tx_ring) +{ +	u8 opcode = 0, inner_hdr_len = 0, outer_hdr_len = 0, total_hdr_len = 0; +	int copied, copy_len, descr_size; +	u32 producer = tx_ring->producer; +	struct cmd_desc_type0 *hwdesc; +	u16 flags = 0, encap_descr = 0; + +	opcode = QLCNIC_TX_ETHER_PKT; +	encap_descr = QLCNIC_ENCAP_VXLAN_PKT; + +	if (skb_is_gso(skb)) { +		inner_hdr_len = skb_inner_transport_header(skb) + +				inner_tcp_hdrlen(skb) - +				skb_inner_mac_header(skb); + +		/* VXLAN header size = 8 */ +		outer_hdr_len = skb_transport_offset(skb) + 8 + +				sizeof(struct udphdr); +		first_desc->outer_hdr_length = outer_hdr_len; +		total_hdr_len = inner_hdr_len + outer_hdr_len; +		encap_descr |= QLCNIC_ENCAP_DO_L3_CSUM | +			       QLCNIC_ENCAP_DO_L4_CSUM; +		first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size); +		first_desc->hdr_length = inner_hdr_len; + +		/* Copy inner and outer headers in Tx descriptor(s) +		 * If total_hdr_len > cmd_desc_type0, use multiple +		 * descriptors +		 */ +		copied = 0; +		descr_size = (int)sizeof(struct cmd_desc_type0); +		while (copied < total_hdr_len) { +			copy_len = min(descr_size, (total_hdr_len - copied)); +			hwdesc = &tx_ring->desc_head[producer]; +			tx_ring->cmd_buf_arr[producer].skb = NULL; +			skb_copy_from_linear_data_offset(skb, copied, +							 (char *)hwdesc, +							 copy_len); +			copied += copy_len; +			producer = get_next_index(producer, tx_ring->num_desc); +		} + +		tx_ring->producer = producer; + +		/* Make sure updated tx_ring->producer is visible +		 * for qlcnic_tx_avail() +		 */ +		smp_mb(); +		adapter->stats.encap_lso_frames++; + +		opcode = QLCNIC_TX_ENCAP_LSO; +	} else if (skb->ip_summed == CHECKSUM_PARTIAL) { +		if (inner_ip_hdr(skb)->version == 6) { +			if (inner_ipv6_hdr(skb)->nexthdr == IPPROTO_UDP) +				encap_descr |= QLCNIC_ENCAP_INNER_L4_UDP; +		} else { +			if (inner_ip_hdr(skb)->protocol == IPPROTO_UDP) +				encap_descr |= QLCNIC_ENCAP_INNER_L4_UDP; +		} + +		adapter->stats.encap_tx_csummed++; +		opcode = QLCNIC_TX_ENCAP_PKT; +	} + +	/* Prepare first 16 bits of byte offset 16 of Tx descriptor */ +	if (ip_hdr(skb)->version == 6) +		encap_descr |= QLCNIC_ENCAP_OUTER_L3_IP6; + +	/* outer IP header's size in 32bit words size*/ +	encap_descr |= (skb_network_header_len(skb) >> 2) << 6; + +	/* outer IP header offset */ +	encap_descr |= skb_network_offset(skb) << 10; +	first_desc->encap_descr = cpu_to_le16(encap_descr); + +	first_desc->tcp_hdr_offset = skb_inner_transport_header(skb) - +				     skb->data; +	first_desc->ip_hdr_offset = skb_inner_network_offset(skb); + +	qlcnic_set_tx_flags_opcode(first_desc, flags, opcode); + +	return 0; +} +  static int qlcnic_tx_pkt(struct qlcnic_adapter *adapter,  			 struct cmd_desc_type0 *first_desc, struct sk_buff *skb,  			 struct qlcnic_host_tx_ring *tx_ring) @@ -384,11 +469,11 @@ static int qlcnic_tx_pkt(struct qlcnic_adapter *adapter,  	if (protocol == ETH_P_8021Q) {  		vh = (struct vlan_ethhdr *)skb->data; -		flags = FLAGS_VLAN_TAGGED; +		flags = QLCNIC_FLAGS_VLAN_TAGGED;  		vlan_tci = ntohs(vh->h_vlan_TCI);  		protocol = ntohs(vh->h_vlan_encapsulated_proto);  	} else if (vlan_tx_tag_present(skb)) { -		flags = FLAGS_VLAN_OOB; +		flags = QLCNIC_FLAGS_VLAN_OOB;  		vlan_tci = vlan_tx_tag_get(skb);  	}  	if (unlikely(adapter->tx_pvid)) { @@ -397,7 +482,7 @@ static int qlcnic_tx_pkt(struct qlcnic_adapter *adapter,  		if (vlan_tci && (adapter->flags & QLCNIC_TAGGING_ENABLED))  			goto set_flags; -		flags = FLAGS_VLAN_OOB; +		flags = QLCNIC_FLAGS_VLAN_OOB;  		vlan_tci = adapter->tx_pvid;  	}  set_flags: @@ -408,25 +493,26 @@ set_flags:  		flags |= BIT_0;  		memcpy(&first_desc->eth_addr, skb->data, ETH_ALEN);  	} -	opcode = TX_ETHER_PKT; +	opcode = QLCNIC_TX_ETHER_PKT;  	if (skb_is_gso(skb)) {  		hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);  		first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size); -		first_desc->total_hdr_length = hdr_len; -		opcode = (protocol == ETH_P_IPV6) ? TX_TCP_LSO6 : TX_TCP_LSO; +		first_desc->hdr_length = hdr_len; +		opcode = (protocol == ETH_P_IPV6) ? QLCNIC_TX_TCP_LSO6 : +						    QLCNIC_TX_TCP_LSO;  		/* For LSO, we need to copy the MAC/IP/TCP headers into  		* the descriptor ring */  		copied = 0;  		offset = 2; -		if (flags & FLAGS_VLAN_OOB) { -			first_desc->total_hdr_length += VLAN_HLEN; +		if (flags & QLCNIC_FLAGS_VLAN_OOB) { +			first_desc->hdr_length += VLAN_HLEN;  			first_desc->tcp_hdr_offset = VLAN_HLEN;  			first_desc->ip_hdr_offset = VLAN_HLEN;  			/* Only in case of TSO on vlan device */ -			flags |= FLAGS_VLAN_TAGGED; +			flags |= QLCNIC_FLAGS_VLAN_TAGGED;  			/* Create a TSO vlan header template for firmware */  			hwdesc = &tx_ring->desc_head[producer]; @@ -470,16 +556,16 @@ set_flags:  			l4proto = ip_hdr(skb)->protocol;  			if (l4proto == IPPROTO_TCP) -				opcode = TX_TCP_PKT; +				opcode = QLCNIC_TX_TCP_PKT;  			else if (l4proto == IPPROTO_UDP) -				opcode = TX_UDP_PKT; +				opcode = QLCNIC_TX_UDP_PKT;  		} else if (protocol == ETH_P_IPV6) {  			l4proto = ipv6_hdr(skb)->nexthdr;  			if (l4proto == IPPROTO_TCP) -				opcode = TX_TCPV6_PKT; +				opcode = QLCNIC_TX_TCPV6_PKT;  			else if (l4proto == IPPROTO_UDP) -				opcode = TX_UDPV6_PKT; +				opcode = QLCNIC_TX_UDPV6_PKT;  		}  	}  	first_desc->tcp_hdr_offset += skb_transport_offset(skb); @@ -569,6 +655,8 @@ netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)  	struct ethhdr *phdr;  	int i, k, frag_count, delta = 0;  	u32 producer, num_txd; +	u16 protocol; +	bool l4_is_udp = false;  	if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {  		netif_tx_stop_all_queues(netdev); @@ -581,10 +669,7 @@ netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)  			goto drop_packet;  	} -	if (qlcnic_check_multi_tx(adapter)) -		tx_ring = &adapter->tx_ring[skb_get_queue_mapping(skb)]; -	else -		tx_ring = &adapter->tx_ring[0]; +	tx_ring = &adapter->tx_ring[skb_get_queue_mapping(skb)];  	num_txd = tx_ring->num_desc;  	frag_count = skb_shinfo(skb)->nr_frags + 1; @@ -607,8 +692,7 @@ netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)  		if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) {  			netif_tx_start_queue(tx_ring->txq);  		} else { -			adapter->stats.xmit_off++; -			tx_ring->xmit_off++; +			tx_ring->tx_stats.xmit_off++;  			return NETDEV_TX_BUSY;  		}  	} @@ -663,15 +747,29 @@ netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)  	tx_ring->producer = get_next_index(producer, num_txd);  	smp_mb(); -	if (unlikely(qlcnic_tx_pkt(adapter, first_desc, skb, tx_ring))) -		goto unwind_buff; +	protocol = ntohs(skb->protocol); +	if (protocol == ETH_P_IP) +		l4_is_udp = ip_hdr(skb)->protocol == IPPROTO_UDP; +	else if (protocol == ETH_P_IPV6) +		l4_is_udp = ipv6_hdr(skb)->nexthdr == IPPROTO_UDP; + +	/* Check if it is a VXLAN packet */ +	if (!skb->encapsulation || !l4_is_udp || +	    !qlcnic_encap_tx_offload(adapter)) { +		if (unlikely(qlcnic_tx_pkt(adapter, first_desc, skb, +					   tx_ring))) +			goto unwind_buff; +	} else { +		if (unlikely(qlcnic_tx_encap_pkt(adapter, first_desc, +						 skb, tx_ring))) +			goto unwind_buff; +	}  	if (adapter->drv_mac_learn)  		qlcnic_send_filter(adapter, first_desc, skb); -	adapter->stats.txbytes += skb->len; -	adapter->stats.xmitcalled++; -	tx_ring->xmit_called++; +	tx_ring->tx_stats.tx_bytes += skb->len; +	tx_ring->tx_stats.xmit_called++;  	qlcnic_update_cmd_producer(tx_ring); @@ -692,17 +790,20 @@ void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup)  	if (adapter->ahw->linkup && !linkup) {  		netdev_info(netdev, "NIC Link is down\n");  		adapter->ahw->linkup = 0; -		if (netif_running(netdev)) { -			netif_carrier_off(netdev); -			netif_tx_stop_all_queues(netdev); -		} +		netif_carrier_off(netdev);  	} else if (!adapter->ahw->linkup && linkup) { -		netdev_info(netdev, "NIC Link is up\n");  		adapter->ahw->linkup = 1; -		if (netif_running(netdev)) { -			netif_carrier_on(netdev); -			netif_wake_queue(netdev); + +		/* Do not advertise Link up to the stack if device +		 * is in loopback mode +		 */ +		if (qlcnic_83xx_check(adapter) && adapter->ahw->lb_mode) { +			netdev_info(netdev, "NIC Link is up for loopback test\n"); +			return;  		} + +		netdev_info(netdev, "NIC Link is up\n"); +		netif_carrier_on(netdev);  	}  } @@ -789,6 +890,9 @@ static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter,  	struct net_device *netdev = adapter->netdev;  	struct qlcnic_skb_frag *frag; +	if (!spin_trylock(&tx_ring->tx_clean_lock)) +		return 1; +  	sw_consumer = tx_ring->sw_consumer;  	hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer)); @@ -805,8 +909,7 @@ static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter,  					       PCI_DMA_TODEVICE);  				frag->dma = 0ULL;  			} -			adapter->stats.xmitfinished++; -			tx_ring->xmit_finished++; +			tx_ring->tx_stats.xmit_finished++;  			dev_kfree_skb_any(buffer->skb);  			buffer->skb = NULL;  		} @@ -816,15 +919,15 @@ static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter,  			break;  	} +	tx_ring->sw_consumer = sw_consumer; +  	if (count && netif_running(netdev)) { -		tx_ring->sw_consumer = sw_consumer;  		smp_mb();  		if (netif_tx_queue_stopped(tx_ring->txq) &&  		    netif_carrier_ok(netdev)) {  			if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) {  				netif_tx_wake_queue(tx_ring->txq); -				adapter->stats.xmit_on++; -				tx_ring->xmit_on++; +				tx_ring->tx_stats.xmit_on++;  			}  		}  		adapter->tx_timeo_cnt = 0; @@ -845,6 +948,8 @@ static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter,  	hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer));  	done = (sw_consumer == hw_consumer); +	spin_unlock(&tx_ring->tx_clean_lock); +  	return done;  } @@ -865,7 +970,7 @@ static int qlcnic_poll(struct napi_struct *napi, int budget)  	if ((work_done < budget) && tx_complete) {  		napi_complete(&sds_ring->napi);  		if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) { -			qlcnic_enable_int(sds_ring); +			qlcnic_enable_sds_intr(adapter, sds_ring);  			qlcnic_enable_tx_intr(adapter, tx_ring);  		}  	} @@ -906,7 +1011,7 @@ static int qlcnic_rx_poll(struct napi_struct *napi, int budget)  	if (work_done < budget) {  		napi_complete(&sds_ring->napi);  		if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) -			qlcnic_enable_int(sds_ring); +			qlcnic_enable_sds_intr(adapter, sds_ring);  	}  	return work_done; @@ -1011,16 +1116,16 @@ static void qlcnic_handle_fw_message(int desc_cnt, int index,  		}  		break;  	case QLCNIC_C2H_OPCODE_GET_DCB_AEN: -		qlcnic_dcb_handle_aen(adapter, (void *)&msg); +		qlcnic_dcb_aen_handler(adapter->dcb, (void *)&msg);  		break;  	default:  		break;  	}  } -struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter, -				     struct qlcnic_host_rds_ring *ring, -				     u16 index, u16 cksum) +static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter, +					    struct qlcnic_host_rds_ring *ring, +					    u16 index, u16 cksum)  {  	struct qlcnic_rx_buffer *buffer;  	struct sk_buff *skb; @@ -1104,8 +1209,7 @@ qlcnic_process_rcv(struct qlcnic_adapter *adapter,  	if (!skb)  		return buffer; -	if (adapter->drv_mac_learn && -	    (adapter->flags & QLCNIC_ESWITCH_ENABLED)) { +	if (adapter->rx_mac_learn) {  		t_vid = 0;  		is_lb_pkt = qlcnic_82xx_is_lb_pkt(sts_data0);  		qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, t_vid); @@ -1159,13 +1263,13 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,  	u16 lro_length, length, data_offset, t_vid, vid = 0xffff;  	u32 seq_number; -	if (unlikely(ring > adapter->max_rds_rings)) +	if (unlikely(ring >= adapter->max_rds_rings))  		return NULL;  	rds_ring = &recv_ctx->rds_rings[ring];  	index = qlcnic_get_lro_sts_refhandle(sts_data0); -	if (unlikely(index > rds_ring->num_desc)) +	if (unlikely(index >= rds_ring->num_desc))  		return NULL;  	buffer = &rds_ring->rx_buf_arr[index]; @@ -1181,8 +1285,7 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,  	if (!skb)  		return buffer; -	if (adapter->drv_mac_learn && -	    (adapter->flags & QLCNIC_ESWITCH_ENABLED)) { +	if (adapter->rx_mac_learn) {  		t_vid = 0;  		is_lb_pkt = qlcnic_82xx_is_lb_pkt(sts_data0);  		qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, t_vid); @@ -1239,7 +1342,7 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,  	return buffer;  } -int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max) +static int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max)  {  	struct qlcnic_host_rds_ring *rds_ring;  	struct qlcnic_adapter *adapter = sds_ring->adapter; @@ -1463,18 +1566,17 @@ int qlcnic_82xx_napi_add(struct qlcnic_adapter *adapter,  	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;  	struct qlcnic_host_tx_ring *tx_ring; -	if (qlcnic_alloc_sds_rings(recv_ctx, adapter->max_sds_rings)) +	if (qlcnic_alloc_sds_rings(recv_ctx, adapter->drv_sds_rings))  		return -ENOMEM; -	for (ring = 0; ring < adapter->max_sds_rings; ring++) { +	for (ring = 0; ring < adapter->drv_sds_rings; ring++) {  		sds_ring = &recv_ctx->sds_rings[ring];  		if (qlcnic_check_multi_tx(adapter) && -		    !adapter->ahw->diag_test && -		    (adapter->max_drv_tx_rings > 1)) { +		    !adapter->ahw->diag_test) {  			netif_napi_add(netdev, &sds_ring->napi, qlcnic_rx_poll,  				       NAPI_POLL_WEIGHT);  		} else { -			if (ring == (adapter->max_sds_rings - 1)) +			if (ring == (adapter->drv_sds_rings - 1))  				netif_napi_add(netdev, &sds_ring->napi,  					       qlcnic_poll,  					       NAPI_POLL_WEIGHT); @@ -1491,7 +1593,7 @@ int qlcnic_82xx_napi_add(struct qlcnic_adapter *adapter,  	}  	if (qlcnic_check_multi_tx(adapter) && !adapter->ahw->diag_test) { -		for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) { +		for (ring = 0; ring < adapter->drv_tx_rings; ring++) {  			tx_ring = &adapter->tx_ring[ring];  			netif_napi_add(netdev, &tx_ring->napi, qlcnic_tx_poll,  				       NAPI_POLL_WEIGHT); @@ -1508,7 +1610,7 @@ void qlcnic_82xx_napi_del(struct qlcnic_adapter *adapter)  	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;  	struct qlcnic_host_tx_ring *tx_ring; -	for (ring = 0; ring < adapter->max_sds_rings; ring++) { +	for (ring = 0; ring < adapter->drv_sds_rings; ring++) {  		sds_ring = &recv_ctx->sds_rings[ring];  		netif_napi_del(&sds_ring->napi);  	} @@ -1516,7 +1618,7 @@ void qlcnic_82xx_napi_del(struct qlcnic_adapter *adapter)  	qlcnic_free_sds_rings(adapter->recv_ctx);  	if (qlcnic_check_multi_tx(adapter) && !adapter->ahw->diag_test) { -		for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) { +		for (ring = 0; ring < adapter->drv_tx_rings; ring++) {  			tx_ring = &adapter->tx_ring[ring];  			netif_napi_del(&tx_ring->napi);  		} @@ -1535,17 +1637,16 @@ void qlcnic_82xx_napi_enable(struct qlcnic_adapter *adapter)  	if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)  		return; -	for (ring = 0; ring < adapter->max_sds_rings; ring++) { +	for (ring = 0; ring < adapter->drv_sds_rings; ring++) {  		sds_ring = &recv_ctx->sds_rings[ring];  		napi_enable(&sds_ring->napi); -		qlcnic_enable_int(sds_ring); +		qlcnic_enable_sds_intr(adapter, sds_ring);  	}  	if (qlcnic_check_multi_tx(adapter) &&  	    (adapter->flags & QLCNIC_MSIX_ENABLED) && -	    !adapter->ahw->diag_test && -	    (adapter->max_drv_tx_rings > 1)) { -		for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) { +	    !adapter->ahw->diag_test) { +		for (ring = 0; ring < adapter->drv_tx_rings; ring++) {  			tx_ring = &adapter->tx_ring[ring];  			napi_enable(&tx_ring->napi);  			qlcnic_enable_tx_intr(adapter, tx_ring); @@ -1563,9 +1664,9 @@ void qlcnic_82xx_napi_disable(struct qlcnic_adapter *adapter)  	if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)  		return; -	for (ring = 0; ring < adapter->max_sds_rings; ring++) { +	for (ring = 0; ring < adapter->drv_sds_rings; ring++) {  		sds_ring = &recv_ctx->sds_rings[ring]; -		qlcnic_disable_int(sds_ring); +		qlcnic_disable_sds_intr(adapter, sds_ring);  		napi_synchronize(&sds_ring->napi);  		napi_disable(&sds_ring->napi);  	} @@ -1573,9 +1674,9 @@ void qlcnic_82xx_napi_disable(struct qlcnic_adapter *adapter)  	if ((adapter->flags & QLCNIC_MSIX_ENABLED) &&  	    !adapter->ahw->diag_test &&  	    qlcnic_check_multi_tx(adapter)) { -		for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) { +		for (ring = 0; ring < adapter->drv_tx_rings; ring++) {  			tx_ring = &adapter->tx_ring[ring]; -			qlcnic_disable_tx_int(adapter, tx_ring); +			qlcnic_disable_tx_intr(adapter, tx_ring);  			napi_synchronize(&tx_ring->napi);  			napi_disable(&tx_ring->napi);  		} @@ -1593,6 +1694,13 @@ static inline int qlcnic_83xx_is_lb_pkt(u64 sts_data, int lro_pkt)  		return (sts_data & QLC_83XX_NORMAL_LB_PKT) ? 1 : 0;  } +#define QLCNIC_ENCAP_LENGTH_MASK	0x7f + +static inline u8 qlcnic_encap_length(u64 sts_data) +{ +	return sts_data & QLCNIC_ENCAP_LENGTH_MASK; +} +  static struct qlcnic_rx_buffer *  qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter,  			struct qlcnic_host_sds_ring *sds_ring, @@ -1604,7 +1712,8 @@ qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter,  	struct sk_buff *skb;  	struct qlcnic_host_rds_ring *rds_ring;  	int index, length, cksum, is_lb_pkt; -	u16 vid = 0xffff, t_vid; +	u16 vid = 0xffff; +	int err;  	if (unlikely(ring >= adapter->max_rds_rings))  		return NULL; @@ -1622,19 +1731,19 @@ qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter,  	if (!skb)  		return buffer; -	if (adapter->drv_mac_learn && -	    (adapter->flags & QLCNIC_ESWITCH_ENABLED)) { -		t_vid = 0; -		is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 0); -		qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, t_vid); -	} -  	if (length > rds_ring->skb_size)  		skb_put(skb, rds_ring->skb_size);  	else  		skb_put(skb, length); -	if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) { +	err = qlcnic_check_rx_tagging(adapter, skb, &vid); + +	if (adapter->rx_mac_learn) { +		is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 0); +		qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, vid); +	} + +	if (unlikely(err)) {  		adapter->stats.rxdropped++;  		dev_kfree_skb(skb);  		return buffer; @@ -1642,6 +1751,12 @@ qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter,  	skb->protocol = eth_type_trans(skb, netdev); +	if (qlcnic_encap_length(sts_data[1]) && +	    skb->ip_summed == CHECKSUM_UNNECESSARY) { +		skb->encapsulation = 1; +		adapter->stats.encap_rx_csummed++; +	} +  	if (vid != 0xffff)  		__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid); @@ -1669,15 +1784,16 @@ qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter,  	int l2_hdr_offset, l4_hdr_offset;  	int index, is_lb_pkt;  	u16 lro_length, length, data_offset, gso_size; -	u16 vid = 0xffff, t_vid; +	u16 vid = 0xffff; +	int err; -	if (unlikely(ring > adapter->max_rds_rings)) +	if (unlikely(ring >= adapter->max_rds_rings))  		return NULL;  	rds_ring = &recv_ctx->rds_rings[ring];  	index = qlcnic_83xx_hndl(sts_data[0]); -	if (unlikely(index > rds_ring->num_desc)) +	if (unlikely(index >= rds_ring->num_desc))  		return NULL;  	buffer = &rds_ring->rx_buf_arr[index]; @@ -1691,12 +1807,6 @@ qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter,  	if (!skb)  		return buffer; -	if (adapter->drv_mac_learn && -	    (adapter->flags & QLCNIC_ESWITCH_ENABLED)) { -		t_vid = 0; -		is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 1); -		qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, t_vid); -	}  	if (qlcnic_83xx_is_tstamp(sts_data[1]))  		data_offset = l4_hdr_offset + QLCNIC_TCP_TS_HDR_SIZE;  	else @@ -1705,7 +1815,14 @@ qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter,  	skb_put(skb, lro_length + data_offset);  	skb_pull(skb, l2_hdr_offset); -	if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) { +	err = qlcnic_check_rx_tagging(adapter, skb, &vid); + +	if (adapter->rx_mac_learn) { +		is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 1); +		qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, vid); +	} + +	if (unlikely(err)) {  		adapter->stats.rxdropped++;  		dev_kfree_skb(skb);  		return buffer; @@ -1835,7 +1952,7 @@ static int qlcnic_83xx_msix_sriov_vf_poll(struct napi_struct *napi, int budget)  	work_done = qlcnic_83xx_process_rcv_ring(sds_ring, budget);  	if ((work_done < budget) && tx_complete) {  		napi_complete(&sds_ring->napi); -		qlcnic_83xx_enable_intr(adapter, sds_ring); +		qlcnic_enable_sds_intr(adapter, sds_ring);  	}  	return work_done; @@ -1858,7 +1975,7 @@ static int qlcnic_83xx_poll(struct napi_struct *napi, int budget)  	work_done = qlcnic_83xx_process_rcv_ring(sds_ring, budget);  	if ((work_done < budget) && tx_complete) {  		napi_complete(&sds_ring->napi); -		qlcnic_83xx_enable_intr(adapter, sds_ring); +		qlcnic_enable_sds_intr(adapter, sds_ring);  	}  	return work_done; @@ -1877,7 +1994,7 @@ static int qlcnic_83xx_msix_tx_poll(struct napi_struct *napi, int budget)  	if (work_done) {  		napi_complete(&tx_ring->napi);  		if (test_bit(__QLCNIC_DEV_UP , &adapter->state)) -			qlcnic_83xx_enable_tx_intr(adapter, tx_ring); +			qlcnic_enable_tx_intr(adapter, tx_ring);  	}  	return work_done; @@ -1895,7 +2012,7 @@ static int qlcnic_83xx_rx_poll(struct napi_struct *napi, int budget)  	if (work_done < budget) {  		napi_complete(&sds_ring->napi);  		if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) -			qlcnic_83xx_enable_intr(adapter, sds_ring); +			qlcnic_enable_sds_intr(adapter, sds_ring);  	}  	return work_done; @@ -1911,19 +2028,19 @@ void qlcnic_83xx_napi_enable(struct qlcnic_adapter *adapter)  	if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)  		return; -	for (ring = 0; ring < adapter->max_sds_rings; ring++) { +	for (ring = 0; ring < adapter->drv_sds_rings; ring++) {  		sds_ring = &recv_ctx->sds_rings[ring];  		napi_enable(&sds_ring->napi);  		if (adapter->flags & QLCNIC_MSIX_ENABLED) -			qlcnic_83xx_enable_intr(adapter, sds_ring); +			qlcnic_enable_sds_intr(adapter, sds_ring);  	}  	if ((adapter->flags & QLCNIC_MSIX_ENABLED) &&  	    !(adapter->flags & QLCNIC_TX_INTR_SHARED)) { -		for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) { +		for (ring = 0; ring < adapter->drv_tx_rings; ring++) {  			tx_ring = &adapter->tx_ring[ring];  			napi_enable(&tx_ring->napi); -			qlcnic_83xx_enable_tx_intr(adapter, tx_ring); +			qlcnic_enable_tx_intr(adapter, tx_ring);  		}  	}  } @@ -1938,19 +2055,19 @@ void qlcnic_83xx_napi_disable(struct qlcnic_adapter *adapter)  	if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)  		return; -	for (ring = 0; ring < adapter->max_sds_rings; ring++) { +	for (ring = 0; ring < adapter->drv_sds_rings; ring++) {  		sds_ring = &recv_ctx->sds_rings[ring];  		if (adapter->flags & QLCNIC_MSIX_ENABLED) -			qlcnic_83xx_disable_intr(adapter, sds_ring); +			qlcnic_disable_sds_intr(adapter, sds_ring);  		napi_synchronize(&sds_ring->napi);  		napi_disable(&sds_ring->napi);  	}  	if ((adapter->flags & QLCNIC_MSIX_ENABLED) &&  	    !(adapter->flags & QLCNIC_TX_INTR_SHARED)) { -		for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) { +		for (ring = 0; ring < adapter->drv_tx_rings; ring++) {  			tx_ring = &adapter->tx_ring[ring]; -			qlcnic_83xx_disable_tx_intr(adapter, tx_ring); +			qlcnic_disable_tx_intr(adapter, tx_ring);  			napi_synchronize(&tx_ring->napi);  			napi_disable(&tx_ring->napi);  		} @@ -1965,10 +2082,10 @@ int qlcnic_83xx_napi_add(struct qlcnic_adapter *adapter,  	struct qlcnic_host_tx_ring *tx_ring;  	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; -	if (qlcnic_alloc_sds_rings(recv_ctx, adapter->max_sds_rings)) +	if (qlcnic_alloc_sds_rings(recv_ctx, adapter->drv_sds_rings))  		return -ENOMEM; -	for (ring = 0; ring < adapter->max_sds_rings; ring++) { +	for (ring = 0; ring < adapter->drv_sds_rings; ring++) {  		sds_ring = &recv_ctx->sds_rings[ring];  		if (adapter->flags & QLCNIC_MSIX_ENABLED) {  			if (!(adapter->flags & QLCNIC_TX_INTR_SHARED)) @@ -1994,7 +2111,7 @@ int qlcnic_83xx_napi_add(struct qlcnic_adapter *adapter,  	if ((adapter->flags & QLCNIC_MSIX_ENABLED) &&  	    !(adapter->flags & QLCNIC_TX_INTR_SHARED)) { -		for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) { +		for (ring = 0; ring < adapter->drv_tx_rings; ring++) {  			tx_ring = &adapter->tx_ring[ring];  			netif_napi_add(netdev, &tx_ring->napi,  				       qlcnic_83xx_msix_tx_poll, @@ -2012,7 +2129,7 @@ void qlcnic_83xx_napi_del(struct qlcnic_adapter *adapter)  	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;  	struct qlcnic_host_tx_ring *tx_ring; -	for (ring = 0; ring < adapter->max_sds_rings; ring++) { +	for (ring = 0; ring < adapter->drv_sds_rings; ring++) {  		sds_ring = &recv_ctx->sds_rings[ring];  		netif_napi_del(&sds_ring->napi);  	} @@ -2021,7 +2138,7 @@ void qlcnic_83xx_napi_del(struct qlcnic_adapter *adapter)  	if ((adapter->flags & QLCNIC_MSIX_ENABLED) &&  	    !(adapter->flags & QLCNIC_TX_INTR_SHARED)) { -		for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) { +		for (ring = 0; ring < adapter->drv_tx_rings; ring++) {  			tx_ring = &adapter->tx_ring[ring];  			netif_napi_del(&tx_ring->napi);  		} @@ -2030,8 +2147,8 @@ void qlcnic_83xx_napi_del(struct qlcnic_adapter *adapter)  	qlcnic_free_tx_rings(adapter);  } -void qlcnic_83xx_process_rcv_diag(struct qlcnic_adapter *adapter, -				  int ring, u64 sts_data[]) +static void qlcnic_83xx_process_rcv_diag(struct qlcnic_adapter *adapter, +					 int ring, u64 sts_data[])  {  	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;  	struct sk_buff *skb; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index c4c5023e1fd..4fc186713b6 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -21,6 +21,9 @@  #include <linux/aer.h>  #include <linux/log2.h>  #include <linux/pci.h> +#ifdef CONFIG_QLCNIC_VXLAN +#include <net/vxlan.h> +#endif  MODULE_DESCRIPTION("QLogic 1/10 GbE Converged/Intelligent Ethernet Driver");  MODULE_LICENSE("GPL"); @@ -81,6 +84,15 @@ static int qlcnicvf_start_firmware(struct qlcnic_adapter *);  static int qlcnic_vlan_rx_add(struct net_device *, __be16, u16);  static int qlcnic_vlan_rx_del(struct net_device *, __be16, u16); +static int qlcnic_82xx_setup_intr(struct qlcnic_adapter *); +static void qlcnic_82xx_dev_request_reset(struct qlcnic_adapter *, u32); +static irqreturn_t qlcnic_82xx_clear_legacy_intr(struct qlcnic_adapter *); +static pci_ers_result_t qlcnic_82xx_io_slot_reset(struct pci_dev *); +static int qlcnic_82xx_start_firmware(struct qlcnic_adapter *); +static void qlcnic_82xx_io_resume(struct pci_dev *); +static void qlcnic_82xx_set_mac_filter_count(struct qlcnic_adapter *); +static pci_ers_result_t qlcnic_82xx_io_error_detected(struct pci_dev *, +						      pci_channel_state_t);  static u32 qlcnic_vlan_tx_check(struct qlcnic_adapter *adapter)  {  	struct qlcnic_hardware_context *ahw = adapter->ahw; @@ -308,12 +320,12 @@ int qlcnic_read_mac_addr(struct qlcnic_adapter *adapter)  static void qlcnic_delete_adapter_mac(struct qlcnic_adapter *adapter)  { -	struct qlcnic_mac_list_s *cur; +	struct qlcnic_mac_vlan_list *cur;  	struct list_head *head;  	list_for_each(head, &adapter->mac_list) { -		cur = list_entry(head, struct qlcnic_mac_list_s, list); -		if (!memcmp(adapter->mac_addr, cur->mac_addr, ETH_ALEN)) { +		cur = list_entry(head, struct qlcnic_mac_vlan_list, list); +		if (ether_addr_equal_unaligned(adapter->mac_addr, cur->mac_addr)) {  			qlcnic_sre_macaddr_change(adapter, cur->mac_addr,  						  0, QLCNIC_MAC_DEL);  			list_del(&cur->list); @@ -337,7 +349,7 @@ static int qlcnic_set_mac(struct net_device *netdev, void *p)  	if (!is_valid_ether_addr(addr->sa_data))  		return -EINVAL; -	if (!memcmp(adapter->mac_addr, addr->sa_data, ETH_ALEN)) +	if (ether_addr_equal_unaligned(adapter->mac_addr, addr->sa_data))  		return 0;  	if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) { @@ -366,7 +378,8 @@ static int qlcnic_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],  	if (!adapter->fdb_mac_learn)  		return ndo_dflt_fdb_del(ndm, tb, netdev, addr); -	if (adapter->flags & QLCNIC_ESWITCH_ENABLED) { +	if ((adapter->flags & QLCNIC_ESWITCH_ENABLED) || +	    qlcnic_sriov_check(adapter)) {  		if (is_unicast_ether_addr(addr)) {  			err = dev_uc_del(netdev, addr);  			if (!err) @@ -390,7 +403,8 @@ static int qlcnic_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],  	if (!adapter->fdb_mac_learn)  		return ndo_dflt_fdb_add(ndm, tb, netdev, addr, flags); -	if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) { +	if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) && +	    !qlcnic_sriov_check(adapter)) {  		pr_info("%s: FDB e-switch is not enabled\n", __func__);  		return -EOPNOTSUPP;  	} @@ -420,7 +434,8 @@ static int qlcnic_fdb_dump(struct sk_buff *skb, struct netlink_callback *ncb,  	if (!adapter->fdb_mac_learn)  		return ndo_dflt_fdb_dump(skb, ncb, netdev, idx); -	if (adapter->flags & QLCNIC_ESWITCH_ENABLED) +	if ((adapter->flags & QLCNIC_ESWITCH_ENABLED) || +	    qlcnic_sriov_check(adapter))  		idx = ndo_dflt_fdb_dump(skb, ncb, netdev, idx);  	return idx; @@ -431,6 +446,9 @@ static void qlcnic_82xx_cancel_idc_work(struct qlcnic_adapter *adapter)  	while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))  		usleep_range(10000, 11000); +	if (!adapter->fw_work.work.func) +		return; +  	cancel_delayed_work_sync(&adapter->fw_work);  } @@ -449,6 +467,37 @@ static int qlcnic_get_phys_port_id(struct net_device *netdev,  	return 0;  } +#ifdef CONFIG_QLCNIC_VXLAN +static void qlcnic_add_vxlan_port(struct net_device *netdev, +				  sa_family_t sa_family, __be16 port) +{ +	struct qlcnic_adapter *adapter = netdev_priv(netdev); +	struct qlcnic_hardware_context *ahw = adapter->ahw; + +	/* Adapter supports only one VXLAN port. Use very first port +	 * for enabling offload +	 */ +	if (!qlcnic_encap_rx_offload(adapter) || ahw->vxlan_port) +		return; + +	ahw->vxlan_port = ntohs(port); +	adapter->flags |= QLCNIC_ADD_VXLAN_PORT; +} + +static void qlcnic_del_vxlan_port(struct net_device *netdev, +				  sa_family_t sa_family, __be16 port) +{ +	struct qlcnic_adapter *adapter = netdev_priv(netdev); +	struct qlcnic_hardware_context *ahw = adapter->ahw; + +	if (!qlcnic_encap_rx_offload(adapter) || !ahw->vxlan_port || +	    (ahw->vxlan_port != ntohs(port))) +		return; + +	adapter->flags |= QLCNIC_DEL_VXLAN_PORT; +} +#endif +  static const struct net_device_ops qlcnic_netdev_ops = {  	.ndo_open	   = qlcnic_open,  	.ndo_stop	   = qlcnic_close, @@ -467,12 +516,16 @@ static const struct net_device_ops qlcnic_netdev_ops = {  	.ndo_fdb_del		= qlcnic_fdb_del,  	.ndo_fdb_dump		= qlcnic_fdb_dump,  	.ndo_get_phys_port_id	= qlcnic_get_phys_port_id, +#ifdef CONFIG_QLCNIC_VXLAN +	.ndo_add_vxlan_port	= qlcnic_add_vxlan_port, +	.ndo_del_vxlan_port	= qlcnic_del_vxlan_port, +#endif  #ifdef CONFIG_NET_POLL_CONTROLLER  	.ndo_poll_controller = qlcnic_poll_controller,  #endif  #ifdef CONFIG_QLCNIC_SRIOV  	.ndo_set_vf_mac		= qlcnic_sriov_set_vf_mac, -	.ndo_set_vf_tx_rate	= qlcnic_sriov_set_vf_tx_rate, +	.ndo_set_vf_rate	= qlcnic_sriov_set_vf_tx_rate,  	.ndo_get_vf_config	= qlcnic_sriov_get_vf_config,  	.ndo_set_vf_vlan	= qlcnic_sriov_set_vf_vlan,  	.ndo_set_vf_spoofchk	= qlcnic_sriov_set_vf_spoofchk, @@ -543,41 +596,146 @@ static struct qlcnic_hardware_ops qlcnic_hw_ops = {  	.io_error_detected		= qlcnic_82xx_io_error_detected,  	.io_slot_reset			= qlcnic_82xx_io_slot_reset,  	.io_resume			= qlcnic_82xx_io_resume, +	.get_beacon_state		= qlcnic_82xx_get_beacon_state, +	.enable_sds_intr		= qlcnic_82xx_enable_sds_intr, +	.disable_sds_intr		= qlcnic_82xx_disable_sds_intr, +	.enable_tx_intr			= qlcnic_82xx_enable_tx_intr, +	.disable_tx_intr		= qlcnic_82xx_disable_tx_intr, +	.get_saved_state		= qlcnic_82xx_get_saved_state, +	.set_saved_state		= qlcnic_82xx_set_saved_state, +	.cache_tmpl_hdr_values		= qlcnic_82xx_cache_tmpl_hdr_values, +	.get_cap_size			= qlcnic_82xx_get_cap_size, +	.set_sys_info			= qlcnic_82xx_set_sys_info, +	.store_cap_mask			= qlcnic_82xx_store_cap_mask,  }; -static void qlcnic_get_multiq_capability(struct qlcnic_adapter *adapter) +static int qlcnic_check_multi_tx_capability(struct qlcnic_adapter *adapter)  {  	struct qlcnic_hardware_context *ahw = adapter->ahw; -	int num_tx_q; -	if (ahw->msix_supported && +	if (qlcnic_82xx_check(adapter) &&  	    (ahw->extra_capability[0] & QLCNIC_FW_CAPABILITY_2_MULTI_TX)) { -		num_tx_q = min_t(int, QLCNIC_DEF_NUM_TX_RINGS, -				 num_online_cpus()); -		if (num_tx_q > 1) { -			test_and_set_bit(__QLCNIC_MULTI_TX_UNIQUE, -					 &adapter->state); -			adapter->max_drv_tx_rings = num_tx_q; -		} +		test_and_set_bit(__QLCNIC_MULTI_TX_UNIQUE, &adapter->state); +		return 0;  	} else { -		adapter->max_drv_tx_rings = 1; +		return 1;  	}  } -int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix) +static int qlcnic_max_rings(struct qlcnic_adapter *adapter, u8 ring_cnt, +			    int queue_type) +{ +	int num_rings, max_rings = QLCNIC_MAX_SDS_RINGS; + +	if (queue_type == QLCNIC_RX_QUEUE) +		max_rings = adapter->max_sds_rings; +	else if (queue_type == QLCNIC_TX_QUEUE) +		max_rings = adapter->max_tx_rings; + +	num_rings = rounddown_pow_of_two(min_t(int, num_online_cpus(), +					      max_rings)); + +	if (ring_cnt > num_rings) +		return num_rings; +	else +		return ring_cnt; +} + +void qlcnic_set_tx_ring_count(struct qlcnic_adapter *adapter, u8 tx_cnt) +{ +	/* 83xx adapter does not have max_tx_rings intialized in probe */ +	if (adapter->max_tx_rings) +		adapter->drv_tx_rings = qlcnic_max_rings(adapter, tx_cnt, +							 QLCNIC_TX_QUEUE); +	else +		adapter->drv_tx_rings = tx_cnt; +} + +void qlcnic_set_sds_ring_count(struct qlcnic_adapter *adapter, u8 rx_cnt) +{ +	/* 83xx adapter does not have max_sds_rings intialized in probe */ +	if (adapter->max_sds_rings) +		adapter->drv_sds_rings = qlcnic_max_rings(adapter, rx_cnt, +							  QLCNIC_RX_QUEUE); +	else +		adapter->drv_sds_rings = rx_cnt; +} + +int qlcnic_setup_tss_rss_intr(struct qlcnic_adapter *adapter)  {  	struct pci_dev *pdev = adapter->pdev; -	int max_tx_rings, max_sds_rings, tx_vector; -	int err = -1, i; +	int num_msix = 0, err = 0, vector; -	if (adapter->flags & QLCNIC_TX_INTR_SHARED) { -		max_tx_rings = 0; -		tx_vector = 0; -	} else { -		max_tx_rings = adapter->max_drv_tx_rings; -		tx_vector = 1; +	adapter->flags &= ~QLCNIC_TSS_RSS; + +	if (adapter->drv_tss_rings > 0) +		num_msix += adapter->drv_tss_rings; +	else +		num_msix += adapter->drv_tx_rings; + +	if (adapter->drv_rss_rings > 0) +		num_msix += adapter->drv_rss_rings; +	else +		num_msix += adapter->drv_sds_rings; + +	if (qlcnic_83xx_check(adapter)) +		num_msix += 1; + +	if (!adapter->msix_entries) { +		adapter->msix_entries = kcalloc(num_msix, +						sizeof(struct msix_entry), +						GFP_KERNEL); +		if (!adapter->msix_entries) +			return -ENOMEM;  	} +	for (vector = 0; vector < num_msix; vector++) +		adapter->msix_entries[vector].entry = vector; + +restore: +	err = pci_enable_msix_exact(pdev, adapter->msix_entries, num_msix); +	if (err == -ENOSPC) { +		if (!adapter->drv_tss_rings && !adapter->drv_rss_rings) +			return err; + +		netdev_info(adapter->netdev, +			    "Unable to allocate %d MSI-X vectors, Available vectors %d\n", +			    num_msix, err); + +		num_msix = adapter->drv_tx_rings + adapter->drv_sds_rings; + +		/* Set rings to 0 so we can restore original TSS/RSS count */ +		adapter->drv_tss_rings = 0; +		adapter->drv_rss_rings = 0; + +		if (qlcnic_83xx_check(adapter)) +			num_msix += 1; + +		netdev_info(adapter->netdev, +			    "Restoring %d Tx, %d SDS rings for total %d vectors.\n", +			    adapter->drv_tx_rings, adapter->drv_sds_rings, +			    num_msix); + +		goto restore; +	} else if (err < 0) { +		return err; +	} + +	adapter->ahw->num_msix = num_msix; +	if (adapter->drv_tss_rings > 0) +		adapter->drv_tx_rings = adapter->drv_tss_rings; + +	if (adapter->drv_rss_rings > 0) +		adapter->drv_sds_rings = adapter->drv_rss_rings; + +	return 0; +} + +int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix) +{ +	struct pci_dev *pdev = adapter->pdev; +	int err, vector; +  	if (!adapter->msix_entries) {  		adapter->msix_entries = kcalloc(num_msix,  						sizeof(struct msix_entry), @@ -586,48 +744,47 @@ int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix)  			return -ENOMEM;  	} -	adapter->max_sds_rings = 1;  	adapter->flags &= ~(QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED);  	if (adapter->ahw->msix_supported) { - enable_msix: -		for (i = 0; i < num_msix; i++) -			adapter->msix_entries[i].entry = i; -		err = pci_enable_msix(pdev, adapter->msix_entries, num_msix); -		if (err == 0) { +enable_msix: +		for (vector = 0; vector < num_msix; vector++) +			adapter->msix_entries[vector].entry = vector; + +		err = pci_enable_msix_range(pdev, +					    adapter->msix_entries, 1, num_msix); + +		if (err == num_msix) {  			adapter->flags |= QLCNIC_MSIX_ENABLED; -			if (qlcnic_83xx_check(adapter)) { -				adapter->ahw->num_msix = num_msix; -				/* subtract mail box and tx ring vectors */ -				adapter->max_sds_rings = num_msix - -							 max_tx_rings - 1; -			} else { -				adapter->ahw->num_msix = num_msix; -				if (qlcnic_check_multi_tx(adapter) && -				    !adapter->ahw->diag_test && -				    (adapter->max_drv_tx_rings > 1)) -					max_sds_rings = num_msix - max_tx_rings; -				else -					max_sds_rings = num_msix; - -				adapter->max_sds_rings = max_sds_rings; -			} +			adapter->ahw->num_msix = num_msix;  			dev_info(&pdev->dev, "using msi-x interrupts\n"); -			return err; +			return 0;  		} else if (err > 0) { +			pci_disable_msix(pdev); +  			dev_info(&pdev->dev, -				 "Unable to allocate %d MSI-X interrupt vectors\n", -				 num_msix); -			if (qlcnic_83xx_check(adapter)) { -				if (err < (QLC_83XX_MINIMUM_VECTOR - tx_vector)) -					return err; -				err -= (max_tx_rings + 1); +				 "Unable to allocate %d MSI-X vectors, Available vectors %d\n", +				 num_msix, err); + +			if (qlcnic_82xx_check(adapter)) {  				num_msix = rounddown_pow_of_two(err); -				num_msix += (max_tx_rings + 1); +				if (err < QLCNIC_82XX_MINIMUM_VECTOR) +					return -ENOSPC;  			} else { -				num_msix = rounddown_pow_of_two(err); -				if (qlcnic_check_multi_tx(adapter)) -					num_msix += max_tx_rings; +				num_msix = rounddown_pow_of_two(err - 1); +				num_msix += 1; +				if (err < QLCNIC_83XX_MINIMUM_VECTOR) +					return -ENOSPC; +			} + +			if (qlcnic_82xx_check(adapter) && +			    !qlcnic_check_multi_tx(adapter)) { +				adapter->drv_sds_rings = num_msix; +				adapter->drv_tx_rings = QLCNIC_SINGLE_RING; +			} else { +				/* Distribute vectors equally */ +				adapter->drv_tx_rings = num_msix / 2; +				adapter->drv_sds_rings = adapter->drv_tx_rings;  			}  			if (num_msix) { @@ -638,12 +795,27 @@ int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix)  			}  		} else {  			dev_info(&pdev->dev, -				 "Unable to allocate %d MSI-X interrupt vectors\n", -				 num_msix); +				 "Unable to allocate %d MSI-X vectors, err=%d\n", +				 num_msix, err); +			return err;  		}  	} -	return err; +	return -EIO; +} + +static int qlcnic_82xx_calculate_msix_vector(struct qlcnic_adapter *adapter) +{ +	int num_msix; + +	num_msix = adapter->drv_sds_rings; + +	if (qlcnic_check_multi_tx(adapter)) +		num_msix += adapter->drv_tx_rings; +	else +		num_msix += QLCNIC_SINGLE_RING; + +	return num_msix;  }  static int qlcnic_enable_msi_legacy(struct qlcnic_adapter *adapter) @@ -680,36 +852,30 @@ static int qlcnic_enable_msi_legacy(struct qlcnic_adapter *adapter)  	return err;  } -int qlcnic_82xx_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr, int txq) +static int qlcnic_82xx_setup_intr(struct qlcnic_adapter *adapter)  { -	struct qlcnic_hardware_context *ahw = adapter->ahw;  	int num_msix, err = 0; -	if (!num_intr) -		num_intr = QLCNIC_DEF_NUM_STS_DESC_RINGS; - -	if (ahw->msix_supported) { -		num_msix = rounddown_pow_of_two(min_t(int, num_online_cpus(), -						num_intr)); -		if (qlcnic_check_multi_tx(adapter)) { -			if (txq) -				adapter->max_drv_tx_rings = txq; -			num_msix += adapter->max_drv_tx_rings; -		} +	if (adapter->flags & QLCNIC_TSS_RSS) { +		err = qlcnic_setup_tss_rss_intr(adapter); +		if (err < 0) +			return err; +		num_msix = adapter->ahw->num_msix;  	} else { -		num_msix = 1; -	} +		num_msix = qlcnic_82xx_calculate_msix_vector(adapter); -	err = qlcnic_enable_msix(adapter, num_msix); -	if (err == -ENOMEM) -		return err; +		err = qlcnic_enable_msix(adapter, num_msix); +		if (err == -ENOMEM) +			return err; -	if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) { -		qlcnic_disable_multi_tx(adapter); +		if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) { +			qlcnic_disable_multi_tx(adapter); +			adapter->drv_sds_rings = QLCNIC_SINGLE_RING; -		err = qlcnic_enable_msi_legacy(adapter); -		if (!err) -			return err; +			err = qlcnic_enable_msi_legacy(adapter); +			if (err) +				return err; +		}  	}  	return 0; @@ -769,25 +935,26 @@ static void qlcnic_cleanup_pci_map(struct qlcnic_hardware_context *ahw)  static int qlcnic_get_act_pci_func(struct qlcnic_adapter *adapter)  { +	struct qlcnic_hardware_context *ahw = adapter->ahw;  	struct qlcnic_pci_info *pci_info;  	int ret;  	if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) { -		switch (adapter->ahw->port_type) { +		switch (ahw->port_type) {  		case QLCNIC_GBE: -			adapter->ahw->act_pci_func = QLCNIC_NIU_MAX_GBE_PORTS; +			ahw->total_nic_func = QLCNIC_NIU_MAX_GBE_PORTS;  			break;  		case QLCNIC_XGBE: -			adapter->ahw->act_pci_func = QLCNIC_NIU_MAX_XG_PORTS; +			ahw->total_nic_func = QLCNIC_NIU_MAX_XG_PORTS;  			break;  		}  		return 0;  	} -	if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC) +	if (ahw->op_mode == QLCNIC_MGMT_FUNC)  		return 0; -	pci_info = kcalloc(QLCNIC_MAX_PCI_FUNC, sizeof(*pci_info), GFP_KERNEL); +	pci_info = kcalloc(ahw->max_vnic_func, sizeof(*pci_info), GFP_KERNEL);  	if (!pci_info)  		return -ENOMEM; @@ -815,12 +982,13 @@ static bool qlcnic_port_eswitch_cfg_capability(struct qlcnic_adapter *adapter)  int qlcnic_init_pci_info(struct qlcnic_adapter *adapter)  { +	struct qlcnic_hardware_context *ahw = adapter->ahw;  	struct qlcnic_pci_info *pci_info; -	int i, ret = 0, j = 0; +	int i, id = 0, ret = 0, j = 0;  	u16 act_pci_func;  	u8 pfn; -	pci_info = kcalloc(QLCNIC_MAX_PCI_FUNC, sizeof(*pci_info), GFP_KERNEL); +	pci_info = kcalloc(ahw->max_vnic_func, sizeof(*pci_info), GFP_KERNEL);  	if (!pci_info)  		return -ENOMEM; @@ -828,7 +996,7 @@ int qlcnic_init_pci_info(struct qlcnic_adapter *adapter)  	if (ret)  		goto err_pci_info; -	act_pci_func = adapter->ahw->act_pci_func; +	act_pci_func = ahw->total_nic_func;  	adapter->npars = kzalloc(sizeof(struct qlcnic_npar_info) *  				 act_pci_func, GFP_KERNEL); @@ -844,11 +1012,13 @@ int qlcnic_init_pci_info(struct qlcnic_adapter *adapter)  		goto err_npars;  	} -	for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) { +	for (i = 0; i < ahw->max_vnic_func; i++) {  		pfn = pci_info[i].id; -		if (pfn >= QLCNIC_MAX_PCI_FUNC) { +		if (pfn >= ahw->max_vnic_func) {  			ret = QL_STATUS_INVALID_PARAM; +			dev_err(&adapter->pdev->dev, "%s: Invalid function 0x%x, max 0x%x\n", +				__func__, pfn, ahw->max_vnic_func);  			goto err_eswitch;  		} @@ -857,7 +1027,8 @@ int qlcnic_init_pci_info(struct qlcnic_adapter *adapter)  			continue;  		if (qlcnic_port_eswitch_cfg_capability(adapter)) { -			if (!qlcnic_83xx_enable_port_eswitch(adapter, pfn)) +			if (!qlcnic_83xx_set_port_eswitch_status(adapter, pfn, +								 &id))  				adapter->npars[j].eswitch_status = true;  			else  				continue; @@ -872,15 +1043,16 @@ int qlcnic_init_pci_info(struct qlcnic_adapter *adapter)  		adapter->npars[j].min_bw = pci_info[i].tx_min_bw;  		adapter->npars[j].max_bw = pci_info[i].tx_max_bw; +		memcpy(&adapter->npars[j].mac, &pci_info[i].mac, ETH_ALEN);  		j++;  	} -	if (qlcnic_82xx_check(adapter)) { +	/* Update eSwitch status for adapters without per port eSwitch +	 * configuration capability +	 */ +	if (!qlcnic_port_eswitch_cfg_capability(adapter)) {  		for (i = 0; i < QLCNIC_NIU_MAX_XG_PORTS; i++)  			adapter->eswitch[i].flags |= QLCNIC_SWITCH_ENABLE; -	} else if (!qlcnic_port_eswitch_cfg_capability(adapter)) { -		for (i = 0; i < QLCNIC_NIU_MAX_XG_PORTS; i++) -			qlcnic_enable_eswitch(adapter, i, 1);  	}  	kfree(pci_info); @@ -1128,18 +1300,26 @@ qlcnic_initialize_nic(struct qlcnic_adapter *adapter)  		if (err == -EIO)  			return err;  		adapter->ahw->extra_capability[0] = temp; +	} else { +		adapter->ahw->extra_capability[0] = 0;  	} +  	adapter->ahw->max_mac_filters = nic_info.max_mac_filters;  	adapter->ahw->max_mtu = nic_info.max_mtu; -	/* Disable NPAR for 83XX */ -	if (qlcnic_83xx_check(adapter)) -		return err; - -	if (adapter->ahw->capabilities & BIT_6) +	if (adapter->ahw->capabilities & BIT_6) {  		adapter->flags |= QLCNIC_ESWITCH_ENABLED; -	else +		adapter->ahw->nic_mode = QLCNIC_VNIC_MODE; +		adapter->max_tx_rings = QLCNIC_MAX_HW_VNIC_TX_RINGS; +		adapter->max_sds_rings = QLCNIC_MAX_VNIC_SDS_RINGS; + +		dev_info(&adapter->pdev->dev, "vNIC mode enabled.\n"); +	} else { +		adapter->ahw->nic_mode = QLCNIC_DEFAULT_MODE; +		adapter->max_tx_rings = QLCNIC_MAX_HW_TX_RINGS; +		adapter->max_sds_rings = QLCNIC_MAX_SDS_RINGS;  		adapter->flags &= ~QLCNIC_ESWITCH_ENABLED; +	}  	return err;  } @@ -1287,6 +1467,8 @@ qlcnic_check_eswitch_mode(struct qlcnic_adapter *adapter)  				"HAL Version: %d, Privileged function\n",  				 adapter->ahw->fw_hal_version);  		} +	} else { +		adapter->ahw->nic_mode = QLCNIC_DEFAULT_MODE;  	}  	adapter->flags |= QLCNIC_ADAPTER_INITIALIZED; @@ -1303,7 +1485,7 @@ int qlcnic_set_default_offload_settings(struct qlcnic_adapter *adapter)  	if (adapter->need_fw_reset)  		return 0; -	for (i = 0; i < adapter->ahw->act_pci_func; i++) { +	for (i = 0; i < adapter->ahw->total_nic_func; i++) {  		if (!adapter->npars[i].eswitch_status)  			continue; @@ -1366,7 +1548,7 @@ int qlcnic_reset_npar_config(struct qlcnic_adapter *adapter)  			return 0;  	/* Set the NPAR config data after FW reset */ -	for (i = 0; i < adapter->ahw->act_pci_func; i++) { +	for (i = 0; i < adapter->ahw->total_nic_func; i++) {  		npar = &adapter->npars[i];  		pci_func = npar->pci_func;  		if (!adapter->npars[i].eswitch_status) @@ -1441,7 +1623,7 @@ qlcnic_set_mgmt_operations(struct qlcnic_adapter *adapter)  	return err;  } -int qlcnic_82xx_start_firmware(struct qlcnic_adapter *adapter) +static int qlcnic_82xx_start_firmware(struct qlcnic_adapter *adapter)  {  	int err; @@ -1546,7 +1728,7 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter)  		if (qlcnic_82xx_check(adapter) ||  		    (qlcnic_83xx_check(adapter) &&  		     (adapter->flags & QLCNIC_MSIX_ENABLED))) { -			num_sds_rings = adapter->max_sds_rings; +			num_sds_rings = adapter->drv_sds_rings;  			for (ring = 0; ring < num_sds_rings; ring++) {  				sds_ring = &recv_ctx->sds_rings[ring];  				if (qlcnic_82xx_check(adapter) && @@ -1580,7 +1762,7 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter)  		     (adapter->flags & QLCNIC_MSIX_ENABLED) &&  		     !(adapter->flags & QLCNIC_TX_INTR_SHARED))) {  			handler = qlcnic_msix_tx_intr; -			for (ring = 0; ring < adapter->max_drv_tx_rings; +			for (ring = 0; ring < adapter->drv_tx_rings;  			     ring++) {  				tx_ring = &adapter->tx_ring[ring];  				snprintf(tx_ring->name, sizeof(tx_ring->name), @@ -1608,7 +1790,7 @@ qlcnic_free_irq(struct qlcnic_adapter *adapter)  		if (qlcnic_82xx_check(adapter) ||  		    (qlcnic_83xx_check(adapter) &&  		     (adapter->flags & QLCNIC_MSIX_ENABLED))) { -			for (ring = 0; ring < adapter->max_sds_rings; ring++) { +			for (ring = 0; ring < adapter->drv_sds_rings; ring++) {  				sds_ring = &recv_ctx->sds_rings[ring];  				free_irq(sds_ring->irq, sds_ring);  			} @@ -1617,7 +1799,7 @@ qlcnic_free_irq(struct qlcnic_adapter *adapter)  		     !(adapter->flags & QLCNIC_TX_INTR_SHARED)) ||  		    (qlcnic_82xx_check(adapter) &&  		     qlcnic_check_multi_tx(adapter))) { -			for (ring = 0; ring < adapter->max_drv_tx_rings; +			for (ring = 0; ring < adapter->drv_tx_rings;  			     ring++) {  				tx_ring = &adapter->tx_ring[ring];  				if (tx_ring->irq) @@ -1642,6 +1824,33 @@ static void qlcnic_get_lro_mss_capability(struct qlcnic_adapter *adapter)  	}  } +static int qlcnic_config_def_intr_coalesce(struct qlcnic_adapter *adapter) +{ +	struct qlcnic_hardware_context *ahw = adapter->ahw; +	int err; + +	/* Initialize interrupt coalesce parameters */ +	ahw->coal.flag = QLCNIC_INTR_DEFAULT; + +	if (qlcnic_83xx_check(adapter)) { +		ahw->coal.type = QLCNIC_INTR_COAL_TYPE_RX_TX; +		ahw->coal.tx_time_us = QLCNIC_DEF_INTR_COALESCE_TX_TIME_US; +		ahw->coal.tx_packets = QLCNIC_DEF_INTR_COALESCE_TX_PACKETS; +		ahw->coal.rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US; +		ahw->coal.rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS; + +		err = qlcnic_83xx_set_rx_tx_intr_coal(adapter); +	} else { +		ahw->coal.type = QLCNIC_INTR_COAL_TYPE_RX; +		ahw->coal.rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US; +		ahw->coal.rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS; + +		err = qlcnic_82xx_set_rx_coalesce(adapter); +	} + +	return err; +} +  int __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)  {  	int ring; @@ -1671,10 +1880,10 @@ int __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)  	adapter->ahw->linkup = 0; -	if (adapter->max_sds_rings > 1) +	if (adapter->drv_sds_rings > 1)  		qlcnic_config_rss(adapter, 1); -	qlcnic_config_intr_coalesce(adapter); +	qlcnic_config_def_intr_coalesce(adapter);  	if (netdev->features & NETIF_F_LRO)  		qlcnic_config_hw_lro(adapter, QLCNIC_LRO_ENABLED); @@ -1685,6 +1894,7 @@ int __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)  	qlcnic_linkevent_request(adapter, 1);  	adapter->ahw->reset_context = 0; +	netif_tx_start_all_queues(netdev);  	return 0;  } @@ -1710,8 +1920,6 @@ void __qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)  	if (!test_and_clear_bit(__QLCNIC_DEV_UP, &adapter->state))  		return; -	if (qlcnic_sriov_vf_check(adapter)) -		qlcnic_sriov_cleanup_async_list(&adapter->ahw->sriov->bc);  	smp_mb();  	netif_carrier_off(netdev);  	adapter->ahw->linkup = 0; @@ -1723,6 +1931,8 @@ void __qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)  		qlcnic_delete_lb_filters(adapter);  	qlcnic_nic_set_promisc(adapter, QLCNIC_NIU_NON_PROMISC_MODE); +	if (qlcnic_sriov_vf_check(adapter)) +		qlcnic_sriov_cleanup_async_list(&adapter->ahw->sriov->bc);  	qlcnic_napi_disable(adapter); @@ -1731,7 +1941,7 @@ void __qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)  	qlcnic_reset_rx_buffers_list(adapter); -	for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) +	for (ring = 0; ring < adapter->drv_tx_rings; ring++)  		qlcnic_release_tx_buffers(adapter, &adapter->tx_ring[ring]);  } @@ -1780,6 +1990,11 @@ qlcnic_attach(struct qlcnic_adapter *adapter)  	qlcnic_create_sysfs_entries(adapter); +#ifdef CONFIG_QLCNIC_VXLAN +	if (qlcnic_encap_rx_offload(adapter)) +		vxlan_get_rx_port(netdev); +#endif +  	adapter->is_up = QLCNIC_ADAPTER_UP_MAGIC;  	return 0; @@ -1808,18 +2023,18 @@ void qlcnic_detach(struct qlcnic_adapter *adapter)  	adapter->is_up = 0;  } -void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings) +void qlcnic_diag_free_res(struct net_device *netdev, int drv_sds_rings)  {  	struct qlcnic_adapter *adapter = netdev_priv(netdev);  	struct qlcnic_host_sds_ring *sds_ring; -	int max_tx_rings = adapter->max_drv_tx_rings; +	int drv_tx_rings = adapter->drv_tx_rings;  	int ring;  	clear_bit(__QLCNIC_DEV_UP, &adapter->state);  	if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) { -		for (ring = 0; ring < adapter->max_sds_rings; ring++) { +		for (ring = 0; ring < adapter->drv_sds_rings; ring++) {  			sds_ring = &adapter->recv_ctx->sds_rings[ring]; -			qlcnic_disable_int(sds_ring); +			qlcnic_disable_sds_intr(adapter, sds_ring);  		}  	} @@ -1828,8 +2043,8 @@ void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings)  	qlcnic_detach(adapter);  	adapter->ahw->diag_test = 0; -	adapter->max_sds_rings = max_sds_rings; -	adapter->max_drv_tx_rings = max_tx_rings; +	adapter->drv_sds_rings = drv_sds_rings; +	adapter->drv_tx_rings = drv_tx_rings;  	if (qlcnic_attach(adapter))  		goto out; @@ -1851,15 +2066,19 @@ static int qlcnic_alloc_adapter_resources(struct qlcnic_adapter *adapter)  		err = -ENOMEM;  		goto err_out;  	} -	/* Initialize interrupt coalesce parameters */ -	ahw->coal.flag = QLCNIC_INTR_DEFAULT; -	ahw->coal.type = QLCNIC_INTR_COAL_TYPE_RX; -	ahw->coal.rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US; -	ahw->coal.rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS; +  	if (qlcnic_83xx_check(adapter)) { +		ahw->coal.type = QLCNIC_INTR_COAL_TYPE_RX_TX;  		ahw->coal.tx_time_us = QLCNIC_DEF_INTR_COALESCE_TX_TIME_US;  		ahw->coal.tx_packets = QLCNIC_DEF_INTR_COALESCE_TX_PACKETS; +		ahw->coal.rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US; +		ahw->coal.rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS; +	} else { +		ahw->coal.type = QLCNIC_INTR_COAL_TYPE_RX; +		ahw->coal.rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US; +		ahw->coal.rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS;  	} +  	/* clear stats */  	memset(&adapter->stats, 0, sizeof(adapter->stats));  err_out: @@ -1868,12 +2087,20 @@ err_out:  static void qlcnic_free_adapter_resources(struct qlcnic_adapter *adapter)  { +	struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; +  	kfree(adapter->recv_ctx);  	adapter->recv_ctx = NULL; -	if (adapter->ahw->fw_dump.tmpl_hdr) { -		vfree(adapter->ahw->fw_dump.tmpl_hdr); -		adapter->ahw->fw_dump.tmpl_hdr = NULL; +	if (fw_dump->tmpl_hdr) { +		vfree(fw_dump->tmpl_hdr); +		fw_dump->tmpl_hdr = NULL; +	} + +	if (fw_dump->dma_buffer) { +		dma_free_coherent(&adapter->pdev->dev, QLC_PEX_DMA_READ_SIZE, +				  fw_dump->dma_buffer, fw_dump->phys_addr); +		fw_dump->dma_buffer = NULL;  	}  	kfree(adapter->ahw->reset.buff); @@ -1895,10 +2122,9 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test)  	qlcnic_detach(adapter); -	adapter->max_sds_rings = 1; +	adapter->drv_sds_rings = QLCNIC_SINGLE_RING;  	adapter->ahw->diag_test = test;  	adapter->ahw->linkup = 0; -	adapter->max_drv_tx_rings = 1;  	ret = qlcnic_attach(adapter);  	if (ret) { @@ -1919,9 +2145,9 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test)  	}  	if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) { -		for (ring = 0; ring < adapter->max_sds_rings; ring++) { +		for (ring = 0; ring < adapter->drv_sds_rings; ring++) {  			sds_ring = &adapter->recv_ctx->sds_rings[ring]; -			qlcnic_enable_int(sds_ring); +			qlcnic_enable_sds_intr(adapter, sds_ring);  		}  	} @@ -1953,7 +2179,7 @@ qlcnic_reset_hw_context(struct qlcnic_adapter *adapter)  	netif_device_attach(netdev);  	clear_bit(__QLCNIC_RESETTING, &adapter->state); -	dev_err(&adapter->pdev->dev, "%s:\n", __func__); +	netdev_info(adapter->netdev, "%s: soft reset complete\n", __func__);  	return 0;  } @@ -1990,10 +2216,10 @@ qlcnic_reset_context(struct qlcnic_adapter *adapter)  	return err;  } -void qlcnic_82xx_set_mac_filter_count(struct qlcnic_adapter *adapter) +static void qlcnic_82xx_set_mac_filter_count(struct qlcnic_adapter *adapter)  {  	struct qlcnic_hardware_context *ahw = adapter->ahw; -	u16 act_pci_fn = ahw->act_pci_func; +	u16 act_pci_fn = ahw->total_nic_func;  	u16 count;  	ahw->max_mc_count = QLCNIC_MAX_MC_COUNT; @@ -2006,6 +2232,31 @@ void qlcnic_82xx_set_mac_filter_count(struct qlcnic_adapter *adapter)  	ahw->max_uc_count = count;  } +static int qlcnic_set_real_num_queues(struct qlcnic_adapter *adapter, +				      u8 tx_queues, u8 rx_queues) +{ +	struct net_device *netdev = adapter->netdev; +	int err = 0; + +	if (tx_queues) { +		err = netif_set_real_num_tx_queues(netdev, tx_queues); +		if (err) { +			netdev_err(netdev, "failed to set %d Tx queues\n", +				   tx_queues); +			return err; +		} +	} + +	if (rx_queues) { +		err = netif_set_real_num_rx_queues(netdev, rx_queues); +		if (err) +			netdev_err(netdev, "failed to set %d Rx queues\n", +				   rx_queues); +	} + +	return err; +} +  int  qlcnic_setup_netdev(struct qlcnic_adapter *adapter, struct net_device *netdev,  		    int pci_using_dac) @@ -2022,10 +2273,8 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, struct net_device *netdev,  	qlcnic_change_mtu(netdev, netdev->mtu); -	if (qlcnic_sriov_vf_check(adapter)) -		SET_ETHTOOL_OPS(netdev, &qlcnic_sriov_vf_ethtool_ops); -	else -		SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_ops); +	netdev->ethtool_ops = (qlcnic_sriov_vf_check(adapter)) ? +		&qlcnic_sriov_vf_ethtool_ops : &qlcnic_ethtool_ops;  	netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM |  			     NETIF_F_IPV6_CSUM | NETIF_F_GRO | @@ -2052,11 +2301,25 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, struct net_device *netdev,  	if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)  		netdev->features |= NETIF_F_LRO; +	if (qlcnic_encap_tx_offload(adapter)) { +		netdev->features |= NETIF_F_GSO_UDP_TUNNEL; + +		/* encapsulation Tx offload supported by Adapter */ +		netdev->hw_enc_features = NETIF_F_IP_CSUM        | +					  NETIF_F_GSO_UDP_TUNNEL | +					  NETIF_F_TSO            | +					  NETIF_F_TSO6; +	} + +	if (qlcnic_encap_rx_offload(adapter)) +		netdev->hw_enc_features |= NETIF_F_RXCSUM; +  	netdev->hw_features = netdev->features;  	netdev->priv_flags |= IFF_UNICAST_FLT;  	netdev->irq = adapter->msix_entries[0].vector; -	err = qlcnic_set_real_num_queues(adapter, netdev); +	err = qlcnic_set_real_num_queues(adapter, adapter->drv_tx_rings, +					 adapter->drv_sds_rings);  	if (err)  		return err; @@ -2066,7 +2329,7 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, struct net_device *netdev,  		return err;  	} -	qlcnic_dcb_init_dcbnl_ops(adapter); +	qlcnic_dcb_init_dcbnl_ops(adapter->dcb);  	return 0;  } @@ -2092,7 +2355,7 @@ void qlcnic_free_tx_rings(struct qlcnic_adapter *adapter)  	int ring;  	struct qlcnic_host_tx_ring *tx_ring; -	for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) { +	for (ring = 0; ring < adapter->drv_tx_rings; ring++) {  		tx_ring = &adapter->tx_ring[ring];  		if (tx_ring && tx_ring->cmd_buf_arr != NULL) {  			vfree(tx_ring->cmd_buf_arr); @@ -2110,14 +2373,14 @@ int qlcnic_alloc_tx_rings(struct qlcnic_adapter *adapter,  	struct qlcnic_host_tx_ring *tx_ring;  	struct qlcnic_cmd_buffer *cmd_buf_arr; -	tx_ring = kcalloc(adapter->max_drv_tx_rings, +	tx_ring = kcalloc(adapter->drv_tx_rings,  			  sizeof(struct qlcnic_host_tx_ring), GFP_KERNEL);  	if (tx_ring == NULL)  		return -ENOMEM;  	adapter->tx_ring = tx_ring; -	for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) { +	for (ring = 0; ring < adapter->drv_tx_rings; ring++) {  		tx_ring = &adapter->tx_ring[ring];  		tx_ring->num_desc = adapter->num_txd;  		tx_ring->txq = netdev_get_tx_queue(netdev, ring); @@ -2128,15 +2391,16 @@ int qlcnic_alloc_tx_rings(struct qlcnic_adapter *adapter,  		}  		memset(cmd_buf_arr, 0, TX_BUFF_RINGSIZE(tx_ring));  		tx_ring->cmd_buf_arr = cmd_buf_arr; +		spin_lock_init(&tx_ring->tx_clean_lock);  	}  	if (qlcnic_83xx_check(adapter) ||  	    (qlcnic_82xx_check(adapter) && qlcnic_check_multi_tx(adapter))) { -		for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) { +		for (ring = 0; ring < adapter->drv_tx_rings; ring++) {  			tx_ring = &adapter->tx_ring[ring];  			tx_ring->adapter = adapter;  			if (adapter->flags & QLCNIC_MSIX_ENABLED) { -				index = adapter->max_sds_rings + ring; +				index = adapter->drv_sds_rings + ring;  				vector = adapter->msix_entries[index].vector;  				tx_ring->irq = vector;  			} @@ -2156,21 +2420,17 @@ void qlcnic_set_drv_version(struct qlcnic_adapter *adapter)  	else if (qlcnic_83xx_check(adapter))  		fw_cmd = QLCNIC_CMD_83XX_SET_DRV_VER; -	if ((ahw->capabilities & QLCNIC_FW_CAPABILITY_MORE_CAPS) && -	    (ahw->extra_capability[0] & QLCNIC_FW_CAPABILITY_SET_DRV_VER)) +	if (ahw->extra_capability[0] & QLCNIC_FW_CAPABILITY_SET_DRV_VER)  		qlcnic_fw_cmd_set_drv_version(adapter, fw_cmd);  } -static int qlcnic_register_dcb(struct qlcnic_adapter *adapter) +/* Reset firmware API lock */ +static void qlcnic_reset_api_lock(struct qlcnic_adapter *adapter)  { -	return __qlcnic_register_dcb(adapter); +	qlcnic_api_lock(adapter); +	qlcnic_api_unlock(adapter);  } -void qlcnic_clear_dcb_ops(struct qlcnic_adapter *adapter) -{ -	kfree(adapter->dcb); -	adapter->dcb = NULL; -}  static int  qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -2181,9 +2441,6 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  	int err, pci_using_dac = -1;  	char board_name[QLCNIC_MAX_BOARD_NAME_LEN + 19]; /* MAC + ": " + name */ -	if (pdev->is_virtfn) -		return -ENODEV; -  	err = pci_enable_device(pdev);  	if (err)  		return err; @@ -2254,10 +2511,11 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  	err = qlcnic_alloc_adapter_resources(adapter);  	if (err) -		goto err_out_free_netdev; +		goto err_out_free_wq;  	adapter->dev_rst_time = jiffies; -	adapter->ahw->revision_id = pdev->revision; +	ahw->revision_id = pdev->revision; +	ahw->max_vnic_func = qlcnic_get_vnic_func_count(adapter);  	if (qlcnic_mac_learn == FDB_MAC_LEARN)  		adapter->fdb_mac_learn = true;  	else if (qlcnic_mac_learn == DRV_MAC_LEARN) @@ -2273,44 +2531,57 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  	if (qlcnic_82xx_check(adapter)) {  		qlcnic_check_vf(adapter, ent);  		adapter->portnum = adapter->ahw->pci_func; +		qlcnic_reset_api_lock(adapter);  		err = qlcnic_start_firmware(adapter);  		if (err) { -			dev_err(&pdev->dev, "Loading fw failed.Please Reboot\n"); -			goto err_out_free_hw; +			dev_err(&pdev->dev, "Loading fw failed.Please Reboot\n" +				"\t\tIf reboot doesn't help, try flashing the card\n"); +			goto err_out_maintenance_mode;  		} -		qlcnic_get_multiq_capability(adapter); - -		if ((adapter->ahw->act_pci_func > 2) && -		    qlcnic_check_multi_tx(adapter)) { -			adapter->max_drv_tx_rings = QLCNIC_DEF_NUM_TX_RINGS; -			dev_info(&adapter->pdev->dev, -				 "vNIC mode enabled, Set max TX rings = %d\n", -				 adapter->max_drv_tx_rings); +		/* compute and set default and max tx/sds rings */ +		if (adapter->ahw->msix_supported) { +			if (qlcnic_check_multi_tx_capability(adapter) == 1) +				qlcnic_set_tx_ring_count(adapter, +							 QLCNIC_SINGLE_RING); +			else +				qlcnic_set_tx_ring_count(adapter, +							 QLCNIC_DEF_TX_RINGS); +			qlcnic_set_sds_ring_count(adapter, +						  QLCNIC_DEF_SDS_RINGS); +		} else { +			qlcnic_set_tx_ring_count(adapter, QLCNIC_SINGLE_RING); +			qlcnic_set_sds_ring_count(adapter, QLCNIC_SINGLE_RING);  		} -		if (!qlcnic_check_multi_tx(adapter)) { -			clear_bit(__QLCNIC_MULTI_TX_UNIQUE, &adapter->state); -			adapter->max_drv_tx_rings = 1; -		}  		err = qlcnic_setup_idc_param(adapter);  		if (err)  			goto err_out_free_hw;  		adapter->flags |= QLCNIC_NEED_FLR; -		if (adapter->dcb && qlcnic_dcb_attach(adapter)) -			qlcnic_clear_dcb_ops(adapter); -  	} else if (qlcnic_83xx_check(adapter)) { -		adapter->max_drv_tx_rings = 1;  		qlcnic_83xx_check_vf(adapter, ent);  		adapter->portnum = adapter->ahw->pci_func;  		err = qlcnic_83xx_init(adapter, pci_using_dac);  		if (err) { -			dev_err(&pdev->dev, "%s: failed\n", __func__); -			goto err_out_free_hw; +			switch (err) { +			case -ENOTRECOVERABLE: +				dev_err(&pdev->dev, "Adapter initialization failed due to a faulty hardware\n"); +				dev_err(&pdev->dev, "Please replace the adapter with new one and return the faulty adapter for repair\n"); +				goto err_out_free_hw; +			case -ENOMEM: +				dev_err(&pdev->dev, "Adapter initialization failed. Please reboot\n"); +				goto err_out_free_hw; +			case -EOPNOTSUPP: +				dev_err(&pdev->dev, "Adapter initialization failed\n"); +				goto err_out_free_hw; +			default: +				dev_err(&pdev->dev, "Adapter initialization failed. Driver will load in maintenance mode to recover the adapter using the application\n"); +				goto err_out_maintenance_mode; +			}  		} +  		if (qlcnic_sriov_vf_check(adapter))  			return 0;  	} else { @@ -2338,7 +2609,10 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  			 "Device does not support MSI interrupts\n");  	if (qlcnic_82xx_check(adapter)) { -		err = qlcnic_setup_intr(adapter, 0, 0); +		qlcnic_dcb_enable(adapter->dcb); +		qlcnic_dcb_get_info(adapter->dcb); +		err = qlcnic_setup_intr(adapter); +  		if (err) {  			dev_err(&pdev->dev, "Failed to setup interrupt\n");  			goto err_out_disable_msi; @@ -2377,7 +2651,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  		qlcnic_alloc_lb_filters_mem(adapter);  	qlcnic_add_sysfs(adapter); - +	qlcnic_register_hwmon_dev(adapter);  	return 0;  err_out_disable_mbx_intr: @@ -2392,6 +2666,9 @@ err_out_disable_msi:  err_out_free_hw:  	qlcnic_free_adapter_resources(adapter); +err_out_free_wq: +	destroy_workqueue(adapter->qlcnic_wq); +  err_out_free_netdev:  	free_netdev(netdev); @@ -2405,9 +2682,32 @@ err_out_free_res:  	pci_release_regions(pdev);  err_out_disable_pdev: -	pci_set_drvdata(pdev, NULL);  	pci_disable_device(pdev);  	return err; + +err_out_maintenance_mode: +	set_bit(__QLCNIC_MAINTENANCE_MODE, &adapter->state); +	netdev->netdev_ops = &qlcnic_netdev_failed_ops; +	netdev->ethtool_ops = &qlcnic_ethtool_failed_ops; +	ahw->port_type = QLCNIC_XGBE; + +	if (qlcnic_83xx_check(adapter)) +		adapter->tgt_status_reg = NULL; +	else +		ahw->board_type = QLCNIC_BRDTYPE_P3P_10G_SFP_PLUS; + +	err = register_netdev(netdev); + +	if (err) { +		dev_err(&pdev->dev, "Failed to register net device\n"); +		qlcnic_clr_all_drv_state(adapter, 0); +		goto err_out_free_hw; +	} + +	pci_set_drvdata(pdev, adapter); +	qlcnic_add_sysfs(adapter); + +	return 0;  }  static void qlcnic_remove(struct pci_dev *pdev) @@ -2421,18 +2721,16 @@ static void qlcnic_remove(struct pci_dev *pdev)  		return;  	netdev = adapter->netdev; -	qlcnic_sriov_pf_disable(adapter);  	qlcnic_cancel_idc_work(adapter); +	qlcnic_sriov_pf_disable(adapter);  	ahw = adapter->ahw; -	qlcnic_dcb_free(adapter); -  	unregister_netdev(netdev);  	qlcnic_sriov_cleanup(adapter);  	if (qlcnic_83xx_check(adapter)) { -		qlcnic_83xx_register_nic_idc_func(adapter, 0); +		qlcnic_83xx_initialize_nic(adapter, 0);  		cancel_delayed_work_sync(&adapter->idc_aen_work);  		qlcnic_83xx_free_mbx_intr(adapter);  		qlcnic_83xx_detach_mailbox_work(adapter); @@ -2440,6 +2738,8 @@ static void qlcnic_remove(struct pci_dev *pdev)  		kfree(ahw->fw_info);  	} +	qlcnic_dcb_free(adapter->dcb); +  	qlcnic_detach(adapter);  	if (adapter->npars != NULL) @@ -2458,6 +2758,8 @@ static void qlcnic_remove(struct pci_dev *pdev)  	qlcnic_remove_sysfs(adapter); +	qlcnic_unregister_hwmon_dev(adapter); +  	qlcnic_cleanup_pci_map(adapter->ahw);  	qlcnic_release_firmware(adapter); @@ -2465,7 +2767,6 @@ static void qlcnic_remove(struct pci_dev *pdev)  	pci_disable_pcie_error_reporting(pdev);  	pci_release_regions(pdev);  	pci_disable_device(pdev); -	pci_set_drvdata(pdev, NULL);  	if (adapter->qlcnic_wq) {  		destroy_workqueue(adapter->qlcnic_wq); @@ -2520,6 +2821,13 @@ static int qlcnic_open(struct net_device *netdev)  	struct qlcnic_adapter *adapter = netdev_priv(netdev);  	int err; +	if (test_bit(__QLCNIC_MAINTENANCE_MODE, &adapter->state)) { +		netdev_err(netdev, "%s: Device is in non-operational state\n", +			   __func__); + +		return -EIO; +	} +  	netif_carrier_off(netdev);  	err = qlcnic_attach(adapter); @@ -2528,14 +2836,8 @@ static int qlcnic_open(struct net_device *netdev)  	err = __qlcnic_up(adapter, netdev);  	if (err) -		goto err_out; - -	netif_tx_start_all_queues(netdev); - -	return 0; +		qlcnic_detach(adapter); -err_out: -	qlcnic_detach(adapter);  	return err;  } @@ -2551,6 +2853,8 @@ static int qlcnic_close(struct net_device *netdev)  	return 0;  } +#define QLCNIC_VF_LB_BUCKET_SIZE 1 +  void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter)  {  	void *head; @@ -2562,11 +2866,14 @@ void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter)  	if (adapter->fhash.fmax && adapter->fhash.fhead)  		return; -	act_pci_func = adapter->ahw->act_pci_func; +	act_pci_func = adapter->ahw->total_nic_func;  	spin_lock_init(&adapter->mac_learn_lock);  	spin_lock_init(&adapter->rx_mac_learn_lock); -	if (qlcnic_82xx_check(adapter)) { +	if (qlcnic_sriov_vf_check(adapter)) { +		filter_size = QLCNIC_83XX_SRIOV_VF_MAX_MAC - 1; +		adapter->fhash.fbucket_size = QLCNIC_VF_LB_BUCKET_SIZE; +	} else if (qlcnic_82xx_check(adapter)) {  		filter_size = QLCNIC_LB_MAX_FILTERS;  		adapter->fhash.fbucket_size = QLCNIC_LB_BUCKET_SIZE;  	} else { @@ -2659,12 +2966,62 @@ int qlcnic_check_temp(struct qlcnic_adapter *adapter)  	return rv;  } -static void qlcnic_tx_timeout(struct net_device *netdev) +static inline void dump_tx_ring_desc(struct qlcnic_host_tx_ring *tx_ring)  { -	struct qlcnic_adapter *adapter = netdev_priv(netdev); +	int i; +	struct cmd_desc_type0 *tx_desc_info; + +	for (i = 0; i < tx_ring->num_desc; i++) { +		tx_desc_info = &tx_ring->desc_head[i]; +		pr_info("TX Desc: %d\n", i); +		print_hex_dump(KERN_INFO, "TX: ", DUMP_PREFIX_OFFSET, 16, 1, +			       &tx_ring->desc_head[i], +			       sizeof(struct cmd_desc_type0), true); +	} +} + +static void qlcnic_dump_tx_rings(struct qlcnic_adapter *adapter) +{ +	struct net_device *netdev = adapter->netdev;  	struct qlcnic_host_tx_ring *tx_ring;  	int ring; +	if (!netdev || !netif_running(netdev)) +		return; + +	for (ring = 0; ring < adapter->drv_tx_rings; ring++) { +		tx_ring = &adapter->tx_ring[ring]; +		netdev_info(netdev, "Tx ring=%d Context Id=0x%x\n", +			    ring, tx_ring->ctx_id); +		netdev_info(netdev, +			    "xmit_finished=%llu, xmit_called=%llu, xmit_on=%llu, xmit_off=%llu\n", +			    tx_ring->tx_stats.xmit_finished, +			    tx_ring->tx_stats.xmit_called, +			    tx_ring->tx_stats.xmit_on, +			    tx_ring->tx_stats.xmit_off); + +		if (tx_ring->crb_intr_mask) +			netdev_info(netdev, "crb_intr_mask=%d\n", +				    readl(tx_ring->crb_intr_mask)); + +		netdev_info(netdev, +			    "hw_producer=%d, sw_producer=%d sw_consumer=%d, hw_consumer=%d\n", +			    readl(tx_ring->crb_cmd_producer), +			    tx_ring->producer, tx_ring->sw_consumer, +			    le32_to_cpu(*(tx_ring->hw_consumer))); + +		netdev_info(netdev, "Total desc=%d, Available desc=%d\n", +			    tx_ring->num_desc, qlcnic_tx_avail(tx_ring)); + +		if (netif_msg_tx_done(adapter->ahw)) +			dump_tx_ring_desc(tx_ring); +	} +} + +static void qlcnic_tx_timeout(struct net_device *netdev) +{ +	struct qlcnic_adapter *adapter = netdev_priv(netdev); +  	if (test_bit(__QLCNIC_RESETTING, &adapter->state))  		return; @@ -2677,25 +3034,7 @@ static void qlcnic_tx_timeout(struct net_device *netdev)  						      QLCNIC_FORCE_FW_DUMP_KEY);  	} else {  		netdev_info(netdev, "Tx timeout, reset adapter context.\n"); -		if (qlcnic_82xx_check(adapter)) { -			for (ring = 0; ring < adapter->max_drv_tx_rings; -			     ring++) { -				tx_ring = &adapter->tx_ring[ring]; -				dev_info(&netdev->dev, "ring=%d\n", ring); -				dev_info(&netdev->dev, "crb_intr_mask=%d\n", -					 readl(tx_ring->crb_intr_mask)); -				dev_info(&netdev->dev, "producer=%d\n", -					 readl(tx_ring->crb_cmd_producer)); -				dev_info(&netdev->dev, "sw_consumer = %d\n", -					 tx_ring->sw_consumer); -				dev_info(&netdev->dev, "hw_consumer = %d\n", -					 le32_to_cpu(*(tx_ring->hw_consumer))); -				dev_info(&netdev->dev, "xmit-on=%llu\n", -					 tx_ring->xmit_on); -				dev_info(&netdev->dev, "xmit-off=%llu\n", -					 tx_ring->xmit_off); -			} -		} +		qlcnic_dump_tx_rings(adapter);  		adapter->ahw->reset_context = 1;  	}  } @@ -2705,6 +3044,9 @@ static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev)  	struct qlcnic_adapter *adapter = netdev_priv(netdev);  	struct net_device_stats *stats = &netdev->stats; +	if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) +		qlcnic_update_stats(adapter); +  	stats->rx_packets = adapter->stats.rx_pkts + adapter->stats.lro_pkts;  	stats->tx_packets = adapter->stats.xmitfinished;  	stats->rx_bytes = adapter->stats.rxbytes + adapter->stats.lrobytes; @@ -2715,7 +3057,7 @@ static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev)  	return stats;  } -irqreturn_t qlcnic_82xx_clear_legacy_intr(struct qlcnic_adapter *adapter) +static irqreturn_t qlcnic_82xx_clear_legacy_intr(struct qlcnic_adapter *adapter)  {  	u32 status; @@ -2754,7 +3096,7 @@ static irqreturn_t qlcnic_tmp_intr(int irq, void *data)  done:  	adapter->ahw->diag_cnt++; -	qlcnic_enable_int(sds_ring); +	qlcnic_enable_sds_intr(adapter, sds_ring);  	return IRQ_HANDLED;  } @@ -2802,17 +3144,39 @@ static irqreturn_t qlcnic_msix_tx_intr(int irq, void *data)  #ifdef CONFIG_NET_POLL_CONTROLLER  static void qlcnic_poll_controller(struct net_device *netdev)  { -	int ring; -	struct qlcnic_host_sds_ring *sds_ring;  	struct qlcnic_adapter *adapter = netdev_priv(netdev); -	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; +	struct qlcnic_host_sds_ring *sds_ring; +	struct qlcnic_recv_context *recv_ctx; +	struct qlcnic_host_tx_ring *tx_ring; +	int ring; + +	if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) +		return; + +	recv_ctx = adapter->recv_ctx; -	disable_irq(adapter->irq); -	for (ring = 0; ring < adapter->max_sds_rings; ring++) { +	for (ring = 0; ring < adapter->drv_sds_rings; ring++) {  		sds_ring = &recv_ctx->sds_rings[ring]; -		qlcnic_intr(adapter->irq, sds_ring); +		qlcnic_disable_sds_intr(adapter, sds_ring); +		napi_schedule(&sds_ring->napi); +	} + +	if (adapter->flags & QLCNIC_MSIX_ENABLED) { +		/* Only Multi-Tx queue capable devices need to +		 * schedule NAPI for TX rings +		 */ +		if ((qlcnic_83xx_check(adapter) && +		     (adapter->flags & QLCNIC_TX_INTR_SHARED)) || +		    (qlcnic_82xx_check(adapter) && +		     !qlcnic_check_multi_tx(adapter))) +			return; + +		for (ring = 0; ring < adapter->drv_tx_rings; ring++) { +			tx_ring = &adapter->tx_ring[ring]; +			qlcnic_disable_tx_intr(adapter, tx_ring); +			napi_schedule(&tx_ring->napi); +		}  	} -	enable_irq(adapter->irq);  }  #endif @@ -3208,7 +3572,8 @@ qlcnic_set_npar_non_operational(struct qlcnic_adapter *adapter)  	qlcnic_api_unlock(adapter);  } -void qlcnic_82xx_dev_request_reset(struct qlcnic_adapter *adapter, u32 key) +static void qlcnic_82xx_dev_request_reset(struct qlcnic_adapter *adapter, +					  u32 key)  {  	u32 state, xg_val = 0, gb_val = 0; @@ -3229,6 +3594,14 @@ void qlcnic_82xx_dev_request_reset(struct qlcnic_adapter *adapter, u32 key)  	state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE); +	if (test_bit(__QLCNIC_MAINTENANCE_MODE, &adapter->state)) { +		netdev_err(adapter->netdev, "%s: Device is in non-operational state\n", +			   __func__); +		qlcnic_api_unlock(adapter); + +		return; +	} +  	if (state == QLCNIC_DEV_READY) {  		QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE,  				    QLCNIC_DEV_NEED_RESET); @@ -3289,7 +3662,7 @@ qlcnic_attach_work(struct work_struct *work)  		return;  	}  attach: -	qlcnic_dcb_get_info(adapter); +	qlcnic_dcb_get_info(adapter->dcb);  	if (netif_running(netdev)) {  		if (qlcnic_up(adapter, netdev)) @@ -3314,6 +3687,8 @@ done:  static int  qlcnic_check_health(struct qlcnic_adapter *adapter)  { +	struct qlcnic_hardware_context *ahw = adapter->ahw; +	struct qlcnic_fw_dump *fw_dump = &ahw->fw_dump;  	u32 state = 0, heartbeat;  	u32 peg_status;  	int err = 0; @@ -3338,7 +3713,7 @@ qlcnic_check_health(struct qlcnic_adapter *adapter)  		if (adapter->need_fw_reset)  			goto detach; -		if (adapter->ahw->reset_context && qlcnic_auto_fw_reset) +		if (ahw->reset_context && qlcnic_auto_fw_reset)  			qlcnic_reset_hw_context(adapter);  		return 0; @@ -3381,6 +3756,9 @@ detach:  		qlcnic_schedule_work(adapter, qlcnic_detach_work, 0);  		QLCDB(adapter, DRV, "fw recovery scheduled.\n"); +	} else if (!qlcnic_auto_fw_reset && fw_dump->enable && +		   adapter->flags & QLCNIC_FW_RESET_OWNER) { +		qlcnic_dump_fw(adapter);  	}  	return 1; @@ -3462,7 +3840,7 @@ static int qlcnic_attach_func(struct pci_dev *pdev)  	qlcnic_clr_drv_state(adapter);  	kfree(adapter->msix_entries);  	adapter->msix_entries = NULL; -	err = qlcnic_setup_intr(adapter, 0, 0); +	err = qlcnic_setup_intr(adapter);  	if (err) {  		kfree(adapter->msix_entries); @@ -3490,8 +3868,8 @@ static int qlcnic_attach_func(struct pci_dev *pdev)  	return err;  } -pci_ers_result_t qlcnic_82xx_io_error_detected(struct pci_dev *pdev, -					       pci_channel_state_t state) +static pci_ers_result_t qlcnic_82xx_io_error_detected(struct pci_dev *pdev, +						      pci_channel_state_t state)  {  	struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);  	struct net_device *netdev = adapter->netdev; @@ -3521,13 +3899,13 @@ pci_ers_result_t qlcnic_82xx_io_error_detected(struct pci_dev *pdev,  	return PCI_ERS_RESULT_NEED_RESET;  } -pci_ers_result_t qlcnic_82xx_io_slot_reset(struct pci_dev *pdev) +static pci_ers_result_t qlcnic_82xx_io_slot_reset(struct pci_dev *pdev)  {  	return qlcnic_attach_func(pdev) ? PCI_ERS_RESULT_DISCONNECT :  				PCI_ERS_RESULT_RECOVERED;  } -void qlcnic_82xx_io_resume(struct pci_dev *pdev) +static void qlcnic_82xx_io_resume(struct pci_dev *pdev)  {  	u32 state;  	struct qlcnic_adapter *adapter = pci_get_drvdata(pdev); @@ -3607,145 +3985,97 @@ qlcnicvf_start_firmware(struct qlcnic_adapter *adapter)  	return err;  } -int qlcnic_validate_max_tx_rings(struct qlcnic_adapter *adapter, u32 txq) +int qlcnic_validate_rings(struct qlcnic_adapter *adapter, __u32 ring_cnt, +			  int queue_type)  {  	struct net_device *netdev = adapter->netdev; -	u8 max_hw = QLCNIC_MAX_TX_RINGS; -	u32 max_allowed; - -	if (!qlcnic_82xx_check(adapter)) { -		netdev_err(netdev, "No Multi TX-Q support\n"); -		return -EINVAL; -	} - -	if (!qlcnic_use_msi_x && !qlcnic_use_msi) { -		netdev_err(netdev, "No Multi TX-Q support in INT-x mode\n"); -		return -EINVAL; +	u8 max_hw_rings = 0; +	char buf[8]; +	int cur_rings; + +	if (queue_type == QLCNIC_RX_QUEUE) { +		max_hw_rings = adapter->max_sds_rings; +		cur_rings = adapter->drv_sds_rings; +		strcpy(buf, "SDS"); +	} else if (queue_type == QLCNIC_TX_QUEUE) { +		max_hw_rings = adapter->max_tx_rings; +		cur_rings = adapter->drv_tx_rings; +		strcpy(buf, "Tx");  	} -	if (!qlcnic_check_multi_tx(adapter)) { -		netdev_err(netdev, "No Multi TX-Q support\n"); +	if (!is_power_of_2(ring_cnt)) { +		netdev_err(netdev, "%s rings value should be a power of 2\n", +			   buf);  		return -EINVAL;  	} -	if (txq > QLCNIC_MAX_TX_RINGS) { -		netdev_err(netdev, "Invalid ring count\n"); -		return -EINVAL; +	if (qlcnic_82xx_check(adapter) && (queue_type == QLCNIC_TX_QUEUE) && +	    !qlcnic_check_multi_tx(adapter)) { +			netdev_err(netdev, "No Multi Tx queue support\n"); +			return -EINVAL;  	} -	max_allowed = rounddown_pow_of_two(min_t(int, max_hw, -						 num_online_cpus())); -	if ((txq > max_allowed) || !is_power_of_2(txq)) { -		if (!is_power_of_2(txq)) -			netdev_err(netdev, -				   "TX queue should be a power of 2\n"); -		if (txq > num_online_cpus()) -			netdev_err(netdev, -				   "Tx queue should not be higher than [%u], number of online CPUs in the system\n", -				   num_online_cpus()); -		netdev_err(netdev, "Unable to configure %u Tx rings\n", txq); +	if (ring_cnt > num_online_cpus()) { +		netdev_err(netdev, +			   "%s value[%u] should not be higher than, number of online CPUs\n", +			   buf, num_online_cpus());  		return -EINVAL;  	}  	return 0;  } -int qlcnic_validate_max_rss(struct qlcnic_adapter *adapter, -				__u32 val) +int qlcnic_setup_rings(struct qlcnic_adapter *adapter)  {  	struct net_device *netdev = adapter->netdev; -	u8 max_hw = adapter->ahw->max_rx_ques; -	u32 max_allowed; - -	if (qlcnic_82xx_check(adapter) && !qlcnic_use_msi_x && -	    !qlcnic_use_msi) { -		netdev_err(netdev, "No RSS support in INT-x mode\n"); -		return -EINVAL; -	} - -	if (val > QLCNIC_MAX_SDS_RINGS) { -		netdev_err(netdev, "RSS value should not be higher than %u\n", -			   QLCNIC_MAX_SDS_RINGS); -		return -EINVAL; -	} - -	max_allowed = rounddown_pow_of_two(min_t(int, max_hw, -						 num_online_cpus())); -	if ((val > max_allowed) || (val < 2) || !is_power_of_2(val)) { -		if (!is_power_of_2(val)) -			netdev_err(netdev, "RSS value should be a power of 2\n"); - -		if (val < 2) -			netdev_err(netdev, "RSS value should not be lower than 2\n"); - -		if (val > max_hw) -			netdev_err(netdev, -				   "RSS value should not be higher than[%u], the max RSS rings supported by the adapter\n", -				   max_hw); - -		if (val > num_online_cpus()) -			netdev_err(netdev, -				   "RSS value should not be higher than[%u], number of online CPUs in the system\n", -				   num_online_cpus()); - -		netdev_err(netdev, "Unable to configure %u RSS rings\n", val); - -		return -EINVAL; -	} -	return 0; -} - -int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data, int txq) -{ +	u8 tx_rings, rx_rings;  	int err; -	struct net_device *netdev = adapter->netdev; -	int num_msix;  	if (test_bit(__QLCNIC_RESETTING, &adapter->state))  		return -EBUSY; -	if (qlcnic_82xx_check(adapter) && !qlcnic_use_msi_x && -	    !qlcnic_use_msi) { -		netdev_err(netdev, "No RSS support in INT-x mode\n"); -		return -EINVAL; -	} +	tx_rings = adapter->drv_tss_rings; +	rx_rings = adapter->drv_rss_rings;  	netif_device_detach(netdev); + +	err = qlcnic_set_real_num_queues(adapter, tx_rings, rx_rings); +	if (err) +		goto done; +  	if (netif_running(netdev))  		__qlcnic_down(adapter, netdev);  	qlcnic_detach(adapter); -	if (qlcnic_82xx_check(adapter)) { -		if (txq != 0) -			adapter->max_drv_tx_rings = txq; - -		if (qlcnic_check_multi_tx(adapter) && -		    (txq > adapter->max_drv_tx_rings)) -			num_msix = adapter->max_drv_tx_rings; -		else -			num_msix = data; -	} -  	if (qlcnic_83xx_check(adapter)) {  		qlcnic_83xx_free_mbx_intr(adapter);  		qlcnic_83xx_enable_mbx_poll(adapter);  	} -	netif_set_real_num_tx_queues(netdev, adapter->max_drv_tx_rings); -  	qlcnic_teardown_intr(adapter); -	err = qlcnic_setup_intr(adapter, data, txq); +	err = qlcnic_setup_intr(adapter);  	if (err) {  		kfree(adapter->msix_entries);  		netdev_err(netdev, "failed to setup interrupt\n");  		return err;  	} +	/* Check if we need to update real_num_{tx|rx}_queues because +	 * qlcnic_setup_intr() may change Tx/Rx rings size +	 */ +	if ((tx_rings != adapter->drv_tx_rings) || +	    (rx_rings != adapter->drv_sds_rings)) { +		err = qlcnic_set_real_num_queues(adapter, +						 adapter->drv_tx_rings, +						 adapter->drv_sds_rings); +		if (err) +			goto done; +	} +  	if (qlcnic_83xx_check(adapter)) { -		/* register for NIC IDC AEN Events */ -		qlcnic_83xx_register_nic_idc_func(adapter, 1); +		qlcnic_83xx_initialize_nic(adapter, 1);  		err = qlcnic_83xx_setup_mbx_intr(adapter);  		qlcnic_83xx_disable_mbx_poll(adapter);  		if (err) { @@ -3812,7 +4142,7 @@ void qlcnic_restore_indev_addr(struct net_device *netdev, unsigned long event)  	rcu_read_lock();  	for_each_set_bit(vid, adapter->vlans, VLAN_N_VID) { -		dev = __vlan_find_dev_deep(netdev, htons(ETH_P_8021Q), vid); +		dev = __vlan_find_dev_deep_rcu(netdev, htons(ETH_P_8021Q), vid);  		if (!dev)  			continue;  		qlcnic_config_indev_addr(adapter, dev, event); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c index 15513608d48..e46fc39d425 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c @@ -211,6 +211,114 @@ enum qlcnic_minidump_opcode {  	QLCNIC_DUMP_RDEND	= 255  }; +inline u32 qlcnic_82xx_get_saved_state(void *t_hdr, u32 index) +{ +	struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr; + +	return hdr->saved_state[index]; +} + +inline void qlcnic_82xx_set_saved_state(void *t_hdr, u32 index, +					u32 value) +{ +	struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr; + +	hdr->saved_state[index] = value; +} + +void qlcnic_82xx_cache_tmpl_hdr_values(struct qlcnic_fw_dump *fw_dump) +{ +	struct qlcnic_82xx_dump_template_hdr *hdr; + +	hdr = fw_dump->tmpl_hdr; +	fw_dump->tmpl_hdr_size = hdr->size; +	fw_dump->version = hdr->version; +	fw_dump->num_entries = hdr->num_entries; +	fw_dump->offset = hdr->offset; + +	hdr->drv_cap_mask = hdr->cap_mask; +	fw_dump->cap_mask = hdr->cap_mask; + +	fw_dump->use_pex_dma = (hdr->capabilities & BIT_0) ? true : false; +} + +inline u32 qlcnic_82xx_get_cap_size(void *t_hdr, int index) +{ +	struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr; + +	return hdr->cap_sizes[index]; +} + +void qlcnic_82xx_set_sys_info(void *t_hdr, int idx, u32 value) +{ +	struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr; + +	hdr->sys_info[idx] = value; +} + +void qlcnic_82xx_store_cap_mask(void *tmpl_hdr, u32 mask) +{ +	struct qlcnic_82xx_dump_template_hdr *hdr = tmpl_hdr; + +	hdr->drv_cap_mask = mask; +} + +inline u32 qlcnic_83xx_get_saved_state(void *t_hdr, u32 index) +{ +	struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr; + +	return hdr->saved_state[index]; +} + +inline void qlcnic_83xx_set_saved_state(void *t_hdr, u32 index, +					u32 value) +{ +	struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr; + +	hdr->saved_state[index] = value; +} + +#define QLCNIC_TEMPLATE_VERSION (0x20001) + +void qlcnic_83xx_cache_tmpl_hdr_values(struct qlcnic_fw_dump *fw_dump) +{ +	struct qlcnic_83xx_dump_template_hdr *hdr; + +	hdr = fw_dump->tmpl_hdr; +	fw_dump->tmpl_hdr_size = hdr->size; +	fw_dump->version = hdr->version; +	fw_dump->num_entries = hdr->num_entries; +	fw_dump->offset = hdr->offset; + +	hdr->drv_cap_mask = hdr->cap_mask; +	fw_dump->cap_mask = hdr->cap_mask; + +	fw_dump->use_pex_dma = (fw_dump->version & 0xfffff) >= +			       QLCNIC_TEMPLATE_VERSION; +} + +inline u32 qlcnic_83xx_get_cap_size(void *t_hdr, int index) +{ +	struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr; + +	return hdr->cap_sizes[index]; +} + +void qlcnic_83xx_set_sys_info(void *t_hdr, int idx, u32 value) +{ +	struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr; + +	hdr->sys_info[idx] = value; +} + +void qlcnic_83xx_store_cap_mask(void *tmpl_hdr, u32 mask) +{ +	struct qlcnic_83xx_dump_template_hdr *hdr; + +	hdr = tmpl_hdr; +	hdr->drv_cap_mask = mask; +} +  struct qlcnic_dump_operations {  	enum qlcnic_minidump_opcode opcode;  	u32 (*handler)(struct qlcnic_adapter *, struct qlcnic_dump_entry *, @@ -238,11 +346,11 @@ static u32 qlcnic_dump_crb(struct qlcnic_adapter *adapter,  static u32 qlcnic_dump_ctrl(struct qlcnic_adapter *adapter,  			    struct qlcnic_dump_entry *entry, __le32 *buffer)  { +	void *hdr = adapter->ahw->fw_dump.tmpl_hdr; +	struct __ctrl *ctr = &entry->region.ctrl;  	int i, k, timeout = 0; -	u32 addr, data; +	u32 addr, data, temp;  	u8 no_ops; -	struct __ctrl *ctr = &entry->region.ctrl; -	struct qlcnic_dump_template_hdr *t_hdr = adapter->ahw->fw_dump.tmpl_hdr;  	addr = ctr->addr;  	no_ops = ctr->no_ops; @@ -285,29 +393,42 @@ static u32 qlcnic_dump_ctrl(struct qlcnic_adapter *adapter,  				}  				break;  			case QLCNIC_DUMP_RD_SAVE: -				if (ctr->index_a) -					addr = t_hdr->saved_state[ctr->index_a]; +				temp = ctr->index_a; +				if (temp) +					addr = qlcnic_get_saved_state(adapter, +								      hdr, +								      temp);  				data = qlcnic_ind_rd(adapter, addr); -				t_hdr->saved_state[ctr->index_v] = data; +				qlcnic_set_saved_state(adapter, hdr, +						       ctr->index_v, data);  				break;  			case QLCNIC_DUMP_WRT_SAVED: -				if (ctr->index_v) -					data = t_hdr->saved_state[ctr->index_v]; +				temp = ctr->index_v; +				if (temp) +					data = qlcnic_get_saved_state(adapter, +								      hdr, +								      temp);  				else  					data = ctr->val1; -				if (ctr->index_a) -					addr = t_hdr->saved_state[ctr->index_a]; + +				temp = ctr->index_a; +				if (temp) +					addr = qlcnic_get_saved_state(adapter, +								      hdr, +								      temp);  				qlcnic_ind_wr(adapter, addr, data);  				break;  			case QLCNIC_DUMP_MOD_SAVE_ST: -				data = t_hdr->saved_state[ctr->index_v]; +				data = qlcnic_get_saved_state(adapter, hdr, +							      ctr->index_v);  				data <<= ctr->shl_val;  				data >>= ctr->shr_val;  				if (ctr->val2)  					data &= ctr->val2;  				data |= ctr->val3;  				data += ctr->val1; -				t_hdr->saved_state[ctr->index_v] = data; +				qlcnic_set_saved_state(adapter, hdr, +						       ctr->index_v, data);  				break;  			default:  				dev_info(&adapter->pdev->dev, @@ -539,34 +660,31 @@ out:  #define QLC_DMA_CMD_BUFF_ADDR_HI	4  #define QLC_DMA_CMD_STATUS_CTRL		8 -#define QLC_PEX_DMA_READ_SIZE		(PAGE_SIZE * 16) -  static int qlcnic_start_pex_dma(struct qlcnic_adapter *adapter,  				struct __mem *mem)  { -	struct qlcnic_dump_template_hdr *tmpl_hdr;  	struct device *dev = &adapter->pdev->dev;  	u32 dma_no, dma_base_addr, temp_addr;  	int i, ret, dma_sts; +	void *tmpl_hdr;  	tmpl_hdr = adapter->ahw->fw_dump.tmpl_hdr; -	dma_no = tmpl_hdr->saved_state[QLC_83XX_DMA_ENGINE_INDEX]; +	dma_no = qlcnic_get_saved_state(adapter, tmpl_hdr, +					QLC_83XX_DMA_ENGINE_INDEX);  	dma_base_addr = QLC_DMA_REG_BASE_ADDR(dma_no);  	temp_addr = dma_base_addr + QLC_DMA_CMD_BUFF_ADDR_LOW; -	ret = qlcnic_83xx_wrt_reg_indirect(adapter, temp_addr, -					   mem->desc_card_addr); +	ret = qlcnic_ind_wr(adapter, temp_addr, mem->desc_card_addr);  	if (ret)  		return ret;  	temp_addr = dma_base_addr + QLC_DMA_CMD_BUFF_ADDR_HI; -	ret = qlcnic_83xx_wrt_reg_indirect(adapter, temp_addr, 0); +	ret = qlcnic_ind_wr(adapter, temp_addr, 0);  	if (ret)  		return ret;  	temp_addr = dma_base_addr + QLC_DMA_CMD_STATUS_CTRL; -	ret = qlcnic_83xx_wrt_reg_indirect(adapter, temp_addr, -					   mem->start_dma_cmd); +	ret = qlcnic_ind_wr(adapter, temp_addr, mem->start_dma_cmd);  	if (ret)  		return ret; @@ -596,15 +714,16 @@ static u32 qlcnic_read_memory_pexdma(struct qlcnic_adapter *adapter,  	struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;  	u32 temp, dma_base_addr, size = 0, read_size = 0;  	struct qlcnic_pex_dma_descriptor *dma_descr; -	struct qlcnic_dump_template_hdr *tmpl_hdr;  	struct device *dev = &adapter->pdev->dev;  	dma_addr_t dma_phys_addr;  	void *dma_buffer; +	void *tmpl_hdr;  	tmpl_hdr = fw_dump->tmpl_hdr;  	/* Check if DMA engine is available */ -	temp = tmpl_hdr->saved_state[QLC_83XX_DMA_ENGINE_INDEX]; +	temp = qlcnic_get_saved_state(adapter, tmpl_hdr, +				      QLC_83XX_DMA_ENGINE_INDEX);  	dma_base_addr = QLC_DMA_REG_BASE_ADDR(temp);  	temp = qlcnic_ind_rd(adapter,  			     dma_base_addr + QLC_DMA_CMD_STATUS_CTRL); @@ -650,8 +769,8 @@ static u32 qlcnic_read_memory_pexdma(struct qlcnic_adapter *adapter,  		/* Write DMA descriptor to MS memory*/  		temp = sizeof(struct qlcnic_pex_dma_descriptor) / 16; -		*ret = qlcnic_83xx_ms_mem_write128(adapter, mem->desc_card_addr, -						   (u32 *)dma_descr, temp); +		*ret = qlcnic_ms_mem_write128(adapter, mem->desc_card_addr, +					      (u32 *)dma_descr, temp);  		if (*ret) {  			dev_info(dev, "Failed to write DMA descriptor to MS memory at address 0x%x\n",  				 mem->desc_card_addr); @@ -938,8 +1057,8 @@ static int  qlcnic_fw_flash_get_minidump_temp_size(struct qlcnic_adapter *adapter,  				       struct qlcnic_cmd_args *cmd)  { -	struct qlcnic_dump_template_hdr tmp_hdr; -	u32 size = sizeof(struct qlcnic_dump_template_hdr) / sizeof(u32); +	struct qlcnic_83xx_dump_template_hdr tmp_hdr; +	u32 size = sizeof(tmp_hdr) / sizeof(u32);  	int ret = 0;  	if (qlcnic_82xx_check(adapter)) @@ -1029,15 +1148,16 @@ free_mem:  int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)  { -	int err; -	u32 temp_size = 0; -	u32 version, csum, *tmp_buf;  	struct qlcnic_hardware_context *ahw; -	struct qlcnic_dump_template_hdr *tmpl_hdr; +	struct qlcnic_fw_dump *fw_dump; +	u32 version, csum, *tmp_buf;  	u8 use_flash_temp = 0; +	u32 temp_size = 0; +	void *temp_buffer; +	int err;  	ahw = adapter->ahw; - +	fw_dump = &ahw->fw_dump;  	err = qlcnic_fw_get_minidump_temp_size(adapter, &version, &temp_size,  					       &use_flash_temp);  	if (err) { @@ -1046,11 +1166,11 @@ int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)  		return -EIO;  	} -	ahw->fw_dump.tmpl_hdr = vzalloc(temp_size); -	if (!ahw->fw_dump.tmpl_hdr) +	fw_dump->tmpl_hdr = vzalloc(temp_size); +	if (!fw_dump->tmpl_hdr)  		return -ENOMEM; -	tmp_buf = (u32 *)ahw->fw_dump.tmpl_hdr; +	tmp_buf = (u32 *)fw_dump->tmpl_hdr;  	if (use_flash_temp)  		goto flash_temp; @@ -1065,8 +1185,8 @@ flash_temp:  			dev_err(&adapter->pdev->dev,  				"Failed to get minidump template header %d\n",  				err); -			vfree(ahw->fw_dump.tmpl_hdr); -			ahw->fw_dump.tmpl_hdr = NULL; +			vfree(fw_dump->tmpl_hdr); +			fw_dump->tmpl_hdr = NULL;  			return -EIO;  		}  	} @@ -1076,21 +1196,29 @@ flash_temp:  	if (csum) {  		dev_err(&adapter->pdev->dev,  			"Template header checksum validation failed\n"); -		vfree(ahw->fw_dump.tmpl_hdr); -		ahw->fw_dump.tmpl_hdr = NULL; +		vfree(fw_dump->tmpl_hdr); +		fw_dump->tmpl_hdr = NULL;  		return -EIO;  	} -	tmpl_hdr = ahw->fw_dump.tmpl_hdr; -	tmpl_hdr->drv_cap_mask = tmpl_hdr->cap_mask; +	qlcnic_cache_tmpl_hdr_values(adapter, fw_dump); + +	if (fw_dump->use_pex_dma) { +		fw_dump->dma_buffer = NULL; +		temp_buffer = dma_alloc_coherent(&adapter->pdev->dev, +						 QLC_PEX_DMA_READ_SIZE, +						 &fw_dump->phys_addr, +						 GFP_KERNEL); +		if (!temp_buffer) +			fw_dump->use_pex_dma = false; +		else +			fw_dump->dma_buffer = temp_buffer; +	} + +  	dev_info(&adapter->pdev->dev,  		 "Default minidump capture mask 0x%x\n", -		 tmpl_hdr->cap_mask); - -	if ((tmpl_hdr->version & 0xfffff) >= 0x20001) -		ahw->fw_dump.use_pex_dma = true; -	else -		ahw->fw_dump.use_pex_dma = false; +		 fw_dump->cap_mask);  	qlcnic_enable_fw_dump_state(adapter); @@ -1099,21 +1227,22 @@ flash_temp:  int qlcnic_dump_fw(struct qlcnic_adapter *adapter)  { -	__le32 *buffer; -	u32 ocm_window; -	char mesg[64]; -	char *msg[] = {mesg, NULL}; -	int i, k, ops_cnt, ops_index, dump_size = 0; -	u32 entry_offset, dump, no_entries, buf_offset = 0; -	struct qlcnic_dump_entry *entry;  	struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; -	struct qlcnic_dump_template_hdr *tmpl_hdr = fw_dump->tmpl_hdr;  	static const struct qlcnic_dump_operations *fw_dump_ops; +	struct qlcnic_83xx_dump_template_hdr *hdr_83xx; +	u32 entry_offset, dump, no_entries, buf_offset = 0; +	int i, k, ops_cnt, ops_index, dump_size = 0;  	struct device *dev = &adapter->pdev->dev;  	struct qlcnic_hardware_context *ahw; -	void *temp_buffer; +	struct qlcnic_dump_entry *entry; +	void *tmpl_hdr; +	u32 ocm_window; +	__le32 *buffer; +	char mesg[64]; +	char *msg[] = {mesg, NULL};  	ahw = adapter->ahw; +	tmpl_hdr = fw_dump->tmpl_hdr;  	/* Return if we don't have firmware dump template header */  	if (!tmpl_hdr) @@ -1133,8 +1262,9 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)  	netif_info(adapter->ahw, drv, adapter->netdev, "Take FW dump\n");  	/* Calculate the size for dump data area only */  	for (i = 2, k = 1; (i & QLCNIC_DUMP_MASK_MAX); i <<= 1, k++) -		if (i & tmpl_hdr->drv_cap_mask) -			dump_size += tmpl_hdr->cap_sizes[k]; +		if (i & fw_dump->cap_mask) +			dump_size += qlcnic_get_cap_size(adapter, tmpl_hdr, k); +  	if (!dump_size)  		return -EIO; @@ -1144,35 +1274,26 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)  	buffer = fw_dump->data;  	fw_dump->size = dump_size; -	no_entries = tmpl_hdr->num_entries; -	entry_offset = tmpl_hdr->offset; -	tmpl_hdr->sys_info[0] = QLCNIC_DRIVER_VERSION; -	tmpl_hdr->sys_info[1] = adapter->fw_version; - -	if (fw_dump->use_pex_dma) { -		temp_buffer = dma_alloc_coherent(dev, QLC_PEX_DMA_READ_SIZE, -						 &fw_dump->phys_addr, -						 GFP_KERNEL); -		if (!temp_buffer) -			fw_dump->use_pex_dma = false; -		else -			fw_dump->dma_buffer = temp_buffer; -	} +	no_entries = fw_dump->num_entries; +	entry_offset = fw_dump->offset; +	qlcnic_set_sys_info(adapter, tmpl_hdr, 0, QLCNIC_DRIVER_VERSION); +	qlcnic_set_sys_info(adapter, tmpl_hdr, 1, adapter->fw_version);  	if (qlcnic_82xx_check(adapter)) {  		ops_cnt = ARRAY_SIZE(qlcnic_fw_dump_ops);  		fw_dump_ops = qlcnic_fw_dump_ops;  	} else { +		hdr_83xx = tmpl_hdr;  		ops_cnt = ARRAY_SIZE(qlcnic_83xx_fw_dump_ops);  		fw_dump_ops = qlcnic_83xx_fw_dump_ops; -		ocm_window = tmpl_hdr->ocm_wnd_reg[adapter->ahw->pci_func]; -		tmpl_hdr->saved_state[QLC_83XX_OCM_INDEX] = ocm_window; -		tmpl_hdr->saved_state[QLC_83XX_PCI_INDEX] = ahw->pci_func; +		ocm_window = hdr_83xx->ocm_wnd_reg[ahw->pci_func]; +		hdr_83xx->saved_state[QLC_83XX_OCM_INDEX] = ocm_window; +		hdr_83xx->saved_state[QLC_83XX_PCI_INDEX] = ahw->pci_func;  	}  	for (i = 0; i < no_entries; i++) { -		entry = (void *)tmpl_hdr + entry_offset; -		if (!(entry->hdr.mask & tmpl_hdr->drv_cap_mask)) { +		entry = tmpl_hdr + entry_offset; +		if (!(entry->hdr.mask & fw_dump->cap_mask)) {  			entry->hdr.flags |= QLCNIC_DUMP_SKIP;  			entry_offset += entry->hdr.offset;  			continue; @@ -1187,41 +1308,35 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)  		}  		if (ops_index == ops_cnt) { -			dev_info(&adapter->pdev->dev, -				 "Invalid entry type %d, exiting dump\n", +			dev_info(dev, "Skipping unknown entry opcode %d\n",  				 entry->hdr.type); -			goto error; +			entry->hdr.flags |= QLCNIC_DUMP_SKIP; +			entry_offset += entry->hdr.offset; +			continue;  		}  		/* Collect dump for this entry */  		dump = fw_dump_ops[ops_index].handler(adapter, entry, buffer); -		if (!qlcnic_valid_dump_entry(&adapter->pdev->dev, entry, dump)) +		if (!qlcnic_valid_dump_entry(dev, entry, dump)) {  			entry->hdr.flags |= QLCNIC_DUMP_SKIP; +			entry_offset += entry->hdr.offset; +			continue; +		} +  		buf_offset += entry->hdr.cap_size;  		entry_offset += entry->hdr.offset;  		buffer = fw_dump->data + buf_offset;  	} -	if (dump_size != buf_offset) { -		dev_info(&adapter->pdev->dev, -			 "Captured(%d) and expected size(%d) do not match\n", -			 buf_offset, dump_size); -		goto error; -	} else { -		fw_dump->clr = 1; -		snprintf(mesg, sizeof(mesg), "FW_DUMP=%s", -			 adapter->netdev->name); -		dev_info(&adapter->pdev->dev, "%s: Dump data, %d bytes captured\n", -			 adapter->netdev->name, fw_dump->size); -		/* Send a udev event to notify availability of FW dump */ -		kobject_uevent_env(&adapter->pdev->dev.kobj, KOBJ_CHANGE, msg); -		return 0; -	} -error: -	if (fw_dump->use_pex_dma) -		dma_free_coherent(dev, QLC_PEX_DMA_READ_SIZE, -				  fw_dump->dma_buffer, fw_dump->phys_addr); -	vfree(fw_dump->data); -	return -EINVAL; + +	fw_dump->clr = 1; +	snprintf(mesg, sizeof(mesg), "FW_DUMP=%s", adapter->netdev->name); +	netdev_info(adapter->netdev, +		    "Dump data %d bytes captured, template header size %d bytes\n", +		    fw_dump->size, fw_dump->tmpl_hdr_size); +	/* Send a udev event to notify availability of FW dump */ +	kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, msg); + +	return 0;  }  void qlcnic_83xx_get_minidump_template(struct qlcnic_adapter *adapter) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h index 0daf660e12a..4677b2edccc 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h @@ -52,6 +52,7 @@ enum qlcnic_bc_commands {  	QLCNIC_BC_CMD_CFG_GUEST_VLAN = 0x3,  }; +#define QLCNIC_83XX_SRIOV_VF_MAX_MAC 2  #define QLC_BC_CMD 1  struct qlcnic_trans_list { @@ -126,8 +127,8 @@ struct qlcnic_vport {  	u16			handle;  	u16			max_tx_bw;  	u16			min_tx_bw; +	u16			pvid;  	u8			vlan_mode; -	u16			vlan;  	u8			qos;  	bool			spoofchk;  	u8			mac[6]; @@ -137,6 +138,8 @@ struct qlcnic_vf_info {  	u8				pci_func;  	u16				rx_ctx_id;  	u16				tx_ctx_id; +	u16				*sriov_vlans; +	int				num_vlan;  	unsigned long			state;  	struct completion		ch_free_cmpl;  	struct work_struct		trans_work; @@ -149,12 +152,14 @@ struct qlcnic_vf_info {  	struct qlcnic_trans_list	rcv_pend;  	struct qlcnic_adapter		*adapter;  	struct qlcnic_vport		*vp; +	spinlock_t			vlan_list_lock;	/* Lock for VLAN list */  };  struct qlcnic_async_work_list {  	struct list_head	list;  	struct work_struct	work;  	void			*ptr; +	struct qlcnic_cmd_args	*cmd;  };  struct qlcnic_back_channel { @@ -185,7 +190,6 @@ void qlcnic_sriov_vf_register_map(struct qlcnic_hardware_context *);  int qlcnic_sriov_vf_init(struct qlcnic_adapter *, int);  void qlcnic_sriov_vf_set_ops(struct qlcnic_adapter *);  int qlcnic_sriov_func_to_index(struct qlcnic_adapter *, u8); -int qlcnic_sriov_channel_cfg_cmd(struct qlcnic_adapter *, u8);  void qlcnic_sriov_handle_bc_event(struct qlcnic_adapter *, u32);  int qlcnic_sriov_cfg_bc_intr(struct qlcnic_adapter *, u8);  void qlcnic_sriov_cleanup_async_list(struct qlcnic_back_channel *); @@ -195,8 +199,13 @@ int __qlcnic_sriov_add_act_list(struct qlcnic_sriov *, struct qlcnic_vf_info *,  int qlcnic_sriov_get_vf_vport_info(struct qlcnic_adapter *,  				   struct qlcnic_info *, u16);  int qlcnic_sriov_cfg_vf_guest_vlan(struct qlcnic_adapter *, u16, u8); -int qlcnic_sriov_vf_shutdown(struct pci_dev *); -int qlcnic_sriov_vf_resume(struct qlcnic_adapter *); +void qlcnic_sriov_free_vlans(struct qlcnic_adapter *); +void qlcnic_sriov_alloc_vlans(struct qlcnic_adapter *); +bool qlcnic_sriov_check_any_vlan(struct qlcnic_vf_info *); +void qlcnic_sriov_del_vlan_id(struct qlcnic_sriov *, +			      struct qlcnic_vf_info *, u16); +void qlcnic_sriov_add_vlan_id(struct qlcnic_sriov *, +			      struct qlcnic_vf_info *, u16);  static inline bool qlcnic_sriov_enable_check(struct qlcnic_adapter *adapter)  { @@ -224,7 +233,7 @@ bool qlcnic_sriov_soft_flr_check(struct qlcnic_adapter *,  void qlcnic_sriov_pf_reset(struct qlcnic_adapter *);  int qlcnic_sriov_pf_reinit(struct qlcnic_adapter *);  int qlcnic_sriov_set_vf_mac(struct net_device *, int, u8 *); -int qlcnic_sriov_set_vf_tx_rate(struct net_device *, int, int); +int qlcnic_sriov_set_vf_tx_rate(struct net_device *, int, int, int);  int qlcnic_sriov_get_vf_config(struct net_device *, int ,  			       struct ifla_vf_info *);  int qlcnic_sriov_set_vf_vlan(struct net_device *, int, u16, u8); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c index 652cc13c502..1659c804f1d 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c @@ -35,7 +35,12 @@ static void qlcnic_sriov_vf_cancel_fw_work(struct qlcnic_adapter *);  static void qlcnic_sriov_cleanup_transaction(struct qlcnic_bc_trans *);  static int qlcnic_sriov_issue_cmd(struct qlcnic_adapter *,  				  struct qlcnic_cmd_args *); +static int qlcnic_sriov_channel_cfg_cmd(struct qlcnic_adapter *, u8);  static void qlcnic_sriov_process_bc_cmd(struct work_struct *); +static int qlcnic_sriov_vf_shutdown(struct pci_dev *); +static int qlcnic_sriov_vf_resume(struct qlcnic_adapter *); +static int qlcnic_sriov_async_issue_cmd(struct qlcnic_adapter *, +					struct qlcnic_cmd_args *);  static struct qlcnic_hardware_ops qlcnic_sriov_vf_hw_ops = {  	.read_crb			= qlcnic_83xx_read_crb, @@ -68,6 +73,8 @@ static struct qlcnic_hardware_ops qlcnic_sriov_vf_hw_ops = {  	.change_l2_filter		= qlcnic_83xx_change_l2_filter,  	.get_board_info			= qlcnic_83xx_get_port_info,  	.free_mac_list			= qlcnic_sriov_vf_free_mac_list, +	.enable_sds_intr		= qlcnic_83xx_enable_sds_intr, +	.disable_sds_intr		= qlcnic_83xx_disable_sds_intr,  };  static struct qlcnic_nic_template qlcnic_sriov_vf_ops = { @@ -176,6 +183,7 @@ int qlcnic_sriov_init(struct qlcnic_adapter *adapter, int num_vfs)  		vf->adapter = adapter;  		vf->pci_func = qlcnic_sriov_virtid_fn(adapter, i);  		mutex_init(&vf->send_cmd_lock); +		spin_lock_init(&vf->vlan_list_lock);  		INIT_LIST_HEAD(&vf->rcv_act.wait_list);  		INIT_LIST_HEAD(&vf->rcv_pend.wait_list);  		spin_lock_init(&vf->rcv_act.lock); @@ -191,8 +199,10 @@ int qlcnic_sriov_init(struct qlcnic_adapter *adapter, int num_vfs)  				goto qlcnic_destroy_async_wq;  			}  			sriov->vf_info[i].vp = vp; +			vp->vlan_mode = QLC_GUEST_VLAN_MODE;  			vp->max_tx_bw = MAX_BW; -			vp->spoofchk = true; +			vp->min_tx_bw = MIN_BW; +			vp->spoofchk = false;  			random_ether_addr(vp->mac);  			dev_info(&adapter->pdev->dev,  				 "MAC Address %pM is configured for VF %d\n", @@ -276,6 +286,11 @@ static void qlcnic_sriov_vf_cleanup(struct qlcnic_adapter *adapter)  void qlcnic_sriov_cleanup(struct qlcnic_adapter *adapter)  { +	if (!test_bit(__QLCNIC_SRIOV_ENABLE, &adapter->state)) +		return; + +	qlcnic_sriov_free_vlans(adapter); +  	if (qlcnic_sriov_pf_check(adapter))  		qlcnic_sriov_pf_cleanup(adapter); @@ -416,10 +431,15 @@ static int qlcnic_sriov_set_guest_vlan_mode(struct qlcnic_adapter *adapter,  		return 0;  	sriov->any_vlan = cmd->rsp.arg[2] & 0xf; +	sriov->num_allowed_vlans = cmd->rsp.arg[2] >> 16; +	dev_info(&adapter->pdev->dev, "Number of allowed Guest VLANs = %d\n", +		 sriov->num_allowed_vlans); + +	qlcnic_sriov_alloc_vlans(adapter); +  	if (!sriov->any_vlan)  		return 0; -	sriov->num_allowed_vlans = cmd->rsp.arg[2] >> 16;  	num_vlans = sriov->num_allowed_vlans;  	sriov->allowed_vlans = kzalloc(sizeof(u16) * num_vlans, GFP_KERNEL);  	if (!sriov->allowed_vlans) @@ -432,13 +452,13 @@ static int qlcnic_sriov_set_guest_vlan_mode(struct qlcnic_adapter *adapter,  	return 0;  } -static int qlcnic_sriov_get_vf_acl(struct qlcnic_adapter *adapter, -				   struct qlcnic_info *info) +static int qlcnic_sriov_get_vf_acl(struct qlcnic_adapter *adapter)  {  	struct qlcnic_sriov *sriov = adapter->ahw->sriov;  	struct qlcnic_cmd_args cmd;  	int ret = 0; +	memset(&cmd, 0, sizeof(cmd));  	ret = qlcnic_sriov_alloc_bc_mbx_args(&cmd, QLCNIC_BC_CMD_GET_ACL);  	if (ret)  		return ret; @@ -473,14 +493,12 @@ static int qlcnic_sriov_vf_init_driver(struct qlcnic_adapter *adapter)  	if (err)  		return err; +	ahw->max_mc_count = nic_info.max_rx_mcast_mac_filters; +  	err = qlcnic_get_nic_info(adapter, &nic_info, ahw->pci_func);  	if (err)  		return -EIO; -	err = qlcnic_sriov_get_vf_acl(adapter, &nic_info); -	if (err) -		return err; -  	if (qlcnic_83xx_get_port_info(adapter))  		return -EIO; @@ -502,12 +520,18 @@ static int qlcnic_sriov_setup_vf(struct qlcnic_adapter *adapter,  {  	int err; +	adapter->flags |= QLCNIC_VLAN_FILTERING; +	adapter->ahw->total_nic_func = 1;  	INIT_LIST_HEAD(&adapter->vf_mc_list);  	if (!qlcnic_use_msi_x && !!qlcnic_use_msi)  		dev_warn(&adapter->pdev->dev,  			 "Device does not support MSI interrupts\n"); -	err = qlcnic_setup_intr(adapter, 1, 0); +	/* compute and set default and max tx/sds rings */ +	qlcnic_set_tx_ring_count(adapter, QLCNIC_SINGLE_RING); +	qlcnic_set_sds_ring_count(adapter, QLCNIC_SINGLE_RING); + +	err = qlcnic_setup_intr(adapter);  	if (err) {  		dev_err(&adapter->pdev->dev, "Failed to setup interrupt\n");  		goto err_out_disable_msi; @@ -533,8 +557,9 @@ static int qlcnic_sriov_setup_vf(struct qlcnic_adapter *adapter,  	if (err)  		goto err_out_send_channel_term; -	if (adapter->dcb && qlcnic_dcb_attach(adapter)) -		qlcnic_clear_dcb_ops(adapter); +	err = qlcnic_sriov_get_vf_acl(adapter); +	if (err) +		goto err_out_send_channel_term;  	err = qlcnic_setup_netdev(adapter, adapter->netdev, pci_using_dac);  	if (err) @@ -752,6 +777,7 @@ static int qlcnic_sriov_prepare_bc_hdr(struct qlcnic_bc_trans *trans,  		cmd->req.arg = (u32 *)trans->req_pay;  		cmd->rsp.arg = (u32 *)trans->rsp_pay;  		cmd_op = cmd->req.arg[0] & 0xff; +		cmd->cmd_op = cmd_op;  		remainder = (trans->rsp_pay_size) % (bc_pay_sz);  		num_frags = (trans->rsp_pay_size) / (bc_pay_sz);  		if (remainder) @@ -1338,7 +1364,7 @@ static int qlcnic_sriov_retry_bc_cmd(struct qlcnic_adapter *adapter,  	return -EIO;  } -static int qlcnic_sriov_issue_cmd(struct qlcnic_adapter *adapter, +static int __qlcnic_sriov_issue_cmd(struct qlcnic_adapter *adapter,  				  struct qlcnic_cmd_args *cmd)  {  	struct qlcnic_hardware_context *ahw = adapter->ahw; @@ -1352,7 +1378,7 @@ static int qlcnic_sriov_issue_cmd(struct qlcnic_adapter *adapter,  	rsp = qlcnic_sriov_alloc_bc_trans(&trans);  	if (rsp) -		return rsp; +		goto free_cmd;  	rsp = qlcnic_sriov_prepare_bc_hdr(trans, cmd, seq, QLC_BC_COMMAND);  	if (rsp) @@ -1390,12 +1416,17 @@ retry:  	    (mbx_err_code == QLCNIC_MBX_PORT_RSP_OK)) {  		rsp = QLCNIC_RCODE_SUCCESS;  	} else { -		rsp = mbx_err_code; -		if (!rsp) -			rsp = 1; -		dev_err(dev, -			"MBX command 0x%x failed with err:0x%x for VF %d\n", -			opcode, mbx_err_code, func); +		if (cmd->type == QLC_83XX_MBX_CMD_NO_WAIT) { +			rsp = QLCNIC_RCODE_SUCCESS; +		} else { +			rsp = mbx_err_code; +			if (!rsp) +				rsp = 1; + +			dev_err(dev, +				"MBX command 0x%x failed with err:0x%x for VF %d\n", +				opcode, mbx_err_code, func); +		}  	}  err_out: @@ -1407,15 +1438,33 @@ err_out:  cleanup_transaction:  	qlcnic_sriov_cleanup_transaction(trans); + +free_cmd: +	if (cmd->type == QLC_83XX_MBX_CMD_NO_WAIT) { +		qlcnic_free_mbx_args(cmd); +		kfree(cmd); +	} +  	return rsp;  } -int qlcnic_sriov_channel_cfg_cmd(struct qlcnic_adapter *adapter, u8 cmd_op) + +static int qlcnic_sriov_issue_cmd(struct qlcnic_adapter *adapter, +				  struct qlcnic_cmd_args *cmd) +{ +	if (cmd->type == QLC_83XX_MBX_CMD_NO_WAIT) +		return qlcnic_sriov_async_issue_cmd(adapter, cmd); +	else +		return __qlcnic_sriov_issue_cmd(adapter, cmd); +} + +static int qlcnic_sriov_channel_cfg_cmd(struct qlcnic_adapter *adapter, u8 cmd_op)  {  	struct qlcnic_cmd_args cmd;  	struct qlcnic_vf_info *vf = &adapter->ahw->sriov->vf_info[0];  	int ret; +	memset(&cmd, 0, sizeof(cmd));  	if (qlcnic_sriov_alloc_bc_mbx_args(&cmd, cmd_op))  		return -ENOMEM; @@ -1440,29 +1489,28 @@ out:  	return ret;  } -void qlcnic_vf_add_mc_list(struct net_device *netdev, u16 vlan) +static void qlcnic_vf_add_mc_list(struct net_device *netdev, const u8 *mac)  {  	struct qlcnic_adapter *adapter = netdev_priv(netdev); -	struct qlcnic_mac_list_s *cur; -	struct list_head *head, tmp_list; - -	INIT_LIST_HEAD(&tmp_list); -	head = &adapter->vf_mc_list; -	netif_addr_lock_bh(netdev); - -	while (!list_empty(head)) { -		cur = list_entry(head->next, struct qlcnic_mac_list_s, list); -		list_move(&cur->list, &tmp_list); -	} +	struct qlcnic_sriov *sriov = adapter->ahw->sriov; +	struct qlcnic_vf_info *vf; +	u16 vlan_id; +	int i; -	netif_addr_unlock_bh(netdev); +	vf = &adapter->ahw->sriov->vf_info[0]; -	while (!list_empty(&tmp_list)) { -		cur = list_entry((&tmp_list)->next, -				 struct qlcnic_mac_list_s, list); -		qlcnic_nic_add_mac(adapter, cur->mac_addr, vlan); -		list_del(&cur->list); -		kfree(cur); +	if (!qlcnic_sriov_check_any_vlan(vf)) { +		qlcnic_nic_add_mac(adapter, mac, 0); +	} else { +		spin_lock(&vf->vlan_list_lock); +		for (i = 0; i < sriov->num_allowed_vlans; i++) { +			vlan_id = vf->sriov_vlans[i]; +			if (vlan_id) +				qlcnic_nic_add_mac(adapter, mac, vlan_id); +		} +		spin_unlock(&vf->vlan_list_lock); +		if (qlcnic_84xx_check(adapter)) +			qlcnic_nic_add_mac(adapter, mac, 0);  	}  } @@ -1471,6 +1519,7 @@ void qlcnic_sriov_cleanup_async_list(struct qlcnic_back_channel *bc)  	struct list_head *head = &bc->async_list;  	struct qlcnic_async_work_list *entry; +	flush_workqueue(bc->bc_async_wq);  	while (!list_empty(head)) {  		entry = list_entry(head->next, struct qlcnic_async_work_list,  				   list); @@ -1480,27 +1529,68 @@ void qlcnic_sriov_cleanup_async_list(struct qlcnic_back_channel *bc)  	}  } -static void qlcnic_sriov_vf_set_multi(struct net_device *netdev) +void qlcnic_sriov_vf_set_multi(struct net_device *netdev)  {  	struct qlcnic_adapter *adapter = netdev_priv(netdev); -	u16 vlan; +	struct qlcnic_hardware_context *ahw = adapter->ahw; +	static const u8 bcast_addr[ETH_ALEN] = { +		0xff, 0xff, 0xff, 0xff, 0xff, 0xff +	}; +	struct netdev_hw_addr *ha; +	u32 mode = VPORT_MISS_MODE_DROP;  	if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))  		return; -	vlan = adapter->ahw->sriov->vlan; -	__qlcnic_set_multi(netdev, vlan); +	if (netdev->flags & IFF_PROMISC) { +		if (!(adapter->flags & QLCNIC_PROMISC_DISABLED)) +			mode = VPORT_MISS_MODE_ACCEPT_ALL; +	} else if ((netdev->flags & IFF_ALLMULTI) || +		   (netdev_mc_count(netdev) > ahw->max_mc_count)) { +		mode = VPORT_MISS_MODE_ACCEPT_MULTI; +	} else { +		qlcnic_vf_add_mc_list(netdev, bcast_addr); +		if (!netdev_mc_empty(netdev)) { +			netdev_for_each_mc_addr(ha, netdev) +				qlcnic_vf_add_mc_list(netdev, ha->addr); +		} +	} + +	/* configure unicast MAC address, if there is not sufficient space +	 * to store all the unicast addresses then enable promiscuous mode +	 */ +	if (netdev_uc_count(netdev) > ahw->max_uc_count) { +		mode = VPORT_MISS_MODE_ACCEPT_ALL; +	} else if (!netdev_uc_empty(netdev)) { +		netdev_for_each_uc_addr(ha, netdev) +			qlcnic_vf_add_mc_list(netdev, ha->addr); +	} + +	if (adapter->pdev->is_virtfn) { +		if (mode == VPORT_MISS_MODE_ACCEPT_ALL && +		    !adapter->fdb_mac_learn) { +			qlcnic_alloc_lb_filters_mem(adapter); +			adapter->drv_mac_learn = 1; +			adapter->rx_mac_learn = true; +		} else { +			adapter->drv_mac_learn = 0; +			adapter->rx_mac_learn = false; +		} +	} + +	qlcnic_nic_set_promisc(adapter, mode);  } -static void qlcnic_sriov_handle_async_multi(struct work_struct *work) +static void qlcnic_sriov_handle_async_issue_cmd(struct work_struct *work)  {  	struct qlcnic_async_work_list *entry; -	struct net_device *netdev; +	struct qlcnic_adapter *adapter; +	struct qlcnic_cmd_args *cmd;  	entry = container_of(work, struct qlcnic_async_work_list, work); -	netdev = (struct net_device *)entry->ptr; - -	qlcnic_sriov_vf_set_multi(netdev); +	adapter = entry->ptr; +	cmd = entry->cmd; +	__qlcnic_sriov_issue_cmd(adapter, cmd);  	return;  } @@ -1530,8 +1620,9 @@ qlcnic_sriov_get_free_node_async_work(struct qlcnic_back_channel *bc)  	return entry;  } -static void qlcnic_sriov_schedule_bc_async_work(struct qlcnic_back_channel *bc, -						work_func_t func, void *data) +static void qlcnic_sriov_schedule_async_cmd(struct qlcnic_back_channel *bc, +					    work_func_t func, void *data, +					    struct qlcnic_cmd_args *cmd)  {  	struct qlcnic_async_work_list *entry = NULL; @@ -1540,27 +1631,30 @@ static void qlcnic_sriov_schedule_bc_async_work(struct qlcnic_back_channel *bc,  		return;  	entry->ptr = data; +	entry->cmd = cmd;  	INIT_WORK(&entry->work, func);  	queue_work(bc->bc_async_wq, &entry->work);  } -void qlcnic_sriov_vf_schedule_multi(struct net_device *netdev) +static int qlcnic_sriov_async_issue_cmd(struct qlcnic_adapter *adapter, +					struct qlcnic_cmd_args *cmd)  { -	struct qlcnic_adapter *adapter = netdev_priv(netdev);  	struct qlcnic_back_channel *bc = &adapter->ahw->sriov->bc;  	if (adapter->need_fw_reset) -		return; +		return -EIO; -	qlcnic_sriov_schedule_bc_async_work(bc, qlcnic_sriov_handle_async_multi, -					    netdev); +	qlcnic_sriov_schedule_async_cmd(bc, qlcnic_sriov_handle_async_issue_cmd, +					adapter, cmd); +	return 0;  }  static int qlcnic_sriov_vf_reinit_driver(struct qlcnic_adapter *adapter)  {  	int err; +	adapter->need_fw_reset = 0;  	qlcnic_83xx_reinit_mbx_work(adapter->ahw->mailbox);  	qlcnic_83xx_enable_mbx_interrupt(adapter); @@ -1576,8 +1670,6 @@ static int qlcnic_sriov_vf_reinit_driver(struct qlcnic_adapter *adapter)  	if (err)  		goto err_out_term_channel; -	qlcnic_dcb_get_info(adapter); -  	return 0;  err_out_term_channel: @@ -1779,6 +1871,12 @@ static int qlcnic_sriov_vf_idc_unknown_state(struct qlcnic_adapter *adapter)  	return 0;  } +static void qlcnic_sriov_vf_periodic_tasks(struct qlcnic_adapter *adapter) +{ +	if (adapter->fhash.fnum) +		qlcnic_prune_lb_filters(adapter); +} +  static void qlcnic_sriov_vf_poll_dev_state(struct work_struct *work)  {  	struct qlcnic_adapter *adapter; @@ -1810,6 +1908,8 @@ static void qlcnic_sriov_vf_poll_dev_state(struct work_struct *work)  	}  	idc->prev_state = idc->curr_state; +	qlcnic_sriov_vf_periodic_tasks(adapter); +  	if (!ret && test_bit(QLC_83XX_MODULE_LOADED, &idc->status))  		qlcnic_schedule_work(adapter, qlcnic_sriov_vf_poll_dev_state,  				     idc->delay); @@ -1825,18 +1925,60 @@ static void qlcnic_sriov_vf_cancel_fw_work(struct qlcnic_adapter *adapter)  	cancel_delayed_work_sync(&adapter->fw_work);  } -static int qlcnic_sriov_validate_vlan_cfg(struct qlcnic_sriov *sriov, +static int qlcnic_sriov_check_vlan_id(struct qlcnic_sriov *sriov, +				      struct qlcnic_vf_info *vf, u16 vlan_id) +{ +	int i, err = -EINVAL; + +	if (!vf->sriov_vlans) +		return err; + +	spin_lock_bh(&vf->vlan_list_lock); + +	for (i = 0; i < sriov->num_allowed_vlans; i++) { +		if (vf->sriov_vlans[i] == vlan_id) { +			err = 0; +			break; +		} +	} + +	spin_unlock_bh(&vf->vlan_list_lock); +	return err; +} + +static int qlcnic_sriov_validate_num_vlans(struct qlcnic_sriov *sriov, +					   struct qlcnic_vf_info *vf) +{ +	int err = 0; + +	spin_lock_bh(&vf->vlan_list_lock); + +	if (vf->num_vlan >= sriov->num_allowed_vlans) +		err = -EINVAL; + +	spin_unlock_bh(&vf->vlan_list_lock); +	return err; +} + +static int qlcnic_sriov_validate_vlan_cfg(struct qlcnic_adapter *adapter,  					  u16 vid, u8 enable)  { -	u16 vlan = sriov->vlan; +	struct qlcnic_sriov *sriov = adapter->ahw->sriov; +	struct qlcnic_vf_info *vf; +	bool vlan_exist;  	u8 allowed = 0;  	int i; +	vf = &adapter->ahw->sriov->vf_info[0]; +	vlan_exist = qlcnic_sriov_check_any_vlan(vf);  	if (sriov->vlan_mode != QLC_GUEST_VLAN_MODE)  		return -EINVAL;  	if (enable) { -		if (vlan) +		if (qlcnic_83xx_vf_check(adapter) && vlan_exist) +			return -EINVAL; + +		if (qlcnic_sriov_validate_num_vlans(sriov, vf))  			return -EINVAL;  		if (sriov->any_vlan) { @@ -1849,24 +1991,56 @@ static int qlcnic_sriov_validate_vlan_cfg(struct qlcnic_sriov *sriov,  				return -EINVAL;  		}  	} else { -		if (!vlan || vlan != vid) +		if (!vlan_exist || qlcnic_sriov_check_vlan_id(sriov, vf, vid))  			return -EINVAL;  	}  	return 0;  } +static void qlcnic_sriov_vlan_operation(struct qlcnic_vf_info *vf, u16 vlan_id, +					enum qlcnic_vlan_operations opcode) +{ +	struct qlcnic_adapter *adapter = vf->adapter; +	struct qlcnic_sriov *sriov; + +	sriov = adapter->ahw->sriov; + +	if (!vf->sriov_vlans) +		return; + +	spin_lock_bh(&vf->vlan_list_lock); + +	switch (opcode) { +	case QLC_VLAN_ADD: +		qlcnic_sriov_add_vlan_id(sriov, vf, vlan_id); +		break; +	case QLC_VLAN_DELETE: +		qlcnic_sriov_del_vlan_id(sriov, vf, vlan_id); +		break; +	default: +		netdev_err(adapter->netdev, "Invalid VLAN operation\n"); +	} + +	spin_unlock_bh(&vf->vlan_list_lock); +	return; +} +  int qlcnic_sriov_cfg_vf_guest_vlan(struct qlcnic_adapter *adapter,  				   u16 vid, u8 enable)  {  	struct qlcnic_sriov *sriov = adapter->ahw->sriov; +	struct net_device *netdev = adapter->netdev; +	struct qlcnic_vf_info *vf;  	struct qlcnic_cmd_args cmd;  	int ret; +	memset(&cmd, 0, sizeof(cmd));  	if (vid == 0)  		return 0; -	ret = qlcnic_sriov_validate_vlan_cfg(sriov, vid, enable); +	vf = &adapter->ahw->sriov->vf_info[0]; +	ret = qlcnic_sriov_validate_vlan_cfg(adapter, vid, enable);  	if (ret)  		return ret; @@ -1883,14 +2057,18 @@ int qlcnic_sriov_cfg_vf_guest_vlan(struct qlcnic_adapter *adapter,  		dev_err(&adapter->pdev->dev,  			"Failed to configure guest VLAN, err=%d\n", ret);  	} else { +		netif_addr_lock_bh(netdev);  		qlcnic_free_mac_list(adapter); +		netif_addr_unlock_bh(netdev);  		if (enable) -			sriov->vlan = vid; +			qlcnic_sriov_vlan_operation(vf, vid, QLC_VLAN_ADD);  		else -			sriov->vlan = 0; +			qlcnic_sriov_vlan_operation(vf, vid, QLC_VLAN_DELETE); -		qlcnic_sriov_vf_set_multi(adapter->netdev); +		netif_addr_lock_bh(netdev); +		qlcnic_set_multi(netdev); +		netif_addr_unlock_bh(netdev);  	}  	qlcnic_free_mbx_args(&cmd); @@ -1900,21 +2078,19 @@ int qlcnic_sriov_cfg_vf_guest_vlan(struct qlcnic_adapter *adapter,  static void qlcnic_sriov_vf_free_mac_list(struct qlcnic_adapter *adapter)  {  	struct list_head *head = &adapter->mac_list; -	struct qlcnic_mac_list_s *cur; -	u16 vlan; - -	vlan = adapter->ahw->sriov->vlan; +	struct qlcnic_mac_vlan_list *cur;  	while (!list_empty(head)) { -		cur = list_entry(head->next, struct qlcnic_mac_list_s, list); -		qlcnic_sre_macaddr_change(adapter, cur->mac_addr, -					  vlan, QLCNIC_MAC_DEL); +		cur = list_entry(head->next, struct qlcnic_mac_vlan_list, list); +		qlcnic_sre_macaddr_change(adapter, cur->mac_addr, cur->vlan_id, +					  QLCNIC_MAC_DEL);  		list_del(&cur->list);  		kfree(cur);  	}  } -int qlcnic_sriov_vf_shutdown(struct pci_dev *pdev) + +static int qlcnic_sriov_vf_shutdown(struct pci_dev *pdev)  {  	struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);  	struct net_device *netdev = adapter->netdev; @@ -1938,7 +2114,7 @@ int qlcnic_sriov_vf_shutdown(struct pci_dev *pdev)  	return 0;  } -int qlcnic_sriov_vf_resume(struct qlcnic_adapter *adapter) +static int qlcnic_sriov_vf_resume(struct qlcnic_adapter *adapter)  {  	struct qlc_83xx_idc *idc = &adapter->ahw->idc;  	struct net_device *netdev = adapter->netdev; @@ -1964,3 +2140,70 @@ int qlcnic_sriov_vf_resume(struct qlcnic_adapter *adapter)  			     idc->delay);  	return err;  } + +void qlcnic_sriov_alloc_vlans(struct qlcnic_adapter *adapter) +{ +	struct qlcnic_sriov *sriov = adapter->ahw->sriov; +	struct qlcnic_vf_info *vf; +	int i; + +	for (i = 0; i < sriov->num_vfs; i++) { +		vf = &sriov->vf_info[i]; +		vf->sriov_vlans = kcalloc(sriov->num_allowed_vlans, +					  sizeof(*vf->sriov_vlans), GFP_KERNEL); +	} +} + +void qlcnic_sriov_free_vlans(struct qlcnic_adapter *adapter) +{ +	struct qlcnic_sriov *sriov = adapter->ahw->sriov; +	struct qlcnic_vf_info *vf; +	int i; + +	for (i = 0; i < sriov->num_vfs; i++) { +		vf = &sriov->vf_info[i]; +		kfree(vf->sriov_vlans); +		vf->sriov_vlans = NULL; +	} +} + +void qlcnic_sriov_add_vlan_id(struct qlcnic_sriov *sriov, +			      struct qlcnic_vf_info *vf, u16 vlan_id) +{ +	int i; + +	for (i = 0; i < sriov->num_allowed_vlans; i++) { +		if (!vf->sriov_vlans[i]) { +			vf->sriov_vlans[i] = vlan_id; +			vf->num_vlan++; +			return; +		} +	} +} + +void qlcnic_sriov_del_vlan_id(struct qlcnic_sriov *sriov, +			      struct qlcnic_vf_info *vf, u16 vlan_id) +{ +	int i; + +	for (i = 0; i < sriov->num_allowed_vlans; i++) { +		if (vf->sriov_vlans[i] == vlan_id) { +			vf->sriov_vlans[i] = 0; +			vf->num_vlan--; +			return; +		} +	} +} + +bool qlcnic_sriov_check_any_vlan(struct qlcnic_vf_info *vf) +{ +	bool err = false; + +	spin_lock_bh(&vf->vlan_list_lock); + +	if (vf->num_vlan) +		err = true; + +	spin_unlock_bh(&vf->vlan_list_lock); +	return err; +} diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c index 330d9a8774a..a29538b86ed 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c @@ -9,9 +9,14 @@  #include "qlcnic.h"  #include <linux/types.h> -#define QLCNIC_SRIOV_VF_MAX_MAC 1 +#define QLCNIC_SRIOV_VF_MAX_MAC 7  #define QLC_VF_MIN_TX_RATE	100  #define QLC_VF_MAX_TX_RATE	9999 +#define QLC_MAC_OPCODE_MASK	0x7 +#define QLC_VF_FLOOD_BIT	BIT_16 +#define QLC_FLOOD_MODE		0x5 +#define QLC_SRIOV_ALLOW_VLAN0	BIT_19 +#define QLC_INTR_COAL_TYPE_MASK	0x7  static int qlcnic_sriov_pf_get_vport_handle(struct qlcnic_adapter *, u8); @@ -64,9 +69,10 @@ static int qlcnic_sriov_pf_cal_res_limit(struct qlcnic_adapter *adapter,  {  	struct qlcnic_sriov *sriov = adapter->ahw->sriov;  	struct qlcnic_resources *res = &sriov->ff_max; -	u32 temp, num_vf_macs, num_vfs, max; +	u16 num_macs = sriov->num_allowed_vlans + 1;  	int ret = -EIO, vpid, id;  	struct qlcnic_vport *vp; +	u32 num_vfs, max, temp;  	vpid = qlcnic_sriov_pf_get_vport_handle(adapter, func);  	if (vpid < 0) @@ -76,16 +82,25 @@ static int qlcnic_sriov_pf_cal_res_limit(struct qlcnic_adapter *adapter,  	max = num_vfs + 1;  	info->bit_offsets = 0xffff;  	info->max_tx_ques = res->num_tx_queues / max; + +	if (qlcnic_83xx_pf_check(adapter)) +		num_macs = QLCNIC_83XX_SRIOV_VF_MAX_MAC; +  	info->max_rx_mcast_mac_filters = res->num_rx_mcast_mac_filters; -	num_vf_macs = QLCNIC_SRIOV_VF_MAX_MAC;  	if (adapter->ahw->pci_func == func) { -		temp = res->num_rx_mcast_mac_filters - (num_vfs * num_vf_macs); -		info->max_rx_ucast_mac_filters = temp; -		temp = res->num_tx_mac_filters - (num_vfs * num_vf_macs); -		info->max_tx_mac_filters = temp;  		info->min_tx_bw = 0;  		info->max_tx_bw = MAX_BW; + +		temp = res->num_rx_ucast_mac_filters - num_macs * num_vfs; +		info->max_rx_ucast_mac_filters = temp; +		temp = res->num_tx_mac_filters - num_macs * num_vfs; +		info->max_tx_mac_filters = temp; +		temp = num_macs * num_vfs * QLCNIC_SRIOV_VF_MAX_MAC; +		temp = res->num_rx_mcast_mac_filters - temp; +		info->max_rx_mcast_mac_filters = temp; + +		info->max_tx_ques = res->num_tx_queues - sriov->num_vfs;  	} else {  		id = qlcnic_sriov_func_to_index(adapter, func);  		if (id < 0) @@ -93,8 +108,13 @@ static int qlcnic_sriov_pf_cal_res_limit(struct qlcnic_adapter *adapter,  		vp = sriov->vf_info[id].vp;  		info->min_tx_bw = vp->min_tx_bw;  		info->max_tx_bw = vp->max_tx_bw; -		info->max_rx_ucast_mac_filters = num_vf_macs; -		info->max_tx_mac_filters = num_vf_macs; + +		info->max_rx_ucast_mac_filters = num_macs; +		info->max_tx_mac_filters = num_macs; +		temp = num_macs * QLCNIC_SRIOV_VF_MAX_MAC; +		info->max_rx_mcast_mac_filters = temp; + +		info->max_tx_ques = QLCNIC_SINGLE_RING;  	}  	info->max_rx_ip_addr = res->num_destip / max; @@ -132,6 +152,25 @@ static void qlcnic_sriov_pf_set_ff_max_res(struct qlcnic_adapter *adapter,  	ff_max->max_local_ipv6_addrs = info->max_local_ipv6_addrs;  } +static void qlcnic_sriov_set_vf_max_vlan(struct qlcnic_adapter *adapter, +					 struct qlcnic_info *npar_info) +{ +	struct qlcnic_sriov *sriov = adapter->ahw->sriov; +	int temp, total_fn; + +	temp = npar_info->max_rx_mcast_mac_filters; +	total_fn = sriov->num_vfs + 1; + +	temp = temp / (QLCNIC_SRIOV_VF_MAX_MAC * total_fn); +	sriov->num_allowed_vlans = temp - 1; + +	if (qlcnic_83xx_pf_check(adapter)) +		sriov->num_allowed_vlans = 1; + +	netdev_info(adapter->netdev, "Max Guest VLANs supported per VF = %d\n", +		    sriov->num_allowed_vlans); +} +  static int qlcnic_sriov_get_pf_info(struct qlcnic_adapter *adapter,  				    struct qlcnic_info *npar_info)  { @@ -165,6 +204,7 @@ static int qlcnic_sriov_get_pf_info(struct qlcnic_adapter *adapter,  	npar_info->max_local_ipv6_addrs = LSW(cmd.rsp.arg[8]);  	npar_info->max_remote_ipv6_addrs = MSW(cmd.rsp.arg[8]); +	qlcnic_sriov_set_vf_max_vlan(adapter, npar_info);  	qlcnic_sriov_pf_set_ff_max_res(adapter, npar_info);  	dev_info(&adapter->pdev->dev,  		 "\n\ttotal_pf: %d,\n" @@ -297,8 +337,14 @@ static int qlcnic_sriov_pf_cfg_vlan_filtering(struct qlcnic_adapter *adapter,  		return err;  	cmd.req.arg[1] = 0x4; -	if (enable) +	if (enable) { +		adapter->flags |= QLCNIC_VLAN_FILTERING;  		cmd.req.arg[1] |= BIT_16; +		if (qlcnic_84xx_check(adapter)) +			cmd.req.arg[1] |= QLC_SRIOV_ALLOW_VLAN0; +	} else { +		adapter->flags &= ~QLCNIC_VLAN_FILTERING; +	}  	err = qlcnic_issue_cmd(adapter, &cmd);  	if (err) @@ -309,6 +355,28 @@ static int qlcnic_sriov_pf_cfg_vlan_filtering(struct qlcnic_adapter *adapter,  	return err;  } +/* On configuring VF flood bit, PFD will receive traffic from all VFs */ +static int qlcnic_sriov_pf_cfg_flood(struct qlcnic_adapter *adapter) +{ +	struct qlcnic_cmd_args cmd; +	int err; + +	err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_NIC_INFO); +	if (err) +		return err; + +	cmd.req.arg[1] = QLC_FLOOD_MODE | QLC_VF_FLOOD_BIT; + +	err = qlcnic_issue_cmd(adapter, &cmd); +	if (err) +		dev_err(&adapter->pdev->dev, +			"Failed to configure VF Flood bit on PF, err=%d\n", +			err); + +	qlcnic_free_mbx_args(&cmd); +	return err; +} +  static int qlcnic_sriov_pf_cfg_eswitch(struct qlcnic_adapter *adapter,  				       u8 func, u8 enable)  { @@ -397,22 +465,38 @@ static int qlcnic_pci_sriov_disable(struct qlcnic_adapter *adapter)  {  	struct net_device *netdev = adapter->netdev; +	if (pci_vfs_assigned(adapter->pdev)) { +		netdev_err(adapter->netdev, +			   "SR-IOV VFs belonging to port %d are assigned to VMs. SR-IOV can not be disabled on this port\n", +			   adapter->portnum); +		netdev_info(adapter->netdev, +			    "Please detach SR-IOV VFs belonging to port %d from VMs, and then try to disable SR-IOV on this port\n", +			    adapter->portnum); +		return -EPERM; +	} + +	qlcnic_sriov_pf_disable(adapter); + +	rtnl_lock();  	if (netif_running(netdev))  		__qlcnic_down(adapter, netdev); -	qlcnic_sriov_pf_disable(adapter); +	qlcnic_sriov_free_vlans(adapter);  	qlcnic_sriov_pf_cleanup(adapter);  	/* After disabling SRIOV re-init the driver in default mode  	   configure opmode based on op_mode of function  	 */ -	if (qlcnic_83xx_configure_opmode(adapter)) +	if (qlcnic_83xx_configure_opmode(adapter)) { +		rtnl_unlock();  		return -EIO; +	}  	if (netif_running(netdev))  		__qlcnic_up(adapter, netdev); +	rtnl_unlock();  	return 0;  } @@ -430,6 +514,12 @@ static int qlcnic_sriov_pf_init(struct qlcnic_adapter *adapter)  	if (err)  		return err; +	if (qlcnic_84xx_check(adapter)) { +		err = qlcnic_sriov_pf_cfg_flood(adapter); +		if (err) +			goto disable_vlan_filtering; +	} +  	err = qlcnic_sriov_pf_cfg_eswitch(adapter, func, 1);  	if (err)  		goto disable_vlan_filtering; @@ -507,7 +597,8 @@ static int __qlcnic_pci_sriov_enable(struct qlcnic_adapter *adapter,  	if (err)  		goto del_flr_queue; -	err = qlcnic_sriov_pf_enable(adapter, num_vfs); +	qlcnic_sriov_alloc_vlans(adapter); +  	return err;  del_flr_queue: @@ -533,28 +624,41 @@ static int qlcnic_pci_sriov_enable(struct qlcnic_adapter *adapter, int num_vfs)  		return -EIO;  	} +	rtnl_lock();  	if (netif_running(netdev))  		__qlcnic_down(adapter, netdev);  	err = __qlcnic_pci_sriov_enable(adapter, num_vfs); -	if (err) { -		netdev_info(netdev, "Failed to enable SR-IOV on port %d\n", -			    adapter->portnum); +	if (err) +		goto error; -		err = -EIO; -		if (qlcnic_83xx_configure_opmode(adapter)) -			goto error; -	} else { +	if (netif_running(netdev)) +		__qlcnic_up(adapter, netdev); + +	rtnl_unlock(); +	err = qlcnic_sriov_pf_enable(adapter, num_vfs); +	if (!err) {  		netdev_info(netdev,  			    "SR-IOV is enabled successfully on port %d\n",  			    adapter->portnum);  		/* Return number of vfs enabled */ -		err = num_vfs; +		return num_vfs;  	} + +	rtnl_lock();  	if (netif_running(netdev)) -		__qlcnic_up(adapter, netdev); +		__qlcnic_down(adapter, netdev);  error: +	if (!qlcnic_83xx_configure_opmode(adapter)) { +		if (netif_running(netdev)) +			__qlcnic_up(adapter, netdev); +	} + +	rtnl_unlock(); +	netdev_info(netdev, "Failed to enable SR-IOV on port %d\n", +		    adapter->portnum); +  	return err;  } @@ -602,7 +706,7 @@ static int qlcnic_sriov_set_vf_acl(struct qlcnic_adapter *adapter, u8 func)  	if (vp->vlan_mode == QLC_PVID_MODE) {  		cmd.req.arg[2] |= BIT_6; -		cmd.req.arg[3] |= vp->vlan << 8; +		cmd.req.arg[3] |= vp->pvid << 8;  	}  	err = qlcnic_issue_cmd(adapter, &cmd); @@ -637,10 +741,13 @@ static int qlcnic_sriov_pf_channel_cfg_cmd(struct qlcnic_bc_trans *trans,  	struct qlcnic_vf_info *vf = trans->vf;  	struct qlcnic_vport *vp = vf->vp;  	struct qlcnic_adapter *adapter; +	struct qlcnic_sriov *sriov;  	u16 func = vf->pci_func; +	size_t size;  	int err;  	adapter = vf->adapter; +	sriov = adapter->ahw->sriov;  	if (trans->req_hdr->cmd_op == QLCNIC_BC_CMD_CHANNEL_INIT) {  		err = qlcnic_sriov_pf_config_vport(adapter, 1, func); @@ -650,8 +757,12 @@ static int qlcnic_sriov_pf_channel_cfg_cmd(struct qlcnic_bc_trans *trans,  				qlcnic_sriov_pf_config_vport(adapter, 0, func);  		}  	} else { -		if (vp->vlan_mode == QLC_GUEST_VLAN_MODE) -			vp->vlan = 0; +		if (vp->vlan_mode == QLC_GUEST_VLAN_MODE) { +			size = sizeof(*vf->sriov_vlans); +			size = size * sriov->num_allowed_vlans; +			memset(vf->sriov_vlans, 0, size); +		} +  		err = qlcnic_sriov_pf_config_vport(adapter, 0, func);  	} @@ -673,31 +784,40 @@ err_out:  }  static int qlcnic_sriov_cfg_vf_def_mac(struct qlcnic_adapter *adapter, -				       struct qlcnic_vport *vp, -				       u16 func, u16 vlan, u8 op) +				       struct qlcnic_vf_info *vf, +				       u16 vlan, u8 op)  { -	struct qlcnic_cmd_args cmd; +	struct qlcnic_cmd_args *cmd;  	struct qlcnic_macvlan_mbx mv; +	struct qlcnic_vport *vp;  	u8 *addr;  	int err;  	u32 *buf;  	int vpid; -	if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_MAC_VLAN)) +	vp = vf->vp; + +	cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC); +	if (!cmd)  		return -ENOMEM; -	vpid = qlcnic_sriov_pf_get_vport_handle(adapter, func); +	err = qlcnic_alloc_mbx_args(cmd, adapter, QLCNIC_CMD_CONFIG_MAC_VLAN); +	if (err) +		goto free_cmd; + +	cmd->type = QLC_83XX_MBX_CMD_NO_WAIT; +	vpid = qlcnic_sriov_pf_get_vport_handle(adapter, vf->pci_func);  	if (vpid < 0) {  		err = -EINVAL; -		goto out; +		goto free_args;  	}  	if (vlan)  		op = ((op == QLCNIC_MAC_ADD || op == QLCNIC_MAC_VLAN_ADD) ?  		      QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_VLAN_DEL); -	cmd.req.arg[1] = op | (1 << 8) | (3 << 6); -	cmd.req.arg[1] |= ((vpid & 0xffff) << 16) | BIT_31; +	cmd->req.arg[1] = op | (1 << 8) | (3 << 6); +	cmd->req.arg[1] |= ((vpid & 0xffff) << 16) | BIT_31;  	addr = vp->mac;  	mv.vlan = vlan; @@ -707,18 +827,18 @@ static int qlcnic_sriov_cfg_vf_def_mac(struct qlcnic_adapter *adapter,  	mv.mac_addr3 = addr[3];  	mv.mac_addr4 = addr[4];  	mv.mac_addr5 = addr[5]; -	buf = &cmd.req.arg[2]; +	buf = &cmd->req.arg[2];  	memcpy(buf, &mv, sizeof(struct qlcnic_macvlan_mbx)); -	err = qlcnic_issue_cmd(adapter, &cmd); +	err = qlcnic_issue_cmd(adapter, cmd); -	if (err) -		dev_err(&adapter->pdev->dev, -			"MAC-VLAN %s to CAM failed, err=%d.\n", -			((op == 1) ? "add " : "delete "), err); +	if (!err) +		return err; -out: -	qlcnic_free_mbx_args(&cmd); +free_args: +	qlcnic_free_mbx_args(cmd); +free_cmd: +	kfree(cmd);  	return err;  } @@ -730,6 +850,35 @@ static int qlcnic_sriov_validate_create_rx_ctx(struct qlcnic_cmd_args *cmd)  	return 0;  } +static void qlcnic_83xx_cfg_default_mac_vlan(struct qlcnic_adapter *adapter, +					     struct qlcnic_vf_info *vf, +					     int opcode) +{ +	struct qlcnic_sriov *sriov; +	u16 vlan; +	int i; + +	sriov = adapter->ahw->sriov; + +	spin_lock_bh(&vf->vlan_list_lock); +	if (vf->num_vlan) { +		for (i = 0; i < sriov->num_allowed_vlans; i++) { +			vlan = vf->sriov_vlans[i]; +			if (vlan) +				qlcnic_sriov_cfg_vf_def_mac(adapter, vf, vlan, +							    opcode); +		} +	} +	spin_unlock_bh(&vf->vlan_list_lock); + +	if (vf->vp->vlan_mode != QLC_PVID_MODE) { +		if (qlcnic_83xx_pf_check(adapter) && +		    qlcnic_sriov_check_any_vlan(vf)) +			return; +		qlcnic_sriov_cfg_vf_def_mac(adapter, vf, 0, opcode); +	} +} +  static int qlcnic_sriov_pf_create_rx_ctx_cmd(struct qlcnic_bc_trans *tran,  					     struct qlcnic_cmd_args *cmd)  { @@ -737,7 +886,6 @@ static int qlcnic_sriov_pf_create_rx_ctx_cmd(struct qlcnic_bc_trans *tran,  	struct qlcnic_adapter *adapter = vf->adapter;  	struct qlcnic_rcv_mbx_out *mbx_out;  	int err; -	u16 vlan;  	err = qlcnic_sriov_validate_create_rx_ctx(cmd);  	if (err) { @@ -748,12 +896,10 @@ static int qlcnic_sriov_pf_create_rx_ctx_cmd(struct qlcnic_bc_trans *tran,  	cmd->req.arg[6] = vf->vp->handle;  	err = qlcnic_issue_cmd(adapter, cmd); -	vlan = vf->vp->vlan;  	if (!err) {  		mbx_out = (struct qlcnic_rcv_mbx_out *)&cmd->rsp.arg[1];  		vf->rx_ctx_id = mbx_out->ctx_id; -		qlcnic_sriov_cfg_vf_def_mac(adapter, vf->vp, vf->pci_func, -					    vlan, QLCNIC_MAC_ADD); +		qlcnic_83xx_cfg_default_mac_vlan(adapter, vf, QLCNIC_MAC_ADD);  	} else {  		vf->rx_ctx_id = 0;  	} @@ -837,7 +983,6 @@ static int qlcnic_sriov_pf_del_rx_ctx_cmd(struct qlcnic_bc_trans *trans,  	struct qlcnic_vf_info *vf = trans->vf;  	struct qlcnic_adapter *adapter = vf->adapter;  	int err; -	u16 vlan;  	err = qlcnic_sriov_validate_del_rx_ctx(vf, cmd);  	if (err) { @@ -845,9 +990,7 @@ static int qlcnic_sriov_pf_del_rx_ctx_cmd(struct qlcnic_bc_trans *trans,  		return err;  	} -	vlan = vf->vp->vlan; -	qlcnic_sriov_cfg_vf_def_mac(adapter, vf->vp, vf->pci_func, -				    vlan, QLCNIC_MAC_DEL); +	qlcnic_83xx_cfg_default_mac_vlan(adapter, vf, QLCNIC_MAC_DEL);  	cmd->req.arg[1] |= vf->vp->handle << 16;  	err = qlcnic_issue_cmd(adapter, cmd); @@ -1055,19 +1198,41 @@ static int qlcnic_sriov_validate_cfg_intrcoal(struct qlcnic_adapter *adapter,  {  	struct qlcnic_nic_intr_coalesce *coal = &adapter->ahw->coal;  	u16 ctx_id, pkts, time; +	int err = -EINVAL; +	u8 type; +	type = cmd->req.arg[1] & QLC_INTR_COAL_TYPE_MASK;  	ctx_id = cmd->req.arg[1] >> 16;  	pkts = cmd->req.arg[2] & 0xffff;  	time = cmd->req.arg[2] >> 16; -	if (ctx_id != vf->rx_ctx_id) -		return -EINVAL; -	if (pkts > coal->rx_packets) -		return -EINVAL; -	if (time < coal->rx_time_us) -		return -EINVAL; +	switch (type) { +	case QLCNIC_INTR_COAL_TYPE_RX: +		if (ctx_id != vf->rx_ctx_id || pkts > coal->rx_packets || +		    time < coal->rx_time_us) +			goto err_label; +		break; +	case QLCNIC_INTR_COAL_TYPE_TX: +		if (ctx_id != vf->tx_ctx_id || pkts > coal->tx_packets || +		    time < coal->tx_time_us) +			goto err_label; +		break; +	default: +		netdev_err(adapter->netdev, "Invalid coalescing type 0x%x received\n", +			   type); +		return err; +	}  	return 0; + +err_label: +	netdev_err(adapter->netdev, "Expected: rx_ctx_id 0x%x rx_packets 0x%x rx_time_us 0x%x tx_ctx_id 0x%x tx_packets 0x%x tx_time_us 0x%x\n", +		   vf->rx_ctx_id, coal->rx_packets, coal->rx_time_us, +		   vf->tx_ctx_id, coal->tx_packets, coal->tx_time_us); +	netdev_err(adapter->netdev, "Received: ctx_id 0x%x packets 0x%x time_us 0x%x type 0x%x\n", +		   ctx_id, pkts, time, type); + +	return err;  }  static int qlcnic_sriov_pf_cfg_intrcoal_cmd(struct qlcnic_bc_trans *tran, @@ -1091,7 +1256,6 @@ static int qlcnic_sriov_validate_cfg_macvlan(struct qlcnic_adapter *adapter,  					     struct qlcnic_vf_info *vf,  					     struct qlcnic_cmd_args *cmd)  { -	struct qlcnic_macvlan_mbx *macvlan;  	struct qlcnic_vport *vp = vf->vp;  	u8 op, new_op; @@ -1101,20 +1265,12 @@ static int qlcnic_sriov_validate_cfg_macvlan(struct qlcnic_adapter *adapter,  	cmd->req.arg[1] |= (vf->vp->handle << 16);  	cmd->req.arg[1] |= BIT_31; -	macvlan = (struct qlcnic_macvlan_mbx *)&cmd->req.arg[2]; -	if (!(macvlan->mac_addr0 & BIT_0)) { -		dev_err(&adapter->pdev->dev, -			"MAC address change is not allowed from VF %d", -			vf->pci_func); -		return -EINVAL; -	} -  	if (vp->vlan_mode == QLC_PVID_MODE) {  		op = cmd->req.arg[1] & 0x7;  		cmd->req.arg[1] &= ~0x7;  		new_op = (op == QLCNIC_MAC_ADD || op == QLCNIC_MAC_VLAN_ADD) ?  			 QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_VLAN_DEL; -		cmd->req.arg[3] |= vp->vlan << 16; +		cmd->req.arg[3] |= vp->pvid << 16;  		cmd->req.arg[1] |= new_op;  	} @@ -1184,8 +1340,10 @@ static int qlcnic_sriov_pf_get_acl_cmd(struct qlcnic_bc_trans *trans,  	struct qlcnic_vport *vp = vf->vp;  	u8 cmd_op, mode = vp->vlan_mode;  	struct qlcnic_adapter *adapter; +	struct qlcnic_sriov *sriov;  	adapter = vf->adapter; +	sriov = adapter->ahw->sriov;  	cmd_op = trans->req_hdr->cmd_op;  	cmd->rsp.arg[0] |= 1 << 25; @@ -1199,10 +1357,10 @@ static int qlcnic_sriov_pf_get_acl_cmd(struct qlcnic_bc_trans *trans,  	switch (mode) {  	case QLC_GUEST_VLAN_MODE:  		cmd->rsp.arg[1] = mode | 1 << 8; -		cmd->rsp.arg[2] = 1 << 16; +		cmd->rsp.arg[2] = sriov->num_allowed_vlans << 16;  		break;  	case QLC_PVID_MODE: -		cmd->rsp.arg[1] = mode | 1 << 8 | vp->vlan << 16; +		cmd->rsp.arg[1] = mode | 1 << 8 | vp->pvid << 16;  		break;  	} @@ -1210,24 +1368,27 @@ static int qlcnic_sriov_pf_get_acl_cmd(struct qlcnic_bc_trans *trans,  }  static int qlcnic_sriov_pf_del_guest_vlan(struct qlcnic_adapter *adapter, -					  struct qlcnic_vf_info *vf) - +					  struct qlcnic_vf_info *vf, +					  struct qlcnic_cmd_args *cmd)  { -	struct qlcnic_vport *vp = vf->vp; +	struct qlcnic_sriov *sriov = adapter->ahw->sriov; +	u16 vlan; -	if (!vp->vlan) +	if (!qlcnic_sriov_check_any_vlan(vf))  		return -EINVAL; +	vlan = cmd->req.arg[1] >> 16;  	if (!vf->rx_ctx_id) { -		vp->vlan = 0; +		qlcnic_sriov_del_vlan_id(sriov, vf, vlan);  		return 0;  	} -	qlcnic_sriov_cfg_vf_def_mac(adapter, vp, vf->pci_func, -				    vp->vlan, QLCNIC_MAC_DEL); -	vp->vlan = 0; -	qlcnic_sriov_cfg_vf_def_mac(adapter, vp, vf->pci_func, -				    0, QLCNIC_MAC_ADD); +	qlcnic_sriov_cfg_vf_def_mac(adapter, vf, vlan, QLCNIC_MAC_DEL); +	qlcnic_sriov_del_vlan_id(sriov, vf, vlan); + +	if (qlcnic_83xx_pf_check(adapter)) +		qlcnic_sriov_cfg_vf_def_mac(adapter, vf, +					    0, QLCNIC_MAC_ADD);  	return 0;  } @@ -1235,32 +1396,37 @@ static int qlcnic_sriov_pf_add_guest_vlan(struct qlcnic_adapter *adapter,  					  struct qlcnic_vf_info *vf,  					  struct qlcnic_cmd_args *cmd)  { -	struct qlcnic_vport *vp = vf->vp; +	struct qlcnic_sriov *sriov = adapter->ahw->sriov;  	int err = -EIO; +	u16 vlan; -	if (vp->vlan) +	if (qlcnic_83xx_pf_check(adapter) && qlcnic_sriov_check_any_vlan(vf))  		return err; +	vlan = cmd->req.arg[1] >> 16; +  	if (!vf->rx_ctx_id) { -		vp->vlan = cmd->req.arg[1] >> 16; +		qlcnic_sriov_add_vlan_id(sriov, vf, vlan);  		return 0;  	} -	err = qlcnic_sriov_cfg_vf_def_mac(adapter, vp, vf->pci_func, -					  0, QLCNIC_MAC_DEL); -	if (err) -		return err; +	if (qlcnic_83xx_pf_check(adapter)) { +		err = qlcnic_sriov_cfg_vf_def_mac(adapter, vf, 0, +						  QLCNIC_MAC_DEL); +		if (err) +			return err; +	} -	vp->vlan = cmd->req.arg[1] >> 16; -	err = qlcnic_sriov_cfg_vf_def_mac(adapter, vp, vf->pci_func, -					  vp->vlan, QLCNIC_MAC_ADD); +	err = qlcnic_sriov_cfg_vf_def_mac(adapter, vf, vlan, QLCNIC_MAC_ADD);  	if (err) { -		qlcnic_sriov_cfg_vf_def_mac(adapter, vp, vf->pci_func, -					    0, QLCNIC_MAC_ADD); -		vp->vlan = 0; +		if (qlcnic_83xx_pf_check(adapter)) +			qlcnic_sriov_cfg_vf_def_mac(adapter, vf, 0, +						    QLCNIC_MAC_ADD); +		return err;  	} +	qlcnic_sriov_add_vlan_id(sriov, vf, vlan);  	return err;  } @@ -1283,7 +1449,7 @@ static int qlcnic_sriov_pf_cfg_guest_vlan_cmd(struct qlcnic_bc_trans *tran,  	if (op)  		err = qlcnic_sriov_pf_add_guest_vlan(adapter, vf, cmd);  	else -		err = qlcnic_sriov_pf_del_guest_vlan(adapter, vf); +		err = qlcnic_sriov_pf_del_guest_vlan(adapter, vf, cmd);  	cmd->rsp.arg[0] |= err ? 2 << 25 : 1 << 25;  	return err; @@ -1293,8 +1459,6 @@ static const int qlcnic_pf_passthru_supp_cmds[] = {  	QLCNIC_CMD_GET_STATISTICS,  	QLCNIC_CMD_GET_PORT_CONFIG,  	QLCNIC_CMD_GET_LINK_STATUS, -	QLCNIC_CMD_DCB_QUERY_CAP, -	QLCNIC_CMD_DCB_QUERY_PARAM,  	QLCNIC_CMD_INIT_NIC_FUNC,  	QLCNIC_CMD_STOP_NIC_FUNC,  }; @@ -1590,7 +1754,8 @@ void qlcnic_sriov_pf_handle_flr(struct qlcnic_sriov *sriov,  	}  	if (vp->vlan_mode == QLC_GUEST_VLAN_MODE) -		vp->vlan = 0; +		memset(vf->sriov_vlans, 0, +		       sizeof(*vf->sriov_vlans) * sriov->num_allowed_vlans);  	qlcnic_sriov_schedule_flr(sriov, vf, qlcnic_sriov_pf_process_flr);  	netdev_info(dev, "FLR received for PCI func %d\n", vf->pci_func); @@ -1683,7 +1848,8 @@ int qlcnic_sriov_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)  	return 0;  } -int qlcnic_sriov_set_vf_tx_rate(struct net_device *netdev, int vf, int tx_rate) +int qlcnic_sriov_set_vf_tx_rate(struct net_device *netdev, int vf, +				int min_tx_rate, int max_tx_rate)  {  	struct qlcnic_adapter *adapter = netdev_priv(netdev);  	struct qlcnic_sriov *sriov = adapter->ahw->sriov; @@ -1698,35 +1864,52 @@ int qlcnic_sriov_set_vf_tx_rate(struct net_device *netdev, int vf, int tx_rate)  	if (vf >= sriov->num_vfs)  		return -EINVAL; -	if (tx_rate >= 10000 || tx_rate < 100) { +	vf_info = &sriov->vf_info[vf]; +	vp = vf_info->vp; +	vpid = vp->handle; + +	if (!min_tx_rate) +		min_tx_rate = QLC_VF_MIN_TX_RATE; + +	if (max_tx_rate && +	    (max_tx_rate >= 10000 || max_tx_rate < min_tx_rate)) {  		netdev_err(netdev, -			   "Invalid Tx rate, allowed range is [%d - %d]", -			   QLC_VF_MIN_TX_RATE, QLC_VF_MAX_TX_RATE); +			   "Invalid max Tx rate, allowed range is [%d - %d]", +			   min_tx_rate, QLC_VF_MAX_TX_RATE);  		return -EINVAL;  	} -	if (tx_rate == 0) -		tx_rate = 10000; +	if (!max_tx_rate) +		max_tx_rate = 10000; -	vf_info = &sriov->vf_info[vf]; -	vp = vf_info->vp; -	vpid = vp->handle; +	if (min_tx_rate && +	    (min_tx_rate > max_tx_rate || min_tx_rate < QLC_VF_MIN_TX_RATE)) { +		netdev_err(netdev, +			   "Invalid min Tx rate, allowed range is [%d - %d]", +			   QLC_VF_MIN_TX_RATE, max_tx_rate); +		return -EINVAL; +	}  	if (test_bit(QLC_BC_VF_STATE, &vf_info->state)) {  		if (qlcnic_sriov_get_vf_vport_info(adapter, &nic_info, vpid))  			return -EIO; -		nic_info.max_tx_bw = tx_rate / 100; +		nic_info.max_tx_bw = max_tx_rate / 100; +		nic_info.min_tx_bw = min_tx_rate / 100;  		nic_info.bit_offsets = BIT_0;  		if (qlcnic_sriov_pf_set_vport_info(adapter, &nic_info, vpid))  			return -EIO;  	} -	vp->max_tx_bw = tx_rate / 100; +	vp->max_tx_bw = max_tx_rate / 100; +	netdev_info(netdev, +		    "Setting Max Tx rate %d (Mbps), %d %% of PF bandwidth, for VF %d\n", +		    max_tx_rate, vp->max_tx_bw, vf); +	vp->min_tx_bw = min_tx_rate / 100;  	netdev_info(netdev, -		    "Setting Tx rate %d (Mbps), %d %% of PF bandwidth, for VF %d\n", -		    tx_rate, vp->max_tx_bw, vf); +		    "Setting Min Tx rate %d (Mbps), %d %% of PF bandwidth, for VF %d\n", +		    min_tx_rate, vp->min_tx_bw, vf);  	return 0;  } @@ -1760,20 +1943,22 @@ int qlcnic_sriov_set_vf_vlan(struct net_device *netdev, int vf,  		return -EOPNOTSUPP;  	} +	memset(vf_info->sriov_vlans, 0, +	       sizeof(*vf_info->sriov_vlans) * sriov->num_allowed_vlans); +  	switch (vlan) {  	case 4095: -		vp->vlan = 0;  		vp->vlan_mode = QLC_GUEST_VLAN_MODE;  		break;  	case 0:  		vp->vlan_mode = QLC_NO_VLAN_MODE; -		vp->vlan = 0;  		vp->qos = 0;  		break;  	default:  		vp->vlan_mode = QLC_PVID_MODE; -		vp->vlan = vlan; +		qlcnic_sriov_add_vlan_id(sriov, vf_info, vlan);  		vp->qos = qos; +		vp->pvid = vlan;  	}  	netdev_info(netdev, "Setting VLAN %d, QoS %d, for VF %d\n", @@ -1788,7 +1973,7 @@ static __u32 qlcnic_sriov_get_vf_vlan(struct qlcnic_adapter *adapter,  	switch (vp->vlan_mode) {  	case QLC_PVID_MODE: -		vlan = vp->vlan; +		vlan = vp->pvid;  		break;  	case QLC_GUEST_VLAN_MODE:  		vlan = MAX_VLAN_ID; @@ -1823,9 +2008,13 @@ int qlcnic_sriov_get_vf_config(struct net_device *netdev,  	ivi->qos = vp->qos;  	ivi->spoofchk = vp->spoofchk;  	if (vp->max_tx_bw == MAX_BW) -		ivi->tx_rate = 0; +		ivi->max_tx_rate = 0; +	else +		ivi->max_tx_rate = vp->max_tx_bw * 100; +	if (vp->min_tx_bw == MIN_BW) +		ivi->min_tx_rate = 0;  	else -		ivi->tx_rate = vp->max_tx_bw * 100; +		ivi->min_tx_rate = vp->min_tx_bw * 100;  	ivi->vf = vf;  	return 0; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c index c6165d05cc1..f5786d5792d 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c @@ -6,7 +6,6 @@   */  #include <linux/slab.h> -#include <linux/vmalloc.h>  #include <linux/interrupt.h>  #include "qlcnic.h" @@ -20,6 +19,10 @@  #include <linux/sysfs.h>  #include <linux/aer.h>  #include <linux/log2.h> +#ifdef CONFIG_QLCNIC_HWMON +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#endif  #define QLC_STATUS_UNSUPPORTED_CMD	-2 @@ -127,6 +130,8 @@ static int qlcnic_83xx_store_beacon(struct qlcnic_adapter *adapter,  	if (kstrtoul(buf, 2, &h_beacon))  		return -EINVAL; +	qlcnic_get_beacon_state(adapter); +  	if (ahw->beacon_state == h_beacon)  		return len; @@ -156,9 +161,9 @@ static int qlcnic_82xx_store_beacon(struct qlcnic_adapter *adapter,  				    const char *buf, size_t len)  {  	struct qlcnic_hardware_context *ahw = adapter->ahw; -	int err, max_sds_rings = adapter->max_sds_rings; +	int err, drv_sds_rings = adapter->drv_sds_rings;  	u16 beacon; -	u8 h_beacon_state, b_state, b_rate; +	u8 b_state, b_rate;  	if (len != sizeof(u16))  		return QL_STATUS_INVALID_PARAM; @@ -168,18 +173,7 @@ static int qlcnic_82xx_store_beacon(struct qlcnic_adapter *adapter,  	if (err)  		return err; -	if (ahw->extra_capability[0] & QLCNIC_FW_CAPABILITY_2_BEACON) { -		err = qlcnic_get_beacon_state(adapter, &h_beacon_state); -		if (err) { -			netdev_err(adapter->netdev, -				   "Failed to get current beacon state\n"); -		} else { -			if (h_beacon_state == QLCNIC_BEACON_DISABLE) -				ahw->beacon_state = 0; -			else if (h_beacon_state == QLCNIC_BEACON_EANBLE) -				ahw->beacon_state = 2; -		} -	} +	qlcnic_get_beacon_state(adapter);  	if (ahw->beacon_state == b_state)  		return len; @@ -211,7 +205,7 @@ static int qlcnic_82xx_store_beacon(struct qlcnic_adapter *adapter,  	}  	if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state)) -		qlcnic_diag_free_res(adapter->netdev, max_sds_rings); +		qlcnic_diag_free_res(adapter->netdev, drv_sds_rings);  out:  	if (!ahw->beacon_state) @@ -360,15 +354,17 @@ static ssize_t qlcnic_sysfs_write_mem(struct file *filp, struct kobject *kobj,  	return size;  } -static int qlcnic_is_valid_nic_func(struct qlcnic_adapter *adapter, u8 pci_func) +int qlcnic_is_valid_nic_func(struct qlcnic_adapter *adapter, u8 pci_func)  {  	int i; -	for (i = 0; i < adapter->ahw->act_pci_func; i++) { + +	for (i = 0; i < adapter->ahw->total_nic_func; i++) {  		if (adapter->npars[i].pci_func == pci_func)  			return i;  	} -	return -1; +	dev_err(&adapter->pdev->dev, "%s: Invalid nic function\n", __func__); +	return -EINVAL;  }  static int validate_pm_config(struct qlcnic_adapter *adapter, @@ -382,7 +378,6 @@ static int validate_pm_config(struct qlcnic_adapter *adapter,  		src_pci_func = pm_cfg[i].pci_func;  		dest_pci_func = pm_cfg[i].dest_npar;  		src_index = qlcnic_is_valid_nic_func(adapter, src_pci_func); -  		if (src_index < 0)  			return QL_STATUS_INVALID_PARAM; @@ -439,6 +434,8 @@ static ssize_t qlcnic_sysfs_write_pm_config(struct file *filp,  	for (i = 0; i < count; i++) {  		pci_func = pm_cfg[i].pci_func;  		index = qlcnic_is_valid_nic_func(adapter, pci_func); +		if (index < 0) +			return QL_STATUS_INVALID_PARAM;  		id = adapter->npars[index].phy_port;  		adapter->npars[index].enable_pm = !!pm_cfg[i].action;  		adapter->npars[index].dest_npar = id; @@ -455,21 +452,21 @@ static ssize_t qlcnic_sysfs_read_pm_config(struct file *filp,  {  	struct device *dev = container_of(kobj, struct device, kobj);  	struct qlcnic_adapter *adapter = dev_get_drvdata(dev); -	struct qlcnic_pm_func_cfg pm_cfg[QLCNIC_MAX_PCI_FUNC]; -	int i; +	struct qlcnic_pm_func_cfg *pm_cfg;  	u8 pci_func; +	u32 count; +	int i; -	if (size != sizeof(pm_cfg)) -		return QL_STATUS_INVALID_PARAM; - -	memset(&pm_cfg, 0, -	       sizeof(struct qlcnic_pm_func_cfg) * QLCNIC_MAX_PCI_FUNC); - -	for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) { +	memset(buf, 0, size); +	pm_cfg = (struct qlcnic_pm_func_cfg *)buf; +	count = size / sizeof(struct qlcnic_pm_func_cfg); +	for (i = 0; i < adapter->ahw->total_nic_func; i++) {  		pci_func = adapter->npars[i].pci_func; -		if (!adapter->npars[i].active) +		if (pci_func >= count) { +			dev_dbg(dev, "%s: Total nic functions[%d], App sent function count[%d]\n", +				__func__, adapter->ahw->total_nic_func, count);  			continue; - +		}  		if (!adapter->npars[i].eswitch_status)  			continue; @@ -477,26 +474,25 @@ static ssize_t qlcnic_sysfs_read_pm_config(struct file *filp,  		pm_cfg[pci_func].dest_npar = 0;  		pm_cfg[pci_func].pci_func = i;  	} -	memcpy(buf, &pm_cfg, size); -  	return size;  }  static int validate_esw_config(struct qlcnic_adapter *adapter,  			       struct qlcnic_esw_func_cfg *esw_cfg, int count)  { +	struct qlcnic_hardware_context *ahw = adapter->ahw; +	int i, ret;  	u32 op_mode;  	u8 pci_func; -	int i, ret;  	if (qlcnic_82xx_check(adapter)) -		op_mode = readl(adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE); +		op_mode = readl(ahw->pci_base0 + QLCNIC_DRV_OP_MODE);  	else -		op_mode = QLCRDX(adapter->ahw, QLC_83XX_DRV_OP_MODE); +		op_mode = QLCRDX(ahw, QLC_83XX_DRV_OP_MODE);  	for (i = 0; i < count; i++) {  		pci_func = esw_cfg[i].pci_func; -		if (pci_func >= QLCNIC_MAX_PCI_FUNC) +		if (pci_func >= ahw->max_vnic_func)  			return QL_STATUS_INVALID_PARAM;  		if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC) @@ -600,6 +596,8 @@ static ssize_t qlcnic_sysfs_write_esw_config(struct file *file,  	for (i = 0; i < count; i++) {  		pci_func = esw_cfg[i].pci_func;  		index = qlcnic_is_valid_nic_func(adapter, pci_func); +		if (index < 0) +			return QL_STATUS_INVALID_PARAM;  		npar = &adapter->npars[index];  		switch (esw_cfg[i].op_mode) {  		case QLCNIC_PORT_DEFAULTS: @@ -629,20 +627,21 @@ static ssize_t qlcnic_sysfs_read_esw_config(struct file *file,  {  	struct device *dev = container_of(kobj, struct device, kobj);  	struct qlcnic_adapter *adapter = dev_get_drvdata(dev); -	struct qlcnic_esw_func_cfg esw_cfg[QLCNIC_MAX_PCI_FUNC]; -	u8 i, pci_func; - -	if (size != sizeof(esw_cfg)) -		return QL_STATUS_INVALID_PARAM; - -	memset(&esw_cfg, 0, -	       sizeof(struct qlcnic_esw_func_cfg) * QLCNIC_MAX_PCI_FUNC); +	struct qlcnic_esw_func_cfg *esw_cfg; +	u8 pci_func; +	u32 count; +	int i; -	for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) { +	memset(buf, 0, size); +	esw_cfg = (struct qlcnic_esw_func_cfg *)buf; +	count = size / sizeof(struct qlcnic_esw_func_cfg); +	for (i = 0; i < adapter->ahw->total_nic_func; i++) {  		pci_func = adapter->npars[i].pci_func; -		if (!adapter->npars[i].active) +		if (pci_func >= count) { +			dev_dbg(dev, "%s: Total nic functions[%d], App sent function count[%d]\n", +				__func__, adapter->ahw->total_nic_func, count);  			continue; - +		}  		if (!adapter->npars[i].eswitch_status)  			continue; @@ -650,9 +649,6 @@ static ssize_t qlcnic_sysfs_read_esw_config(struct file *file,  		if (qlcnic_get_eswitch_port_config(adapter, &esw_cfg[pci_func]))  			return QL_STATUS_INVALID_PARAM;  	} - -	memcpy(buf, &esw_cfg, size); -  	return size;  } @@ -711,6 +707,8 @@ static ssize_t qlcnic_sysfs_write_npar_config(struct file *file,  		if (ret)  			return ret;  		index = qlcnic_is_valid_nic_func(adapter, pci_func); +		if (index < 0) +			return QL_STATUS_INVALID_PARAM;  		adapter->npars[index].min_bw = nic_info.min_tx_bw;  		adapter->npars[index].max_bw = nic_info.max_tx_bw;  	} @@ -726,38 +724,41 @@ static ssize_t qlcnic_sysfs_read_npar_config(struct file *file,  {  	struct device *dev = container_of(kobj, struct device, kobj);  	struct qlcnic_adapter *adapter = dev_get_drvdata(dev); +	struct qlcnic_npar_func_cfg *np_cfg;  	struct qlcnic_info nic_info; -	struct qlcnic_npar_func_cfg np_cfg[QLCNIC_MAX_PCI_FUNC]; +	u8 pci_func;  	int i, ret; - -	if (size != sizeof(np_cfg)) -		return QL_STATUS_INVALID_PARAM; +	u32 count;  	memset(&nic_info, 0, sizeof(struct qlcnic_info)); -	memset(&np_cfg, 0, -	       sizeof(struct qlcnic_npar_func_cfg) * QLCNIC_MAX_PCI_FUNC); +	memset(buf, 0, size); +	np_cfg = (struct qlcnic_npar_func_cfg *)buf; -	for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) { -		if (qlcnic_is_valid_nic_func(adapter, i) < 0) +	count = size / sizeof(struct qlcnic_npar_func_cfg); +	for (i = 0; i < adapter->ahw->total_nic_func; i++) { +		if (adapter->npars[i].pci_func >= count) { +			dev_dbg(dev, "%s: Total nic functions[%d], App sent function count[%d]\n", +				__func__, adapter->ahw->total_nic_func, count);  			continue; -		ret = qlcnic_get_nic_info(adapter, &nic_info, i); -		if (ret) -			return ret; - +		}  		if (!adapter->npars[i].eswitch_status)  			continue; +		pci_func = adapter->npars[i].pci_func; +		if (qlcnic_is_valid_nic_func(adapter, pci_func) < 0) +			continue; +		ret = qlcnic_get_nic_info(adapter, &nic_info, pci_func); +		if (ret) +			return ret; -		np_cfg[i].pci_func = i; -		np_cfg[i].op_mode = (u8)nic_info.op_mode; -		np_cfg[i].port_num = nic_info.phys_port; -		np_cfg[i].fw_capab = nic_info.capabilities; -		np_cfg[i].min_bw = nic_info.min_tx_bw; -		np_cfg[i].max_bw = nic_info.max_tx_bw; -		np_cfg[i].max_tx_queues = nic_info.max_tx_ques; -		np_cfg[i].max_rx_queues = nic_info.max_rx_ques; +		np_cfg[pci_func].pci_func = pci_func; +		np_cfg[pci_func].op_mode = (u8)nic_info.op_mode; +		np_cfg[pci_func].port_num = nic_info.phys_port; +		np_cfg[pci_func].fw_capab = nic_info.capabilities; +		np_cfg[pci_func].min_bw = nic_info.min_tx_bw; +		np_cfg[pci_func].max_bw = nic_info.max_tx_bw; +		np_cfg[pci_func].max_tx_queues = nic_info.max_tx_ques; +		np_cfg[pci_func].max_rx_queues = nic_info.max_rx_ques;  	} - -	memcpy(buf, &np_cfg, size);  	return size;  } @@ -778,7 +779,7 @@ static ssize_t qlcnic_sysfs_get_port_stats(struct file *file,  	if (size != sizeof(struct qlcnic_esw_statistics))  		return QL_STATUS_INVALID_PARAM; -	if (offset >= QLCNIC_MAX_PCI_FUNC) +	if (offset >= adapter->ahw->max_vnic_func)  		return QL_STATUS_INVALID_PARAM;  	memset(&port_stats, 0, size); @@ -874,7 +875,7 @@ static ssize_t qlcnic_sysfs_clear_port_stats(struct file *file,  	if (qlcnic_83xx_check(adapter))  		return QLC_STATUS_UNSUPPORTED_CMD; -	if (offset >= QLCNIC_MAX_PCI_FUNC) +	if (offset >= adapter->ahw->max_vnic_func)  		return QL_STATUS_INVALID_PARAM;  	ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset, @@ -898,14 +899,12 @@ static ssize_t qlcnic_sysfs_read_pci_config(struct file *file,  {  	struct device *dev = container_of(kobj, struct device, kobj);  	struct qlcnic_adapter *adapter = dev_get_drvdata(dev); -	struct qlcnic_pci_func_cfg pci_cfg[QLCNIC_MAX_PCI_FUNC]; +	struct qlcnic_pci_func_cfg *pci_cfg;  	struct qlcnic_pci_info *pci_info;  	int i, ret; +	u32 count; -	if (size != sizeof(pci_cfg)) -		return QL_STATUS_INVALID_PARAM; - -	pci_info = kcalloc(QLCNIC_MAX_PCI_FUNC, sizeof(*pci_info), GFP_KERNEL); +	pci_info = kcalloc(size, sizeof(*pci_info), GFP_KERNEL);  	if (!pci_info)  		return -ENOMEM; @@ -915,19 +914,18 @@ static ssize_t qlcnic_sysfs_read_pci_config(struct file *file,  		return ret;  	} -	memset(&pci_cfg, 0, -	       sizeof(struct qlcnic_pci_func_cfg) * QLCNIC_MAX_PCI_FUNC); - -	for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) { +	pci_cfg = (struct qlcnic_pci_func_cfg *)buf; +	count = size / sizeof(struct qlcnic_pci_func_cfg); +	for (i = 0; i < count; i++) {  		pci_cfg[i].pci_func = pci_info[i].id;  		pci_cfg[i].func_type = pci_info[i].type; +		pci_cfg[i].func_state = 0;  		pci_cfg[i].port_num = pci_info[i].default_port;  		pci_cfg[i].min_bw = pci_info[i].tx_min_bw;  		pci_cfg[i].max_bw = pci_info[i].tx_max_bw;  		memcpy(&pci_cfg[i].def_mac_addr, &pci_info[i].mac, ETH_ALEN);  	} -	memcpy(buf, &pci_cfg, size);  	kfree(pci_info);  	return size;  } @@ -1251,6 +1249,68 @@ static struct bin_attribute bin_attr_flash = {  	.write = qlcnic_83xx_sysfs_flash_write_handler,  }; +#ifdef CONFIG_QLCNIC_HWMON + +static ssize_t qlcnic_hwmon_show_temp(struct device *dev, +				      struct device_attribute *dev_attr, +				      char *buf) +{ +	struct qlcnic_adapter *adapter = dev_get_drvdata(dev); +	unsigned int temperature = 0, value = 0; + +	if (qlcnic_83xx_check(adapter)) +		value = QLCRDX(adapter->ahw, QLC_83XX_ASIC_TEMP); +	else if (qlcnic_82xx_check(adapter)) +		value = QLC_SHARED_REG_RD32(adapter, QLCNIC_ASIC_TEMP); + +	temperature = qlcnic_get_temp_val(value); +	/* display millidegree celcius */ +	temperature *= 1000; +	return sprintf(buf, "%u\n", temperature); +} + +/* hwmon-sysfs attributes */ +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, +			  qlcnic_hwmon_show_temp, NULL, 1); + +static struct attribute *qlcnic_hwmon_attrs[] = { +	&sensor_dev_attr_temp1_input.dev_attr.attr, +	NULL +}; + +ATTRIBUTE_GROUPS(qlcnic_hwmon); + +void qlcnic_register_hwmon_dev(struct qlcnic_adapter *adapter) +{ +	struct device *dev = &adapter->pdev->dev; +	struct device *hwmon_dev; + +	/* Skip hwmon registration for a VF device */ +	if (qlcnic_sriov_vf_check(adapter)) { +		adapter->ahw->hwmon_dev = NULL; +		return; +	} +	hwmon_dev = hwmon_device_register_with_groups(dev, qlcnic_driver_name, +						      adapter, +						      qlcnic_hwmon_groups); +	if (IS_ERR(hwmon_dev)) { +		dev_err(dev, "Cannot register with hwmon, err=%ld\n", +			PTR_ERR(hwmon_dev)); +		hwmon_dev = NULL; +	} +	adapter->ahw->hwmon_dev = hwmon_dev; +} + +void qlcnic_unregister_hwmon_dev(struct qlcnic_adapter *adapter) +{ +	struct device *hwmon_dev = adapter->ahw->hwmon_dev; +	if (hwmon_dev) { +		hwmon_device_unregister(hwmon_dev); +		adapter->ahw->hwmon_dev = NULL; +	} +} +#endif +  void qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter)  {  	struct device *dev = &adapter->pdev->dev; @@ -1269,7 +1329,7 @@ void qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter)  		device_remove_file(dev, &dev_attr_bridged_mode);  } -void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter) +static void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)  {  	struct device *dev = &adapter->pdev->dev; @@ -1285,8 +1345,12 @@ void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)  	if (device_create_bin_file(dev, &bin_attr_mem))  		dev_info(dev, "failed to create mem sysfs entry\n"); +	if (test_bit(__QLCNIC_MAINTENANCE_MODE, &adapter->state)) +		return; +  	if (device_create_bin_file(dev, &bin_attr_pci_config))  		dev_info(dev, "failed to create pci config sysfs entry"); +  	if (device_create_file(dev, &dev_attr_beacon))  		dev_info(dev, "failed to create beacon sysfs entry"); @@ -1304,7 +1368,7 @@ void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)  		dev_info(dev, "failed to create eswitch stats sysfs entry");  } -void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter) +static void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)  {  	struct device *dev = &adapter->pdev->dev; @@ -1315,6 +1379,10 @@ void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)  	device_remove_file(dev, &dev_attr_diag_mode);  	device_remove_bin_file(dev, &bin_attr_crb);  	device_remove_bin_file(dev, &bin_attr_mem); + +	if (test_bit(__QLCNIC_MAINTENANCE_MODE, &adapter->state)) +		return; +  	device_remove_bin_file(dev, &bin_attr_pci_config);  	device_remove_file(dev, &dev_attr_beacon);  	if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) diff --git a/drivers/net/ethernet/qlogic/qlge/qlge.h b/drivers/net/ethernet/qlogic/qlge/qlge.h index 89943377846..ef332708e5f 100644 --- a/drivers/net/ethernet/qlogic/qlge/qlge.h +++ b/drivers/net/ethernet/qlogic/qlge/qlge.h @@ -18,7 +18,7 @@   */  #define DRV_NAME  	"qlge"  #define DRV_STRING 	"QLogic 10 Gigabit PCI-E Ethernet Driver " -#define DRV_VERSION	"v1.00.00.32" +#define DRV_VERSION	"1.00.00.34"  #define WQ_ADDR_ALIGN	0x3	/* 4 byte alignment */ @@ -2206,14 +2206,14 @@ extern char qlge_driver_name[];  extern const char qlge_driver_version[];  extern const struct ethtool_ops qlge_ethtool_ops; -extern int ql_sem_spinlock(struct ql_adapter *qdev, u32 sem_mask); -extern void ql_sem_unlock(struct ql_adapter *qdev, u32 sem_mask); -extern int ql_read_xgmac_reg(struct ql_adapter *qdev, u32 reg, u32 *data); -extern int ql_get_mac_addr_reg(struct ql_adapter *qdev, u32 type, u16 index, -			       u32 *value); -extern int ql_get_routing_reg(struct ql_adapter *qdev, u32 index, u32 *value); -extern int ql_write_cfg(struct ql_adapter *qdev, void *ptr, int size, u32 bit, -			u16 q_id); +int ql_sem_spinlock(struct ql_adapter *qdev, u32 sem_mask); +void ql_sem_unlock(struct ql_adapter *qdev, u32 sem_mask); +int ql_read_xgmac_reg(struct ql_adapter *qdev, u32 reg, u32 *data); +int ql_get_mac_addr_reg(struct ql_adapter *qdev, u32 type, u16 index, +			u32 *value); +int ql_get_routing_reg(struct ql_adapter *qdev, u32 index, u32 *value); +int ql_write_cfg(struct ql_adapter *qdev, void *ptr, int size, u32 bit, +		 u16 q_id);  void ql_queue_fw_error(struct ql_adapter *qdev);  void ql_mpi_work(struct work_struct *work);  void ql_mpi_reset_work(struct work_struct *work); @@ -2233,10 +2233,9 @@ int ql_unpause_mpi_risc(struct ql_adapter *qdev);  int ql_pause_mpi_risc(struct ql_adapter *qdev);  int ql_hard_reset_mpi_risc(struct ql_adapter *qdev);  int ql_soft_reset_mpi_risc(struct ql_adapter *qdev); -int ql_dump_risc_ram_area(struct ql_adapter *qdev, void *buf, -		u32 ram_addr, int word_count); -int ql_core_dump(struct ql_adapter *qdev, -		struct ql_mpi_coredump *mpi_coredump); +int ql_dump_risc_ram_area(struct ql_adapter *qdev, void *buf, u32 ram_addr, +			  int word_count); +int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump);  int ql_mb_about_fw(struct ql_adapter *qdev);  int ql_mb_wol_set_magic(struct ql_adapter *qdev, u32 enable_wol);  int ql_mb_wol_mode(struct ql_adapter *qdev, u32 wol); @@ -2249,8 +2248,6 @@ int ql_mb_get_port_cfg(struct ql_adapter *qdev);  int ql_mb_set_port_cfg(struct ql_adapter *qdev);  int ql_wait_fifo_empty(struct ql_adapter *qdev);  void ql_get_dump(struct ql_adapter *qdev, void *buff); -void ql_gen_reg_dump(struct ql_adapter *qdev, -			struct ql_reg_dump *mpi_coredump);  netdev_tx_t ql_lb_send(struct sk_buff *skb, struct net_device *ndev);  void ql_check_lb_frame(struct ql_adapter *, struct sk_buff *);  int ql_own_firmware(struct ql_adapter *qdev); @@ -2264,9 +2261,9 @@ int ql_clean_lb_rx_ring(struct rx_ring *rx_ring, int budget);  /* #define QL_OB_DUMP */  #ifdef QL_REG_DUMP -extern void ql_dump_xgmac_control_regs(struct ql_adapter *qdev); -extern void ql_dump_routing_entries(struct ql_adapter *qdev); -extern void ql_dump_regs(struct ql_adapter *qdev); +void ql_dump_xgmac_control_regs(struct ql_adapter *qdev); +void ql_dump_routing_entries(struct ql_adapter *qdev); +void ql_dump_regs(struct ql_adapter *qdev);  #define QL_DUMP_REGS(qdev) ql_dump_regs(qdev)  #define QL_DUMP_ROUTE(qdev) ql_dump_routing_entries(qdev)  #define QL_DUMP_XGMAC_CONTROL_REGS(qdev) ql_dump_xgmac_control_regs(qdev) @@ -2277,26 +2274,26 @@ extern void ql_dump_regs(struct ql_adapter *qdev);  #endif  #ifdef QL_STAT_DUMP -extern void ql_dump_stat(struct ql_adapter *qdev); +void ql_dump_stat(struct ql_adapter *qdev);  #define QL_DUMP_STAT(qdev) ql_dump_stat(qdev)  #else  #define QL_DUMP_STAT(qdev)  #endif  #ifdef QL_DEV_DUMP -extern void ql_dump_qdev(struct ql_adapter *qdev); +void ql_dump_qdev(struct ql_adapter *qdev);  #define QL_DUMP_QDEV(qdev) ql_dump_qdev(qdev)  #else  #define QL_DUMP_QDEV(qdev)  #endif  #ifdef QL_CB_DUMP -extern void ql_dump_wqicb(struct wqicb *wqicb); -extern void ql_dump_tx_ring(struct tx_ring *tx_ring); -extern void ql_dump_ricb(struct ricb *ricb); -extern void ql_dump_cqicb(struct cqicb *cqicb); -extern void ql_dump_rx_ring(struct rx_ring *rx_ring); -extern void ql_dump_hw_cb(struct ql_adapter *qdev, int size, u32 bit, u16 q_id); +void ql_dump_wqicb(struct wqicb *wqicb); +void ql_dump_tx_ring(struct tx_ring *tx_ring); +void ql_dump_ricb(struct ricb *ricb); +void ql_dump_cqicb(struct cqicb *cqicb); +void ql_dump_rx_ring(struct rx_ring *rx_ring); +void ql_dump_hw_cb(struct ql_adapter *qdev, int size, u32 bit, u16 q_id);  #define QL_DUMP_RICB(ricb) ql_dump_ricb(ricb)  #define QL_DUMP_WQICB(wqicb) ql_dump_wqicb(wqicb)  #define QL_DUMP_TX_RING(tx_ring) ql_dump_tx_ring(tx_ring) @@ -2314,9 +2311,9 @@ extern void ql_dump_hw_cb(struct ql_adapter *qdev, int size, u32 bit, u16 q_id);  #endif  #ifdef QL_OB_DUMP -extern void ql_dump_tx_desc(struct tx_buf_desc *tbd); -extern void ql_dump_ob_mac_iocb(struct ob_mac_iocb_req *ob_mac_iocb); -extern void ql_dump_ob_mac_rsp(struct ob_mac_iocb_rsp *ob_mac_rsp); +void ql_dump_tx_desc(struct tx_buf_desc *tbd); +void ql_dump_ob_mac_iocb(struct ob_mac_iocb_req *ob_mac_iocb); +void ql_dump_ob_mac_rsp(struct ob_mac_iocb_rsp *ob_mac_rsp);  #define QL_DUMP_OB_MAC_IOCB(ob_mac_iocb) ql_dump_ob_mac_iocb(ob_mac_iocb)  #define QL_DUMP_OB_MAC_RSP(ob_mac_rsp) ql_dump_ob_mac_rsp(ob_mac_rsp)  #else @@ -2325,14 +2322,14 @@ extern void ql_dump_ob_mac_rsp(struct ob_mac_iocb_rsp *ob_mac_rsp);  #endif  #ifdef QL_IB_DUMP -extern void ql_dump_ib_mac_rsp(struct ib_mac_iocb_rsp *ib_mac_rsp); +void ql_dump_ib_mac_rsp(struct ib_mac_iocb_rsp *ib_mac_rsp);  #define QL_DUMP_IB_MAC_RSP(ib_mac_rsp) ql_dump_ib_mac_rsp(ib_mac_rsp)  #else  #define QL_DUMP_IB_MAC_RSP(ib_mac_rsp)  #endif  #ifdef	QL_ALL_DUMP -extern void ql_dump_all(struct ql_adapter *qdev); +void ql_dump_all(struct ql_adapter *qdev);  #define QL_DUMP_ALL(qdev) ql_dump_all(qdev)  #else  #define QL_DUMP_ALL(qdev) diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c b/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c index 10093f0c4c0..829be21f97b 100644 --- a/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c +++ b/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c @@ -740,8 +740,8 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump)  	int i;  	if (!mpi_coredump) { -		netif_err(qdev, drv, qdev->ndev, "No memory available\n"); -		return -ENOMEM; +		netif_err(qdev, drv, qdev->ndev, "No memory allocated\n"); +		return -EINVAL;  	}  	/* Try to get the spinlock, but dont worry if @@ -1242,8 +1242,8 @@ static void ql_get_core_dump(struct ql_adapter *qdev)  	ql_queue_fw_error(qdev);  } -void ql_gen_reg_dump(struct ql_adapter *qdev, -			struct ql_reg_dump *mpi_coredump) +static void ql_gen_reg_dump(struct ql_adapter *qdev, +			    struct ql_reg_dump *mpi_coredump)  {  	int i, status; diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_ethtool.c b/drivers/net/ethernet/qlogic/qlge/qlge_ethtool.c index 0780e039b27..c3c514e332b 100644 --- a/drivers/net/ethernet/qlogic/qlge/qlge_ethtool.c +++ b/drivers/net/ethernet/qlogic/qlge/qlge_ethtool.c @@ -1,5 +1,4 @@  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/types.h>  #include <linux/module.h>  #include <linux/list.h> @@ -181,6 +180,7 @@ static const char ql_gstrings_test[][ETH_GSTRING_LEN] = {  };  #define QLGE_TEST_LEN (sizeof(ql_gstrings_test) / ETH_GSTRING_LEN)  #define QLGE_STATS_LEN ARRAY_SIZE(ql_gstrings_stats) +#define QLGE_RCV_MAC_ERR_STATS	7  static int ql_update_ring_coalescing(struct ql_adapter *qdev)  { @@ -280,6 +280,9 @@ static void ql_update_stats(struct ql_adapter *qdev)  		iter++;  	} +	/* Update receive mac error statistics */ +	iter += QLGE_RCV_MAC_ERR_STATS; +  	/*  	 * Get Per-priority TX pause frame counter statistics.  	 */ diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_main.c b/drivers/net/ethernet/qlogic/qlge/qlge_main.c index 2553cf4503b..b40050e03a5 100644 --- a/drivers/net/ethernet/qlogic/qlge/qlge_main.c +++ b/drivers/net/ethernet/qlogic/qlge/qlge_main.c @@ -6,7 +6,6 @@   *                      Ron Mercer <ron.mercer@qlogic.com>   */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/bitops.h>  #include <linux/types.h>  #include <linux/module.h> @@ -96,8 +95,10 @@ static DEFINE_PCI_DEVICE_TABLE(qlge_pci_tbl) = {  MODULE_DEVICE_TABLE(pci, qlge_pci_tbl); -static int ql_wol(struct ql_adapter *qdev); -static void qlge_set_multicast_list(struct net_device *ndev); +static int ql_wol(struct ql_adapter *); +static void qlge_set_multicast_list(struct net_device *); +static int ql_adapter_down(struct ql_adapter *); +static int ql_adapter_up(struct ql_adapter *);  /* This hardware semaphore causes exclusive access to   * resources shared between the NIC driver, MPI firmware, @@ -1464,6 +1465,29 @@ static void ql_categorize_rx_err(struct ql_adapter *qdev, u8 rx_err,  	}  } +/** + * ql_update_mac_hdr_len - helper routine to update the mac header length + * based on vlan tags if present + */ +static void ql_update_mac_hdr_len(struct ql_adapter *qdev, +				  struct ib_mac_iocb_rsp *ib_mac_rsp, +				  void *page, size_t *len) +{ +	u16 *tags; + +	if (qdev->ndev->features & NETIF_F_HW_VLAN_CTAG_RX) +		return; +	if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) { +		tags = (u16 *)page; +		/* Look for stacked vlan tags in ethertype field */ +		if (tags[6] == ETH_P_8021Q && +		    tags[8] == ETH_P_8021Q) +			*len += 2 * VLAN_HLEN; +		else +			*len += VLAN_HLEN; +	} +} +  /* Process an inbound completion from an rx ring. */  static void ql_process_mac_rx_gro_page(struct ql_adapter *qdev,  					struct rx_ring *rx_ring, @@ -1523,6 +1547,7 @@ static void ql_process_mac_rx_page(struct ql_adapter *qdev,  	void *addr;  	struct bq_desc *lbq_desc = ql_get_curr_lchunk(qdev, rx_ring);  	struct napi_struct *napi = &rx_ring->napi; +	size_t hlen = ETH_HLEN;  	skb = netdev_alloc_skb(ndev, length);  	if (!skb) { @@ -1540,25 +1565,28 @@ static void ql_process_mac_rx_page(struct ql_adapter *qdev,  		goto err_out;  	} +	/* Update the MAC header length*/ +	ql_update_mac_hdr_len(qdev, ib_mac_rsp, addr, &hlen); +  	/* The max framesize filter on this chip is set higher than  	 * MTU since FCoE uses 2k frames.  	 */ -	if (skb->len > ndev->mtu + ETH_HLEN) { +	if (skb->len > ndev->mtu + hlen) {  		netif_err(qdev, drv, qdev->ndev,  			  "Segment too small, dropping.\n");  		rx_ring->rx_dropped++;  		goto err_out;  	} -	memcpy(skb_put(skb, ETH_HLEN), addr, ETH_HLEN); +	memcpy(skb_put(skb, hlen), addr, hlen);  	netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev,  		     "%d bytes of headers and data in large. Chain page to new skb and pull tail.\n",  		     length);  	skb_fill_page_desc(skb, 0, lbq_desc->p.pg_chunk.page, -				lbq_desc->p.pg_chunk.offset+ETH_HLEN, -				length-ETH_HLEN); -	skb->len += length-ETH_HLEN; -	skb->data_len += length-ETH_HLEN; -	skb->truesize += length-ETH_HLEN; +				lbq_desc->p.pg_chunk.offset + hlen, +				length - hlen); +	skb->len += length - hlen; +	skb->data_len += length - hlen; +	skb->truesize += length - hlen;  	rx_ring->rx_packets++;  	rx_ring->rx_bytes += skb->len; @@ -1576,7 +1604,7 @@ static void ql_process_mac_rx_page(struct ql_adapter *qdev,  				(ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_V4)) {  			/* Unfragmented ipv4 UDP frame. */  			struct iphdr *iph = -				(struct iphdr *) ((u8 *)addr + ETH_HLEN); +				(struct iphdr *)((u8 *)addr + hlen);  			if (!(iph->frag_off &  				htons(IP_MF|IP_OFFSET))) {  				skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -1726,7 +1754,8 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev,  	struct bq_desc *sbq_desc;  	struct sk_buff *skb = NULL;  	u32 length = le32_to_cpu(ib_mac_rsp->data_len); -       u32 hdr_len = le32_to_cpu(ib_mac_rsp->hdr_len); +	u32 hdr_len = le32_to_cpu(ib_mac_rsp->hdr_len); +	size_t hlen = ETH_HLEN;  	/*  	 * Handle the header buffer if present. @@ -1853,9 +1882,10 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev,  			skb->data_len += length;  			skb->truesize += length;  			length -= length; -			__pskb_pull_tail(skb, -				(ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) ? -				VLAN_ETH_HLEN : ETH_HLEN); +			ql_update_mac_hdr_len(qdev, ib_mac_rsp, +					      lbq_desc->p.pg_chunk.va, +					      &hlen); +			__pskb_pull_tail(skb, hlen);  		}  	} else {  		/* @@ -1910,8 +1940,9 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev,  			length -= size;  			i++;  		} -		__pskb_pull_tail(skb, (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) ? -				VLAN_ETH_HLEN : ETH_HLEN); +		ql_update_mac_hdr_len(qdev, ib_mac_rsp, lbq_desc->p.pg_chunk.va, +				      &hlen); +		__pskb_pull_tail(skb, hlen);  	}  	return skb;  } @@ -2003,7 +2034,7 @@ static void ql_process_mac_split_rx_intr(struct ql_adapter *qdev,  	rx_ring->rx_packets++;  	rx_ring->rx_bytes += skb->len;  	skb_record_rx_queue(skb, rx_ring->cq_id); -	if ((ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) && (vlan_id != 0)) +	if (vlan_id != 0xffff)  		__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_id);  	if (skb->ip_summed == CHECKSUM_UNNECESSARY)  		napi_gro_receive(&rx_ring->napi, skb); @@ -2017,7 +2048,8 @@ static unsigned long ql_process_mac_rx_intr(struct ql_adapter *qdev,  					struct ib_mac_iocb_rsp *ib_mac_rsp)  {  	u32 length = le32_to_cpu(ib_mac_rsp->data_len); -	u16 vlan_id = (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) ? +	u16 vlan_id = ((ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) && +			(qdev->ndev->features & NETIF_F_HW_VLAN_CTAG_RX)) ?  			((le16_to_cpu(ib_mac_rsp->vlan_id) &  			IB_MAC_IOCB_RSP_VLAN_MASK)) : 0xffff; @@ -2310,17 +2342,44 @@ static void qlge_vlan_mode(struct net_device *ndev, netdev_features_t features)  	}  } +/** + * qlge_update_hw_vlan_features - helper routine to reinitialize the adapter + * based on the features to enable/disable hardware vlan accel + */ +static int qlge_update_hw_vlan_features(struct net_device *ndev, +					netdev_features_t features) +{ +	struct ql_adapter *qdev = netdev_priv(ndev); +	int status = 0; + +	status = ql_adapter_down(qdev); +	if (status) { +		netif_err(qdev, link, qdev->ndev, +			  "Failed to bring down the adapter\n"); +		return status; +	} + +	/* update the features with resent change */ +	ndev->features = features; + +	status = ql_adapter_up(qdev); +	if (status) { +		netif_err(qdev, link, qdev->ndev, +			  "Failed to bring up the adapter\n"); +		return status; +	} +	return status; +} +  static netdev_features_t qlge_fix_features(struct net_device *ndev,  	netdev_features_t features)  { -	/* -	 * Since there is no support for separate rx/tx vlan accel -	 * enable/disable make sure tx flag is always in same state as rx. -	 */ -	if (features & NETIF_F_HW_VLAN_CTAG_RX) -		features |= NETIF_F_HW_VLAN_CTAG_TX; -	else -		features &= ~NETIF_F_HW_VLAN_CTAG_TX; +	int err; + +	/* Update the behavior of vlan accel in the adapter */ +	err = qlge_update_hw_vlan_features(ndev, features); +	if (err) +		return err;  	return features;  } @@ -2497,11 +2556,10 @@ static int ql_tso(struct sk_buff *skb, struct ob_mac_tso_iocb_req *mac_iocb_ptr)  	if (skb_is_gso(skb)) {  		int err; -		if (skb_header_cloned(skb)) { -			err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); -			if (err) -				return err; -		} + +		err = skb_cow_head(skb, 0); +		if (err < 0) +			return err;  		mac_iocb_ptr->opcode = OPCODE_OB_MAC_TSO_IOCB;  		mac_iocb_ptr->flags3 |= OB_MAC_TSO_IOCB_IC; @@ -3272,24 +3330,16 @@ static void ql_enable_msix(struct ql_adapter *qdev)  		for (i = 0; i < qdev->intr_count; i++)  			qdev->msi_x_entry[i].entry = i; -		/* Loop to get our vectors.  We start with -		 * what we want and settle for what we get. -		 */ -		do { -			err = pci_enable_msix(qdev->pdev, -				qdev->msi_x_entry, qdev->intr_count); -			if (err > 0) -				qdev->intr_count = err; -		} while (err > 0); - +		err = pci_enable_msix_range(qdev->pdev, qdev->msi_x_entry, +					    1, qdev->intr_count);  		if (err < 0) {  			kfree(qdev->msi_x_entry);  			qdev->msi_x_entry = NULL;  			netif_warn(qdev, ifup, qdev->ndev,  				   "MSI-X Enable failed, trying MSI.\n"); -			qdev->intr_count = 1;  			qlge_irq_type = MSI_IRQ; -		} else if (err == 0) { +		} else { +			qdev->intr_count = err;  			set_bit(QL_MSIX_ENABLED, &qdev->flags);  			netif_info(qdev, ifup, qdev->ndev,  				   "MSI-X Enabled, got %d vectors.\n", @@ -3545,7 +3595,7 @@ static int ql_request_irq(struct ql_adapter *qdev)  	}  	return status;  err_irq: -	netif_err(qdev, ifup, qdev->ndev, "Failed to get the interrupts!!!/n"); +	netif_err(qdev, ifup, qdev->ndev, "Failed to get the interrupts!!!\n");  	ql_free_irq(qdev);  	return status;  } @@ -3704,8 +3754,12 @@ static int ql_adapter_initialize(struct ql_adapter *qdev)  	ql_write32(qdev, SYS, mask | value);  	/* Set the default queue, and VLAN behavior. */ -	value = NIC_RCV_CFG_DFQ | NIC_RCV_CFG_RV; -	mask = NIC_RCV_CFG_DFQ_MASK | (NIC_RCV_CFG_RV << 16); +	value = NIC_RCV_CFG_DFQ; +	mask = NIC_RCV_CFG_DFQ_MASK; +	if (qdev->ndev->features & NETIF_F_HW_VLAN_CTAG_RX) { +		value |= NIC_RCV_CFG_RV; +		mask |= (NIC_RCV_CFG_RV << 16); +	}  	ql_write32(qdev, NIC_RCV_CFG, (mask | value));  	/* Set the MPI interrupt to enabled. */ @@ -4505,7 +4559,6 @@ static void ql_release_all(struct pci_dev *pdev)  		iounmap(qdev->doorbell_area);  	vfree(qdev->mpi_coredump);  	pci_release_regions(pdev); -	pci_set_drvdata(pdev, NULL);  }  static int ql_init_device(struct pci_dev *pdev, struct net_device *ndev, @@ -4692,12 +4745,20 @@ static int qlge_probe(struct pci_dev *pdev,  	qdev = netdev_priv(ndev);  	SET_NETDEV_DEV(ndev, &pdev->dev); -	ndev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | -		NETIF_F_TSO | NETIF_F_TSO_ECN | -		NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_RXCSUM; -	ndev->features = ndev->hw_features | -		NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_FILTER; +	ndev->hw_features = NETIF_F_SG | +			    NETIF_F_IP_CSUM | +			    NETIF_F_TSO | +			    NETIF_F_TSO_ECN | +			    NETIF_F_HW_VLAN_CTAG_TX | +			    NETIF_F_HW_VLAN_CTAG_RX | +			    NETIF_F_HW_VLAN_CTAG_FILTER | +			    NETIF_F_RXCSUM; +	ndev->features = ndev->hw_features;  	ndev->vlan_features = ndev->hw_features; +	/* vlan gets same features (except vlan filter) */ +	ndev->vlan_features &= ~(NETIF_F_HW_VLAN_CTAG_FILTER | +				 NETIF_F_HW_VLAN_CTAG_TX | +				 NETIF_F_HW_VLAN_CTAG_RX);  	if (test_bit(QL_DMA64, &qdev->flags))  		ndev->features |= NETIF_F_HIGHDMA; @@ -4709,7 +4770,7 @@ static int qlge_probe(struct pci_dev *pdev,  	ndev->irq = pdev->irq;  	ndev->netdev_ops = &qlge_netdev_ops; -	SET_ETHTOOL_OPS(ndev, &qlge_ethtool_ops); +	ndev->ethtool_ops = &qlge_ethtool_ops;  	ndev->watchdog_timeo = 10 * HZ;  	err = register_netdev(ndev); diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_mpi.c b/drivers/net/ethernet/qlogic/qlge/qlge_mpi.c index ff2bf8a4e24..7ad146080c3 100644 --- a/drivers/net/ethernet/qlogic/qlge/qlge_mpi.c +++ b/drivers/net/ethernet/qlogic/qlge/qlge_mpi.c @@ -1274,7 +1274,7 @@ void ql_mpi_reset_work(struct work_struct *work)  		return;  	} -	if (!ql_core_dump(qdev, qdev->mpi_coredump)) { +	if (qdev->mpi_coredump && !ql_core_dump(qdev, qdev->mpi_coredump)) {  		netif_err(qdev, drv, qdev->ndev, "Core is dumped!\n");  		qdev->core_is_dumped = 1;  		queue_delayed_work(qdev->workqueue,  | 
