From af19b49152bdb68fda894183e88096d6d1aa5c3d Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Wed, 13 Jan 2010 00:37:25 +0000 Subject: qlcnic: Qlogic ethernet driver for CNA devices o 1G/10G Ethernet Driver for Qlgic QLE8240 and QLE8242 CNA devices. Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/qlcnic/Makefile | 8 + drivers/net/qlcnic/qlcnic.h | 1106 +++++++++++++++ drivers/net/qlcnic/qlcnic_ctx.c | 536 +++++++ drivers/net/qlcnic/qlcnic_ethtool.c | 870 ++++++++++++ drivers/net/qlcnic/qlcnic_hdr.h | 937 +++++++++++++ drivers/net/qlcnic/qlcnic_hw.c | 1201 ++++++++++++++++ drivers/net/qlcnic/qlcnic_init.c | 1466 ++++++++++++++++++++ drivers/net/qlcnic/qlcnic_main.c | 2604 +++++++++++++++++++++++++++++++++++ 8 files changed, 8728 insertions(+) create mode 100644 drivers/net/qlcnic/Makefile create mode 100644 drivers/net/qlcnic/qlcnic.h create mode 100644 drivers/net/qlcnic/qlcnic_ctx.c create mode 100644 drivers/net/qlcnic/qlcnic_ethtool.c create mode 100644 drivers/net/qlcnic/qlcnic_hdr.h create mode 100644 drivers/net/qlcnic/qlcnic_hw.c create mode 100644 drivers/net/qlcnic/qlcnic_init.c create mode 100644 drivers/net/qlcnic/qlcnic_main.c (limited to 'drivers/net/qlcnic') diff --git a/drivers/net/qlcnic/Makefile b/drivers/net/qlcnic/Makefile new file mode 100644 index 00000000000..ddba83ef3f4 --- /dev/null +++ b/drivers/net/qlcnic/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for Qlogic 1G/10G Ethernet Driver for CNA devices +# + +obj-$(CONFIG_QLCNIC) := qlcnic.o + +qlcnic-y := qlcnic_hw.o qlcnic_main.o qlcnic_init.o \ + qlcnic_ethtool.o qlcnic_ctx.o diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h new file mode 100644 index 00000000000..abec4684653 --- /dev/null +++ b/drivers/net/qlcnic/qlcnic.h @@ -0,0 +1,1106 @@ +/* + * Copyright (C) 2009 - QLogic Corporation. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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. + * + * The full GNU General Public License is included in this distribution + * in the file called "COPYING". + * + */ + +#ifndef _QLCNIC_H_ +#define _QLCNIC_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include "qlcnic_hdr.h" + +#define _QLCNIC_LINUX_MAJOR 5 +#define _QLCNIC_LINUX_MINOR 0 +#define _QLCNIC_LINUX_SUBVERSION 0 +#define QLCNIC_LINUX_VERSIONID "5.0.0" + +#define QLCNIC_VERSION_CODE(a, b, c) (((a) << 24) + ((b) << 16) + (c)) +#define _major(v) (((v) >> 24) & 0xff) +#define _minor(v) (((v) >> 16) & 0xff) +#define _build(v) ((v) & 0xffff) + +/* version in image has weird encoding: + * 7:0 - major + * 15:8 - minor + * 31:16 - build (little endian) + */ +#define QLCNIC_DECODE_VERSION(v) \ + QLCNIC_VERSION_CODE(((v) & 0xff), (((v) >> 8) & 0xff), ((v) >> 16)) + +#define QLCNIC_NUM_FLASH_SECTORS (64) +#define QLCNIC_FLASH_SECTOR_SIZE (64 * 1024) +#define QLCNIC_FLASH_TOTAL_SIZE (QLCNIC_NUM_FLASH_SECTORS \ + * QLCNIC_FLASH_SECTOR_SIZE) + +#define RCV_DESC_RINGSIZE(rds_ring) \ + (sizeof(struct rcv_desc) * (rds_ring)->num_desc) +#define RCV_BUFF_RINGSIZE(rds_ring) \ + (sizeof(struct qlcnic_rx_buffer) * rds_ring->num_desc) +#define STATUS_DESC_RINGSIZE(sds_ring) \ + (sizeof(struct status_desc) * (sds_ring)->num_desc) +#define TX_BUFF_RINGSIZE(tx_ring) \ + (sizeof(struct qlcnic_cmd_buffer) * tx_ring->num_desc) +#define TX_DESC_RINGSIZE(tx_ring) \ + (sizeof(struct cmd_desc_type0) * tx_ring->num_desc) + +#define QLCNIC_P3P_A0 0x50 + +#define QLCNIC_IS_REVISION_P3P(REVISION) (REVISION >= QLCNIC_P3P_A0) + +#define FIRST_PAGE_GROUP_START 0 +#define FIRST_PAGE_GROUP_END 0x100000 + +#define P3_MAX_MTU (9600) +#define QLCNIC_MAX_ETHERHDR 32 /* This contains some padding */ + +#define QLCNIC_P3_RX_BUF_MAX_LEN (QLCNIC_MAX_ETHERHDR + ETH_DATA_LEN) +#define QLCNIC_P3_RX_JUMBO_BUF_MAX_LEN (QLCNIC_MAX_ETHERHDR + P3_MAX_MTU) +#define QLCNIC_CT_DEFAULT_RX_BUF_LEN 2048 +#define QLCNIC_LRO_BUFFER_EXTRA 2048 + +#define QLCNIC_RX_LRO_BUFFER_LENGTH (8060) + +/* Opcodes to be used with the commands */ +#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_IPSEC 0x07 +#define TX_IPSEC_CMD 0x0a +#define TX_TCPV6_PKT 0x0b +#define TX_UDPV6_PKT 0x0c + +/* Tx defines */ +#define MAX_BUFFERS_PER_CMD 32 +#define TX_STOP_THRESH ((MAX_SKB_FRAGS >> 2) + 4) +#define QLCNIC_MAX_TX_TIMEOUTS 2 + +/* + * Following are the states of the Phantom. Phantom will set them and + * Host will read to check if the fields are correct. + */ +#define PHAN_INITIALIZE_FAILED 0xffff +#define PHAN_INITIALIZE_COMPLETE 0xff01 + +/* Host writes the following to notify that it has done the init-handshake */ +#define PHAN_INITIALIZE_ACK 0xf00f +#define PHAN_PEG_RCV_INITIALIZED 0xff01 + +#define NUM_RCV_DESC_RINGS 3 +#define NUM_STS_DESC_RINGS 4 + +#define RCV_RING_NORMAL 0 +#define RCV_RING_JUMBO 1 +#define RCV_RING_LRO 2 + +#define MIN_CMD_DESCRIPTORS 64 +#define MIN_RCV_DESCRIPTORS 64 +#define MIN_JUMBO_DESCRIPTORS 32 + +#define MAX_CMD_DESCRIPTORS 1024 +#define MAX_RCV_DESCRIPTORS_1G 4096 +#define MAX_RCV_DESCRIPTORS_10G 8192 +#define MAX_JUMBO_RCV_DESCRIPTORS_1G 512 +#define MAX_JUMBO_RCV_DESCRIPTORS_10G 1024 +#define MAX_LRO_RCV_DESCRIPTORS 8 + +#define DEFAULT_RCV_DESCRIPTORS_1G 2048 +#define DEFAULT_RCV_DESCRIPTORS_10G 4096 + +#define get_next_index(index, length) \ + (((index) + 1) & ((length) - 1)) + +#define MPORT_MULTI_FUNCTION_MODE 0x2222 + +/* + * Following data structures describe the descriptors that will be used. + * Added fileds of tcpHdrSize and ipHdrSize, The driver needs to do it only when + * we are doing LSO (above the 1500 size packet) only. + */ + +#define FLAGS_VLAN_TAGGED 0x10 +#define FLAGS_VLAN_OOB 0x40 + +#define qlcnic_set_tx_vlan_tci(cmd_desc, v) \ + (cmd_desc)->vlan_TCI = cpu_to_le16(v); +#define qlcnic_set_cmd_desc_port(cmd_desc, var) \ + ((cmd_desc)->port_ctxid |= ((var) & 0x0F)) +#define qlcnic_set_cmd_desc_ctxid(cmd_desc, var) \ + ((cmd_desc)->port_ctxid |= ((var) << 4 & 0xF0)) + +#define qlcnic_set_tx_port(_desc, _port) \ + ((_desc)->port_ctxid = ((_port) & 0xf) | (((_port) << 4) & 0xf0)) + +#define qlcnic_set_tx_flags_opcode(_desc, _flags, _opcode) \ + ((_desc)->flags_opcode = \ + cpu_to_le16(((_flags) & 0x7f) | (((_opcode) & 0x3f) << 7))) + +#define qlcnic_set_tx_frags_len(_desc, _frags, _len) \ + ((_desc)->nfrags__length = \ + cpu_to_le32(((_frags) & 0xff) | (((_len) & 0xffffff) << 8))) + +struct cmd_desc_type0 { + u8 tcp_hdr_offset; /* For LSO only */ + u8 ip_hdr_offset; /* For LSO only */ + __le16 flags_opcode; /* 15:13 unused, 12:7 opcode, 6:0 flags */ + __le32 nfrags__length; /* 31:8 total len, 7:0 frag count */ + + __le64 addr_buffer2; + + __le16 reference_handle; + __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 */ + + __le64 addr_buffer3; + __le64 addr_buffer1; + + __le16 buffer_length[4]; + + __le64 addr_buffer4; + + __le32 reserved2; + __le16 reserved; + __le16 vlan_TCI; + +} __attribute__ ((aligned(64))); + +/* Note: sizeof(rcv_desc) should always be a mutliple of 2 */ +struct rcv_desc { + __le16 reference_handle; + __le16 reserved; + __le32 buffer_length; /* allocated buffer length (usually 2K) */ + __le64 addr_buffer; +}; + +/* opcode field in status_desc */ +#define QLCNIC_SYN_OFFLOAD 0x03 +#define QLCNIC_RXPKT_DESC 0x04 +#define QLCNIC_OLD_RXPKT_DESC 0x3f +#define QLCNIC_RESPONSE_DESC 0x05 +#define QLCNIC_LRO_DESC 0x12 + +/* for status field in status_desc */ +#define STATUS_CKSUM_OK (2) + +/* owner bits of status_desc */ +#define STATUS_OWNER_HOST (0x1ULL << 56) +#define STATUS_OWNER_PHANTOM (0x2ULL << 56) + +/* Status descriptor: + 0-3 port, 4-7 status, 8-11 type, 12-27 total_length + 28-43 reference_handle, 44-47 protocol, 48-52 pkt_offset + 53-55 desc_cnt, 56-57 owner, 58-63 opcode + */ +#define qlcnic_get_sts_port(sts_data) \ + ((sts_data) & 0x0F) +#define qlcnic_get_sts_status(sts_data) \ + (((sts_data) >> 4) & 0x0F) +#define qlcnic_get_sts_type(sts_data) \ + (((sts_data) >> 8) & 0x0F) +#define qlcnic_get_sts_totallength(sts_data) \ + (((sts_data) >> 12) & 0xFFFF) +#define qlcnic_get_sts_refhandle(sts_data) \ + (((sts_data) >> 28) & 0xFFFF) +#define qlcnic_get_sts_prot(sts_data) \ + (((sts_data) >> 44) & 0x0F) +#define qlcnic_get_sts_pkt_offset(sts_data) \ + (((sts_data) >> 48) & 0x1F) +#define qlcnic_get_sts_desc_cnt(sts_data) \ + (((sts_data) >> 53) & 0x7) +#define qlcnic_get_sts_opcode(sts_data) \ + (((sts_data) >> 58) & 0x03F) + +#define qlcnic_get_lro_sts_refhandle(sts_data) \ + ((sts_data) & 0x0FFFF) +#define qlcnic_get_lro_sts_length(sts_data) \ + (((sts_data) >> 16) & 0x0FFFF) +#define qlcnic_get_lro_sts_l2_hdr_offset(sts_data) \ + (((sts_data) >> 32) & 0x0FF) +#define qlcnic_get_lro_sts_l4_hdr_offset(sts_data) \ + (((sts_data) >> 40) & 0x0FF) +#define qlcnic_get_lro_sts_timestamp(sts_data) \ + (((sts_data) >> 48) & 0x1) +#define qlcnic_get_lro_sts_type(sts_data) \ + (((sts_data) >> 49) & 0x7) +#define qlcnic_get_lro_sts_push_flag(sts_data) \ + (((sts_data) >> 52) & 0x1) +#define qlcnic_get_lro_sts_seq_number(sts_data) \ + ((sts_data) & 0x0FFFFFFFF) + + +struct status_desc { + __le64 status_desc_data[2]; +} __attribute__ ((aligned(16))); + +/* UNIFIED ROMIMAGE */ +#define QLCNIC_UNI_FW_MIN_SIZE 0xc8000 +#define QLCNIC_UNI_DIR_SECT_PRODUCT_TBL 0x0 +#define QLCNIC_UNI_DIR_SECT_BOOTLD 0x6 +#define QLCNIC_UNI_DIR_SECT_FW 0x7 + +/*Offsets */ +#define QLCNIC_UNI_CHIP_REV_OFF 10 +#define QLCNIC_UNI_FLAGS_OFF 11 +#define QLCNIC_UNI_BIOS_VERSION_OFF 12 +#define QLCNIC_UNI_BOOTLD_IDX_OFF 27 +#define QLCNIC_UNI_FIRMWARE_IDX_OFF 29 + +struct uni_table_desc{ + u32 findex; + u32 num_entries; + u32 entry_size; + u32 reserved[5]; +}; + +struct uni_data_desc{ + u32 findex; + u32 size; + u32 reserved[5]; +}; + +/* Magic number to let user know flash is programmed */ +#define QLCNIC_BDINFO_MAGIC 0x12345678 + +#define QLCNIC_BRDTYPE_P3_REF_QG 0x0021 +#define QLCNIC_BRDTYPE_P3_HMEZ 0x0022 +#define QLCNIC_BRDTYPE_P3_10G_CX4_LP 0x0023 +#define QLCNIC_BRDTYPE_P3_4_GB 0x0024 +#define QLCNIC_BRDTYPE_P3_IMEZ 0x0025 +#define QLCNIC_BRDTYPE_P3_10G_SFP_PLUS 0x0026 +#define QLCNIC_BRDTYPE_P3_10000_BASE_T 0x0027 +#define QLCNIC_BRDTYPE_P3_XG_LOM 0x0028 +#define QLCNIC_BRDTYPE_P3_4_GB_MM 0x0029 +#define QLCNIC_BRDTYPE_P3_10G_SFP_CT 0x002a +#define QLCNIC_BRDTYPE_P3_10G_SFP_QT 0x002b +#define QLCNIC_BRDTYPE_P3_10G_CX4 0x0031 +#define QLCNIC_BRDTYPE_P3_10G_XFP 0x0032 +#define QLCNIC_BRDTYPE_P3_10G_TP 0x0080 + +/* Flash memory map */ +#define QLCNIC_BRDCFG_START 0x4000 /* board config */ +#define QLCNIC_BOOTLD_START 0x10000 /* bootld */ +#define QLCNIC_IMAGE_START 0x43000 /* compressed image */ +#define QLCNIC_USER_START 0x3E8000 /* Firmare info */ + +#define QLCNIC_FW_VERSION_OFFSET (QLCNIC_USER_START+0x408) +#define QLCNIC_FW_SIZE_OFFSET (QLCNIC_USER_START+0x40c) +#define QLCNIC_FW_SERIAL_NUM_OFFSET (QLCNIC_USER_START+0x81c) +#define QLCNIC_BIOS_VERSION_OFFSET (QLCNIC_USER_START+0x83c) + +#define QLCNIC_BRDTYPE_OFFSET (QLCNIC_BRDCFG_START+0x8) +#define QLCNIC_FW_MAGIC_OFFSET (QLCNIC_BRDCFG_START+0x128) + +#define QLCNIC_FW_MIN_SIZE (0x3fffff) +#define QLCNIC_UNIFIED_ROMIMAGE 0 +#define QLCNIC_FLASH_ROMIMAGE 1 +#define QLCNIC_UNKNOWN_ROMIMAGE 0xff + +#define QLCNIC_UNIFIED_ROMIMAGE_NAME "phanfw.bin" +#define QLCNIC_FLASH_ROMIMAGE_NAME "flash" + +extern char qlcnic_driver_name[]; + +/* Number of status descriptors to handle per interrupt */ +#define MAX_STATUS_HANDLE (64) + +/* + * qlcnic_skb_frag{} is to contain mapping info for each SG list. This + * has to be freed when DMA is complete. This is part of qlcnic_tx_buffer{}. + */ +struct qlcnic_skb_frag { + u64 dma; + u64 length; +}; + +struct qlcnic_recv_crb { + u32 crb_rcv_producer[NUM_RCV_DESC_RINGS]; + u32 crb_sts_consumer[NUM_STS_DESC_RINGS]; + u32 sw_int_mask[NUM_STS_DESC_RINGS]; +}; + +/* Following defines are for the state of the buffers */ +#define QLCNIC_BUFFER_FREE 0 +#define QLCNIC_BUFFER_BUSY 1 + +/* + * There will be one qlcnic_buffer per skb packet. These will be + * used to save the dma info for pci_unmap_page() + */ +struct qlcnic_cmd_buffer { + struct sk_buff *skb; + struct qlcnic_skb_frag frag_array[MAX_BUFFERS_PER_CMD + 1]; + u32 frag_count; +}; + +/* In rx_buffer, we do not need multiple fragments as is a single buffer */ +struct qlcnic_rx_buffer { + struct list_head list; + struct sk_buff *skb; + u64 dma; + u16 ref_handle; + u16 state; +}; + +/* Board types */ +#define QLCNIC_GBE 0x01 +#define QLCNIC_XGBE 0x02 + +/* + * One hardware_context{} per adapter + * contains interrupt info as well shared hardware info. + */ +struct qlcnic_hardware_context { + void __iomem *pci_base0; + void __iomem *ocm_win_crb; + + unsigned long pci_len0; + + u32 ocm_win; + u32 crb_win; + + rwlock_t crb_lock; + struct mutex mem_lock; + + u8 cut_through; + u8 revision_id; + u8 pci_func; + u8 linkup; + u16 port_type; + u16 board_type; +}; + +struct qlcnic_adapter_stats { + u64 xmitcalled; + u64 xmitfinished; + u64 rxdropped; + u64 txdropped; + u64 csummed; + u64 rx_pkts; + u64 lro_pkts; + u64 rxbytes; + u64 txbytes; +}; + +/* + * Rcv Descriptor Context. One such per Rcv Descriptor. There may + * be one Rcv Descriptor for normal packets, one for jumbo and may be others. + */ +struct qlcnic_host_rds_ring { + u32 producer; + u32 num_desc; + u32 dma_size; + u32 skb_size; + u32 flags; + void __iomem *crb_rcv_producer; + struct rcv_desc *desc_head; + struct qlcnic_rx_buffer *rx_buf_arr; + struct list_head free_list; + spinlock_t lock; + dma_addr_t phys_addr; +}; + +struct qlcnic_host_sds_ring { + u32 consumer; + u32 num_desc; + void __iomem *crb_sts_consumer; + void __iomem *crb_intr_mask; + + struct status_desc *desc_head; + struct qlcnic_adapter *adapter; + struct napi_struct napi; + struct list_head free_list[NUM_RCV_DESC_RINGS]; + + int irq; + + dma_addr_t phys_addr; + char name[IFNAMSIZ+4]; +}; + +struct qlcnic_host_tx_ring { + u32 producer; + __le32 *hw_consumer; + u32 sw_consumer; + void __iomem *crb_cmd_producer; + u32 num_desc; + + struct netdev_queue *txq; + + struct qlcnic_cmd_buffer *cmd_buf_arr; + struct cmd_desc_type0 *desc_head; + dma_addr_t phys_addr; + dma_addr_t hw_cons_phys_addr; +}; + +/* + * Receive context. There is one such structure per instance of the + * receive processing. Any state information that is relevant to + * the receive, and is must be in this structure. The global data may be + * present elsewhere. + */ +struct qlcnic_recv_context { + u32 state; + u16 context_id; + u16 virt_port; + + struct qlcnic_host_rds_ring *rds_rings; + struct qlcnic_host_sds_ring *sds_rings; +}; + +/* HW context creation */ + +#define QLCNIC_OS_CRB_RETRY_COUNT 4000 +#define QLCNIC_CDRP_SIGNATURE_MAKE(pcifn, version) \ + (((pcifn) & 0xff) | (((version) & 0xff) << 8) | (0xcafe << 16)) + +#define QLCNIC_CDRP_CMD_BIT 0x80000000 + +/* + * All responses must have the QLCNIC_CDRP_CMD_BIT cleared + * in the crb QLCNIC_CDRP_CRB_OFFSET. + */ +#define QLCNIC_CDRP_FORM_RSP(rsp) (rsp) +#define QLCNIC_CDRP_IS_RSP(rsp) (((rsp) & QLCNIC_CDRP_CMD_BIT) == 0) + +#define QLCNIC_CDRP_RSP_OK 0x00000001 +#define QLCNIC_CDRP_RSP_FAIL 0x00000002 +#define QLCNIC_CDRP_RSP_TIMEOUT 0x00000003 + +/* + * All commands must have the QLCNIC_CDRP_CMD_BIT set in + * the crb QLCNIC_CDRP_CRB_OFFSET. + */ +#define QLCNIC_CDRP_FORM_CMD(cmd) (QLCNIC_CDRP_CMD_BIT | (cmd)) +#define QLCNIC_CDRP_IS_CMD(cmd) (((cmd) & QLCNIC_CDRP_CMD_BIT) != 0) + +#define QLCNIC_CDRP_CMD_SUBMIT_CAPABILITIES 0x00000001 +#define QLCNIC_CDRP_CMD_READ_MAX_RDS_PER_CTX 0x00000002 +#define QLCNIC_CDRP_CMD_READ_MAX_SDS_PER_CTX 0x00000003 +#define QLCNIC_CDRP_CMD_READ_MAX_RULES_PER_CTX 0x00000004 +#define QLCNIC_CDRP_CMD_READ_MAX_RX_CTX 0x00000005 +#define QLCNIC_CDRP_CMD_READ_MAX_TX_CTX 0x00000006 +#define QLCNIC_CDRP_CMD_CREATE_RX_CTX 0x00000007 +#define QLCNIC_CDRP_CMD_DESTROY_RX_CTX 0x00000008 +#define QLCNIC_CDRP_CMD_CREATE_TX_CTX 0x00000009 +#define QLCNIC_CDRP_CMD_DESTROY_TX_CTX 0x0000000a +#define QLCNIC_CDRP_CMD_SETUP_STATISTICS 0x0000000e +#define QLCNIC_CDRP_CMD_GET_STATISTICS 0x0000000f +#define QLCNIC_CDRP_CMD_DELETE_STATISTICS 0x00000010 +#define QLCNIC_CDRP_CMD_SET_MTU 0x00000012 +#define QLCNIC_CDRP_CMD_READ_PHY 0x00000013 +#define QLCNIC_CDRP_CMD_WRITE_PHY 0x00000014 +#define QLCNIC_CDRP_CMD_READ_HW_REG 0x00000015 +#define QLCNIC_CDRP_CMD_GET_FLOW_CTL 0x00000016 +#define QLCNIC_CDRP_CMD_SET_FLOW_CTL 0x00000017 +#define QLCNIC_CDRP_CMD_READ_MAX_MTU 0x00000018 +#define QLCNIC_CDRP_CMD_READ_MAX_LRO 0x00000019 +#define QLCNIC_CDRP_CMD_CONFIGURE_TOE 0x0000001a +#define QLCNIC_CDRP_CMD_FUNC_ATTRIB 0x0000001b +#define QLCNIC_CDRP_CMD_READ_PEXQ_PARAMETERS 0x0000001c +#define QLCNIC_CDRP_CMD_GET_LIC_CAPABILITIES 0x0000001d +#define QLCNIC_CDRP_CMD_READ_MAX_LRO_PER_BOARD 0x0000001e +#define QLCNIC_CDRP_CMD_MAX 0x0000001f + +#define QLCNIC_RCODE_SUCCESS 0 +#define QLCNIC_RCODE_TIMEOUT 17 +#define QLCNIC_DESTROY_CTX_RESET 0 + +/* + * Capabilities Announced + */ +#define QLCNIC_CAP0_LEGACY_CONTEXT (1) +#define QLCNIC_CAP0_LEGACY_MN (1 << 2) +#define QLCNIC_CAP0_LSO (1 << 6) +#define QLCNIC_CAP0_JUMBO_CONTIGUOUS (1 << 7) +#define QLCNIC_CAP0_LRO_CONTIGUOUS (1 << 8) + +/* + * Context state + */ +#define QLCNIC_HOST_CTX_STATE_ACTIVE 2 + +/* + * Rx context + */ + +struct qlcnic_hostrq_sds_ring { + __le64 host_phys_addr; /* Ring base addr */ + __le32 ring_size; /* Ring entries */ + __le16 msi_index; + __le16 rsvd; /* Padding */ +}; + +struct qlcnic_hostrq_rds_ring { + __le64 host_phys_addr; /* Ring base addr */ + __le64 buff_size; /* Packet buffer size */ + __le32 ring_size; /* Ring entries */ + __le32 ring_kind; /* Class of ring */ +}; + +struct qlcnic_hostrq_rx_ctx { + __le64 host_rsp_dma_addr; /* Response dma'd here */ + __le32 capabilities[4]; /* Flag bit vector */ + __le32 host_int_crb_mode; /* Interrupt crb usage */ + __le32 host_rds_crb_mode; /* RDS crb usage */ + /* These ring offsets are relative to data[0] below */ + __le32 rds_ring_offset; /* Offset to RDS config */ + __le32 sds_ring_offset; /* Offset to SDS config */ + __le16 num_rds_rings; /* Count of RDS rings */ + __le16 num_sds_rings; /* Count of SDS rings */ + __le16 rsvd1; /* Padding */ + __le16 rsvd2; /* Padding */ + u8 reserved[128]; /* reserve space for future expansion*/ + /* MUST BE 64-bit aligned. + The following is packed: + - N hostrq_rds_rings + - N hostrq_sds_rings */ + char data[0]; +}; + +struct qlcnic_cardrsp_rds_ring{ + __le32 host_producer_crb; /* Crb to use */ + __le32 rsvd1; /* Padding */ +}; + +struct qlcnic_cardrsp_sds_ring { + __le32 host_consumer_crb; /* Crb to use */ + __le32 interrupt_crb; /* Crb to use */ +}; + +struct qlcnic_cardrsp_rx_ctx { + /* These ring offsets are relative to data[0] below */ + __le32 rds_ring_offset; /* Offset to RDS config */ + __le32 sds_ring_offset; /* Offset to SDS config */ + __le32 host_ctx_state; /* Starting State */ + __le32 num_fn_per_port; /* How many PCI fn share the port */ + __le16 num_rds_rings; /* Count of RDS rings */ + __le16 num_sds_rings; /* Count of SDS rings */ + __le16 context_id; /* Handle for context */ + u8 phys_port; /* Physical id of port */ + u8 virt_port; /* Virtual/Logical id of port */ + u8 reserved[128]; /* save space for future expansion */ + /* MUST BE 64-bit aligned. + The following is packed: + - N cardrsp_rds_rings + - N cardrs_sds_rings */ + char data[0]; +}; + +#define SIZEOF_HOSTRQ_RX(HOSTRQ_RX, rds_rings, sds_rings) \ + (sizeof(HOSTRQ_RX) + \ + (rds_rings)*(sizeof(struct qlcnic_hostrq_rds_ring)) + \ + (sds_rings)*(sizeof(struct qlcnic_hostrq_sds_ring))) + +#define SIZEOF_CARDRSP_RX(CARDRSP_RX, rds_rings, sds_rings) \ + (sizeof(CARDRSP_RX) + \ + (rds_rings)*(sizeof(struct qlcnic_cardrsp_rds_ring)) + \ + (sds_rings)*(sizeof(struct qlcnic_cardrsp_sds_ring))) + +/* + * Tx context + */ + +struct qlcnic_hostrq_cds_ring { + __le64 host_phys_addr; /* Ring base addr */ + __le32 ring_size; /* Ring entries */ + __le32 rsvd; /* Padding */ +}; + +struct qlcnic_hostrq_tx_ctx { + __le64 host_rsp_dma_addr; /* Response dma'd here */ + __le64 cmd_cons_dma_addr; /* */ + __le64 dummy_dma_addr; /* */ + __le32 capabilities[4]; /* Flag bit vector */ + __le32 host_int_crb_mode; /* Interrupt crb usage */ + __le32 rsvd1; /* Padding */ + __le16 rsvd2; /* Padding */ + __le16 interrupt_ctl; + __le16 msi_index; + __le16 rsvd3; /* Padding */ + struct qlcnic_hostrq_cds_ring cds_ring; /* Desc of cds ring */ + u8 reserved[128]; /* future expansion */ +}; + +struct qlcnic_cardrsp_cds_ring { + __le32 host_producer_crb; /* Crb to use */ + __le32 interrupt_crb; /* Crb to use */ +}; + +struct qlcnic_cardrsp_tx_ctx { + __le32 host_ctx_state; /* Starting state */ + __le16 context_id; /* Handle for context */ + u8 phys_port; /* Physical id of port */ + u8 virt_port; /* Virtual/Logical id of port */ + struct qlcnic_cardrsp_cds_ring cds_ring; /* Card cds settings */ + u8 reserved[128]; /* future expansion */ +}; + +#define SIZEOF_HOSTRQ_TX(HOSTRQ_TX) (sizeof(HOSTRQ_TX)) +#define SIZEOF_CARDRSP_TX(CARDRSP_TX) (sizeof(CARDRSP_TX)) + +/* CRB */ + +#define QLCNIC_HOST_RDS_CRB_MODE_UNIQUE 0 +#define QLCNIC_HOST_RDS_CRB_MODE_SHARED 1 +#define QLCNIC_HOST_RDS_CRB_MODE_CUSTOM 2 +#define QLCNIC_HOST_RDS_CRB_MODE_MAX 3 + +#define QLCNIC_HOST_INT_CRB_MODE_UNIQUE 0 +#define QLCNIC_HOST_INT_CRB_MODE_SHARED 1 +#define QLCNIC_HOST_INT_CRB_MODE_NORX 2 +#define QLCNIC_HOST_INT_CRB_MODE_NOTX 3 +#define QLCNIC_HOST_INT_CRB_MODE_NORXTX 4 + + +/* MAC */ + +#define MC_COUNT_P3 38 + +#define QLCNIC_MAC_NOOP 0 +#define QLCNIC_MAC_ADD 1 +#define QLCNIC_MAC_DEL 2 + +struct qlcnic_mac_list_s { + struct list_head list; + uint8_t mac_addr[ETH_ALEN+2]; +}; + +/* + * Interrupt coalescing defaults. The defaults are for 1500 MTU. It is + * adjusted based on configured MTU. + */ +#define QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US 3 +#define QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS 256 +#define QLCNIC_DEFAULT_INTR_COALESCE_TX_PACKETS 64 +#define QLCNIC_DEFAULT_INTR_COALESCE_TX_TIME_US 4 + +#define QLCNIC_INTR_DEFAULT 0x04 + +union qlcnic_nic_intr_coalesce_data { + struct { + u16 rx_packets; + u16 rx_time_us; + u16 tx_packets; + u16 tx_time_us; + } data; + u64 word; +}; + +struct qlcnic_nic_intr_coalesce { + u16 stats_time_us; + u16 rate_sample_time; + u16 flags; + u16 rsvd_1; + u32 low_threshold; + u32 high_threshold; + union qlcnic_nic_intr_coalesce_data normal; + union qlcnic_nic_intr_coalesce_data low; + union qlcnic_nic_intr_coalesce_data high; + union qlcnic_nic_intr_coalesce_data irq; +}; + +#define QLCNIC_HOST_REQUEST 0x13 +#define QLCNIC_REQUEST 0x14 + +#define QLCNIC_MAC_EVENT 0x1 + +#define QLCNIC_IP_UP 2 +#define QLCNIC_IP_DOWN 3 + +/* + * Driver --> Firmware + */ +#define QLCNIC_H2C_OPCODE_START 0 +#define QLCNIC_H2C_OPCODE_CONFIG_RSS 1 +#define QLCNIC_H2C_OPCODE_CONFIG_RSS_TBL 2 +#define QLCNIC_H2C_OPCODE_CONFIG_INTR_COALESCE 3 +#define QLCNIC_H2C_OPCODE_CONFIG_LED 4 +#define QLCNIC_H2C_OPCODE_CONFIG_PROMISCUOUS 5 +#define QLCNIC_H2C_OPCODE_CONFIG_L2_MAC 6 +#define QLCNIC_H2C_OPCODE_LRO_REQUEST 7 +#define QLCNIC_H2C_OPCODE_GET_SNMP_STATS 8 +#define QLCNIC_H2C_OPCODE_PROXY_START_REQUEST 9 +#define QLCNIC_H2C_OPCODE_PROXY_STOP_REQUEST 10 +#define QLCNIC_H2C_OPCODE_PROXY_SET_MTU 11 +#define QLCNIC_H2C_OPCODE_PROXY_SET_VPORT_MISS_MODE 12 +#define QLCNIC_H2C_OPCODE_GET_FINGER_PRINT_REQUEST 13 +#define QLCNIC_H2C_OPCODE_INSTALL_LICENSE_REQUEST 14 +#define QLCNIC_H2C_OPCODE_GET_LICENSE_CAPABILITY_REQUEST 15 +#define QLCNIC_H2C_OPCODE_GET_NET_STATS 16 +#define QLCNIC_H2C_OPCODE_PROXY_UPDATE_P2V 17 +#define QLCNIC_H2C_OPCODE_CONFIG_IPADDR 18 +#define QLCNIC_H2C_OPCODE_CONFIG_LOOPBACK 19 +#define QLCNIC_H2C_OPCODE_PROXY_STOP_DONE 20 +#define QLCNIC_H2C_OPCODE_GET_LINKEVENT 21 +#define QLCNIC_C2C_OPCODE 22 +#define QLCNIC_H2C_OPCODE_CONFIG_BRIDGING 23 +#define QLCNIC_H2C_OPCODE_CONFIG_HW_LRO 24 +#define QLCNIC_H2C_OPCODE_LAST 25 +/* + * Firmware --> Driver + */ + +#define QLCNIC_C2H_OPCODE_START 128 +#define QLCNIC_C2H_OPCODE_CONFIG_RSS_RESPONSE 129 +#define QLCNIC_C2H_OPCODE_CONFIG_RSS_TBL_RESPONSE 130 +#define QLCNIC_C2H_OPCODE_CONFIG_MAC_RESPONSE 131 +#define QLCNIC_C2H_OPCODE_CONFIG_PROMISCUOUS_RESPONSE 132 +#define QLCNIC_C2H_OPCODE_CONFIG_L2_MAC_RESPONSE 133 +#define QLCNIC_C2H_OPCODE_LRO_DELETE_RESPONSE 134 +#define QLCNIC_C2H_OPCODE_LRO_ADD_FAILURE_RESPONSE 135 +#define QLCNIC_C2H_OPCODE_GET_SNMP_STATS 136 +#define QLCNIC_C2H_OPCODE_GET_FINGER_PRINT_REPLY 137 +#define QLCNIC_C2H_OPCODE_INSTALL_LICENSE_REPLY 138 +#define QLCNIC_C2H_OPCODE_GET_LICENSE_CAPABILITIES_REPLY 139 +#define QLCNIC_C2H_OPCODE_GET_NET_STATS_RESPONSE 140 +#define QLCNIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE 141 +#define QLCNIC_C2H_OPCODE_LAST 142 + +#define VPORT_MISS_MODE_DROP 0 /* drop all unmatched */ +#define VPORT_MISS_MODE_ACCEPT_ALL 1 /* accept all packets */ +#define VPORT_MISS_MODE_ACCEPT_MULTI 2 /* accept unmatched multicast */ + +#define QLCNIC_LRO_REQUEST_CLEANUP 4 + +/* Capabilites received */ +#define QLCNIC_FW_CAPABILITY_BDG (1 << 8) +#define QLCNIC_FW_CAPABILITY_FVLANTX (1 << 9) +#define QLCNIC_FW_CAPABILITY_HW_LRO (1 << 10) + +/* module types */ +#define LINKEVENT_MODULE_NOT_PRESENT 1 +#define LINKEVENT_MODULE_OPTICAL_UNKNOWN 2 +#define LINKEVENT_MODULE_OPTICAL_SRLR 3 +#define LINKEVENT_MODULE_OPTICAL_LRM 4 +#define LINKEVENT_MODULE_OPTICAL_SFP_1G 5 +#define LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE 6 +#define LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN 7 +#define LINKEVENT_MODULE_TWINAX 8 + +#define LINKSPEED_10GBPS 10000 +#define LINKSPEED_1GBPS 1000 +#define LINKSPEED_100MBPS 100 +#define LINKSPEED_10MBPS 10 + +#define LINKSPEED_ENCODED_10MBPS 0 +#define LINKSPEED_ENCODED_100MBPS 1 +#define LINKSPEED_ENCODED_1GBPS 2 + +#define LINKEVENT_AUTONEG_DISABLED 0 +#define LINKEVENT_AUTONEG_ENABLED 1 + +#define LINKEVENT_HALF_DUPLEX 0 +#define LINKEVENT_FULL_DUPLEX 1 + +#define LINKEVENT_LINKSPEED_MBPS 0 +#define LINKEVENT_LINKSPEED_ENCODED 1 + +#define AUTO_FW_RESET_ENABLED 0x01 +/* firmware response header: + * 63:58 - message type + * 57:56 - owner + * 55:53 - desc count + * 52:48 - reserved + * 47:40 - completion id + * 39:32 - opcode + * 31:16 - error code + * 15:00 - reserved + */ +#define qlcnic_get_nic_msg_opcode(msg_hdr) \ + ((msg_hdr >> 32) & 0xFF) + +struct qlcnic_fw_msg { + union { + struct { + u64 hdr; + u64 body[7]; + }; + u64 words[8]; + }; +}; + +struct qlcnic_nic_req { + __le64 qhdr; + __le64 req_hdr; + __le64 words[6]; +}; + +struct qlcnic_mac_req { + u8 op; + u8 tag; + u8 mac_addr[6]; +}; + +#define QLCNIC_MSI_ENABLED 0x02 +#define QLCNIC_MSIX_ENABLED 0x04 +#define QLCNIC_LRO_ENABLED 0x08 +#define QLCNIC_BRIDGE_ENABLED 0X10 +#define QLCNIC_DIAG_ENABLED 0x20 +#define QLCNIC_IS_MSI_FAMILY(adapter) \ + ((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED)) + +#define MSIX_ENTRIES_PER_ADAPTER NUM_STS_DESC_RINGS +#define QLCNIC_MSIX_TBL_SPACE 8192 +#define QLCNIC_PCI_REG_MSIX_TBL 0x44 + +#define QLCNIC_NETDEV_WEIGHT 128 +#define QLCNIC_ADAPTER_UP_MAGIC 777 + +#define __QLCNIC_FW_ATTACHED 0 +#define __QLCNIC_DEV_UP 1 +#define __QLCNIC_RESETTING 2 +#define __QLCNIC_START_FW 4 + +struct qlcnic_adapter { + struct qlcnic_hardware_context ahw; + + struct net_device *netdev; + struct pci_dev *pdev; + struct list_head mac_list; + + spinlock_t tx_clean_lock; + + u16 num_txd; + u16 num_rxd; + u16 num_jumbo_rxd; + u16 num_lro_rxd; + + u8 max_rds_rings; + u8 max_sds_rings; + u8 driver_mismatch; + u8 msix_supported; + u8 rx_csum; + u8 pci_using_dac; + u8 portnum; + u8 physical_port; + + u8 mc_enabled; + u8 max_mc_count; + u8 rss_supported; + u8 rsrvd1; + u8 fw_wait_cnt; + u8 fw_fail_cnt; + u8 tx_timeo_cnt; + u8 need_fw_reset; + + u8 has_link_events; + u8 fw_type; + u16 tx_context_id; + u16 mtu; + u16 is_up; + + u16 link_speed; + u16 link_duplex; + u16 link_autoneg; + u16 module_type; + + u32 capabilities; + u32 flags; + u32 irq; + u32 temp; + + u32 int_vec_bit; + u32 heartbit; + + u8 dev_state; + u8 rsrd1; + u32 rsrd2; + + + u8 mac_addr[ETH_ALEN]; + + struct qlcnic_adapter_stats stats; + + struct qlcnic_recv_context recv_ctx; + struct qlcnic_host_tx_ring *tx_ring; + + void __iomem *tgt_mask_reg; + void __iomem *tgt_status_reg; + void __iomem *crb_int_state_reg; + void __iomem *isr_int_vec; + + struct msix_entry msix_entries[MSIX_ENTRIES_PER_ADAPTER]; + + struct delayed_work fw_work; + + struct work_struct tx_timeout_task; + + struct qlcnic_nic_intr_coalesce coal; + + unsigned long state; + __le32 file_prd_off; /*File fw product offset*/ + u32 fw_version; + const struct firmware *fw; +}; + +int qlcnic_fw_cmd_query_phy(struct qlcnic_adapter *adapter, u32 reg, u32 *val); +int qlcnic_fw_cmd_set_phy(struct qlcnic_adapter *adapter, u32 reg, u32 val); + +u32 qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off); +int qlcnic_hw_write_wx_2M(struct qlcnic_adapter *, ulong off, u32 data); +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); + +#define QLCRD32(adapter, off) \ + (qlcnic_hw_read_wx_2M(adapter, off)) +#define QLCWR32(adapter, off, val) \ + (qlcnic_hw_write_wx_2M(adapter, off, val)) + +int qlcnic_pcie_sem_lock(struct qlcnic_adapter *, int, u32); +void qlcnic_pcie_sem_unlock(struct qlcnic_adapter *, int); + +#define qlcnic_rom_lock(a) \ + qlcnic_pcie_sem_lock((a), 2, QLCNIC_ROM_LOCK_ID) +#define qlcnic_rom_unlock(a) \ + qlcnic_pcie_sem_unlock((a), 2) +#define qlcnic_phy_lock(a) \ + qlcnic_pcie_sem_lock((a), 3, QLCNIC_PHY_LOCK_ID) +#define qlcnic_phy_unlock(a) \ + qlcnic_pcie_sem_unlock((a), 3) +#define qlcnic_api_lock(a) \ + qlcnic_pcie_sem_lock((a), 5, 0) +#define qlcnic_api_unlock(a) \ + qlcnic_pcie_sem_unlock((a), 5) +#define qlcnic_sw_lock(a) \ + qlcnic_pcie_sem_lock((a), 6, 0) +#define qlcnic_sw_unlock(a) \ + qlcnic_pcie_sem_unlock((a), 6) +#define crb_win_lock(a) \ + qlcnic_pcie_sem_lock((a), 7, QLCNIC_CRB_WIN_LOCK_ID) +#define crb_win_unlock(a) \ + qlcnic_pcie_sem_unlock((a), 7) + +int qlcnic_get_board_info(struct qlcnic_adapter *adapter); +int qlcnic_wol_supported(struct qlcnic_adapter *adapter); + +/* Functions from qlcnic_init.c */ +int qlcnic_phantom_init(struct qlcnic_adapter *adapter); +int qlcnic_load_firmware(struct qlcnic_adapter *adapter); +int qlcnic_need_fw_reset(struct qlcnic_adapter *adapter); +void qlcnic_request_firmware(struct qlcnic_adapter *adapter); +void qlcnic_release_firmware(struct qlcnic_adapter *adapter); +int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter); + +int qlcnic_rom_fast_read(struct qlcnic_adapter *adapter, int addr, int *valp); +int qlcnic_rom_fast_read_words(struct qlcnic_adapter *adapter, int addr, + u8 *bytes, size_t size); +int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter); +void qlcnic_free_sw_resources(struct qlcnic_adapter *adapter); + +void __iomem *qlcnic_get_ioaddr(struct qlcnic_adapter *, u32); + +int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter); +void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter); + +void qlcnic_release_rx_buffers(struct qlcnic_adapter *adapter); +void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter); + +int qlcnic_init_firmware(struct qlcnic_adapter *adapter); +void qlcnic_watchdog_task(struct work_struct *work); +void qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, u32 ringid, + struct qlcnic_host_rds_ring *rds_ring); +int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max); +void qlcnic_set_multi(struct net_device *netdev); +void qlcnic_free_mac_list(struct qlcnic_adapter *adapter); +int qlcnic_nic_set_promisc(struct qlcnic_adapter *adapter, u32); +int qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter); +int qlcnic_config_rss(struct qlcnic_adapter *adapter, int enable); +int qlcnic_config_ipaddr(struct qlcnic_adapter *adapter, u32 ip, int cmd); +int qlcnic_linkevent_request(struct qlcnic_adapter *adapter, int enable); +void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup); + +int qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu); +int qlcnic_change_mtu(struct net_device *netdev, int new_mtu); +int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable); +int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, int enable); +int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter); +void qlcnic_update_cmd_producer(struct qlcnic_adapter *adapter, + struct qlcnic_host_tx_ring *tx_ring); +int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u64 *mac); + +/* Functions from qlcnic_main.c */ +int qlcnic_reset_context(struct qlcnic_adapter *); + +/* + * QLOGIC Board information + */ + +#define QLCNIC_MAX_BOARD_NAME_LEN 64 +struct qlcnic_brdinfo { + unsigned short vendor; + unsigned short device; + unsigned short sub_vendor; + unsigned short sub_device; + char short_name[QLCNIC_MAX_BOARD_NAME_LEN]; +}; + +static const struct qlcnic_brdinfo qlcnic_boards[] = { + {0x1077, 0x8020, 0x1077, 0x203, "8200 Series Single Port 10GbE CNA"}, + {0x1077, 0x8020, 0x1077, 0x207, "8200 Series Dual Port 10GbE CNA"}, + {0x1077, 0x8020, 0x1077, 0x20b, + "3200 Series Dual Port 10Gb Intelligent Ethernet Adapter"}, + {0x1077, 0x8020, 0x1077, 0x20c, + "3200 Series Quad Port 1Gb Intelligent Ethernet Adapter"}, + {0x1077, 0x8020, 0x1077, 0x20f, + "3200 Series Single Port 10Gb Intelligent Ethernet Adapter"}, + {0x1077, 0x8020, 0x0, 0x0, "cLOM8214 1/10GbE Controller"}, +}; + +#define NUM_SUPPORTED_BOARDS ARRAY_SIZE(qlcnic_boards) + +static inline u32 qlcnic_tx_avail(struct qlcnic_host_tx_ring *tx_ring) +{ + smp_mb(); + if (tx_ring->producer < tx_ring->sw_consumer) + return tx_ring->sw_consumer - tx_ring->producer; + else + return tx_ring->sw_consumer + tx_ring->num_desc - + tx_ring->producer; +} + +extern const struct ethtool_ops qlcnic_ethtool_ops; + +#endif /* __QLCNIC_H_ */ diff --git a/drivers/net/qlcnic/qlcnic_ctx.c b/drivers/net/qlcnic/qlcnic_ctx.c new file mode 100644 index 00000000000..71c16a18345 --- /dev/null +++ b/drivers/net/qlcnic/qlcnic_ctx.c @@ -0,0 +1,536 @@ +/* + * Copyright (C) 2009 - QLogic Corporation. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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. + * + * The full GNU General Public License is included in this distribution + * in the file called "COPYING". + * + */ + +#include "qlcnic.h" + +#define QLCHAL_VERSION 1 + +static u32 +qlcnic_poll_rsp(struct qlcnic_adapter *adapter) +{ + u32 rsp; + int timeout = 0; + + do { + /* give atleast 1ms for firmware to respond */ + msleep(1); + + if (++timeout > QLCNIC_OS_CRB_RETRY_COUNT) + return QLCNIC_CDRP_RSP_TIMEOUT; + + rsp = QLCRD32(adapter, QLCNIC_CDRP_CRB_OFFSET); + } while (!QLCNIC_CDRP_IS_RSP(rsp)); + + return rsp; +} + +static u32 +qlcnic_issue_cmd(struct qlcnic_adapter *adapter, + u32 pci_fn, u32 version, u32 arg1, u32 arg2, u32 arg3, u32 cmd) +{ + u32 rsp; + u32 signature; + u32 rcode = QLCNIC_RCODE_SUCCESS; + struct pci_dev *pdev = adapter->pdev; + + signature = QLCNIC_CDRP_SIGNATURE_MAKE(pci_fn, version); + + /* Acquire semaphore before accessing CRB */ + if (qlcnic_api_lock(adapter)) + return QLCNIC_RCODE_TIMEOUT; + + QLCWR32(adapter, QLCNIC_SIGN_CRB_OFFSET, signature); + QLCWR32(adapter, QLCNIC_ARG1_CRB_OFFSET, arg1); + QLCWR32(adapter, QLCNIC_ARG2_CRB_OFFSET, arg2); + QLCWR32(adapter, QLCNIC_ARG3_CRB_OFFSET, arg3); + QLCWR32(adapter, QLCNIC_CDRP_CRB_OFFSET, QLCNIC_CDRP_FORM_CMD(cmd)); + + rsp = qlcnic_poll_rsp(adapter); + + if (rsp == QLCNIC_CDRP_RSP_TIMEOUT) { + dev_err(&pdev->dev, "card response timeout.\n"); + rcode = QLCNIC_RCODE_TIMEOUT; + } else if (rsp == QLCNIC_CDRP_RSP_FAIL) { + rcode = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET); + dev_err(&pdev->dev, "failed card response code:0x%x\n", + rcode); + } + + /* Release semaphore */ + qlcnic_api_unlock(adapter); + + return rcode; +} + +int +qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu) +{ + struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + + if (recv_ctx->state == QLCNIC_HOST_CTX_STATE_ACTIVE) { + if (qlcnic_issue_cmd(adapter, + adapter->ahw.pci_func, + QLCHAL_VERSION, + recv_ctx->context_id, + mtu, + 0, + QLCNIC_CDRP_CMD_SET_MTU)) { + + dev_err(&adapter->pdev->dev, "Failed to set mtu\n"); + return -EIO; + } + } + + return 0; +} + +static int +qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter) +{ + void *addr; + struct qlcnic_hostrq_rx_ctx *prq; + struct qlcnic_cardrsp_rx_ctx *prsp; + struct qlcnic_hostrq_rds_ring *prq_rds; + struct qlcnic_hostrq_sds_ring *prq_sds; + struct qlcnic_cardrsp_rds_ring *prsp_rds; + struct qlcnic_cardrsp_sds_ring *prsp_sds; + struct qlcnic_host_rds_ring *rds_ring; + struct qlcnic_host_sds_ring *sds_ring; + + dma_addr_t hostrq_phys_addr, cardrsp_phys_addr; + u64 phys_addr; + + int i, nrds_rings, nsds_rings; + size_t rq_size, rsp_size; + u32 cap, reg, val; + int err; + + struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + + nrds_rings = adapter->max_rds_rings; + nsds_rings = adapter->max_sds_rings; + + rq_size = + SIZEOF_HOSTRQ_RX(struct qlcnic_hostrq_rx_ctx, nrds_rings, + nsds_rings); + rsp_size = + SIZEOF_CARDRSP_RX(struct qlcnic_cardrsp_rx_ctx, nrds_rings, + nsds_rings); + + addr = pci_alloc_consistent(adapter->pdev, + rq_size, &hostrq_phys_addr); + if (addr == NULL) + return -ENOMEM; + prq = (struct qlcnic_hostrq_rx_ctx *)addr; + + addr = pci_alloc_consistent(adapter->pdev, + rsp_size, &cardrsp_phys_addr); + if (addr == NULL) { + err = -ENOMEM; + goto out_free_rq; + } + prsp = (struct qlcnic_cardrsp_rx_ctx *)addr; + + prq->host_rsp_dma_addr = cpu_to_le64(cardrsp_phys_addr); + + cap = (QLCNIC_CAP0_LEGACY_CONTEXT | QLCNIC_CAP0_LEGACY_MN); + cap |= (QLCNIC_CAP0_JUMBO_CONTIGUOUS | QLCNIC_CAP0_LRO_CONTIGUOUS); + + prq->capabilities[0] = cpu_to_le32(cap); + prq->host_int_crb_mode = + cpu_to_le32(QLCNIC_HOST_INT_CRB_MODE_SHARED); + prq->host_rds_crb_mode = + cpu_to_le32(QLCNIC_HOST_RDS_CRB_MODE_UNIQUE); + + prq->num_rds_rings = cpu_to_le16(nrds_rings); + prq->num_sds_rings = cpu_to_le16(nsds_rings); + prq->rds_ring_offset = cpu_to_le32(0); + + val = le32_to_cpu(prq->rds_ring_offset) + + (sizeof(struct qlcnic_hostrq_rds_ring) * nrds_rings); + prq->sds_ring_offset = cpu_to_le32(val); + + prq_rds = (struct qlcnic_hostrq_rds_ring *)(prq->data + + le32_to_cpu(prq->rds_ring_offset)); + + for (i = 0; i < nrds_rings; i++) { + + rds_ring = &recv_ctx->rds_rings[i]; + + prq_rds[i].host_phys_addr = cpu_to_le64(rds_ring->phys_addr); + prq_rds[i].ring_size = cpu_to_le32(rds_ring->num_desc); + prq_rds[i].ring_kind = cpu_to_le32(i); + prq_rds[i].buff_size = cpu_to_le64(rds_ring->dma_size); + } + + prq_sds = (struct qlcnic_hostrq_sds_ring *)(prq->data + + le32_to_cpu(prq->sds_ring_offset)); + + for (i = 0; i < nsds_rings; i++) { + + sds_ring = &recv_ctx->sds_rings[i]; + + prq_sds[i].host_phys_addr = cpu_to_le64(sds_ring->phys_addr); + prq_sds[i].ring_size = cpu_to_le32(sds_ring->num_desc); + prq_sds[i].msi_index = cpu_to_le16(i); + } + + phys_addr = hostrq_phys_addr; + err = qlcnic_issue_cmd(adapter, + adapter->ahw.pci_func, + QLCHAL_VERSION, + (u32)(phys_addr >> 32), + (u32)(phys_addr & 0xffffffff), + rq_size, + QLCNIC_CDRP_CMD_CREATE_RX_CTX); + if (err) { + dev_err(&adapter->pdev->dev, + "Failed to create rx ctx in firmware%d\n", err); + goto out_free_rsp; + } + + + prsp_rds = ((struct qlcnic_cardrsp_rds_ring *) + &prsp->data[le32_to_cpu(prsp->rds_ring_offset)]); + + for (i = 0; i < le16_to_cpu(prsp->num_rds_rings); i++) { + rds_ring = &recv_ctx->rds_rings[i]; + + reg = le32_to_cpu(prsp_rds[i].host_producer_crb); + rds_ring->crb_rcv_producer = qlcnic_get_ioaddr(adapter, + QLCNIC_REG(reg - 0x200)); + } + + prsp_sds = ((struct qlcnic_cardrsp_sds_ring *) + &prsp->data[le32_to_cpu(prsp->sds_ring_offset)]); + + for (i = 0; i < le16_to_cpu(prsp->num_sds_rings); i++) { + sds_ring = &recv_ctx->sds_rings[i]; + + reg = le32_to_cpu(prsp_sds[i].host_consumer_crb); + sds_ring->crb_sts_consumer = qlcnic_get_ioaddr(adapter, + QLCNIC_REG(reg - 0x200)); + + reg = le32_to_cpu(prsp_sds[i].interrupt_crb); + sds_ring->crb_intr_mask = qlcnic_get_ioaddr(adapter, + QLCNIC_REG(reg - 0x200)); + } + + recv_ctx->state = le32_to_cpu(prsp->host_ctx_state); + recv_ctx->context_id = le16_to_cpu(prsp->context_id); + recv_ctx->virt_port = prsp->virt_port; + +out_free_rsp: + pci_free_consistent(adapter->pdev, rsp_size, prsp, cardrsp_phys_addr); +out_free_rq: + pci_free_consistent(adapter->pdev, rq_size, prq, hostrq_phys_addr); + return err; +} + +static void +qlcnic_fw_cmd_destroy_rx_ctx(struct qlcnic_adapter *adapter) +{ + struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + + if (qlcnic_issue_cmd(adapter, + adapter->ahw.pci_func, + QLCHAL_VERSION, + recv_ctx->context_id, + QLCNIC_DESTROY_CTX_RESET, + 0, + QLCNIC_CDRP_CMD_DESTROY_RX_CTX)) { + + dev_err(&adapter->pdev->dev, + "Failed to destroy rx ctx in firmware\n"); + } +} + +static int +qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter) +{ + struct qlcnic_hostrq_tx_ctx *prq; + struct qlcnic_hostrq_cds_ring *prq_cds; + struct qlcnic_cardrsp_tx_ctx *prsp; + void *rq_addr, *rsp_addr; + size_t rq_size, rsp_size; + u32 temp; + int err; + u64 phys_addr; + dma_addr_t rq_phys_addr, rsp_phys_addr; + struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring; + + rq_size = SIZEOF_HOSTRQ_TX(struct qlcnic_hostrq_tx_ctx); + rq_addr = pci_alloc_consistent(adapter->pdev, + rq_size, &rq_phys_addr); + if (!rq_addr) + return -ENOMEM; + + rsp_size = SIZEOF_CARDRSP_TX(struct qlcnic_cardrsp_tx_ctx); + rsp_addr = pci_alloc_consistent(adapter->pdev, + rsp_size, &rsp_phys_addr); + if (!rsp_addr) { + err = -ENOMEM; + goto out_free_rq; + } + + memset(rq_addr, 0, rq_size); + prq = (struct qlcnic_hostrq_tx_ctx *)rq_addr; + + memset(rsp_addr, 0, rsp_size); + prsp = (struct qlcnic_cardrsp_tx_ctx *)rsp_addr; + + prq->host_rsp_dma_addr = cpu_to_le64(rsp_phys_addr); + + temp = (QLCNIC_CAP0_LEGACY_CONTEXT | QLCNIC_CAP0_LEGACY_MN | + QLCNIC_CAP0_LSO); + prq->capabilities[0] = cpu_to_le32(temp); + + prq->host_int_crb_mode = + cpu_to_le32(QLCNIC_HOST_INT_CRB_MODE_SHARED); + + prq->interrupt_ctl = 0; + prq->msi_index = 0; + prq->cmd_cons_dma_addr = cpu_to_le64(tx_ring->hw_cons_phys_addr); + + prq_cds = &prq->cds_ring; + + prq_cds->host_phys_addr = cpu_to_le64(tx_ring->phys_addr); + prq_cds->ring_size = cpu_to_le32(tx_ring->num_desc); + + phys_addr = rq_phys_addr; + err = qlcnic_issue_cmd(adapter, + adapter->ahw.pci_func, + QLCHAL_VERSION, + (u32)(phys_addr >> 32), + ((u32)phys_addr & 0xffffffff), + rq_size, + QLCNIC_CDRP_CMD_CREATE_TX_CTX); + + if (err == QLCNIC_RCODE_SUCCESS) { + temp = le32_to_cpu(prsp->cds_ring.host_producer_crb); + tx_ring->crb_cmd_producer = qlcnic_get_ioaddr(adapter, + QLCNIC_REG(temp - 0x200)); + + adapter->tx_context_id = + le16_to_cpu(prsp->context_id); + } else { + dev_err(&adapter->pdev->dev, + "Failed to create tx ctx in firmware%d\n", err); + err = -EIO; + } + + pci_free_consistent(adapter->pdev, rsp_size, rsp_addr, rsp_phys_addr); + +out_free_rq: + pci_free_consistent(adapter->pdev, rq_size, rq_addr, rq_phys_addr); + + return err; +} + +static void +qlcnic_fw_cmd_destroy_tx_ctx(struct qlcnic_adapter *adapter) +{ + if (qlcnic_issue_cmd(adapter, + adapter->ahw.pci_func, + QLCHAL_VERSION, + adapter->tx_context_id, + QLCNIC_DESTROY_CTX_RESET, + 0, + QLCNIC_CDRP_CMD_DESTROY_TX_CTX)) { + + dev_err(&adapter->pdev->dev, + "Failed to destroy tx ctx in firmware\n"); + } +} + +int +qlcnic_fw_cmd_query_phy(struct qlcnic_adapter *adapter, u32 reg, u32 *val) +{ + + if (qlcnic_issue_cmd(adapter, + adapter->ahw.pci_func, + QLCHAL_VERSION, + reg, + 0, + 0, + QLCNIC_CDRP_CMD_READ_PHY)) { + + return -EIO; + } + + return QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET); +} + +int +qlcnic_fw_cmd_set_phy(struct qlcnic_adapter *adapter, u32 reg, u32 val) +{ + return qlcnic_issue_cmd(adapter, + adapter->ahw.pci_func, + QLCHAL_VERSION, + reg, + val, + 0, + QLCNIC_CDRP_CMD_WRITE_PHY); +} + +int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter) +{ + void *addr; + int err; + int ring; + struct qlcnic_recv_context *recv_ctx; + struct qlcnic_host_rds_ring *rds_ring; + struct qlcnic_host_sds_ring *sds_ring; + struct qlcnic_host_tx_ring *tx_ring; + + struct pci_dev *pdev = adapter->pdev; + + recv_ctx = &adapter->recv_ctx; + tx_ring = adapter->tx_ring; + + tx_ring->hw_consumer = (__le32 *)pci_alloc_consistent(pdev, sizeof(u32), + &tx_ring->hw_cons_phys_addr); + if (tx_ring->hw_consumer == NULL) { + dev_err(&pdev->dev, "failed to allocate tx consumer\n"); + return -ENOMEM; + } + *(tx_ring->hw_consumer) = 0; + + /* cmd desc ring */ + addr = pci_alloc_consistent(pdev, TX_DESC_RINGSIZE(tx_ring), + &tx_ring->phys_addr); + + if (addr == NULL) { + dev_err(&pdev->dev, "failed to allocate tx desc ring\n"); + return -ENOMEM; + } + + tx_ring->desc_head = (struct cmd_desc_type0 *)addr; + + for (ring = 0; ring < adapter->max_rds_rings; ring++) { + rds_ring = &recv_ctx->rds_rings[ring]; + addr = pci_alloc_consistent(adapter->pdev, + RCV_DESC_RINGSIZE(rds_ring), + &rds_ring->phys_addr); + if (addr == NULL) { + dev_err(&pdev->dev, + "failed to allocate rds ring [%d]\n", ring); + err = -ENOMEM; + goto err_out_free; + } + rds_ring->desc_head = (struct rcv_desc *)addr; + + } + + for (ring = 0; ring < adapter->max_sds_rings; ring++) { + sds_ring = &recv_ctx->sds_rings[ring]; + + addr = pci_alloc_consistent(adapter->pdev, + STATUS_DESC_RINGSIZE(sds_ring), + &sds_ring->phys_addr); + if (addr == NULL) { + dev_err(&pdev->dev, + "failed to allocate sds ring [%d]\n", ring); + err = -ENOMEM; + goto err_out_free; + } + sds_ring->desc_head = (struct status_desc *)addr; + } + + + err = qlcnic_fw_cmd_create_rx_ctx(adapter); + if (err) + goto err_out_free; + err = qlcnic_fw_cmd_create_tx_ctx(adapter); + if (err) + goto err_out_free; + + set_bit(__QLCNIC_FW_ATTACHED, &adapter->state); + return 0; + +err_out_free: + qlcnic_free_hw_resources(adapter); + return err; +} + +void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter) +{ + struct qlcnic_recv_context *recv_ctx; + struct qlcnic_host_rds_ring *rds_ring; + struct qlcnic_host_sds_ring *sds_ring; + struct qlcnic_host_tx_ring *tx_ring; + int ring; + + + if (test_and_clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) { + qlcnic_fw_cmd_destroy_rx_ctx(adapter); + qlcnic_fw_cmd_destroy_tx_ctx(adapter); + + /* Allow dma queues to drain after context reset */ + msleep(20); + } + + recv_ctx = &adapter->recv_ctx; + + tx_ring = adapter->tx_ring; + if (tx_ring->hw_consumer != NULL) { + pci_free_consistent(adapter->pdev, + sizeof(u32), + tx_ring->hw_consumer, + tx_ring->hw_cons_phys_addr); + tx_ring->hw_consumer = NULL; + } + + if (tx_ring->desc_head != NULL) { + pci_free_consistent(adapter->pdev, + TX_DESC_RINGSIZE(tx_ring), + tx_ring->desc_head, tx_ring->phys_addr); + tx_ring->desc_head = NULL; + } + + for (ring = 0; ring < adapter->max_rds_rings; ring++) { + rds_ring = &recv_ctx->rds_rings[ring]; + + if (rds_ring->desc_head != NULL) { + pci_free_consistent(adapter->pdev, + RCV_DESC_RINGSIZE(rds_ring), + rds_ring->desc_head, + rds_ring->phys_addr); + rds_ring->desc_head = NULL; + } + } + + for (ring = 0; ring < adapter->max_sds_rings; ring++) { + sds_ring = &recv_ctx->sds_rings[ring]; + + if (sds_ring->desc_head != NULL) { + pci_free_consistent(adapter->pdev, + STATUS_DESC_RINGSIZE(sds_ring), + sds_ring->desc_head, + sds_ring->phys_addr); + sds_ring->desc_head = NULL; + } + } +} + diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c new file mode 100644 index 00000000000..65e9620e28f --- /dev/null +++ b/drivers/net/qlcnic/qlcnic_ethtool.c @@ -0,0 +1,870 @@ +/* + * Copyright (C) 2009 - QLogic Corporation. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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. + * + * The full GNU General Public License is included in this distribution + * in the file called "COPYING". + * + */ + +#include +#include +#include +#include +#include +#include + +#include "qlcnic.h" + +struct qlcnic_stats { + char stat_string[ETH_GSTRING_LEN]; + int sizeof_stat; + int stat_offset; +}; + +#define QLC_SIZEOF(m) FIELD_SIZEOF(struct qlcnic_adapter, m) +#define QLC_OFF(m) offsetof(struct qlcnic_adapter, m) + +static const struct qlcnic_stats qlcnic_gstrings_stats[] = { + {"xmit_called", + QLC_SIZEOF(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)}, + {"tx_dropped", + QLC_SIZEOF(stats.txdropped), QLC_OFF(stats.txdropped)}, + {"csummed", + QLC_SIZEOF(stats.csummed), QLC_OFF(stats.csummed)}, + {"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)}, +}; + +#define QLCNIC_STATS_LEN ARRAY_SIZE(qlcnic_gstrings_stats) + +static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = { + "Register_Test_on_offline", + "Link_Test_on_offline" +}; + +#define QLCNIC_TEST_LEN ARRAY_SIZE(qlcnic_gstrings_test) + +#define QLCNIC_RING_REGS_COUNT 20 +#define QLCNIC_RING_REGS_LEN (QLCNIC_RING_REGS_COUNT * sizeof(u32)) +#define QLCNIC_MAX_EEPROM_LEN 1024 + +static const u32 diag_registers[] = { + CRB_CMDPEG_STATE, + CRB_RCVPEG_STATE, + CRB_XG_STATE_P3, + CRB_FW_CAPABILITIES_1, + ISR_INT_STATE_REG, + QLCNIC_CRB_DEV_REF_COUNT, + QLCNIC_CRB_DEV_STATE, + QLCNIC_CRB_DRV_STATE, + QLCNIC_CRB_DRV_SCRATCH, + QLCNIC_CRB_DEV_PARTITION_INFO, + QLCNIC_CRB_DRV_IDC_VER, + QLCNIC_PEG_ALIVE_COUNTER, + QLCNIC_PEG_HALT_STATUS1, + QLCNIC_PEG_HALT_STATUS2, + QLCNIC_CRB_PEG_NET_0+0x3c, + QLCNIC_CRB_PEG_NET_1+0x3c, + QLCNIC_CRB_PEG_NET_2+0x3c, + QLCNIC_CRB_PEG_NET_4+0x3c, + -1 +}; + +static int qlcnic_get_regs_len(struct net_device *dev) +{ + return sizeof(diag_registers) + QLCNIC_RING_REGS_LEN; +} + +static int qlcnic_get_eeprom_len(struct net_device *dev) +{ + return QLCNIC_FLASH_TOTAL_SIZE; +} + +static void +qlcnic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + u32 fw_major, fw_minor, fw_build; + + fw_major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR); + fw_minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR); + fw_build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB); + sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build); + + strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); + strlcpy(drvinfo->driver, qlcnic_driver_name, 32); + strlcpy(drvinfo->version, QLCNIC_LINUX_VERSIONID, 32); +} + +static int +qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + int check_sfp_module = 0; + u16 pcifn = adapter->ahw.pci_func; + + /* read which mode */ + if (adapter->ahw.port_type == QLCNIC_GBE) { + ecmd->supported = (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Half | + SUPPORTED_1000baseT_Full); + + ecmd->advertising = (ADVERTISED_100baseT_Half | + ADVERTISED_100baseT_Full | + ADVERTISED_1000baseT_Half | + ADVERTISED_1000baseT_Full); + + ecmd->speed = adapter->link_speed; + ecmd->duplex = adapter->link_duplex; + ecmd->autoneg = adapter->link_autoneg; + + } else if (adapter->ahw.port_type == QLCNIC_XGBE) { + u32 val; + + val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR); + if (val == QLCNIC_PORT_MODE_802_3_AP) { + ecmd->supported = SUPPORTED_1000baseT_Full; + ecmd->advertising = ADVERTISED_1000baseT_Full; + } else { + ecmd->supported = SUPPORTED_10000baseT_Full; + ecmd->advertising = ADVERTISED_10000baseT_Full; + } + + if (netif_running(dev) && adapter->has_link_events) { + ecmd->speed = adapter->link_speed; + ecmd->autoneg = adapter->link_autoneg; + ecmd->duplex = adapter->link_duplex; + goto skip; + } + + val = QLCRD32(adapter, P3_LINK_SPEED_REG(pcifn)); + ecmd->speed = P3_LINK_SPEED_MHZ * + P3_LINK_SPEED_VAL(pcifn, val); + ecmd->duplex = DUPLEX_FULL; + ecmd->autoneg = AUTONEG_DISABLE; + } else + return -EIO; + +skip: + ecmd->phy_address = adapter->physical_port; + ecmd->transceiver = XCVR_EXTERNAL; + + switch (adapter->ahw.board_type) { + case QLCNIC_BRDTYPE_P3_REF_QG: + case QLCNIC_BRDTYPE_P3_4_GB: + case QLCNIC_BRDTYPE_P3_4_GB_MM: + + ecmd->supported |= SUPPORTED_Autoneg; + ecmd->advertising |= ADVERTISED_Autoneg; + case QLCNIC_BRDTYPE_P3_10G_CX4: + case QLCNIC_BRDTYPE_P3_10G_CX4_LP: + case QLCNIC_BRDTYPE_P3_10000_BASE_T: + ecmd->supported |= SUPPORTED_TP; + ecmd->advertising |= ADVERTISED_TP; + ecmd->port = PORT_TP; + ecmd->autoneg = adapter->link_autoneg; + break; + case QLCNIC_BRDTYPE_P3_IMEZ: + case QLCNIC_BRDTYPE_P3_XG_LOM: + case QLCNIC_BRDTYPE_P3_HMEZ: + ecmd->supported |= SUPPORTED_MII; + ecmd->advertising |= ADVERTISED_MII; + ecmd->port = PORT_MII; + ecmd->autoneg = AUTONEG_DISABLE; + break; + case QLCNIC_BRDTYPE_P3_10G_SFP_PLUS: + case QLCNIC_BRDTYPE_P3_10G_SFP_CT: + case QLCNIC_BRDTYPE_P3_10G_SFP_QT: + ecmd->advertising |= ADVERTISED_TP; + ecmd->supported |= SUPPORTED_TP; + check_sfp_module = netif_running(dev) && + adapter->has_link_events; + case QLCNIC_BRDTYPE_P3_10G_XFP: + ecmd->supported |= SUPPORTED_FIBRE; + ecmd->advertising |= ADVERTISED_FIBRE; + ecmd->port = PORT_FIBRE; + ecmd->autoneg = AUTONEG_DISABLE; + break; + case QLCNIC_BRDTYPE_P3_10G_TP: + if (adapter->ahw.port_type == QLCNIC_XGBE) { + ecmd->autoneg = AUTONEG_DISABLE; + ecmd->supported |= (SUPPORTED_FIBRE | SUPPORTED_TP); + ecmd->advertising |= + (ADVERTISED_FIBRE | ADVERTISED_TP); + ecmd->port = PORT_FIBRE; + check_sfp_module = netif_running(dev) && + adapter->has_link_events; + } else { + ecmd->autoneg = AUTONEG_ENABLE; + ecmd->supported |= (SUPPORTED_TP | SUPPORTED_Autoneg); + ecmd->advertising |= + (ADVERTISED_TP | ADVERTISED_Autoneg); + ecmd->port = PORT_TP; + } + break; + default: + dev_err(&adapter->pdev->dev, "Unsupported board model %d\n", + adapter->ahw.board_type); + return -EIO; + } + + if (check_sfp_module) { + switch (adapter->module_type) { + case LINKEVENT_MODULE_OPTICAL_UNKNOWN: + case LINKEVENT_MODULE_OPTICAL_SRLR: + case LINKEVENT_MODULE_OPTICAL_LRM: + case LINKEVENT_MODULE_OPTICAL_SFP_1G: + ecmd->port = PORT_FIBRE; + break; + case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE: + case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN: + case LINKEVENT_MODULE_TWINAX: + ecmd->port = PORT_TP; + break; + default: + ecmd->port = PORT_OTHER; + } + } + + return 0; +} + +static int +qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + __u32 status; + + /* read which mode */ + if (adapter->ahw.port_type == QLCNIC_GBE) { + /* autonegotiation */ + if (qlcnic_fw_cmd_set_phy(adapter, + QLCNIC_NIU_GB_MII_MGMT_ADDR_AUTONEG, + ecmd->autoneg) != 0) + return -EIO; + else + adapter->link_autoneg = ecmd->autoneg; + + if (qlcnic_fw_cmd_query_phy(adapter, + QLCNIC_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, + &status) != 0) + return -EIO; + + switch (ecmd->speed) { + case SPEED_10: + qlcnic_set_phy_speed(status, 0); + break; + case SPEED_100: + qlcnic_set_phy_speed(status, 1); + break; + case SPEED_1000: + qlcnic_set_phy_speed(status, 2); + break; + } + + if (ecmd->duplex == DUPLEX_HALF) + qlcnic_clear_phy_duplex(status); + if (ecmd->duplex == DUPLEX_FULL) + qlcnic_set_phy_duplex(status); + if (qlcnic_fw_cmd_set_phy(adapter, + QLCNIC_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, + *((int *)&status)) != 0) + return -EIO; + else { + adapter->link_speed = ecmd->speed; + adapter->link_duplex = ecmd->duplex; + } + } else + return -EOPNOTSUPP; + + if (!netif_running(dev)) + return 0; + + dev->netdev_ops->ndo_stop(dev); + return dev->netdev_ops->ndo_open(dev); +} + +static void +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; + u32 *regs_buff = p; + int ring, i = 0; + + memset(p, 0, qlcnic_get_regs_len(dev)); + regs->version = (1 << 24) | (adapter->ahw.revision_id << 16) | + (adapter->pdev)->device; + + if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) + return; + + for (i = 0; diag_registers[i] != -1; i++) + regs_buff[i] = QLCRD32(adapter, diag_registers[i]); + + 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); + + regs_buff[i++] = adapter->max_sds_rings; + + for (ring = 0; ring < adapter->max_sds_rings; ring++) { + sds_ring = &(recv_ctx->sds_rings[ring]); + regs_buff[i++] = readl(sds_ring->crb_sts_consumer); + } +} + +static u32 qlcnic_test_link(struct net_device *dev) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + u32 val; + + val = QLCRD32(adapter, CRB_XG_STATE_P3); + val = XG_LINK_STATE_P3(adapter->ahw.pci_func, val); + return (val == XG_LINK_UP_P3) ? 0 : 1; +} + +static int +qlcnic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, + u8 *bytes) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + int offset; + int ret; + + if (eeprom->len == 0) + return -EINVAL; + + eeprom->magic = (adapter->pdev)->vendor | + ((adapter->pdev)->device << 16); + offset = eeprom->offset; + + ret = qlcnic_rom_fast_read_words(adapter, offset, bytes, + eeprom->len); + if (ret < 0) + return ret; + + return 0; +} + +static void +qlcnic_get_ringparam(struct net_device *dev, + struct ethtool_ringparam *ring) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + + ring->rx_pending = adapter->num_rxd; + ring->rx_jumbo_pending = adapter->num_jumbo_rxd; + ring->rx_jumbo_pending += adapter->num_lro_rxd; + ring->tx_pending = adapter->num_txd; + + if (adapter->ahw.port_type == QLCNIC_GBE) { + ring->rx_max_pending = MAX_RCV_DESCRIPTORS_1G; + ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS_1G; + } else { + ring->rx_max_pending = MAX_RCV_DESCRIPTORS_10G; + ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS_10G; + } + + ring->tx_max_pending = MAX_CMD_DESCRIPTORS; + + ring->rx_mini_max_pending = 0; + ring->rx_mini_pending = 0; +} + +static u32 +qlcnic_validate_ringparam(u32 val, u32 min, u32 max, char *r_name) +{ + u32 num_desc; + num_desc = max(val, min); + num_desc = min(num_desc, max); + num_desc = roundup_pow_of_two(num_desc); + + if (val != num_desc) { + printk(KERN_INFO "%s: setting %s ring size %d instead of %d\n", + qlcnic_driver_name, r_name, num_desc, val); + } + + return num_desc; +} + +static int +qlcnic_set_ringparam(struct net_device *dev, + struct ethtool_ringparam *ring) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + u16 max_rcv_desc = MAX_RCV_DESCRIPTORS_10G; + u16 max_jumbo_desc = MAX_JUMBO_RCV_DESCRIPTORS_10G; + u16 num_rxd, num_jumbo_rxd, num_txd; + + + if (ring->rx_mini_pending) + return -EOPNOTSUPP; + + if (adapter->ahw.port_type == QLCNIC_GBE) { + max_rcv_desc = MAX_RCV_DESCRIPTORS_1G; + max_jumbo_desc = MAX_JUMBO_RCV_DESCRIPTORS_10G; + } + + num_rxd = qlcnic_validate_ringparam(ring->rx_pending, + MIN_RCV_DESCRIPTORS, max_rcv_desc, "rx"); + + num_jumbo_rxd = qlcnic_validate_ringparam(ring->rx_jumbo_pending, + MIN_JUMBO_DESCRIPTORS, max_jumbo_desc, "rx jumbo"); + + num_txd = qlcnic_validate_ringparam(ring->tx_pending, + MIN_CMD_DESCRIPTORS, MAX_CMD_DESCRIPTORS, "tx"); + + if (num_rxd == adapter->num_rxd && num_txd == adapter->num_txd && + num_jumbo_rxd == adapter->num_jumbo_rxd) + return 0; + + adapter->num_rxd = num_rxd; + adapter->num_jumbo_rxd = num_jumbo_rxd; + adapter->num_txd = num_txd; + + return qlcnic_reset_context(adapter); +} + +static void +qlcnic_get_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + int port = adapter->physical_port; + __u32 val; + + if (adapter->ahw.port_type == QLCNIC_GBE) { + if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS)) + return; + /* get flow control settings */ + val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port)); + pause->rx_pause = qlcnic_gb_get_rx_flowctl(val); + val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL); + switch (port) { + case 0: + pause->tx_pause = !(qlcnic_gb_get_gb0_mask(val)); + break; + case 1: + pause->tx_pause = !(qlcnic_gb_get_gb1_mask(val)); + break; + case 2: + pause->tx_pause = !(qlcnic_gb_get_gb2_mask(val)); + break; + case 3: + default: + pause->tx_pause = !(qlcnic_gb_get_gb3_mask(val)); + break; + } + } else if (adapter->ahw.port_type == QLCNIC_XGBE) { + if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS)) + return; + pause->rx_pause = 1; + val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL); + if (port == 0) + pause->tx_pause = !(qlcnic_xg_get_xg0_mask(val)); + else + pause->tx_pause = !(qlcnic_xg_get_xg1_mask(val)); + } else { + dev_err(&netdev->dev, "Unknown board type: %x\n", + adapter->ahw.port_type); + } +} + +static int +qlcnic_set_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + int port = adapter->physical_port; + __u32 val; + + /* read mode */ + if (adapter->ahw.port_type == QLCNIC_GBE) { + if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS)) + return -EIO; + /* set flow control */ + val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port)); + + if (pause->rx_pause) + qlcnic_gb_rx_flowctl(val); + else + qlcnic_gb_unset_rx_flowctl(val); + + QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), + val); + /* set autoneg */ + val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL); + switch (port) { + case 0: + if (pause->tx_pause) + qlcnic_gb_unset_gb0_mask(val); + else + qlcnic_gb_set_gb0_mask(val); + break; + case 1: + if (pause->tx_pause) + qlcnic_gb_unset_gb1_mask(val); + else + qlcnic_gb_set_gb1_mask(val); + break; + case 2: + if (pause->tx_pause) + qlcnic_gb_unset_gb2_mask(val); + else + qlcnic_gb_set_gb2_mask(val); + break; + case 3: + default: + if (pause->tx_pause) + qlcnic_gb_unset_gb3_mask(val); + else + qlcnic_gb_set_gb3_mask(val); + break; + } + QLCWR32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, val); + } else if (adapter->ahw.port_type == QLCNIC_XGBE) { + if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS)) + return -EIO; + val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL); + if (port == 0) { + if (pause->tx_pause) + qlcnic_xg_unset_xg0_mask(val); + else + qlcnic_xg_set_xg0_mask(val); + } else { + if (pause->tx_pause) + qlcnic_xg_unset_xg1_mask(val); + else + qlcnic_xg_set_xg1_mask(val); + } + QLCWR32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, val); + } else { + dev_err(&netdev->dev, "Unknown board type: %x\n", + adapter->ahw.port_type); + } + return 0; +} + +static int qlcnic_reg_test(struct net_device *dev) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + u32 data_read, data_written; + + data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0)); + if ((data_read & 0xffff) != adapter->pdev->vendor) + return 1; + + data_written = (u32)0xa5a5a5a5; + + QLCWR32(adapter, CRB_SCRATCHPAD_TEST, data_written); + data_read = QLCRD32(adapter, CRB_SCRATCHPAD_TEST); + if (data_written != data_read) + return 1; + + return 0; +} + +static int qlcnic_get_sset_count(struct net_device *dev, int sset) +{ + switch (sset) { + case ETH_SS_TEST: + return QLCNIC_TEST_LEN; + case ETH_SS_STATS: + return QLCNIC_STATS_LEN; + default: + return -EOPNOTSUPP; + } +} + +static void +qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test, + u64 *data) +{ + memset(data, 0, sizeof(u64) * QLCNIC_TEST_LEN); + data[0] = qlcnic_reg_test(dev); + if (data[0]) + eth_test->flags |= ETH_TEST_FL_FAILED; + + /* link test */ + data[1] = (u64) qlcnic_test_link(dev); + if (data[1]) + eth_test->flags |= ETH_TEST_FL_FAILED; +} + +static void +qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data) +{ + int index; + + switch (stringset) { + case ETH_SS_TEST: + memcpy(data, *qlcnic_gstrings_test, + QLCNIC_TEST_LEN * ETH_GSTRING_LEN); + break; + case ETH_SS_STATS: + for (index = 0; index < QLCNIC_STATS_LEN; index++) { + memcpy(data + index * ETH_GSTRING_LEN, + qlcnic_gstrings_stats[index].stat_string, + ETH_GSTRING_LEN); + } + break; + } +} + +static void +qlcnic_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 * data) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + int index; + + for (index = 0; index < QLCNIC_STATS_LEN; index++) { + char *p = + (char *)adapter + + qlcnic_gstrings_stats[index].stat_offset; + data[index] = + (qlcnic_gstrings_stats[index].sizeof_stat == + sizeof(u64)) ? *(u64 *)p:(*(u32 *)p); + } +} + +static u32 qlcnic_get_rx_csum(struct net_device *dev) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + return adapter->rx_csum; +} + +static int qlcnic_set_rx_csum(struct net_device *dev, u32 data) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + adapter->rx_csum = !!data; + return 0; +} + +static u32 qlcnic_get_tso(struct net_device *dev) +{ + return (dev->features & (NETIF_F_TSO | NETIF_F_TSO6)) != 0; +} + +static int qlcnic_set_tso(struct net_device *dev, u32 data) +{ + if (data) + dev->features |= (NETIF_F_TSO | NETIF_F_TSO6); + else + dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); + + return 0; +} + +static void +qlcnic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + u32 wol_cfg; + + wol->supported = 0; + wol->wolopts = 0; + + wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV); + if (wol_cfg & (1UL << adapter->portnum)) + wol->supported |= WAKE_MAGIC; + + wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG); + if (wol_cfg & (1UL << adapter->portnum)) + wol->wolopts |= WAKE_MAGIC; +} + +static int +qlcnic_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + u32 wol_cfg; + + if (wol->wolopts & ~WAKE_MAGIC) + return -EOPNOTSUPP; + + wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV); + if (!(wol_cfg & (1 << adapter->portnum))) + return -EOPNOTSUPP; + + wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG); + if (wol->wolopts & WAKE_MAGIC) + wol_cfg |= 1UL << adapter->portnum; + else + wol_cfg &= ~(1UL << adapter->portnum); + + QLCWR32(adapter, QLCNIC_WOL_CONFIG, wol_cfg); + + return 0; +} + +/* + * Set the coalescing parameters. Currently only normal is supported. + * If rx_coalesce_usecs == 0 or rx_max_coalesced_frames == 0 then set the + * firmware coalescing to default. + */ +static int qlcnic_set_intr_coalesce(struct net_device *netdev, + struct ethtool_coalesce *ethcoal) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + + if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) + return -EINVAL; + + /* + * Return Error if unsupported values or + * 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) + return -EINVAL; + + if (!ethcoal->rx_coalesce_usecs || + !ethcoal->rx_max_coalesced_frames) { + adapter->coal.flags = QLCNIC_INTR_DEFAULT; + adapter->coal.normal.data.rx_time_us = + QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US; + adapter->coal.normal.data.rx_packets = + QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS; + } else { + adapter->coal.flags = 0; + adapter->coal.normal.data.rx_time_us = + ethcoal->rx_coalesce_usecs; + adapter->coal.normal.data.rx_packets = + ethcoal->rx_max_coalesced_frames; + } + adapter->coal.normal.data.tx_time_us = ethcoal->tx_coalesce_usecs; + adapter->coal.normal.data.tx_packets = + ethcoal->tx_max_coalesced_frames; + + qlcnic_config_intr_coalesce(adapter); + + return 0; +} + +static int qlcnic_get_intr_coalesce(struct net_device *netdev, + struct ethtool_coalesce *ethcoal) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + + if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) + return -EINVAL; + + ethcoal->rx_coalesce_usecs = adapter->coal.normal.data.rx_time_us; + ethcoal->tx_coalesce_usecs = adapter->coal.normal.data.tx_time_us; + ethcoal->rx_max_coalesced_frames = + adapter->coal.normal.data.rx_packets; + ethcoal->tx_max_coalesced_frames = + adapter->coal.normal.data.tx_packets; + + return 0; +} + +static int qlcnic_set_flags(struct net_device *netdev, u32 data) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + int hw_lro; + + if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)) + return -EINVAL; + + ethtool_op_set_flags(netdev, data); + + hw_lro = (data & ETH_FLAG_LRO) ? QLCNIC_LRO_ENABLED : 0; + + if (qlcnic_config_hw_lro(adapter, hw_lro)) + return -EIO; + + if ((hw_lro == 0) && qlcnic_send_lro_cleanup(adapter)) + return -EIO; + + + return 0; +} + +const struct ethtool_ops qlcnic_ethtool_ops = { + .get_settings = qlcnic_get_settings, + .set_settings = qlcnic_set_settings, + .get_drvinfo = qlcnic_get_drvinfo, + .get_regs_len = qlcnic_get_regs_len, + .get_regs = qlcnic_get_regs, + .get_link = ethtool_op_get_link, + .get_eeprom_len = qlcnic_get_eeprom_len, + .get_eeprom = qlcnic_get_eeprom, + .get_ringparam = qlcnic_get_ringparam, + .set_ringparam = qlcnic_set_ringparam, + .get_pauseparam = qlcnic_get_pauseparam, + .set_pauseparam = qlcnic_set_pauseparam, + .set_tx_csum = ethtool_op_set_tx_csum, + .set_sg = ethtool_op_set_sg, + .get_tso = qlcnic_get_tso, + .set_tso = qlcnic_set_tso, + .get_wol = qlcnic_get_wol, + .set_wol = qlcnic_set_wol, + .self_test = qlcnic_diag_test, + .get_strings = qlcnic_get_strings, + .get_ethtool_stats = qlcnic_get_ethtool_stats, + .get_sset_count = qlcnic_get_sset_count, + .get_rx_csum = qlcnic_get_rx_csum, + .set_rx_csum = qlcnic_set_rx_csum, + .get_coalesce = qlcnic_get_intr_coalesce, + .set_coalesce = qlcnic_set_intr_coalesce, + .get_flags = ethtool_op_get_flags, + .set_flags = qlcnic_set_flags, +}; diff --git a/drivers/net/qlcnic/qlcnic_hdr.h b/drivers/net/qlcnic/qlcnic_hdr.h new file mode 100644 index 00000000000..0469f84360a --- /dev/null +++ b/drivers/net/qlcnic/qlcnic_hdr.h @@ -0,0 +1,937 @@ +/* + * Copyright (C) 2009 - QLogic Corporation. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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. + * + * The full GNU General Public License is included in this distribution + * in the file called "COPYING". + * + */ + +#ifndef __QLCNIC_HDR_H_ +#define __QLCNIC_HDR_H_ + +#include +#include + +/* + * The basic unit of access when reading/writing control registers. + */ + +enum { + QLCNIC_HW_H0_CH_HUB_ADR = 0x05, + QLCNIC_HW_H1_CH_HUB_ADR = 0x0E, + QLCNIC_HW_H2_CH_HUB_ADR = 0x03, + QLCNIC_HW_H3_CH_HUB_ADR = 0x01, + QLCNIC_HW_H4_CH_HUB_ADR = 0x06, + QLCNIC_HW_H5_CH_HUB_ADR = 0x07, + QLCNIC_HW_H6_CH_HUB_ADR = 0x08 +}; + +/* Hub 0 */ +enum { + QLCNIC_HW_MN_CRB_AGT_ADR = 0x15, + QLCNIC_HW_MS_CRB_AGT_ADR = 0x25 +}; + +/* Hub 1 */ +enum { + QLCNIC_HW_PS_CRB_AGT_ADR = 0x73, + QLCNIC_HW_SS_CRB_AGT_ADR = 0x20, + QLCNIC_HW_RPMX3_CRB_AGT_ADR = 0x0b, + QLCNIC_HW_QMS_CRB_AGT_ADR = 0x00, + QLCNIC_HW_SQGS0_CRB_AGT_ADR = 0x01, + QLCNIC_HW_SQGS1_CRB_AGT_ADR = 0x02, + QLCNIC_HW_SQGS2_CRB_AGT_ADR = 0x03, + QLCNIC_HW_SQGS3_CRB_AGT_ADR = 0x04, + QLCNIC_HW_C2C0_CRB_AGT_ADR = 0x58, + QLCNIC_HW_C2C1_CRB_AGT_ADR = 0x59, + QLCNIC_HW_C2C2_CRB_AGT_ADR = 0x5a, + QLCNIC_HW_RPMX2_CRB_AGT_ADR = 0x0a, + QLCNIC_HW_RPMX4_CRB_AGT_ADR = 0x0c, + QLCNIC_HW_RPMX7_CRB_AGT_ADR = 0x0f, + QLCNIC_HW_RPMX9_CRB_AGT_ADR = 0x12, + QLCNIC_HW_SMB_CRB_AGT_ADR = 0x18 +}; + +/* Hub 2 */ +enum { + QLCNIC_HW_NIU_CRB_AGT_ADR = 0x31, + QLCNIC_HW_I2C0_CRB_AGT_ADR = 0x19, + QLCNIC_HW_I2C1_CRB_AGT_ADR = 0x29, + + QLCNIC_HW_SN_CRB_AGT_ADR = 0x10, + QLCNIC_HW_I2Q_CRB_AGT_ADR = 0x20, + QLCNIC_HW_LPC_CRB_AGT_ADR = 0x22, + QLCNIC_HW_ROMUSB_CRB_AGT_ADR = 0x21, + QLCNIC_HW_QM_CRB_AGT_ADR = 0x66, + QLCNIC_HW_SQG0_CRB_AGT_ADR = 0x60, + QLCNIC_HW_SQG1_CRB_AGT_ADR = 0x61, + QLCNIC_HW_SQG2_CRB_AGT_ADR = 0x62, + QLCNIC_HW_SQG3_CRB_AGT_ADR = 0x63, + QLCNIC_HW_RPMX1_CRB_AGT_ADR = 0x09, + QLCNIC_HW_RPMX5_CRB_AGT_ADR = 0x0d, + QLCNIC_HW_RPMX6_CRB_AGT_ADR = 0x0e, + QLCNIC_HW_RPMX8_CRB_AGT_ADR = 0x11 +}; + +/* Hub 3 */ +enum { + QLCNIC_HW_PH_CRB_AGT_ADR = 0x1A, + QLCNIC_HW_SRE_CRB_AGT_ADR = 0x50, + QLCNIC_HW_EG_CRB_AGT_ADR = 0x51, + QLCNIC_HW_RPMX0_CRB_AGT_ADR = 0x08 +}; + +/* Hub 4 */ +enum { + QLCNIC_HW_PEGN0_CRB_AGT_ADR = 0x40, + QLCNIC_HW_PEGN1_CRB_AGT_ADR, + QLCNIC_HW_PEGN2_CRB_AGT_ADR, + QLCNIC_HW_PEGN3_CRB_AGT_ADR, + QLCNIC_HW_PEGNI_CRB_AGT_ADR, + QLCNIC_HW_PEGND_CRB_AGT_ADR, + QLCNIC_HW_PEGNC_CRB_AGT_ADR, + QLCNIC_HW_PEGR0_CRB_AGT_ADR, + QLCNIC_HW_PEGR1_CRB_AGT_ADR, + QLCNIC_HW_PEGR2_CRB_AGT_ADR, + QLCNIC_HW_PEGR3_CRB_AGT_ADR, + QLCNIC_HW_PEGN4_CRB_AGT_ADR +}; + +/* Hub 5 */ +enum { + QLCNIC_HW_PEGS0_CRB_AGT_ADR = 0x40, + QLCNIC_HW_PEGS1_CRB_AGT_ADR, + QLCNIC_HW_PEGS2_CRB_AGT_ADR, + QLCNIC_HW_PEGS3_CRB_AGT_ADR, + QLCNIC_HW_PEGSI_CRB_AGT_ADR, + QLCNIC_HW_PEGSD_CRB_AGT_ADR, + QLCNIC_HW_PEGSC_CRB_AGT_ADR +}; + +/* Hub 6 */ +enum { + QLCNIC_HW_CAS0_CRB_AGT_ADR = 0x46, + QLCNIC_HW_CAS1_CRB_AGT_ADR = 0x47, + QLCNIC_HW_CAS2_CRB_AGT_ADR = 0x48, + QLCNIC_HW_CAS3_CRB_AGT_ADR = 0x49, + QLCNIC_HW_NCM_CRB_AGT_ADR = 0x16, + QLCNIC_HW_TMR_CRB_AGT_ADR = 0x17, + QLCNIC_HW_XDMA_CRB_AGT_ADR = 0x05, + QLCNIC_HW_OCM0_CRB_AGT_ADR = 0x06, + QLCNIC_HW_OCM1_CRB_AGT_ADR = 0x07 +}; + +/* Floaters - non existent modules */ +#define QLCNIC_HW_EFC_RPMX0_CRB_AGT_ADR 0x67 + +/* This field defines PCI/X adr [25:20] of agents on the CRB */ +enum { + QLCNIC_HW_PX_MAP_CRB_PH = 0, + QLCNIC_HW_PX_MAP_CRB_PS, + QLCNIC_HW_PX_MAP_CRB_MN, + QLCNIC_HW_PX_MAP_CRB_MS, + QLCNIC_HW_PX_MAP_CRB_PGR1, + QLCNIC_HW_PX_MAP_CRB_SRE, + QLCNIC_HW_PX_MAP_CRB_NIU, + QLCNIC_HW_PX_MAP_CRB_QMN, + QLCNIC_HW_PX_MAP_CRB_SQN0, + QLCNIC_HW_PX_MAP_CRB_SQN1, + QLCNIC_HW_PX_MAP_CRB_SQN2, + QLCNIC_HW_PX_MAP_CRB_SQN3, + QLCNIC_HW_PX_MAP_CRB_QMS, + QLCNIC_HW_PX_MAP_CRB_SQS0, + QLCNIC_HW_PX_MAP_CRB_SQS1, + QLCNIC_HW_PX_MAP_CRB_SQS2, + QLCNIC_HW_PX_MAP_CRB_SQS3, + QLCNIC_HW_PX_MAP_CRB_PGN0, + QLCNIC_HW_PX_MAP_CRB_PGN1, + QLCNIC_HW_PX_MAP_CRB_PGN2, + QLCNIC_HW_PX_MAP_CRB_PGN3, + QLCNIC_HW_PX_MAP_CRB_PGND, + QLCNIC_HW_PX_MAP_CRB_PGNI, + QLCNIC_HW_PX_MAP_CRB_PGS0, + QLCNIC_HW_PX_MAP_CRB_PGS1, + QLCNIC_HW_PX_MAP_CRB_PGS2, + QLCNIC_HW_PX_MAP_CRB_PGS3, + QLCNIC_HW_PX_MAP_CRB_PGSD, + QLCNIC_HW_PX_MAP_CRB_PGSI, + QLCNIC_HW_PX_MAP_CRB_SN, + QLCNIC_HW_PX_MAP_CRB_PGR2, + QLCNIC_HW_PX_MAP_CRB_EG, + QLCNIC_HW_PX_MAP_CRB_PH2, + QLCNIC_HW_PX_MAP_CRB_PS2, + QLCNIC_HW_PX_MAP_CRB_CAM, + QLCNIC_HW_PX_MAP_CRB_CAS0, + QLCNIC_HW_PX_MAP_CRB_CAS1, + QLCNIC_HW_PX_MAP_CRB_CAS2, + QLCNIC_HW_PX_MAP_CRB_C2C0, + QLCNIC_HW_PX_MAP_CRB_C2C1, + QLCNIC_HW_PX_MAP_CRB_TIMR, + QLCNIC_HW_PX_MAP_CRB_PGR3, + QLCNIC_HW_PX_MAP_CRB_RPMX1, + QLCNIC_HW_PX_MAP_CRB_RPMX2, + QLCNIC_HW_PX_MAP_CRB_RPMX3, + QLCNIC_HW_PX_MAP_CRB_RPMX4, + QLCNIC_HW_PX_MAP_CRB_RPMX5, + QLCNIC_HW_PX_MAP_CRB_RPMX6, + QLCNIC_HW_PX_MAP_CRB_RPMX7, + QLCNIC_HW_PX_MAP_CRB_XDMA, + QLCNIC_HW_PX_MAP_CRB_I2Q, + QLCNIC_HW_PX_MAP_CRB_ROMUSB, + QLCNIC_HW_PX_MAP_CRB_CAS3, + QLCNIC_HW_PX_MAP_CRB_RPMX0, + QLCNIC_HW_PX_MAP_CRB_RPMX8, + QLCNIC_HW_PX_MAP_CRB_RPMX9, + QLCNIC_HW_PX_MAP_CRB_OCM0, + QLCNIC_HW_PX_MAP_CRB_OCM1, + QLCNIC_HW_PX_MAP_CRB_SMB, + QLCNIC_HW_PX_MAP_CRB_I2C0, + QLCNIC_HW_PX_MAP_CRB_I2C1, + QLCNIC_HW_PX_MAP_CRB_LPC, + QLCNIC_HW_PX_MAP_CRB_PGNC, + QLCNIC_HW_PX_MAP_CRB_PGR0 +}; + +/* This field defines CRB adr [31:20] of the agents */ + +#define QLCNIC_HW_CRB_HUB_AGT_ADR_MN \ + ((QLCNIC_HW_H0_CH_HUB_ADR << 7) | QLCNIC_HW_MN_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PH \ + ((QLCNIC_HW_H0_CH_HUB_ADR << 7) | QLCNIC_HW_PH_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_MS \ + ((QLCNIC_HW_H0_CH_HUB_ADR << 7) | QLCNIC_HW_MS_CRB_AGT_ADR) + +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PS \ + ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_PS_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_SS \ + ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_SS_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX3 \ + ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX3_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_QMS \ + ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_QMS_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_SQS0 \ + ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_SQGS0_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_SQS1 \ + ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_SQGS1_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_SQS2 \ + ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_SQGS2_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_SQS3 \ + ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_SQGS3_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_C2C0 \ + ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_C2C0_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_C2C1 \ + ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_C2C1_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX2 \ + ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX2_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX4 \ + ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX4_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX7 \ + ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX7_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX9 \ + ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX9_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_SMB \ + ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_SMB_CRB_AGT_ADR) + +#define QLCNIC_HW_CRB_HUB_AGT_ADR_NIU \ + ((QLCNIC_HW_H2_CH_HUB_ADR << 7) | QLCNIC_HW_NIU_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_I2C0 \ + ((QLCNIC_HW_H2_CH_HUB_ADR << 7) | QLCNIC_HW_I2C0_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_I2C1 \ + ((QLCNIC_HW_H2_CH_HUB_ADR << 7) | QLCNIC_HW_I2C1_CRB_AGT_ADR) + +#define QLCNIC_HW_CRB_HUB_AGT_ADR_SRE \ + ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_SRE_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_EG \ + ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_EG_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX0 \ + ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX0_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_QMN \ + ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_QM_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_SQN0 \ + ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_SQG0_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_SQN1 \ + ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_SQG1_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_SQN2 \ + ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_SQG2_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_SQN3 \ + ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_SQG3_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX1 \ + ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX1_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX5 \ + ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX5_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX6 \ + ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX6_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX8 \ + ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX8_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_CAS0 \ + ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_CAS0_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_CAS1 \ + ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_CAS1_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_CAS2 \ + ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_CAS2_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_CAS3 \ + ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_CAS3_CRB_AGT_ADR) + +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGNI \ + ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGNI_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGND \ + ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGND_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGN0 \ + ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGN0_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGN1 \ + ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGN1_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGN2 \ + ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGN2_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGN3 \ + ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGN3_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGN4 \ + ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGN4_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGNC \ + ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGNC_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGR0 \ + ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGR0_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGR1 \ + ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGR1_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGR2 \ + ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGR2_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGR3 \ + ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGR3_CRB_AGT_ADR) + +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGSI \ + ((QLCNIC_HW_H5_CH_HUB_ADR << 7) | QLCNIC_HW_PEGSI_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGSD \ + ((QLCNIC_HW_H5_CH_HUB_ADR << 7) | QLCNIC_HW_PEGSD_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGS0 \ + ((QLCNIC_HW_H5_CH_HUB_ADR << 7) | QLCNIC_HW_PEGS0_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGS1 \ + ((QLCNIC_HW_H5_CH_HUB_ADR << 7) | QLCNIC_HW_PEGS1_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGS2 \ + ((QLCNIC_HW_H5_CH_HUB_ADR << 7) | QLCNIC_HW_PEGS2_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGS3 \ + ((QLCNIC_HW_H5_CH_HUB_ADR << 7) | QLCNIC_HW_PEGS3_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGSC \ + ((QLCNIC_HW_H5_CH_HUB_ADR << 7) | QLCNIC_HW_PEGSC_CRB_AGT_ADR) + +#define QLCNIC_HW_CRB_HUB_AGT_ADR_CAM \ + ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_NCM_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_TIMR \ + ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_TMR_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_XDMA \ + ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_XDMA_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_SN \ + ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_SN_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_I2Q \ + ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_I2Q_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_ROMUSB \ + ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_ROMUSB_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_OCM0 \ + ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_OCM0_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_OCM1 \ + ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_OCM1_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_LPC \ + ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_LPC_CRB_AGT_ADR) + +#define QLCNIC_SRE_MISC (QLCNIC_CRB_SRE + 0x0002c) + +#define QLCNIC_I2Q_CLR_PCI_HI (QLCNIC_CRB_I2Q + 0x00034) + +#define ROMUSB_GLB (QLCNIC_CRB_ROMUSB + 0x00000) +#define ROMUSB_ROM (QLCNIC_CRB_ROMUSB + 0x10000) + +#define QLCNIC_ROMUSB_GLB_STATUS (ROMUSB_GLB + 0x0004) +#define QLCNIC_ROMUSB_GLB_SW_RESET (ROMUSB_GLB + 0x0008) +#define QLCNIC_ROMUSB_GLB_PAD_GPIO_I (ROMUSB_GLB + 0x000c) +#define QLCNIC_ROMUSB_GLB_CAS_RST (ROMUSB_GLB + 0x0038) +#define QLCNIC_ROMUSB_GLB_TEST_MUX_SEL (ROMUSB_GLB + 0x0044) +#define QLCNIC_ROMUSB_GLB_PEGTUNE_DONE (ROMUSB_GLB + 0x005c) +#define QLCNIC_ROMUSB_GLB_CHIP_CLK_CTRL (ROMUSB_GLB + 0x00A8) + +#define QLCNIC_ROMUSB_GPIO(n) (ROMUSB_GLB + 0x60 + (4 * (n))) + +#define QLCNIC_ROMUSB_ROM_INSTR_OPCODE (ROMUSB_ROM + 0x0004) +#define QLCNIC_ROMUSB_ROM_ADDRESS (ROMUSB_ROM + 0x0008) +#define QLCNIC_ROMUSB_ROM_WDATA (ROMUSB_ROM + 0x000c) +#define QLCNIC_ROMUSB_ROM_ABYTE_CNT (ROMUSB_ROM + 0x0010) +#define QLCNIC_ROMUSB_ROM_DUMMY_BYTE_CNT (ROMUSB_ROM + 0x0014) +#define QLCNIC_ROMUSB_ROM_RDATA (ROMUSB_ROM + 0x0018) + +/* Lock IDs for ROM lock */ +#define ROM_LOCK_DRIVER 0x0d417340 + +/****************************************************************************** +* +* Definitions specific to M25P flash +* +******************************************************************************* +*/ + +/* all are 1MB windows */ + +#define QLCNIC_PCI_CRB_WINDOWSIZE 0x00100000 +#define QLCNIC_PCI_CRB_WINDOW(A) \ + (QLCNIC_PCI_CRBSPACE + (A)*QLCNIC_PCI_CRB_WINDOWSIZE) + +#define QLCNIC_CRB_NIU QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_NIU) +#define QLCNIC_CRB_SRE QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_SRE) +#define QLCNIC_CRB_ROMUSB \ + QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_ROMUSB) +#define QLCNIC_CRB_I2Q QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_I2Q) +#define QLCNIC_CRB_I2C0 QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_I2C0) +#define QLCNIC_CRB_SMB QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_SMB) +#define QLCNIC_CRB_MAX QLCNIC_PCI_CRB_WINDOW(64) + +#define QLCNIC_CRB_PCIX_HOST QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PH) +#define QLCNIC_CRB_PCIX_HOST2 QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PH2) +#define QLCNIC_CRB_PEG_NET_0 QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PGN0) +#define QLCNIC_CRB_PEG_NET_1 QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PGN1) +#define QLCNIC_CRB_PEG_NET_2 QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PGN2) +#define QLCNIC_CRB_PEG_NET_3 QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PGN3) +#define QLCNIC_CRB_PEG_NET_4 QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_SQS2) +#define QLCNIC_CRB_PEG_NET_D QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PGND) +#define QLCNIC_CRB_PEG_NET_I QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PGNI) +#define QLCNIC_CRB_DDR_NET QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_MN) +#define QLCNIC_CRB_QDR_NET QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_SN) + +#define QLCNIC_CRB_PCIX_MD QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PS) +#define QLCNIC_CRB_PCIE QLCNIC_CRB_PCIX_MD + +#define ISR_INT_VECTOR (QLCNIC_PCIX_PS_REG(PCIX_INT_VECTOR)) +#define ISR_INT_MASK (QLCNIC_PCIX_PS_REG(PCIX_INT_MASK)) +#define ISR_INT_MASK_SLOW (QLCNIC_PCIX_PS_REG(PCIX_INT_MASK)) +#define ISR_INT_TARGET_STATUS (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS)) +#define ISR_INT_TARGET_MASK (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK)) +#define ISR_INT_TARGET_STATUS_F1 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS_F1)) +#define ISR_INT_TARGET_MASK_F1 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK_F1)) +#define ISR_INT_TARGET_STATUS_F2 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS_F2)) +#define ISR_INT_TARGET_MASK_F2 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK_F2)) +#define ISR_INT_TARGET_STATUS_F3 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS_F3)) +#define ISR_INT_TARGET_MASK_F3 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK_F3)) +#define ISR_INT_TARGET_STATUS_F4 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS_F4)) +#define ISR_INT_TARGET_MASK_F4 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK_F4)) +#define ISR_INT_TARGET_STATUS_F5 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS_F5)) +#define ISR_INT_TARGET_MASK_F5 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK_F5)) +#define ISR_INT_TARGET_STATUS_F6 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS_F6)) +#define ISR_INT_TARGET_MASK_F6 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK_F6)) +#define ISR_INT_TARGET_STATUS_F7 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS_F7)) +#define ISR_INT_TARGET_MASK_F7 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK_F7)) + +#define QLCNIC_PCI_MN_2M (0) +#define QLCNIC_PCI_MS_2M (0x80000) +#define QLCNIC_PCI_OCM0_2M (0x000c0000UL) +#define QLCNIC_PCI_CRBSPACE (0x06000000UL) +#define QLCNIC_PCI_2MB_SIZE (0x00200000UL) +#define QLCNIC_PCI_CAMQM_2M_BASE (0x000ff800UL) +#define QLCNIC_PCI_CAMQM_2M_END (0x04800800UL) + +#define QLCNIC_CRB_CAM QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_CAM) + +#define QLCNIC_ADDR_DDR_NET (0x0000000000000000ULL) +#define QLCNIC_ADDR_DDR_NET_MAX (0x000000000fffffffULL) +#define QLCNIC_ADDR_OCM0 (0x0000000200000000ULL) +#define QLCNIC_ADDR_OCM0_MAX (0x00000002000fffffULL) +#define QLCNIC_ADDR_OCM1 (0x0000000200400000ULL) +#define QLCNIC_ADDR_OCM1_MAX (0x00000002004fffffULL) +#define QLCNIC_ADDR_QDR_NET (0x0000000300000000ULL) +#define QLCNIC_ADDR_QDR_NET_MAX_P3 (0x0000000303ffffffULL) + +/* + * Register offsets for MN + */ +#define QLCNIC_MIU_CONTROL (0x000) +#define QLCNIC_MIU_MN_CONTROL (QLCNIC_CRB_DDR_NET+QLCNIC_MIU_CONTROL) + +/* 200ms delay in each loop */ +#define QLCNIC_NIU_PHY_WAITLEN 200000 +/* 10 seconds before we give up */ +#define QLCNIC_NIU_PHY_WAITMAX 50 +#define QLCNIC_NIU_MAX_GBE_PORTS 4 +#define QLCNIC_NIU_MAX_XG_PORTS 2 + +#define QLCNIC_NIU_MODE (QLCNIC_CRB_NIU + 0x00000) +#define QLCNIC_NIU_GB_PAUSE_CTL (QLCNIC_CRB_NIU + 0x0030c) +#define QLCNIC_NIU_XG_PAUSE_CTL (QLCNIC_CRB_NIU + 0x00098) + +#define QLCNIC_NIU_GB_MAC_CONFIG_0(I) \ + (QLCNIC_CRB_NIU + 0x30000 + (I)*0x10000) +#define QLCNIC_NIU_GB_MAC_CONFIG_1(I) \ + (QLCNIC_CRB_NIU + 0x30004 + (I)*0x10000) + + +#define TEST_AGT_CTRL (0x00) + +#define TA_CTL_START 1 +#define TA_CTL_ENABLE 2 +#define TA_CTL_WRITE 4 +#define TA_CTL_BUSY 8 + +/* + * Register offsets for MN + */ +#define MIU_TEST_AGT_BASE (0x90) + +#define MIU_TEST_AGT_ADDR_LO (0x04) +#define MIU_TEST_AGT_ADDR_HI (0x08) +#define MIU_TEST_AGT_WRDATA_LO (0x10) +#define MIU_TEST_AGT_WRDATA_HI (0x14) +#define MIU_TEST_AGT_WRDATA_UPPER_LO (0x20) +#define MIU_TEST_AGT_WRDATA_UPPER_HI (0x24) +#define MIU_TEST_AGT_WRDATA(i) (0x10+(0x10*((i)>>1))+(4*((i)&1))) +#define MIU_TEST_AGT_RDDATA_LO (0x18) +#define MIU_TEST_AGT_RDDATA_HI (0x1c) +#define MIU_TEST_AGT_RDDATA_UPPER_LO (0x28) +#define MIU_TEST_AGT_RDDATA_UPPER_HI (0x2c) +#define MIU_TEST_AGT_RDDATA(i) (0x18+(0x10*((i)>>1))+(4*((i)&1))) + +#define MIU_TEST_AGT_ADDR_MASK 0xfffffff8 +#define MIU_TEST_AGT_UPPER_ADDR(off) (0) + +/* + * Register offsets for MS + */ +#define SIU_TEST_AGT_BASE (0x60) + +#define SIU_TEST_AGT_ADDR_LO (0x04) +#define SIU_TEST_AGT_ADDR_HI (0x18) +#define SIU_TEST_AGT_WRDATA_LO (0x08) +#define SIU_TEST_AGT_WRDATA_HI (0x0c) +#define SIU_TEST_AGT_WRDATA(i) (0x08+(4*(i))) +#define SIU_TEST_AGT_RDDATA_LO (0x10) +#define SIU_TEST_AGT_RDDATA_HI (0x14) +#define SIU_TEST_AGT_RDDATA(i) (0x10+(4*(i))) + +#define SIU_TEST_AGT_ADDR_MASK 0x3ffff8 +#define SIU_TEST_AGT_UPPER_ADDR(off) ((off)>>22) + +/* XG Link status */ +#define XG_LINK_UP 0x10 +#define XG_LINK_DOWN 0x20 + +#define XG_LINK_UP_P3 0x01 +#define XG_LINK_DOWN_P3 0x02 +#define XG_LINK_STATE_P3_MASK 0xf +#define XG_LINK_STATE_P3(pcifn, val) \ + (((val) >> ((pcifn) * 4)) & XG_LINK_STATE_P3_MASK) + +#define P3_LINK_SPEED_MHZ 100 +#define P3_LINK_SPEED_MASK 0xff +#define P3_LINK_SPEED_REG(pcifn) \ + (CRB_PF_LINK_SPEED_1 + (((pcifn) / 4) * 4)) +#define P3_LINK_SPEED_VAL(pcifn, reg) \ + (((reg) >> (8 * ((pcifn) & 0x3))) & P3_LINK_SPEED_MASK) + +#define QLCNIC_CAM_RAM_BASE (QLCNIC_CRB_CAM + 0x02000) +#define QLCNIC_CAM_RAM(reg) (QLCNIC_CAM_RAM_BASE + (reg)) +#define QLCNIC_FW_VERSION_MAJOR (QLCNIC_CAM_RAM(0x150)) +#define QLCNIC_FW_VERSION_MINOR (QLCNIC_CAM_RAM(0x154)) +#define QLCNIC_FW_VERSION_SUB (QLCNIC_CAM_RAM(0x158)) +#define QLCNIC_ROM_LOCK_ID (QLCNIC_CAM_RAM(0x100)) +#define QLCNIC_PHY_LOCK_ID (QLCNIC_CAM_RAM(0x120)) +#define QLCNIC_CRB_WIN_LOCK_ID (QLCNIC_CAM_RAM(0x124)) + +#define NIC_CRB_BASE (QLCNIC_CAM_RAM(0x200)) +#define NIC_CRB_BASE_2 (QLCNIC_CAM_RAM(0x700)) +#define QLCNIC_REG(X) (NIC_CRB_BASE+(X)) +#define QLCNIC_REG_2(X) (NIC_CRB_BASE_2+(X)) + +#define QLCNIC_CDRP_CRB_OFFSET (QLCNIC_REG(0x18)) +#define QLCNIC_ARG1_CRB_OFFSET (QLCNIC_REG(0x1c)) +#define QLCNIC_ARG2_CRB_OFFSET (QLCNIC_REG(0x20)) +#define QLCNIC_ARG3_CRB_OFFSET (QLCNIC_REG(0x24)) +#define QLCNIC_SIGN_CRB_OFFSET (QLCNIC_REG(0x28)) + +#define CRB_CMDPEG_STATE (QLCNIC_REG(0x50)) +#define CRB_RCVPEG_STATE (QLCNIC_REG(0x13c)) + +#define CRB_XG_STATE_P3 (QLCNIC_REG(0x98)) +#define CRB_PF_LINK_SPEED_1 (QLCNIC_REG(0xe8)) +#define CRB_PF_LINK_SPEED_2 (QLCNIC_REG(0xec)) + +#define CRB_MPORT_MODE (QLCNIC_REG(0xc4)) +#define CRB_DMA_SHIFT (QLCNIC_REG(0xcc)) + +#define CRB_TEMP_STATE (QLCNIC_REG(0x1b4)) + +#define CRB_V2P_0 (QLCNIC_REG(0x290)) +#define CRB_V2P(port) (CRB_V2P_0+((port)*4)) +#define CRB_DRIVER_VERSION (QLCNIC_REG(0x2a0)) + +#define CRB_SW_INT_MASK_0 (QLCNIC_REG(0x1d8)) +#define CRB_SW_INT_MASK_1 (QLCNIC_REG(0x1e0)) +#define CRB_SW_INT_MASK_2 (QLCNIC_REG(0x1e4)) +#define CRB_SW_INT_MASK_3 (QLCNIC_REG(0x1e8)) + +#define CRB_FW_CAPABILITIES_1 (QLCNIC_CAM_RAM(0x128)) +#define CRB_MAC_BLOCK_START (QLCNIC_CAM_RAM(0x1c0)) + +/* + * capabilities register, can be used to selectively enable/disable features + * for backward compability + */ +#define CRB_NIC_CAPABILITIES_HOST QLCNIC_REG(0x1a8) +#define CRB_NIC_CAPABILITIES_FW QLCNIC_REG(0x1dc) +#define CRB_NIC_MSI_MODE_HOST QLCNIC_REG(0x270) +#define CRB_NIC_MSI_MODE_FW QLCNIC_REG(0x274) + +#define INTR_SCHEME_PERPORT 0x1 +#define MSI_MODE_MULTIFUNC 0x1 + +/* used for ethtool tests */ +#define CRB_SCRATCHPAD_TEST QLCNIC_REG(0x280) + +/* + * CrbPortPhanCntrHi/Lo is used to pass the address of HostPhantomIndex address + * which can be read by the Phantom host to get producer/consumer indexes from + * Phantom/Casper. If it is not HOST_SHARED_MEMORY, then the following + * registers will be used for the addresses of the ring's shared memory + * on the Phantom. + */ + +#define qlcnic_get_temp_val(x) ((x) >> 16) +#define qlcnic_get_temp_state(x) ((x) & 0xffff) +#define qlcnic_encode_temp(val, state) (((val) << 16) | (state)) + +/* + * Temperature control. + */ +enum { + QLCNIC_TEMP_NORMAL = 0x1, /* Normal operating range */ + QLCNIC_TEMP_WARN, /* Sound alert, temperature getting high */ + QLCNIC_TEMP_PANIC /* Fatal error, hardware has shut down. */ +}; + +/* Lock IDs for PHY lock */ +#define PHY_LOCK_DRIVER 0x44524956 + +/* Used for PS PCI Memory access */ +#define PCIX_PS_OP_ADDR_LO (0x10000) +/* via CRB (PS side only) */ +#define PCIX_PS_OP_ADDR_HI (0x10004) + +#define PCIX_INT_VECTOR (0x10100) +#define PCIX_INT_MASK (0x10104) + +#define PCIX_OCM_WINDOW (0x10800) +#define PCIX_OCM_WINDOW_REG(func) (PCIX_OCM_WINDOW + 0x20 * (func)) + +#define PCIX_TARGET_STATUS (0x10118) +#define PCIX_TARGET_STATUS_F1 (0x10160) +#define PCIX_TARGET_STATUS_F2 (0x10164) +#define PCIX_TARGET_STATUS_F3 (0x10168) +#define PCIX_TARGET_STATUS_F4 (0x10360) +#define PCIX_TARGET_STATUS_F5 (0x10364) +#define PCIX_TARGET_STATUS_F6 (0x10368) +#define PCIX_TARGET_STATUS_F7 (0x1036c) + +#define PCIX_TARGET_MASK (0x10128) +#define PCIX_TARGET_MASK_F1 (0x10170) +#define PCIX_TARGET_MASK_F2 (0x10174) +#define PCIX_TARGET_MASK_F3 (0x10178) +#define PCIX_TARGET_MASK_F4 (0x10370) +#define PCIX_TARGET_MASK_F5 (0x10374) +#define PCIX_TARGET_MASK_F6 (0x10378) +#define PCIX_TARGET_MASK_F7 (0x1037c) + +#define PCIX_MSI_F(i) (0x13000+((i)*4)) + +#define QLCNIC_PCIX_PH_REG(reg) (QLCNIC_CRB_PCIE + (reg)) +#define QLCNIC_PCIX_PS_REG(reg) (QLCNIC_CRB_PCIX_MD + (reg)) +#define QLCNIC_PCIE_REG(reg) (QLCNIC_CRB_PCIE + (reg)) + +#define PCIE_SEM0_LOCK (0x1c000) +#define PCIE_SEM0_UNLOCK (0x1c004) +#define PCIE_SEM_LOCK(N) (PCIE_SEM0_LOCK + 8*(N)) +#define PCIE_SEM_UNLOCK(N) (PCIE_SEM0_UNLOCK + 8*(N)) + +#define PCIE_SETUP_FUNCTION (0x12040) +#define PCIE_SETUP_FUNCTION2 (0x12048) +#define PCIE_MISCCFG_RC (0x1206c) +#define PCIE_TGT_SPLIT_CHICKEN (0x12080) +#define PCIE_CHICKEN3 (0x120c8) + +#define ISR_INT_STATE_REG (QLCNIC_PCIX_PS_REG(PCIE_MISCCFG_RC)) +#define PCIE_MAX_MASTER_SPLIT (0x14048) + +#define QLCNIC_PORT_MODE_NONE 0 +#define QLCNIC_PORT_MODE_XG 1 +#define QLCNIC_PORT_MODE_GB 2 +#define QLCNIC_PORT_MODE_802_3_AP 3 +#define QLCNIC_PORT_MODE_AUTO_NEG 4 +#define QLCNIC_PORT_MODE_AUTO_NEG_1G 5 +#define QLCNIC_PORT_MODE_AUTO_NEG_XG 6 +#define QLCNIC_PORT_MODE_ADDR (QLCNIC_CAM_RAM(0x24)) +#define QLCNIC_WOL_PORT_MODE (QLCNIC_CAM_RAM(0x198)) + +#define QLCNIC_WOL_CONFIG_NV (QLCNIC_CAM_RAM(0x184)) +#define QLCNIC_WOL_CONFIG (QLCNIC_CAM_RAM(0x188)) + +#define QLCNIC_PEG_TUNE_MN_PRESENT 0x1 +#define QLCNIC_PEG_TUNE_CAPABILITY (QLCNIC_CAM_RAM(0x02c)) + +#define QLCNIC_DMA_WATCHDOG_CTRL (QLCNIC_CAM_RAM(0x14)) +#define QLCNIC_PEG_ALIVE_COUNTER (QLCNIC_CAM_RAM(0xb0)) +#define QLCNIC_PEG_HALT_STATUS1 (QLCNIC_CAM_RAM(0xa8)) +#define QLCNIC_PEG_HALT_STATUS2 (QLCNIC_CAM_RAM(0xac)) +#define QLCNIC_CRB_DEV_REF_COUNT (QLCNIC_CAM_RAM(0x138)) +#define QLCNIC_CRB_DEV_STATE (QLCNIC_CAM_RAM(0x140)) + +#define QLCNIC_CRB_DRV_STATE (QLCNIC_CAM_RAM(0x144)) +#define QLCNIC_CRB_DRV_SCRATCH (QLCNIC_CAM_RAM(0x148)) +#define QLCNIC_CRB_DEV_PARTITION_INFO (QLCNIC_CAM_RAM(0x14c)) +#define QLCNIC_CRB_DRV_IDC_VER (QLCNIC_CAM_RAM(0x14c)) + + /* Device State */ +#define QLCNIC_DEV_COLD 1 +#define QLCNIC_DEV_INITALIZING 2 +#define QLCNIC_DEV_READY 3 +#define QLCNIC_DEV_NEED_RESET 4 +#define QLCNIC_DEV_NEED_QUISCENT 5 +#define QLCNIC_DEV_FAILED 6 + +#define QLCNIC_RCODE_DRIVER_INFO 0x20000000 +#define QLCNIC_RCODE_DRIVER_CAN_RELOAD 0x40000000 +#define QLCNIC_RCODE_FATAL_ERROR 0x80000000 +#define QLCNIC_FWERROR_PEGNUM(code) ((code) & 0xff) +#define QLCNIC_FWERROR_CODE(code) ((code >> 8) & 0xfffff) + +#define FW_POLL_DELAY (2 * HZ) +#define FW_FAIL_THRESH 3 +#define FW_POLL_THRESH 10 + +#define ISR_MSI_INT_TRIGGER(FUNC) (QLCNIC_PCIX_PS_REG(PCIX_MSI_F(FUNC))) +#define ISR_LEGACY_INT_TRIGGERED(VAL) (((VAL) & 0x300) == 0x200) + +/* + * PCI Interrupt Vector Values. + */ +#define PCIX_INT_VECTOR_BIT_F0 0x0080 +#define PCIX_INT_VECTOR_BIT_F1 0x0100 +#define PCIX_INT_VECTOR_BIT_F2 0x0200 +#define PCIX_INT_VECTOR_BIT_F3 0x0400 +#define PCIX_INT_VECTOR_BIT_F4 0x0800 +#define PCIX_INT_VECTOR_BIT_F5 0x1000 +#define PCIX_INT_VECTOR_BIT_F6 0x2000 +#define PCIX_INT_VECTOR_BIT_F7 0x4000 + +struct qlcnic_legacy_intr_set { + u32 int_vec_bit; + u32 tgt_status_reg; + u32 tgt_mask_reg; + u32 pci_int_reg; +}; + +#define QLCNIC_LEGACY_INTR_CONFIG \ +{ \ + { \ + .int_vec_bit = PCIX_INT_VECTOR_BIT_F0, \ + .tgt_status_reg = ISR_INT_TARGET_STATUS, \ + .tgt_mask_reg = ISR_INT_TARGET_MASK, \ + .pci_int_reg = ISR_MSI_INT_TRIGGER(0) }, \ + \ + { \ + .int_vec_bit = PCIX_INT_VECTOR_BIT_F1, \ + .tgt_status_reg = ISR_INT_TARGET_STATUS_F1, \ + .tgt_mask_reg = ISR_INT_TARGET_MASK_F1, \ + .pci_int_reg = ISR_MSI_INT_TRIGGER(1) }, \ + \ + { \ + .int_vec_bit = PCIX_INT_VECTOR_BIT_F2, \ + .tgt_status_reg = ISR_INT_TARGET_STATUS_F2, \ + .tgt_mask_reg = ISR_INT_TARGET_MASK_F2, \ + .pci_int_reg = ISR_MSI_INT_TRIGGER(2) }, \ + \ + { \ + .int_vec_bit = PCIX_INT_VECTOR_BIT_F3, \ + .tgt_status_reg = ISR_INT_TARGET_STATUS_F3, \ + .tgt_mask_reg = ISR_INT_TARGET_MASK_F3, \ + .pci_int_reg = ISR_MSI_INT_TRIGGER(3) }, \ + \ + { \ + .int_vec_bit = PCIX_INT_VECTOR_BIT_F4, \ + .tgt_status_reg = ISR_INT_TARGET_STATUS_F4, \ + .tgt_mask_reg = ISR_INT_TARGET_MASK_F4, \ + .pci_int_reg = ISR_MSI_INT_TRIGGER(4) }, \ + \ + { \ + .int_vec_bit = PCIX_INT_VECTOR_BIT_F5, \ + .tgt_status_reg = ISR_INT_TARGET_STATUS_F5, \ + .tgt_mask_reg = ISR_INT_TARGET_MASK_F5, \ + .pci_int_reg = ISR_MSI_INT_TRIGGER(5) }, \ + \ + { \ + .int_vec_bit = PCIX_INT_VECTOR_BIT_F6, \ + .tgt_status_reg = ISR_INT_TARGET_STATUS_F6, \ + .tgt_mask_reg = ISR_INT_TARGET_MASK_F6, \ + .pci_int_reg = ISR_MSI_INT_TRIGGER(6) }, \ + \ + { \ + .int_vec_bit = PCIX_INT_VECTOR_BIT_F7, \ + .tgt_status_reg = ISR_INT_TARGET_STATUS_F7, \ + .tgt_mask_reg = ISR_INT_TARGET_MASK_F7, \ + .pci_int_reg = ISR_MSI_INT_TRIGGER(7) }, \ +} + +/* NIU REGS */ + +#define _qlcnic_crb_get_bit(var, bit) ((var >> bit) & 0x1) + +/* + * NIU GB MAC Config Register 0 (applies to GB0, GB1, GB2, GB3) + * + * Bit 0 : enable_tx => 1:enable frame xmit, 0:disable + * Bit 1 : tx_synced => R/O: xmit enable synched to xmit stream + * Bit 2 : enable_rx => 1:enable frame recv, 0:disable + * Bit 3 : rx_synced => R/O: recv enable synched to recv stream + * Bit 4 : tx_flowctl => 1:enable pause frame generation, 0:disable + * Bit 5 : rx_flowctl => 1:act on recv'd pause frames, 0:ignore + * Bit 8 : loopback => 1:loop MAC xmits to MAC recvs, 0:normal + * Bit 16: tx_reset_pb => 1:reset frame xmit protocol blk, 0:no-op + * Bit 17: rx_reset_pb => 1:reset frame recv protocol blk, 0:no-op + * Bit 18: tx_reset_mac => 1:reset data/ctl multiplexer blk, 0:no-op + * Bit 19: rx_reset_mac => 1:reset ctl frames & timers blk, 0:no-op + * Bit 31: soft_reset => 1:reset the MAC and the SERDES, 0:no-op + */ +#define qlcnic_gb_rx_flowctl(config_word) \ + ((config_word) |= 1 << 5) +#define qlcnic_gb_get_rx_flowctl(config_word) \ + _qlcnic_crb_get_bit((config_word), 5) +#define qlcnic_gb_unset_rx_flowctl(config_word) \ + ((config_word) &= ~(1 << 5)) + +/* + * NIU GB Pause Ctl Register + */ + +#define qlcnic_gb_set_gb0_mask(config_word) \ + ((config_word) |= 1 << 0) +#define qlcnic_gb_set_gb1_mask(config_word) \ + ((config_word) |= 1 << 2) +#define qlcnic_gb_set_gb2_mask(config_word) \ + ((config_word) |= 1 << 4) +#define qlcnic_gb_set_gb3_mask(config_word) \ + ((config_word) |= 1 << 6) + +#define qlcnic_gb_get_gb0_mask(config_word) \ + _qlcnic_crb_get_bit((config_word), 0) +#define qlcnic_gb_get_gb1_mask(config_word) \ + _qlcnic_crb_get_bit((config_word), 2) +#define qlcnic_gb_get_gb2_mask(config_word) \ + _qlcnic_crb_get_bit((config_word), 4) +#define qlcnic_gb_get_gb3_mask(config_word) \ + _qlcnic_crb_get_bit((config_word), 6) + +#define qlcnic_gb_unset_gb0_mask(config_word) \ + ((config_word) &= ~(1 << 0)) +#define qlcnic_gb_unset_gb1_mask(config_word) \ + ((config_word) &= ~(1 << 2)) +#define qlcnic_gb_unset_gb2_mask(config_word) \ + ((config_word) &= ~(1 << 4)) +#define qlcnic_gb_unset_gb3_mask(config_word) \ + ((config_word) &= ~(1 << 6)) + +/* + * NIU XG Pause Ctl Register + * + * Bit 0 : xg0_mask => 1:disable tx pause frames + * Bit 1 : xg0_request => 1:request single pause frame + * Bit 2 : xg0_on_off => 1:request is pause on, 0:off + * Bit 3 : xg1_mask => 1:disable tx pause frames + * Bit 4 : xg1_request => 1:request single pause frame + * Bit 5 : xg1_on_off => 1:request is pause on, 0:off + */ + +#define qlcnic_xg_set_xg0_mask(config_word) \ + ((config_word) |= 1 << 0) +#define qlcnic_xg_set_xg1_mask(config_word) \ + ((config_word) |= 1 << 3) + +#define qlcnic_xg_get_xg0_mask(config_word) \ + _qlcnic_crb_get_bit((config_word), 0) +#define qlcnic_xg_get_xg1_mask(config_word) \ + _qlcnic_crb_get_bit((config_word), 3) + +#define qlcnic_xg_unset_xg0_mask(config_word) \ + ((config_word) &= ~(1 << 0)) +#define qlcnic_xg_unset_xg1_mask(config_word) \ + ((config_word) &= ~(1 << 3)) + +/* + * NIU XG Pause Ctl Register + * + * Bit 0 : xg0_mask => 1:disable tx pause frames + * Bit 1 : xg0_request => 1:request single pause frame + * Bit 2 : xg0_on_off => 1:request is pause on, 0:off + * Bit 3 : xg1_mask => 1:disable tx pause frames + * Bit 4 : xg1_request => 1:request single pause frame + * Bit 5 : xg1_on_off => 1:request is pause on, 0:off + */ + +/* + * PHY-Specific MII control/status registers. + */ +#define QLCNIC_NIU_GB_MII_MGMT_ADDR_AUTONEG 4 +#define QLCNIC_NIU_GB_MII_MGMT_ADDR_PHY_STATUS 17 + +/* + * PHY-Specific Status Register (reg 17). + * + * Bit 0 : jabber => 1:jabber detected, 0:not + * Bit 1 : polarity => 1:polarity reversed, 0:normal + * Bit 2 : recvpause => 1:receive pause enabled, 0:disabled + * Bit 3 : xmitpause => 1:transmit pause enabled, 0:disabled + * Bit 4 : energydetect => 1:sleep, 0:active + * Bit 5 : downshift => 1:downshift, 0:no downshift + * Bit 6 : crossover => 1:MDIX (crossover), 0:MDI (no crossover) + * Bits 7-9 : cablelen => not valid in 10Mb/s mode + * 0:<50m, 1:50-80m, 2:80-110m, 3:110-140m, 4:>140m + * Bit 10 : link => 1:link up, 0:link down + * Bit 11 : resolved => 1:speed and duplex resolved, 0:not yet + * Bit 12 : pagercvd => 1:page received, 0:page not received + * Bit 13 : duplex => 1:full duplex, 0:half duplex + * Bits 14-15 : speed => 0:10Mb/s, 1:100Mb/s, 2:1000Mb/s, 3:rsvd + */ + +#define qlcnic_get_phy_speed(config_word) (((config_word) >> 14) & 0x03) + +#define qlcnic_set_phy_speed(config_word, val) \ + ((config_word) |= ((val & 0x03) << 14)) +#define qlcnic_set_phy_duplex(config_word) \ + ((config_word) |= 1 << 13) +#define qlcnic_clear_phy_duplex(config_word) \ + ((config_word) &= ~(1 << 13)) + +#define qlcnic_get_phy_link(config_word) \ + _qlcnic_crb_get_bit(config_word, 10) +#define qlcnic_get_phy_duplex(config_word) \ + _qlcnic_crb_get_bit(config_word, 13) + +#define QLCNIC_NIU_NON_PROMISC_MODE 0 +#define QLCNIC_NIU_PROMISC_MODE 1 +#define QLCNIC_NIU_ALLMULTI_MODE 2 + +struct crb_128M_2M_sub_block_map { + unsigned valid; + unsigned start_128M; + unsigned end_128M; + unsigned start_2M; +}; + +struct crb_128M_2M_block_map{ + struct crb_128M_2M_sub_block_map sub_block[16]; +}; +#endif /* __QLCNIC_HDR_H_ */ diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c new file mode 100644 index 00000000000..91234e7b39e --- /dev/null +++ b/drivers/net/qlcnic/qlcnic_hw.c @@ -0,0 +1,1201 @@ +/* + * Copyright (C) 2009 - QLogic Corporation. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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. + * + * The full GNU General Public License is included in this distribution + * in the file called "COPYING". + * + */ + +#include "qlcnic.h" + +#include + +#define MASK(n) ((1ULL<<(n))-1) +#define OCM_WIN_P3P(addr) (addr & 0xffc0000) + +#define GET_MEM_OFFS_2M(addr) (addr & MASK(18)) + +#define CRB_BLK(off) ((off >> 20) & 0x3f) +#define CRB_SUBBLK(off) ((off >> 16) & 0xf) +#define CRB_WINDOW_2M (0x130060) +#define CRB_HI(off) ((crb_hub_agt[CRB_BLK(off)] << 20) | ((off) & 0xf0000)) +#define CRB_INDIRECT_2M (0x1e0000UL) + + +#ifndef readq +static inline u64 readq(void __iomem *addr) +{ + return readl(addr) | (((u64) readl(addr + 4)) << 32LL); +} +#endif + +#ifndef writeq +static inline void writeq(u64 val, void __iomem *addr) +{ + writel(((u32) (val)), (addr)); + writel(((u32) (val >> 32)), (addr + 4)); +} +#endif + +#define ADDR_IN_RANGE(addr, low, high) \ + (((addr) < (high)) && ((addr) >= (low))) + +#define PCI_OFFSET_FIRST_RANGE(adapter, off) \ + ((adapter)->ahw.pci_base0 + (off)) + +static void __iomem *pci_base_offset(struct qlcnic_adapter *adapter, + unsigned long off) +{ + if (ADDR_IN_RANGE(off, FIRST_PAGE_GROUP_START, FIRST_PAGE_GROUP_END)) + return PCI_OFFSET_FIRST_RANGE(adapter, off); + + return NULL; +} + +static const struct crb_128M_2M_block_map +crb_128M_2M_map[64] __cacheline_aligned_in_smp = { + {{{0, 0, 0, 0} } }, /* 0: PCI */ + {{{1, 0x0100000, 0x0102000, 0x120000}, /* 1: PCIE */ + {1, 0x0110000, 0x0120000, 0x130000}, + {1, 0x0120000, 0x0122000, 0x124000}, + {1, 0x0130000, 0x0132000, 0x126000}, + {1, 0x0140000, 0x0142000, 0x128000}, + {1, 0x0150000, 0x0152000, 0x12a000}, + {1, 0x0160000, 0x0170000, 0x110000}, + {1, 0x0170000, 0x0172000, 0x12e000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {1, 0x01e0000, 0x01e0800, 0x122000}, + {0, 0x0000000, 0x0000000, 0x000000} } }, + {{{1, 0x0200000, 0x0210000, 0x180000} } },/* 2: MN */ + {{{0, 0, 0, 0} } }, /* 3: */ + {{{1, 0x0400000, 0x0401000, 0x169000} } },/* 4: P2NR1 */ + {{{1, 0x0500000, 0x0510000, 0x140000} } },/* 5: SRE */ + {{{1, 0x0600000, 0x0610000, 0x1c0000} } },/* 6: NIU */ + {{{1, 0x0700000, 0x0704000, 0x1b8000} } },/* 7: QM */ + {{{1, 0x0800000, 0x0802000, 0x170000}, /* 8: SQM0 */ + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {1, 0x08f0000, 0x08f2000, 0x172000} } }, + {{{1, 0x0900000, 0x0902000, 0x174000}, /* 9: SQM1*/ + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {1, 0x09f0000, 0x09f2000, 0x176000} } }, + {{{0, 0x0a00000, 0x0a02000, 0x178000}, /* 10: SQM2*/ + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {1, 0x0af0000, 0x0af2000, 0x17a000} } }, + {{{0, 0x0b00000, 0x0b02000, 0x17c000}, /* 11: SQM3*/ + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {1, 0x0bf0000, 0x0bf2000, 0x17e000} } }, + {{{1, 0x0c00000, 0x0c04000, 0x1d4000} } },/* 12: I2Q */ + {{{1, 0x0d00000, 0x0d04000, 0x1a4000} } },/* 13: TMR */ + {{{1, 0x0e00000, 0x0e04000, 0x1a0000} } },/* 14: ROMUSB */ + {{{1, 0x0f00000, 0x0f01000, 0x164000} } },/* 15: PEG4 */ + {{{0, 0x1000000, 0x1004000, 0x1a8000} } },/* 16: XDMA */ + {{{1, 0x1100000, 0x1101000, 0x160000} } },/* 17: PEG0 */ + {{{1, 0x1200000, 0x1201000, 0x161000} } },/* 18: PEG1 */ + {{{1, 0x1300000, 0x1301000, 0x162000} } },/* 19: PEG2 */ + {{{1, 0x1400000, 0x1401000, 0x163000} } },/* 20: PEG3 */ + {{{1, 0x1500000, 0x1501000, 0x165000} } },/* 21: P2ND */ + {{{1, 0x1600000, 0x1601000, 0x166000} } },/* 22: P2NI */ + {{{0, 0, 0, 0} } }, /* 23: */ + {{{0, 0, 0, 0} } }, /* 24: */ + {{{0, 0, 0, 0} } }, /* 25: */ + {{{0, 0, 0, 0} } }, /* 26: */ + {{{0, 0, 0, 0} } }, /* 27: */ + {{{0, 0, 0, 0} } }, /* 28: */ + {{{1, 0x1d00000, 0x1d10000, 0x190000} } },/* 29: MS */ + {{{1, 0x1e00000, 0x1e01000, 0x16a000} } },/* 30: P2NR2 */ + {{{1, 0x1f00000, 0x1f10000, 0x150000} } },/* 31: EPG */ + {{{0} } }, /* 32: PCI */ + {{{1, 0x2100000, 0x2102000, 0x120000}, /* 33: PCIE */ + {1, 0x2110000, 0x2120000, 0x130000}, + {1, 0x2120000, 0x2122000, 0x124000}, + {1, 0x2130000, 0x2132000, 0x126000}, + {1, 0x2140000, 0x2142000, 0x128000}, + {1, 0x2150000, 0x2152000, 0x12a000}, + {1, 0x2160000, 0x2170000, 0x110000}, + {1, 0x2170000, 0x2172000, 0x12e000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000} } }, + {{{1, 0x2200000, 0x2204000, 0x1b0000} } },/* 34: CAM */ + {{{0} } }, /* 35: */ + {{{0} } }, /* 36: */ + {{{0} } }, /* 37: */ + {{{0} } }, /* 38: */ + {{{0} } }, /* 39: */ + {{{1, 0x2800000, 0x2804000, 0x1a4000} } },/* 40: TMR */ + {{{1, 0x2900000, 0x2901000, 0x16b000} } },/* 41: P2NR3 */ + {{{1, 0x2a00000, 0x2a00400, 0x1ac400} } },/* 42: RPMX1 */ + {{{1, 0x2b00000, 0x2b00400, 0x1ac800} } },/* 43: RPMX2 */ + {{{1, 0x2c00000, 0x2c00400, 0x1acc00} } },/* 44: RPMX3 */ + {{{1, 0x2d00000, 0x2d00400, 0x1ad000} } },/* 45: RPMX4 */ + {{{1, 0x2e00000, 0x2e00400, 0x1ad400} } },/* 46: RPMX5 */ + {{{1, 0x2f00000, 0x2f00400, 0x1ad800} } },/* 47: RPMX6 */ + {{{1, 0x3000000, 0x3000400, 0x1adc00} } },/* 48: RPMX7 */ + {{{0, 0x3100000, 0x3104000, 0x1a8000} } },/* 49: XDMA */ + {{{1, 0x3200000, 0x3204000, 0x1d4000} } },/* 50: I2Q */ + {{{1, 0x3300000, 0x3304000, 0x1a0000} } },/* 51: ROMUSB */ + {{{0} } }, /* 52: */ + {{{1, 0x3500000, 0x3500400, 0x1ac000} } },/* 53: RPMX0 */ + {{{1, 0x3600000, 0x3600400, 0x1ae000} } },/* 54: RPMX8 */ + {{{1, 0x3700000, 0x3700400, 0x1ae400} } },/* 55: RPMX9 */ + {{{1, 0x3800000, 0x3804000, 0x1d0000} } },/* 56: OCM0 */ + {{{1, 0x3900000, 0x3904000, 0x1b4000} } },/* 57: CRYPTO */ + {{{1, 0x3a00000, 0x3a04000, 0x1d8000} } },/* 58: SMB */ + {{{0} } }, /* 59: I2C0 */ + {{{0} } }, /* 60: I2C1 */ + {{{1, 0x3d00000, 0x3d04000, 0x1d8000} } },/* 61: LPC */ + {{{1, 0x3e00000, 0x3e01000, 0x167000} } },/* 62: P2NC */ + {{{1, 0x3f00000, 0x3f01000, 0x168000} } } /* 63: P2NR0 */ +}; + +/* + * top 12 bits of crb internal address (hub, agent) + */ +static const unsigned crb_hub_agt[64] = { + 0, + QLCNIC_HW_CRB_HUB_AGT_ADR_PS, + QLCNIC_HW_CRB_HUB_AGT_ADR_MN, + QLCNIC_HW_CRB_HUB_AGT_ADR_MS, + 0, + QLCNIC_HW_CRB_HUB_AGT_ADR_SRE, + QLCNIC_HW_CRB_HUB_AGT_ADR_NIU, + QLCNIC_HW_CRB_HUB_AGT_ADR_QMN, + QLCNIC_HW_CRB_HUB_AGT_ADR_SQN0, + QLCNIC_HW_CRB_HUB_AGT_ADR_SQN1, + QLCNIC_HW_CRB_HUB_AGT_ADR_SQN2, + QLCNIC_HW_CRB_HUB_AGT_ADR_SQN3, + QLCNIC_HW_CRB_HUB_AGT_ADR_I2Q, + QLCNIC_HW_CRB_HUB_AGT_ADR_TIMR, + QLCNIC_HW_CRB_HUB_AGT_ADR_ROMUSB, + QLCNIC_HW_CRB_HUB_AGT_ADR_PGN4, + QLCNIC_HW_CRB_HUB_AGT_ADR_XDMA, + QLCNIC_HW_CRB_HUB_AGT_ADR_PGN0, + QLCNIC_HW_CRB_HUB_AGT_ADR_PGN1, + QLCNIC_HW_CRB_HUB_AGT_ADR_PGN2, + QLCNIC_HW_CRB_HUB_AGT_ADR_PGN3, + QLCNIC_HW_CRB_HUB_AGT_ADR_PGND, + QLCNIC_HW_CRB_HUB_AGT_ADR_PGNI, + QLCNIC_HW_CRB_HUB_AGT_ADR_PGS0, + QLCNIC_HW_CRB_HUB_AGT_ADR_PGS1, + QLCNIC_HW_CRB_HUB_AGT_ADR_PGS2, + QLCNIC_HW_CRB_HUB_AGT_ADR_PGS3, + 0, + QLCNIC_HW_CRB_HUB_AGT_ADR_PGSI, + QLCNIC_HW_CRB_HUB_AGT_ADR_SN, + 0, + QLCNIC_HW_CRB_HUB_AGT_ADR_EG, + 0, + QLCNIC_HW_CRB_HUB_AGT_ADR_PS, + QLCNIC_HW_CRB_HUB_AGT_ADR_CAM, + 0, + 0, + 0, + 0, + 0, + QLCNIC_HW_CRB_HUB_AGT_ADR_TIMR, + 0, + QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX1, + QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX2, + QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX3, + QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX4, + QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX5, + QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX6, + QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX7, + QLCNIC_HW_CRB_HUB_AGT_ADR_XDMA, + QLCNIC_HW_CRB_HUB_AGT_ADR_I2Q, + QLCNIC_HW_CRB_HUB_AGT_ADR_ROMUSB, + 0, + QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX0, + QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX8, + QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX9, + QLCNIC_HW_CRB_HUB_AGT_ADR_OCM0, + 0, + QLCNIC_HW_CRB_HUB_AGT_ADR_SMB, + QLCNIC_HW_CRB_HUB_AGT_ADR_I2C0, + QLCNIC_HW_CRB_HUB_AGT_ADR_I2C1, + 0, + QLCNIC_HW_CRB_HUB_AGT_ADR_PGNC, + 0, +}; + +/* PCI Windowing for DDR regions. */ + +#define QLCNIC_PCIE_SEM_TIMEOUT 10000 + +int +qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg) +{ + int done = 0, timeout = 0; + + while (!done) { + done = QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_LOCK(sem))); + if (done == 1) + break; + if (++timeout >= QLCNIC_PCIE_SEM_TIMEOUT) + return -EIO; + msleep(1); + } + + if (id_reg) + QLCWR32(adapter, id_reg, adapter->portnum); + + return 0; +} + +void +qlcnic_pcie_sem_unlock(struct qlcnic_adapter *adapter, int sem) +{ + QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_UNLOCK(sem))); +} + +static int +qlcnic_send_cmd_descs(struct qlcnic_adapter *adapter, + struct cmd_desc_type0 *cmd_desc_arr, int nr_desc) +{ + u32 i, producer, consumer; + struct qlcnic_cmd_buffer *pbuf; + struct cmd_desc_type0 *cmd_desc; + struct qlcnic_host_tx_ring *tx_ring; + + i = 0; + + if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) + return -EIO; + + tx_ring = adapter->tx_ring; + __netif_tx_lock_bh(tx_ring->txq); + + producer = tx_ring->producer; + consumer = tx_ring->sw_consumer; + + if (nr_desc >= qlcnic_tx_avail(tx_ring)) { + netif_tx_stop_queue(tx_ring->txq); + __netif_tx_unlock_bh(tx_ring->txq); + return -EBUSY; + } + + do { + cmd_desc = &cmd_desc_arr[i]; + + pbuf = &tx_ring->cmd_buf_arr[producer]; + pbuf->skb = NULL; + pbuf->frag_count = 0; + + memcpy(&tx_ring->desc_head[producer], + &cmd_desc_arr[i], sizeof(struct cmd_desc_type0)); + + producer = get_next_index(producer, tx_ring->num_desc); + i++; + + } while (i != nr_desc); + + tx_ring->producer = producer; + + qlcnic_update_cmd_producer(adapter, tx_ring); + + __netif_tx_unlock_bh(tx_ring->txq); + + return 0; +} + +static int +qlcnic_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr, + unsigned op) +{ + struct qlcnic_nic_req req; + struct qlcnic_mac_req *mac_req; + u64 word; + + memset(&req, 0, sizeof(struct qlcnic_nic_req)); + req.qhdr = cpu_to_le64(QLCNIC_REQUEST << 23); + + word = QLCNIC_MAC_EVENT | ((u64)adapter->portnum << 16); + req.req_hdr = cpu_to_le64(word); + + mac_req = (struct qlcnic_mac_req *)&req.words[0]; + mac_req->op = op; + memcpy(mac_req->mac_addr, addr, 6); + + return qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); +} + +static int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, + u8 *addr, struct list_head *del_list) +{ + struct list_head *head; + struct qlcnic_mac_list_s *cur; + + /* look up if already exists */ + list_for_each(head, del_list) { + cur = list_entry(head, struct qlcnic_mac_list_s, list); + + if (memcmp(addr, cur->mac_addr, ETH_ALEN) == 0) { + list_move_tail(head, &adapter->mac_list); + return 0; + } + } + + cur = kzalloc(sizeof(struct qlcnic_mac_list_s), GFP_ATOMIC); + if (cur == NULL) { + dev_err(&adapter->netdev->dev, + "failed to add mac address filter\n"); + return -ENOMEM; + } + memcpy(cur->mac_addr, addr, ETH_ALEN); + list_add_tail(&cur->list, &adapter->mac_list); + + return qlcnic_sre_macaddr_change(adapter, + cur->mac_addr, QLCNIC_MAC_ADD); +} + +void qlcnic_set_multi(struct net_device *netdev) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + struct dev_mc_list *mc_ptr; + u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + u32 mode = VPORT_MISS_MODE_DROP; + LIST_HEAD(del_list); + struct list_head *head; + struct qlcnic_mac_list_s *cur; + + list_splice_tail_init(&adapter->mac_list, &del_list); + + qlcnic_nic_add_mac(adapter, adapter->mac_addr, &del_list); + qlcnic_nic_add_mac(adapter, bcast_addr, &del_list); + + if (netdev->flags & IFF_PROMISC) { + mode = VPORT_MISS_MODE_ACCEPT_ALL; + goto send_fw_cmd; + } + + if ((netdev->flags & IFF_ALLMULTI) || + (netdev->mc_count > adapter->max_mc_count)) { + mode = VPORT_MISS_MODE_ACCEPT_MULTI; + goto send_fw_cmd; + } + + if (netdev->mc_count > 0) { + for (mc_ptr = netdev->mc_list; mc_ptr; + mc_ptr = mc_ptr->next) { + qlcnic_nic_add_mac(adapter, mc_ptr->dmi_addr, + &del_list); + } + } + +send_fw_cmd: + qlcnic_nic_set_promisc(adapter, mode); + head = &del_list; + while (!list_empty(head)) { + cur = list_entry(head->next, struct qlcnic_mac_list_s, list); + + qlcnic_sre_macaddr_change(adapter, + cur->mac_addr, QLCNIC_MAC_DEL); + list_del(&cur->list); + kfree(cur); + } +} + +int qlcnic_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode) +{ + struct qlcnic_nic_req req; + u64 word; + + memset(&req, 0, sizeof(struct qlcnic_nic_req)); + + req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); + + word = QLCNIC_H2C_OPCODE_PROXY_SET_VPORT_MISS_MODE | + ((u64)adapter->portnum << 16); + req.req_hdr = cpu_to_le64(word); + + req.words[0] = cpu_to_le64(mode); + + return qlcnic_send_cmd_descs(adapter, + (struct cmd_desc_type0 *)&req, 1); +} + +void qlcnic_free_mac_list(struct qlcnic_adapter *adapter) +{ + struct qlcnic_mac_list_s *cur; + struct list_head *head = &adapter->mac_list; + + while (!list_empty(head)) { + cur = list_entry(head->next, struct qlcnic_mac_list_s, list); + qlcnic_sre_macaddr_change(adapter, + cur->mac_addr, QLCNIC_MAC_DEL); + list_del(&cur->list); + kfree(cur); + } +} + +#define QLCNIC_CONFIG_INTR_COALESCE 3 + +/* + * Send the interrupt coalescing parameter set by ethtool to the card. + */ +int qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter) +{ + struct qlcnic_nic_req req; + u64 word[6]; + int rv, i; + + memset(&req, 0, sizeof(struct qlcnic_nic_req)); + + req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); + + word[0] = QLCNIC_CONFIG_INTR_COALESCE | ((u64)adapter->portnum << 16); + req.req_hdr = cpu_to_le64(word[0]); + + memcpy(&word[0], &adapter->coal, sizeof(adapter->coal)); + for (i = 0; i < 6; i++) + req.words[i] = cpu_to_le64(word[i]); + + rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); + if (rv != 0) + dev_err(&adapter->netdev->dev, + "Could not send interrupt coalescing parameters\n"); + + return rv; +} + +int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable) +{ + struct qlcnic_nic_req req; + u64 word; + int rv; + + if ((adapter->flags & QLCNIC_LRO_ENABLED) == enable) + return 0; + + memset(&req, 0, sizeof(struct qlcnic_nic_req)); + + req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); + + word = QLCNIC_H2C_OPCODE_CONFIG_HW_LRO | ((u64)adapter->portnum << 16); + req.req_hdr = cpu_to_le64(word); + + req.words[0] = cpu_to_le64(enable); + + rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); + if (rv != 0) + dev_err(&adapter->netdev->dev, + "Could not send configure hw lro request\n"); + + adapter->flags ^= QLCNIC_LRO_ENABLED; + + return rv; +} + +int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, int enable) +{ + struct qlcnic_nic_req req; + u64 word; + int rv; + + if (!!(adapter->flags & QLCNIC_BRIDGE_ENABLED) == enable) + return 0; + + memset(&req, 0, sizeof(struct qlcnic_nic_req)); + + req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); + + word = QLCNIC_H2C_OPCODE_CONFIG_BRIDGING | + ((u64)adapter->portnum << 16); + req.req_hdr = cpu_to_le64(word); + + req.words[0] = cpu_to_le64(enable); + + rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); + if (rv != 0) + dev_err(&adapter->netdev->dev, + "Could not send configure bridge mode request\n"); + + adapter->flags ^= QLCNIC_BRIDGE_ENABLED; + + return rv; +} + + +#define RSS_HASHTYPE_IP_TCP 0x3 + +int qlcnic_config_rss(struct qlcnic_adapter *adapter, int enable) +{ + struct qlcnic_nic_req req; + u64 word; + int i, rv; + + const u64 key[] = { 0xbeac01fa6a42b73bULL, 0x8030f20c77cb2da3ULL, + 0xae7b30b4d0ca2bcbULL, 0x43a38fb04167253dULL, + 0x255b0ec26d5a56daULL }; + + + memset(&req, 0, sizeof(struct qlcnic_nic_req)); + req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); + + word = QLCNIC_H2C_OPCODE_CONFIG_RSS | ((u64)adapter->portnum << 16); + req.req_hdr = cpu_to_le64(word); + + /* + * RSS request: + * bits 3-0: hash_method + * 5-4: hash_type_ipv4 + * 7-6: hash_type_ipv6 + * 8: enable + * 9: use indirection table + * 47-10: reserved + * 63-48: indirection table mask + */ + word = ((u64)(RSS_HASHTYPE_IP_TCP & 0x3) << 4) | + ((u64)(RSS_HASHTYPE_IP_TCP & 0x3) << 6) | + ((u64)(enable & 0x1) << 8) | + ((0x7ULL) << 48); + req.words[0] = cpu_to_le64(word); + for (i = 0; i < 5; i++) + req.words[i+1] = cpu_to_le64(key[i]); + + rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); + if (rv != 0) + dev_err(&adapter->netdev->dev, "could not configure RSS\n"); + + return rv; +} + +int qlcnic_config_ipaddr(struct qlcnic_adapter *adapter, u32 ip, int cmd) +{ + struct qlcnic_nic_req req; + u64 word; + int rv; + + memset(&req, 0, sizeof(struct qlcnic_nic_req)); + req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); + + word = QLCNIC_H2C_OPCODE_CONFIG_IPADDR | ((u64)adapter->portnum << 16); + req.req_hdr = cpu_to_le64(word); + + req.words[0] = cpu_to_le64(cmd); + req.words[1] = cpu_to_le64(ip); + + rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); + if (rv != 0) + dev_err(&adapter->netdev->dev, + "could not notify %s IP 0x%x reuqest\n", + (cmd == QLCNIC_IP_UP) ? "Add" : "Remove", ip); + + return rv; +} + +int qlcnic_linkevent_request(struct qlcnic_adapter *adapter, int enable) +{ + struct qlcnic_nic_req req; + u64 word; + int rv; + + memset(&req, 0, sizeof(struct qlcnic_nic_req)); + req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); + + word = QLCNIC_H2C_OPCODE_GET_LINKEVENT | ((u64)adapter->portnum << 16); + req.req_hdr = cpu_to_le64(word); + req.words[0] = cpu_to_le64(enable | (enable << 8)); + + rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); + if (rv != 0) + dev_err(&adapter->netdev->dev, + "could not configure link notification\n"); + + return rv; +} + +int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter) +{ + struct qlcnic_nic_req req; + u64 word; + int rv; + + memset(&req, 0, sizeof(struct qlcnic_nic_req)); + req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); + + word = QLCNIC_H2C_OPCODE_LRO_REQUEST | + ((u64)adapter->portnum << 16) | + ((u64)QLCNIC_LRO_REQUEST_CLEANUP << 56) ; + + req.req_hdr = cpu_to_le64(word); + + rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); + if (rv != 0) + dev_err(&adapter->netdev->dev, + "could not cleanup lro flows\n"); + + return rv; +} + +/* + * qlcnic_change_mtu - Change the Maximum Transfer Unit + * @returns 0 on success, negative on failure + */ + +int qlcnic_change_mtu(struct net_device *netdev, int mtu) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + int rc = 0; + + if (mtu > P3_MAX_MTU) { + dev_err(&adapter->netdev->dev, "mtu > %d bytes unsupported\n", + P3_MAX_MTU); + return -EINVAL; + } + + rc = qlcnic_fw_cmd_set_mtu(adapter, mtu); + + if (!rc) + netdev->mtu = mtu; + + return rc; +} + +int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u64 *mac) +{ + u32 crbaddr, mac_hi, mac_lo; + int pci_func = adapter->ahw.pci_func; + + crbaddr = CRB_MAC_BLOCK_START + + (4 * ((pci_func/2) * 3)) + (4 * (pci_func & 1)); + + mac_lo = QLCRD32(adapter, crbaddr); + mac_hi = QLCRD32(adapter, crbaddr+4); + + if (pci_func & 1) + *mac = le64_to_cpu((mac_lo >> 16) | ((u64)mac_hi << 16)); + else + *mac = le64_to_cpu((u64)mac_lo | ((u64)mac_hi << 32)); + + return 0; +} + +/* + * Changes the CRB window to the specified window. + */ + /* Returns < 0 if off is not valid, + * 1 if window access is needed. 'off' is set to offset from + * CRB space in 128M pci map + * 0 if no window access is needed. 'off' is set to 2M addr + * In: 'off' is offset from base in 128M pci map + */ +static int +qlcnic_pci_get_crb_addr_2M(struct qlcnic_adapter *adapter, + ulong off, void __iomem **addr) +{ + const struct crb_128M_2M_sub_block_map *m; + + if ((off >= QLCNIC_CRB_MAX) || (off < QLCNIC_PCI_CRBSPACE)) + return -EINVAL; + + off -= QLCNIC_PCI_CRBSPACE; + + /* + * Try direct map + */ + m = &crb_128M_2M_map[CRB_BLK(off)].sub_block[CRB_SUBBLK(off)]; + + if (m->valid && (m->start_128M <= off) && (m->end_128M > off)) { + *addr = adapter->ahw.pci_base0 + m->start_2M + + (off - m->start_128M); + return 0; + } + + /* + * Not in direct map, use crb window + */ + *addr = adapter->ahw.pci_base0 + CRB_INDIRECT_2M + (off & MASK(16)); + return 1; +} + +/* + * In: 'off' is offset from CRB space in 128M pci map + * Out: 'off' is 2M pci map addr + * side effect: lock crb window + */ +static void +qlcnic_pci_set_crbwindow_2M(struct qlcnic_adapter *adapter, ulong off) +{ + u32 window; + void __iomem *addr = adapter->ahw.pci_base0 + CRB_WINDOW_2M; + + off -= QLCNIC_PCI_CRBSPACE; + + window = CRB_HI(off); + + if (adapter->ahw.crb_win == window) + return; + + writel(window, addr); + if (readl(addr) != window) { + if (printk_ratelimit()) + dev_warn(&adapter->pdev->dev, + "failed to set CRB window to %d off 0x%lx\n", + window, off); + } + adapter->ahw.crb_win = window; +} + +int +qlcnic_hw_write_wx_2M(struct qlcnic_adapter *adapter, ulong off, u32 data) +{ + unsigned long flags; + int rv; + void __iomem *addr = NULL; + + rv = qlcnic_pci_get_crb_addr_2M(adapter, off, &addr); + + if (rv == 0) { + writel(data, addr); + return 0; + } + + if (rv > 0) { + /* indirect access */ + write_lock_irqsave(&adapter->ahw.crb_lock, flags); + crb_win_lock(adapter); + qlcnic_pci_set_crbwindow_2M(adapter, off); + writel(data, addr); + crb_win_unlock(adapter); + write_unlock_irqrestore(&adapter->ahw.crb_lock, flags); + return 0; + } + + dev_err(&adapter->pdev->dev, + "%s: invalid offset: 0x%016lx\n", __func__, off); + dump_stack(); + return -EIO; +} + +u32 +qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off) +{ + unsigned long flags; + int rv; + u32 data; + void __iomem *addr = NULL; + + rv = qlcnic_pci_get_crb_addr_2M(adapter, off, &addr); + + if (rv == 0) + return readl(addr); + + if (rv > 0) { + /* indirect access */ + write_lock_irqsave(&adapter->ahw.crb_lock, flags); + crb_win_lock(adapter); + qlcnic_pci_set_crbwindow_2M(adapter, off); + data = readl(addr); + crb_win_unlock(adapter); + write_unlock_irqrestore(&adapter->ahw.crb_lock, flags); + return data; + } + + dev_err(&adapter->pdev->dev, + "%s: invalid offset: 0x%016lx\n", __func__, off); + dump_stack(); + return -1; +} + + +void __iomem * +qlcnic_get_ioaddr(struct qlcnic_adapter *adapter, u32 offset) +{ + void __iomem *addr = NULL; + + WARN_ON(qlcnic_pci_get_crb_addr_2M(adapter, offset, &addr)); + + return addr; +} + + +static int +qlcnic_pci_set_window_2M(struct qlcnic_adapter *adapter, + u64 addr, u32 *start) +{ + u32 window; + struct pci_dev *pdev = adapter->pdev; + + if ((addr & 0x00ff800) == 0xff800) { + if (printk_ratelimit()) + dev_warn(&pdev->dev, "QM access not handled\n"); + return -EIO; + } + + window = OCM_WIN_P3P(addr); + + writel(window, adapter->ahw.ocm_win_crb); + /* read back to flush */ + readl(adapter->ahw.ocm_win_crb); + + adapter->ahw.ocm_win = window; + *start = QLCNIC_PCI_OCM0_2M + GET_MEM_OFFS_2M(addr); + return 0; +} + +static int +qlcnic_pci_mem_access_direct(struct qlcnic_adapter *adapter, u64 off, + u64 *data, int op) +{ + void __iomem *addr, *mem_ptr = NULL; + resource_size_t mem_base; + int ret; + u32 start; + + mutex_lock(&adapter->ahw.mem_lock); + + ret = qlcnic_pci_set_window_2M(adapter, off, &start); + if (ret != 0) + goto unlock; + + addr = pci_base_offset(adapter, start); + if (addr) + goto noremap; + + mem_base = pci_resource_start(adapter->pdev, 0) + (start & PAGE_MASK); + + mem_ptr = ioremap(mem_base, PAGE_SIZE); + if (mem_ptr == NULL) { + ret = -EIO; + goto unlock; + } + + addr = mem_ptr + (start & (PAGE_SIZE - 1)); + +noremap: + if (op == 0) /* read */ + *data = readq(addr); + else /* write */ + writeq(*data, addr); + +unlock: + mutex_unlock(&adapter->ahw.mem_lock); + + if (mem_ptr) + iounmap(mem_ptr); + return ret; +} + +#define MAX_CTL_CHECK 1000 + +int +qlcnic_pci_mem_write_2M(struct qlcnic_adapter *adapter, + u64 off, u64 data) +{ + int i, j, ret; + u32 temp, off8; + u64 stride; + void __iomem *mem_crb; + + /* Only 64-bit aligned access */ + if (off & 7) + return -EIO; + + /* P3 onward, test agent base for MIU and SIU is same */ + if (ADDR_IN_RANGE(off, QLCNIC_ADDR_QDR_NET, + QLCNIC_ADDR_QDR_NET_MAX_P3)) { + mem_crb = qlcnic_get_ioaddr(adapter, + QLCNIC_CRB_QDR_NET+MIU_TEST_AGT_BASE); + goto correct; + } + + if (ADDR_IN_RANGE(off, QLCNIC_ADDR_DDR_NET, QLCNIC_ADDR_DDR_NET_MAX)) { + mem_crb = qlcnic_get_ioaddr(adapter, + QLCNIC_CRB_DDR_NET+MIU_TEST_AGT_BASE); + goto correct; + } + + if (ADDR_IN_RANGE(off, QLCNIC_ADDR_OCM0, QLCNIC_ADDR_OCM0_MAX)) + return qlcnic_pci_mem_access_direct(adapter, off, &data, 1); + + return -EIO; + +correct: + stride = QLCNIC_IS_REVISION_P3P(adapter->ahw.revision_id) ? 16 : 8; + + off8 = off & ~(stride-1); + + mutex_lock(&adapter->ahw.mem_lock); + + writel(off8, (mem_crb + MIU_TEST_AGT_ADDR_LO)); + writel(0, (mem_crb + MIU_TEST_AGT_ADDR_HI)); + + i = 0; + if (stride == 16) { + writel(TA_CTL_ENABLE, (mem_crb + TEST_AGT_CTRL)); + writel((TA_CTL_START | TA_CTL_ENABLE), + (mem_crb + TEST_AGT_CTRL)); + + for (j = 0; j < MAX_CTL_CHECK; j++) { + temp = readl(mem_crb + TEST_AGT_CTRL); + if ((temp & TA_CTL_BUSY) == 0) + break; + } + + if (j >= MAX_CTL_CHECK) { + ret = -EIO; + goto done; + } + + i = (off & 0xf) ? 0 : 2; + writel(readl(mem_crb + MIU_TEST_AGT_RDDATA(i)), + mem_crb + MIU_TEST_AGT_WRDATA(i)); + writel(readl(mem_crb + MIU_TEST_AGT_RDDATA(i+1)), + mem_crb + MIU_TEST_AGT_WRDATA(i+1)); + i = (off & 0xf) ? 2 : 0; + } + + writel(data & 0xffffffff, + mem_crb + MIU_TEST_AGT_WRDATA(i)); + writel((data >> 32) & 0xffffffff, + mem_crb + MIU_TEST_AGT_WRDATA(i+1)); + + writel((TA_CTL_ENABLE | TA_CTL_WRITE), (mem_crb + TEST_AGT_CTRL)); + writel((TA_CTL_START | TA_CTL_ENABLE | TA_CTL_WRITE), + (mem_crb + TEST_AGT_CTRL)); + + for (j = 0; j < MAX_CTL_CHECK; j++) { + temp = readl(mem_crb + TEST_AGT_CTRL); + if ((temp & TA_CTL_BUSY) == 0) + break; + } + + if (j >= MAX_CTL_CHECK) { + if (printk_ratelimit()) + dev_err(&adapter->pdev->dev, + "failed to write through agent\n"); + ret = -EIO; + } else + ret = 0; + +done: + mutex_unlock(&adapter->ahw.mem_lock); + + return ret; +} + +int +qlcnic_pci_mem_read_2M(struct qlcnic_adapter *adapter, + u64 off, u64 *data) +{ + int j, ret; + u32 temp, off8; + u64 val, stride; + void __iomem *mem_crb; + + /* Only 64-bit aligned access */ + if (off & 7) + return -EIO; + + /* P3 onward, test agent base for MIU and SIU is same */ + if (ADDR_IN_RANGE(off, QLCNIC_ADDR_QDR_NET, + QLCNIC_ADDR_QDR_NET_MAX_P3)) { + mem_crb = qlcnic_get_ioaddr(adapter, + QLCNIC_CRB_QDR_NET+MIU_TEST_AGT_BASE); + goto correct; + } + + if (ADDR_IN_RANGE(off, QLCNIC_ADDR_DDR_NET, QLCNIC_ADDR_DDR_NET_MAX)) { + mem_crb = qlcnic_get_ioaddr(adapter, + QLCNIC_CRB_DDR_NET+MIU_TEST_AGT_BASE); + goto correct; + } + + if (ADDR_IN_RANGE(off, QLCNIC_ADDR_OCM0, QLCNIC_ADDR_OCM0_MAX)) { + return qlcnic_pci_mem_access_direct(adapter, + off, data, 0); + } + + return -EIO; + +correct: + stride = QLCNIC_IS_REVISION_P3P(adapter->ahw.revision_id) ? 16 : 8; + + off8 = off & ~(stride-1); + + mutex_lock(&adapter->ahw.mem_lock); + + writel(off8, (mem_crb + MIU_TEST_AGT_ADDR_LO)); + writel(0, (mem_crb + MIU_TEST_AGT_ADDR_HI)); + writel(TA_CTL_ENABLE, (mem_crb + TEST_AGT_CTRL)); + writel((TA_CTL_START | TA_CTL_ENABLE), (mem_crb + TEST_AGT_CTRL)); + + for (j = 0; j < MAX_CTL_CHECK; j++) { + temp = readl(mem_crb + TEST_AGT_CTRL); + if ((temp & TA_CTL_BUSY) == 0) + break; + } + + if (j >= MAX_CTL_CHECK) { + if (printk_ratelimit()) + dev_err(&adapter->pdev->dev, + "failed to read through agent\n"); + ret = -EIO; + } else { + off8 = MIU_TEST_AGT_RDDATA_LO; + if ((stride == 16) && (off & 0xf)) + off8 = MIU_TEST_AGT_RDDATA_UPPER_LO; + + temp = readl(mem_crb + off8 + 4); + val = (u64)temp << 32; + val |= readl(mem_crb + off8); + *data = val; + ret = 0; + } + + mutex_unlock(&adapter->ahw.mem_lock); + + return ret; +} + +int qlcnic_get_board_info(struct qlcnic_adapter *adapter) +{ + int offset, board_type, magic; + struct pci_dev *pdev = adapter->pdev; + + offset = QLCNIC_FW_MAGIC_OFFSET; + if (qlcnic_rom_fast_read(adapter, offset, &magic)) + return -EIO; + + if (magic != QLCNIC_BDINFO_MAGIC) { + dev_err(&pdev->dev, "invalid board config, magic=%08x\n", + magic); + return -EIO; + } + + offset = QLCNIC_BRDTYPE_OFFSET; + if (qlcnic_rom_fast_read(adapter, offset, &board_type)) + return -EIO; + + adapter->ahw.board_type = board_type; + + if (board_type == QLCNIC_BRDTYPE_P3_4_GB_MM) { + u32 gpio = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_PAD_GPIO_I); + if ((gpio & 0x8000) == 0) + board_type = QLCNIC_BRDTYPE_P3_10G_TP; + } + + switch (board_type) { + case QLCNIC_BRDTYPE_P3_HMEZ: + case QLCNIC_BRDTYPE_P3_XG_LOM: + case QLCNIC_BRDTYPE_P3_10G_CX4: + case QLCNIC_BRDTYPE_P3_10G_CX4_LP: + case QLCNIC_BRDTYPE_P3_IMEZ: + case QLCNIC_BRDTYPE_P3_10G_SFP_PLUS: + case QLCNIC_BRDTYPE_P3_10G_SFP_CT: + case QLCNIC_BRDTYPE_P3_10G_SFP_QT: + case QLCNIC_BRDTYPE_P3_10G_XFP: + case QLCNIC_BRDTYPE_P3_10000_BASE_T: + adapter->ahw.port_type = QLCNIC_XGBE; + break; + case QLCNIC_BRDTYPE_P3_REF_QG: + case QLCNIC_BRDTYPE_P3_4_GB: + case QLCNIC_BRDTYPE_P3_4_GB_MM: + adapter->ahw.port_type = QLCNIC_GBE; + break; + case QLCNIC_BRDTYPE_P3_10G_TP: + adapter->ahw.port_type = (adapter->portnum < 2) ? + QLCNIC_XGBE : QLCNIC_GBE; + break; + default: + dev_err(&pdev->dev, "unknown board type %x\n", board_type); + adapter->ahw.port_type = QLCNIC_XGBE; + break; + } + + return 0; +} + +int +qlcnic_wol_supported(struct qlcnic_adapter *adapter) +{ + u32 wol_cfg; + + wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV); + if (wol_cfg & (1UL << adapter->portnum)) { + wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG); + if (wol_cfg & (1 << adapter->portnum)) + return 1; + } + + return 0; +} diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c new file mode 100644 index 00000000000..7ae8bcc1e43 --- /dev/null +++ b/drivers/net/qlcnic/qlcnic_init.c @@ -0,0 +1,1466 @@ +/* + * Copyright (C) 2009 - QLogic Corporation. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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. + * + * The full GNU General Public License is included in this distribution + * in the file called "COPYING". + * + */ + +#include +#include +#include "qlcnic.h" + +struct crb_addr_pair { + u32 addr; + u32 data; +}; + +#define QLCNIC_MAX_CRB_XFORM 60 +static unsigned int crb_addr_xform[QLCNIC_MAX_CRB_XFORM]; + +#define crb_addr_transform(name) \ + (crb_addr_xform[QLCNIC_HW_PX_MAP_CRB_##name] = \ + QLCNIC_HW_CRB_HUB_AGT_ADR_##name << 20) + +#define QLCNIC_ADDR_ERROR (0xffffffff) + +static void +qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter, + struct qlcnic_host_rds_ring *rds_ring); + +static void crb_addr_transform_setup(void) +{ + crb_addr_transform(XDMA); + crb_addr_transform(TIMR); + crb_addr_transform(SRE); + crb_addr_transform(SQN3); + crb_addr_transform(SQN2); + crb_addr_transform(SQN1); + crb_addr_transform(SQN0); + crb_addr_transform(SQS3); + crb_addr_transform(SQS2); + crb_addr_transform(SQS1); + crb_addr_transform(SQS0); + crb_addr_transform(RPMX7); + crb_addr_transform(RPMX6); + crb_addr_transform(RPMX5); + crb_addr_transform(RPMX4); + crb_addr_transform(RPMX3); + crb_addr_transform(RPMX2); + crb_addr_transform(RPMX1); + crb_addr_transform(RPMX0); + crb_addr_transform(ROMUSB); + crb_addr_transform(SN); + crb_addr_transform(QMN); + crb_addr_transform(QMS); + crb_addr_transform(PGNI); + crb_addr_transform(PGND); + crb_addr_transform(PGN3); + crb_addr_transform(PGN2); + crb_addr_transform(PGN1); + crb_addr_transform(PGN0); + crb_addr_transform(PGSI); + crb_addr_transform(PGSD); + crb_addr_transform(PGS3); + crb_addr_transform(PGS2); + crb_addr_transform(PGS1); + crb_addr_transform(PGS0); + crb_addr_transform(PS); + crb_addr_transform(PH); + crb_addr_transform(NIU); + crb_addr_transform(I2Q); + crb_addr_transform(EG); + crb_addr_transform(MN); + crb_addr_transform(MS); + crb_addr_transform(CAS2); + crb_addr_transform(CAS1); + crb_addr_transform(CAS0); + crb_addr_transform(CAM); + crb_addr_transform(C2C1); + crb_addr_transform(C2C0); + crb_addr_transform(SMB); + crb_addr_transform(OCM0); + crb_addr_transform(I2C0); +} + +void qlcnic_release_rx_buffers(struct qlcnic_adapter *adapter) +{ + struct qlcnic_recv_context *recv_ctx; + struct qlcnic_host_rds_ring *rds_ring; + struct qlcnic_rx_buffer *rx_buf; + int i, ring; + + recv_ctx = &adapter->recv_ctx; + for (ring = 0; ring < adapter->max_rds_rings; ring++) { + rds_ring = &recv_ctx->rds_rings[ring]; + for (i = 0; i < rds_ring->num_desc; ++i) { + rx_buf = &(rds_ring->rx_buf_arr[i]); + if (rx_buf->state == QLCNIC_BUFFER_FREE) + continue; + pci_unmap_single(adapter->pdev, + rx_buf->dma, + rds_ring->dma_size, + PCI_DMA_FROMDEVICE); + if (rx_buf->skb != NULL) + dev_kfree_skb_any(rx_buf->skb); + } + } +} + +void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter) +{ + struct qlcnic_cmd_buffer *cmd_buf; + struct qlcnic_skb_frag *buffrag; + int i, j; + struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring; + + cmd_buf = tx_ring->cmd_buf_arr; + for (i = 0; i < tx_ring->num_desc; i++) { + buffrag = cmd_buf->frag_array; + if (buffrag->dma) { + pci_unmap_single(adapter->pdev, buffrag->dma, + buffrag->length, PCI_DMA_TODEVICE); + buffrag->dma = 0ULL; + } + for (j = 0; j < cmd_buf->frag_count; j++) { + buffrag++; + if (buffrag->dma) { + pci_unmap_page(adapter->pdev, buffrag->dma, + buffrag->length, + PCI_DMA_TODEVICE); + buffrag->dma = 0ULL; + } + } + if (cmd_buf->skb) { + dev_kfree_skb_any(cmd_buf->skb); + cmd_buf->skb = NULL; + } + cmd_buf++; + } +} + +void qlcnic_free_sw_resources(struct qlcnic_adapter *adapter) +{ + struct qlcnic_recv_context *recv_ctx; + struct qlcnic_host_rds_ring *rds_ring; + struct qlcnic_host_tx_ring *tx_ring; + int ring; + + recv_ctx = &adapter->recv_ctx; + + if (recv_ctx->rds_rings == NULL) + goto skip_rds; + + for (ring = 0; ring < adapter->max_rds_rings; ring++) { + rds_ring = &recv_ctx->rds_rings[ring]; + vfree(rds_ring->rx_buf_arr); + rds_ring->rx_buf_arr = NULL; + } + kfree(recv_ctx->rds_rings); + +skip_rds: + if (adapter->tx_ring == NULL) + return; + + tx_ring = adapter->tx_ring; + vfree(tx_ring->cmd_buf_arr); + kfree(adapter->tx_ring); +} + +int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter) +{ + struct qlcnic_recv_context *recv_ctx; + struct qlcnic_host_rds_ring *rds_ring; + struct qlcnic_host_sds_ring *sds_ring; + struct qlcnic_host_tx_ring *tx_ring; + struct qlcnic_rx_buffer *rx_buf; + int ring, i, size; + + struct qlcnic_cmd_buffer *cmd_buf_arr; + struct net_device *netdev = adapter->netdev; + + size = sizeof(struct qlcnic_host_tx_ring); + tx_ring = kzalloc(size, GFP_KERNEL); + if (tx_ring == NULL) { + dev_err(&netdev->dev, "failed to allocate tx ring struct\n"); + return -ENOMEM; + } + adapter->tx_ring = tx_ring; + + tx_ring->num_desc = adapter->num_txd; + tx_ring->txq = netdev_get_tx_queue(netdev, 0); + + cmd_buf_arr = vmalloc(TX_BUFF_RINGSIZE(tx_ring)); + if (cmd_buf_arr == NULL) { + dev_err(&netdev->dev, "failed to allocate cmd buffer ring\n"); + return -ENOMEM; + } + memset(cmd_buf_arr, 0, TX_BUFF_RINGSIZE(tx_ring)); + tx_ring->cmd_buf_arr = cmd_buf_arr; + + recv_ctx = &adapter->recv_ctx; + + size = adapter->max_rds_rings * sizeof(struct qlcnic_host_rds_ring); + rds_ring = kzalloc(size, GFP_KERNEL); + if (rds_ring == NULL) { + dev_err(&netdev->dev, "failed to allocate rds ring struct\n"); + return -ENOMEM; + } + recv_ctx->rds_rings = rds_ring; + + for (ring = 0; ring < adapter->max_rds_rings; ring++) { + rds_ring = &recv_ctx->rds_rings[ring]; + switch (ring) { + case RCV_RING_NORMAL: + rds_ring->num_desc = adapter->num_rxd; + if (adapter->ahw.cut_through) { + rds_ring->dma_size = + QLCNIC_CT_DEFAULT_RX_BUF_LEN; + rds_ring->skb_size = + QLCNIC_CT_DEFAULT_RX_BUF_LEN; + } else { + rds_ring->dma_size = + QLCNIC_P3_RX_BUF_MAX_LEN; + rds_ring->skb_size = + rds_ring->dma_size + NET_IP_ALIGN; + } + break; + + case RCV_RING_JUMBO: + rds_ring->num_desc = adapter->num_jumbo_rxd; + rds_ring->dma_size = + QLCNIC_P3_RX_JUMBO_BUF_MAX_LEN; + + if (adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO) + rds_ring->dma_size += QLCNIC_LRO_BUFFER_EXTRA; + + rds_ring->skb_size = + rds_ring->dma_size + NET_IP_ALIGN; + break; + + case RCV_RING_LRO: + rds_ring->num_desc = adapter->num_lro_rxd; + rds_ring->dma_size = QLCNIC_RX_LRO_BUFFER_LENGTH; + rds_ring->skb_size = rds_ring->dma_size + NET_IP_ALIGN; + break; + + } + rds_ring->rx_buf_arr = (struct qlcnic_rx_buffer *) + vmalloc(RCV_BUFF_RINGSIZE(rds_ring)); + if (rds_ring->rx_buf_arr == NULL) { + dev_err(&netdev->dev, "Failed to allocate " + "rx buffer ring %d\n", ring); + goto err_out; + } + memset(rds_ring->rx_buf_arr, 0, RCV_BUFF_RINGSIZE(rds_ring)); + INIT_LIST_HEAD(&rds_ring->free_list); + /* + * Now go through all of them, set reference handles + * and put them in the queues. + */ + rx_buf = rds_ring->rx_buf_arr; + for (i = 0; i < rds_ring->num_desc; i++) { + list_add_tail(&rx_buf->list, + &rds_ring->free_list); + rx_buf->ref_handle = i; + rx_buf->state = QLCNIC_BUFFER_FREE; + rx_buf++; + } + spin_lock_init(&rds_ring->lock); + } + + for (ring = 0; ring < adapter->max_sds_rings; ring++) { + sds_ring = &recv_ctx->sds_rings[ring]; + sds_ring->irq = adapter->msix_entries[ring].vector; + sds_ring->adapter = adapter; + sds_ring->num_desc = adapter->num_rxd; + + for (i = 0; i < NUM_RCV_DESC_RINGS; i++) + INIT_LIST_HEAD(&sds_ring->free_list[i]); + } + + return 0; + +err_out: + qlcnic_free_sw_resources(adapter); + return -ENOMEM; +} + +/* + * Utility to translate from internal Phantom CRB address + * to external PCI CRB address. + */ +static u32 qlcnic_decode_crb_addr(u32 addr) +{ + int i; + u32 base_addr, offset, pci_base; + + crb_addr_transform_setup(); + + pci_base = QLCNIC_ADDR_ERROR; + base_addr = addr & 0xfff00000; + offset = addr & 0x000fffff; + + for (i = 0; i < QLCNIC_MAX_CRB_XFORM; i++) { + if (crb_addr_xform[i] == base_addr) { + pci_base = i << 20; + break; + } + } + if (pci_base == QLCNIC_ADDR_ERROR) + return pci_base; + else + return pci_base + offset; +} + +#define QLCNIC_MAX_ROM_WAIT_USEC 100 + +static int qlcnic_wait_rom_done(struct qlcnic_adapter *adapter) +{ + long timeout = 0; + long done = 0; + + cond_resched(); + + while (done == 0) { + done = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_STATUS); + done &= 2; + if (++timeout >= QLCNIC_MAX_ROM_WAIT_USEC) { + dev_err(&adapter->pdev->dev, + "Timeout reached waiting for rom done"); + return -EIO; + } + udelay(1); + } + return 0; +} + +static int do_rom_fast_read(struct qlcnic_adapter *adapter, + int addr, int *valp) +{ + QLCWR32(adapter, QLCNIC_ROMUSB_ROM_ADDRESS, addr); + QLCWR32(adapter, QLCNIC_ROMUSB_ROM_DUMMY_BYTE_CNT, 0); + QLCWR32(adapter, QLCNIC_ROMUSB_ROM_ABYTE_CNT, 3); + QLCWR32(adapter, QLCNIC_ROMUSB_ROM_INSTR_OPCODE, 0xb); + if (qlcnic_wait_rom_done(adapter)) { + dev_err(&adapter->pdev->dev, "Error waiting for rom done\n"); + return -EIO; + } + /* reset abyte_cnt and dummy_byte_cnt */ + QLCWR32(adapter, QLCNIC_ROMUSB_ROM_ABYTE_CNT, 0); + udelay(10); + QLCWR32(adapter, QLCNIC_ROMUSB_ROM_DUMMY_BYTE_CNT, 0); + + *valp = QLCRD32(adapter, QLCNIC_ROMUSB_ROM_RDATA); + return 0; +} + +static int do_rom_fast_read_words(struct qlcnic_adapter *adapter, int addr, + u8 *bytes, size_t size) +{ + int addridx; + int ret = 0; + + for (addridx = addr; addridx < (addr + size); addridx += 4) { + int v; + ret = do_rom_fast_read(adapter, addridx, &v); + if (ret != 0) + break; + *(__le32 *)bytes = cpu_to_le32(v); + bytes += 4; + } + + return ret; +} + +int +qlcnic_rom_fast_read_words(struct qlcnic_adapter *adapter, int addr, + u8 *bytes, size_t size) +{ + int ret; + + ret = qlcnic_rom_lock(adapter); + if (ret < 0) + return ret; + + ret = do_rom_fast_read_words(adapter, addr, bytes, size); + + qlcnic_rom_unlock(adapter); + return ret; +} + +int qlcnic_rom_fast_read(struct qlcnic_adapter *adapter, int addr, int *valp) +{ + int ret; + + if (qlcnic_rom_lock(adapter) != 0) + return -EIO; + + ret = do_rom_fast_read(adapter, addr, valp); + qlcnic_rom_unlock(adapter); + return ret; +} + +int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter) +{ + int addr, val; + int i, n, init_delay; + struct crb_addr_pair *buf; + unsigned offset; + u32 off; + struct pci_dev *pdev = adapter->pdev; + + /* resetall */ + qlcnic_rom_lock(adapter); + QLCWR32(adapter, QLCNIC_ROMUSB_GLB_SW_RESET, 0xffffffff); + qlcnic_rom_unlock(adapter); + + if (qlcnic_rom_fast_read(adapter, 0, &n) != 0 || (n != 0xcafecafe) || + qlcnic_rom_fast_read(adapter, 4, &n) != 0) { + dev_err(&pdev->dev, "ERROR Reading crb_init area: val:%x\n", n); + return -EIO; + } + offset = n & 0xffffU; + n = (n >> 16) & 0xffffU; + + if (n >= 1024) { + dev_err(&pdev->dev, "QLOGIC card flash not initialized.\n"); + return -EIO; + } + + buf = kcalloc(n, sizeof(struct crb_addr_pair), GFP_KERNEL); + if (buf == NULL) { + dev_err(&pdev->dev, "Unable to calloc memory for rom read.\n"); + return -ENOMEM; + } + + for (i = 0; i < n; i++) { + if (qlcnic_rom_fast_read(adapter, 8*i + 4*offset, &val) != 0 || + qlcnic_rom_fast_read(adapter, 8*i + 4*offset + 4, &addr) != 0) { + kfree(buf); + return -EIO; + } + + buf[i].addr = addr; + buf[i].data = val; + } + + for (i = 0; i < n; i++) { + + off = qlcnic_decode_crb_addr(buf[i].addr); + if (off == QLCNIC_ADDR_ERROR) { + dev_err(&pdev->dev, "CRB init value out of range %x\n", + buf[i].addr); + continue; + } + off += QLCNIC_PCI_CRBSPACE; + + if (off & 1) + continue; + + /* skipping cold reboot MAGIC */ + if (off == QLCNIC_CAM_RAM(0x1fc)) + continue; + if (off == (QLCNIC_CRB_I2C0 + 0x1c)) + continue; + if (off == (ROMUSB_GLB + 0xbc)) /* do not reset PCI */ + continue; + if (off == (ROMUSB_GLB + 0xa8)) + continue; + if (off == (ROMUSB_GLB + 0xc8)) /* core clock */ + continue; + if (off == (ROMUSB_GLB + 0x24)) /* MN clock */ + continue; + if (off == (ROMUSB_GLB + 0x1c)) /* MS clock */ + continue; + if ((off & 0x0ff00000) == QLCNIC_CRB_DDR_NET) + continue; + /* skip the function enable register */ + if (off == QLCNIC_PCIE_REG(PCIE_SETUP_FUNCTION)) + continue; + if (off == QLCNIC_PCIE_REG(PCIE_SETUP_FUNCTION2)) + continue; + if ((off & 0x0ff00000) == QLCNIC_CRB_SMB) + continue; + + init_delay = 1; + /* After writing this register, HW needs time for CRB */ + /* to quiet down (else crb_window returns 0xffffffff) */ + if (off == QLCNIC_ROMUSB_GLB_SW_RESET) + init_delay = 1000; + + QLCWR32(adapter, off, buf[i].data); + + msleep(init_delay); + } + kfree(buf); + + /* p2dn replyCount */ + QLCWR32(adapter, QLCNIC_CRB_PEG_NET_D + 0xec, 0x1e); + /* disable_peg_cache 0 & 1*/ + QLCWR32(adapter, QLCNIC_CRB_PEG_NET_D + 0x4c, 8); + QLCWR32(adapter, QLCNIC_CRB_PEG_NET_I + 0x4c, 8); + + /* peg_clr_all */ + QLCWR32(adapter, QLCNIC_CRB_PEG_NET_0 + 0x8, 0); + QLCWR32(adapter, QLCNIC_CRB_PEG_NET_0 + 0xc, 0); + QLCWR32(adapter, QLCNIC_CRB_PEG_NET_1 + 0x8, 0); + QLCWR32(adapter, QLCNIC_CRB_PEG_NET_1 + 0xc, 0); + QLCWR32(adapter, QLCNIC_CRB_PEG_NET_2 + 0x8, 0); + QLCWR32(adapter, QLCNIC_CRB_PEG_NET_2 + 0xc, 0); + QLCWR32(adapter, QLCNIC_CRB_PEG_NET_3 + 0x8, 0); + QLCWR32(adapter, QLCNIC_CRB_PEG_NET_3 + 0xc, 0); + return 0; +} + +static int +qlcnic_has_mn(struct qlcnic_adapter *adapter) +{ + u32 capability, flashed_ver; + capability = 0; + + qlcnic_rom_fast_read(adapter, + QLCNIC_FW_VERSION_OFFSET, (int *)&flashed_ver); + flashed_ver = QLCNIC_DECODE_VERSION(flashed_ver); + + if (flashed_ver >= QLCNIC_VERSION_CODE(4, 0, 220)) { + + capability = QLCRD32(adapter, QLCNIC_PEG_TUNE_CAPABILITY); + if (capability & QLCNIC_PEG_TUNE_MN_PRESENT) + return 1; + } + return 0; +} + +static +struct uni_table_desc *qlcnic_get_table_desc(const u8 *unirom, int section) +{ + u32 i; + struct uni_table_desc *directory = (struct uni_table_desc *) &unirom[0]; + __le32 entries = cpu_to_le32(directory->num_entries); + + for (i = 0; i < entries; i++) { + + __le32 offs = cpu_to_le32(directory->findex) + + (i * cpu_to_le32(directory->entry_size)); + __le32 tab_type = cpu_to_le32(*((u32 *)&unirom[offs] + 8)); + + if (tab_type == section) + return (struct uni_table_desc *) &unirom[offs]; + } + + return NULL; +} + +static int +qlcnic_set_product_offs(struct qlcnic_adapter *adapter) +{ + struct uni_table_desc *ptab_descr; + const u8 *unirom = adapter->fw->data; + u32 i; + __le32 entries; + int mn_present = qlcnic_has_mn(adapter); + + ptab_descr = qlcnic_get_table_desc(unirom, + QLCNIC_UNI_DIR_SECT_PRODUCT_TBL); + if (ptab_descr == NULL) + return -1; + + entries = cpu_to_le32(ptab_descr->num_entries); +nomn: + for (i = 0; i < entries; i++) { + + __le32 flags, file_chiprev, offs; + u8 chiprev = adapter->ahw.revision_id; + u32 flagbit; + + offs = cpu_to_le32(ptab_descr->findex) + + (i * cpu_to_le32(ptab_descr->entry_size)); + flags = cpu_to_le32(*((int *)&unirom[offs] + + QLCNIC_UNI_FLAGS_OFF)); + file_chiprev = cpu_to_le32(*((int *)&unirom[offs] + + QLCNIC_UNI_CHIP_REV_OFF)); + + flagbit = mn_present ? 1 : 2; + + if ((chiprev == file_chiprev) && + ((1ULL << flagbit) & flags)) { + adapter->file_prd_off = offs; + return 0; + } + } + if (mn_present) { + mn_present = 0; + goto nomn; + } + return -1; +} + +static +struct uni_data_desc *qlcnic_get_data_desc(struct qlcnic_adapter *adapter, + u32 section, u32 idx_offset) +{ + const u8 *unirom = adapter->fw->data; + int idx = cpu_to_le32(*((int *)&unirom[adapter->file_prd_off] + + idx_offset)); + struct uni_table_desc *tab_desc; + __le32 offs; + + tab_desc = qlcnic_get_table_desc(unirom, section); + + if (tab_desc == NULL) + return NULL; + + offs = cpu_to_le32(tab_desc->findex) + + (cpu_to_le32(tab_desc->entry_size) * idx); + + return (struct uni_data_desc *)&unirom[offs]; +} + +static u8 * +qlcnic_get_bootld_offs(struct qlcnic_adapter *adapter) +{ + u32 offs = QLCNIC_BOOTLD_START; + + if (adapter->fw_type == QLCNIC_UNIFIED_ROMIMAGE) + offs = cpu_to_le32((qlcnic_get_data_desc(adapter, + QLCNIC_UNI_DIR_SECT_BOOTLD, + QLCNIC_UNI_BOOTLD_IDX_OFF))->findex); + + return (u8 *)&adapter->fw->data[offs]; +} + +static u8 * +qlcnic_get_fw_offs(struct qlcnic_adapter *adapter) +{ + u32 offs = QLCNIC_IMAGE_START; + + if (adapter->fw_type == QLCNIC_UNIFIED_ROMIMAGE) + offs = cpu_to_le32((qlcnic_get_data_desc(adapter, + QLCNIC_UNI_DIR_SECT_FW, + QLCNIC_UNI_FIRMWARE_IDX_OFF))->findex); + + return (u8 *)&adapter->fw->data[offs]; +} + +static __le32 +qlcnic_get_fw_size(struct qlcnic_adapter *adapter) +{ + if (adapter->fw_type == QLCNIC_UNIFIED_ROMIMAGE) + return cpu_to_le32((qlcnic_get_data_desc(adapter, + QLCNIC_UNI_DIR_SECT_FW, + QLCNIC_UNI_FIRMWARE_IDX_OFF))->size); + else + return cpu_to_le32( + *(u32 *)&adapter->fw->data[QLCNIC_FW_SIZE_OFFSET]); +} + +static __le32 +qlcnic_get_fw_version(struct qlcnic_adapter *adapter) +{ + struct uni_data_desc *fw_data_desc; + const struct firmware *fw = adapter->fw; + __le32 major, minor, sub; + const u8 *ver_str; + int i, ret; + + if (adapter->fw_type != QLCNIC_UNIFIED_ROMIMAGE) + return cpu_to_le32(*(u32 *)&fw->data[QLCNIC_FW_VERSION_OFFSET]); + + fw_data_desc = qlcnic_get_data_desc(adapter, QLCNIC_UNI_DIR_SECT_FW, + QLCNIC_UNI_FIRMWARE_IDX_OFF); + ver_str = fw->data + cpu_to_le32(fw_data_desc->findex) + + cpu_to_le32(fw_data_desc->size) - 17; + + for (i = 0; i < 12; i++) { + if (!strncmp(&ver_str[i], "REV=", 4)) { + ret = sscanf(&ver_str[i+4], "%u.%u.%u ", + &major, &minor, &sub); + if (ret != 3) + return 0; + else + return major + (minor << 8) + (sub << 16); + } + } + + return 0; +} + +static __le32 +qlcnic_get_bios_version(struct qlcnic_adapter *adapter) +{ + const struct firmware *fw = adapter->fw; + __le32 bios_ver, prd_off = adapter->file_prd_off; + + if (adapter->fw_type != QLCNIC_UNIFIED_ROMIMAGE) + return cpu_to_le32( + *(u32 *)&fw->data[QLCNIC_BIOS_VERSION_OFFSET]); + + bios_ver = cpu_to_le32(*((u32 *) (&fw->data[prd_off]) + + QLCNIC_UNI_BIOS_VERSION_OFF)); + + return (bios_ver << 24) + ((bios_ver >> 8) & 0xff00) + (bios_ver >> 24); +} + +int +qlcnic_need_fw_reset(struct qlcnic_adapter *adapter) +{ + u32 count, old_count; + u32 val, version, major, minor, build; + int i, timeout; + + if (adapter->need_fw_reset) + return 1; + + /* last attempt had failed */ + if (QLCRD32(adapter, CRB_CMDPEG_STATE) == PHAN_INITIALIZE_FAILED) + return 1; + + old_count = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER); + + for (i = 0; i < 10; i++) { + + timeout = msleep_interruptible(200); + if (timeout) { + QLCWR32(adapter, CRB_CMDPEG_STATE, + PHAN_INITIALIZE_FAILED); + return -EINTR; + } + + count = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER); + if (count != old_count) + break; + } + + /* firmware is dead */ + if (count == old_count) + return 1; + + /* check if we have got newer or different file firmware */ + if (adapter->fw) { + + val = qlcnic_get_fw_version(adapter); + + version = QLCNIC_DECODE_VERSION(val); + + major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR); + minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR); + build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB); + + if (version > QLCNIC_VERSION_CODE(major, minor, build)) + return 1; + } + + return 0; +} + +static const char *fw_name[] = { + QLCNIC_UNIFIED_ROMIMAGE_NAME, + QLCNIC_FLASH_ROMIMAGE_NAME, +}; + +int +qlcnic_load_firmware(struct qlcnic_adapter *adapter) +{ + u64 *ptr64; + u32 i, flashaddr, size; + const struct firmware *fw = adapter->fw; + struct pci_dev *pdev = adapter->pdev; + + dev_info(&pdev->dev, "loading firmware from %s\n", + fw_name[adapter->fw_type]); + + if (fw) { + __le64 data; + + size = (QLCNIC_IMAGE_START - QLCNIC_BOOTLD_START) / 8; + + ptr64 = (u64 *)qlcnic_get_bootld_offs(adapter); + flashaddr = QLCNIC_BOOTLD_START; + + for (i = 0; i < size; i++) { + data = cpu_to_le64(ptr64[i]); + + if (qlcnic_pci_mem_write_2M(adapter, flashaddr, data)) + return -EIO; + + flashaddr += 8; + } + + size = (__force u32)qlcnic_get_fw_size(adapter) / 8; + + ptr64 = (u64 *)qlcnic_get_fw_offs(adapter); + flashaddr = QLCNIC_IMAGE_START; + + for (i = 0; i < size; i++) { + data = cpu_to_le64(ptr64[i]); + + if (qlcnic_pci_mem_write_2M(adapter, + flashaddr, data)) + return -EIO; + + flashaddr += 8; + } + } else { + u64 data; + u32 hi, lo; + + size = (QLCNIC_IMAGE_START - QLCNIC_BOOTLD_START) / 8; + flashaddr = QLCNIC_BOOTLD_START; + + for (i = 0; i < size; i++) { + if (qlcnic_rom_fast_read(adapter, + flashaddr, (int *)&lo) != 0) + return -EIO; + if (qlcnic_rom_fast_read(adapter, + flashaddr + 4, (int *)&hi) != 0) + return -EIO; + + data = (((u64)hi << 32) | lo); + + if (qlcnic_pci_mem_write_2M(adapter, + flashaddr, data)) + return -EIO; + + flashaddr += 8; + } + } + msleep(1); + + QLCWR32(adapter, QLCNIC_CRB_PEG_NET_0 + 0x18, 0x1020); + QLCWR32(adapter, QLCNIC_ROMUSB_GLB_SW_RESET, 0x80001e); + return 0; +} + +static int +qlcnic_validate_firmware(struct qlcnic_adapter *adapter) +{ + __le32 val; + u32 ver, min_ver, bios, min_size; + struct pci_dev *pdev = adapter->pdev; + const struct firmware *fw = adapter->fw; + u8 fw_type = adapter->fw_type; + + if (fw_type == QLCNIC_UNIFIED_ROMIMAGE) { + if (qlcnic_set_product_offs(adapter)) + return -EINVAL; + + min_size = QLCNIC_UNI_FW_MIN_SIZE; + } else { + val = cpu_to_le32(*(u32 *)&fw->data[QLCNIC_FW_MAGIC_OFFSET]); + if ((__force u32)val != QLCNIC_BDINFO_MAGIC) + return -EINVAL; + + min_size = QLCNIC_FW_MIN_SIZE; + } + + if (fw->size < min_size) + return -EINVAL; + + val = qlcnic_get_fw_version(adapter); + + min_ver = QLCNIC_VERSION_CODE(4, 0, 216); + + ver = QLCNIC_DECODE_VERSION(val); + + if ((_major(ver) > _QLCNIC_LINUX_MAJOR) || (ver < min_ver)) { + dev_err(&pdev->dev, + "%s: firmware version %d.%d.%d unsupported\n", + fw_name[fw_type], _major(ver), _minor(ver), _build(ver)); + return -EINVAL; + } + + val = qlcnic_get_bios_version(adapter); + qlcnic_rom_fast_read(adapter, QLCNIC_BIOS_VERSION_OFFSET, (int *)&bios); + if ((__force u32)val != bios) { + dev_err(&pdev->dev, "%s: firmware bios is incompatible\n", + fw_name[fw_type]); + return -EINVAL; + } + + /* check if flashed firmware is newer */ + if (qlcnic_rom_fast_read(adapter, + QLCNIC_FW_VERSION_OFFSET, (int *)&val)) + return -EIO; + + val = QLCNIC_DECODE_VERSION(val); + if (val > ver) { + dev_info(&pdev->dev, "%s: firmware is older than flash\n", + fw_name[fw_type]); + return -EINVAL; + } + + QLCWR32(adapter, QLCNIC_CAM_RAM(0x1fc), QLCNIC_BDINFO_MAGIC); + return 0; +} + +static void +qlcnic_get_next_fwtype(struct qlcnic_adapter *adapter) +{ + u8 fw_type; + + switch (adapter->fw_type) { + case QLCNIC_UNKNOWN_ROMIMAGE: + fw_type = QLCNIC_UNIFIED_ROMIMAGE; + break; + + case QLCNIC_UNIFIED_ROMIMAGE: + default: + fw_type = QLCNIC_FLASH_ROMIMAGE; + break; + } + + adapter->fw_type = fw_type; +} + + + +void qlcnic_request_firmware(struct qlcnic_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + int rc; + + adapter->fw_type = QLCNIC_UNKNOWN_ROMIMAGE; + +next: + qlcnic_get_next_fwtype(adapter); + + if (adapter->fw_type == QLCNIC_FLASH_ROMIMAGE) { + adapter->fw = NULL; + } else { + rc = request_firmware(&adapter->fw, + fw_name[adapter->fw_type], &pdev->dev); + if (rc != 0) + goto next; + + rc = qlcnic_validate_firmware(adapter); + if (rc != 0) { + release_firmware(adapter->fw); + msleep(1); + goto next; + } + } +} + + +void +qlcnic_release_firmware(struct qlcnic_adapter *adapter) +{ + if (adapter->fw) + release_firmware(adapter->fw); + adapter->fw = NULL; +} + +int qlcnic_phantom_init(struct qlcnic_adapter *adapter) +{ + u32 val; + int retries = 60; + + do { + val = QLCRD32(adapter, CRB_CMDPEG_STATE); + + switch (val) { + case PHAN_INITIALIZE_COMPLETE: + case PHAN_INITIALIZE_ACK: + return 0; + case PHAN_INITIALIZE_FAILED: + goto out_err; + default: + break; + } + + msleep(500); + + } while (--retries); + + QLCWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_FAILED); + +out_err: + dev_err(&adapter->pdev->dev, "firmware init failed\n"); + return -EIO; +} + +static int +qlcnic_receive_peg_ready(struct qlcnic_adapter *adapter) +{ + u32 val; + int retries = 2000; + + do { + val = QLCRD32(adapter, CRB_RCVPEG_STATE); + + if (val == PHAN_PEG_RCV_INITIALIZED) + return 0; + + msleep(10); + + } while (--retries); + + if (!retries) { + dev_err(&adapter->pdev->dev, "Receive Peg initialization not " + "complete, state: 0x%x.\n", val); + return -EIO; + } + + return 0; +} + +int qlcnic_init_firmware(struct qlcnic_adapter *adapter) +{ + int err; + + err = qlcnic_receive_peg_ready(adapter); + if (err) + return err; + + QLCWR32(adapter, CRB_NIC_CAPABILITIES_HOST, INTR_SCHEME_PERPORT); + QLCWR32(adapter, CRB_NIC_MSI_MODE_HOST, MSI_MODE_MULTIFUNC); + QLCWR32(adapter, CRB_MPORT_MODE, MPORT_MULTI_FUNCTION_MODE); + QLCWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_ACK); + + return err; +} + +static void +qlcnic_handle_linkevent(struct qlcnic_adapter *adapter, + struct qlcnic_fw_msg *msg) +{ + u32 cable_OUI; + u16 cable_len; + u16 link_speed; + u8 link_status, module, duplex, autoneg; + struct net_device *netdev = adapter->netdev; + + adapter->has_link_events = 1; + + cable_OUI = msg->body[1] & 0xffffffff; + cable_len = (msg->body[1] >> 32) & 0xffff; + link_speed = (msg->body[1] >> 48) & 0xffff; + + link_status = msg->body[2] & 0xff; + duplex = (msg->body[2] >> 16) & 0xff; + autoneg = (msg->body[2] >> 24) & 0xff; + + module = (msg->body[2] >> 8) & 0xff; + if (module == LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE) + dev_info(&netdev->dev, "unsupported cable: OUI 0x%x, " + "length %d\n", cable_OUI, cable_len); + else if (module == LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN) + dev_info(&netdev->dev, "unsupported cable length %d\n", + cable_len); + + qlcnic_advert_link_change(adapter, link_status); + + if (duplex == LINKEVENT_FULL_DUPLEX) + adapter->link_duplex = DUPLEX_FULL; + else + adapter->link_duplex = DUPLEX_HALF; + + adapter->module_type = module; + adapter->link_autoneg = autoneg; + adapter->link_speed = link_speed; +} + +static void +qlcnic_handle_fw_message(int desc_cnt, int index, + struct qlcnic_host_sds_ring *sds_ring) +{ + struct qlcnic_fw_msg msg; + struct status_desc *desc; + int i = 0, opcode; + + while (desc_cnt > 0 && i < 8) { + desc = &sds_ring->desc_head[index]; + msg.words[i++] = le64_to_cpu(desc->status_desc_data[0]); + msg.words[i++] = le64_to_cpu(desc->status_desc_data[1]); + + index = get_next_index(index, sds_ring->num_desc); + desc_cnt--; + } + + opcode = qlcnic_get_nic_msg_opcode(msg.body[0]); + switch (opcode) { + case QLCNIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE: + qlcnic_handle_linkevent(sds_ring->adapter, &msg); + break; + default: + break; + } +} + +static int +qlcnic_alloc_rx_skb(struct qlcnic_adapter *adapter, + struct qlcnic_host_rds_ring *rds_ring, + struct qlcnic_rx_buffer *buffer) +{ + struct sk_buff *skb; + dma_addr_t dma; + struct pci_dev *pdev = adapter->pdev; + + buffer->skb = dev_alloc_skb(rds_ring->skb_size); + if (!buffer->skb) + return -ENOMEM; + + skb = buffer->skb; + + if (!adapter->ahw.cut_through) + skb_reserve(skb, 2); + + dma = pci_map_single(pdev, skb->data, + rds_ring->dma_size, PCI_DMA_FROMDEVICE); + + if (pci_dma_mapping_error(pdev, dma)) { + dev_kfree_skb_any(skb); + buffer->skb = NULL; + return -ENOMEM; + } + + buffer->skb = skb; + buffer->dma = dma; + buffer->state = QLCNIC_BUFFER_BUSY; + + return 0; +} + +static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter, + struct qlcnic_host_rds_ring *rds_ring, u16 index, u16 cksum) +{ + struct qlcnic_rx_buffer *buffer; + struct sk_buff *skb; + + buffer = &rds_ring->rx_buf_arr[index]; + + pci_unmap_single(adapter->pdev, buffer->dma, rds_ring->dma_size, + PCI_DMA_FROMDEVICE); + + skb = buffer->skb; + if (!skb) + goto no_skb; + + if (likely(adapter->rx_csum && cksum == STATUS_CKSUM_OK)) { + adapter->stats.csummed++; + skb->ip_summed = CHECKSUM_UNNECESSARY; + } else { + skb->ip_summed = CHECKSUM_NONE; + } + + skb->dev = adapter->netdev; + + buffer->skb = NULL; +no_skb: + buffer->state = QLCNIC_BUFFER_FREE; + return skb; +} + +static struct qlcnic_rx_buffer * +qlcnic_process_rcv(struct qlcnic_adapter *adapter, + struct qlcnic_host_sds_ring *sds_ring, + int ring, u64 sts_data0) +{ + struct net_device *netdev = adapter->netdev; + struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_rx_buffer *buffer; + struct sk_buff *skb; + struct qlcnic_host_rds_ring *rds_ring; + int index, length, cksum, pkt_offset; + + if (unlikely(ring >= adapter->max_rds_rings)) + return NULL; + + rds_ring = &recv_ctx->rds_rings[ring]; + + index = qlcnic_get_sts_refhandle(sts_data0); + if (unlikely(index >= rds_ring->num_desc)) + return NULL; + + buffer = &rds_ring->rx_buf_arr[index]; + + length = qlcnic_get_sts_totallength(sts_data0); + cksum = qlcnic_get_sts_status(sts_data0); + pkt_offset = qlcnic_get_sts_pkt_offset(sts_data0); + + skb = qlcnic_process_rxbuf(adapter, rds_ring, index, cksum); + if (!skb) + return buffer; + + if (length > rds_ring->skb_size) + skb_put(skb, rds_ring->skb_size); + else + skb_put(skb, length); + + if (pkt_offset) + skb_pull(skb, pkt_offset); + + skb->truesize = skb->len + sizeof(struct sk_buff); + skb->protocol = eth_type_trans(skb, netdev); + + napi_gro_receive(&sds_ring->napi, skb); + + adapter->stats.rx_pkts++; + adapter->stats.rxbytes += length; + + return buffer; +} + +#define QLC_TCP_HDR_SIZE 20 +#define QLC_TCP_TS_OPTION_SIZE 12 +#define QLC_TCP_TS_HDR_SIZE (QLC_TCP_HDR_SIZE + QLC_TCP_TS_OPTION_SIZE) + +static struct qlcnic_rx_buffer * +qlcnic_process_lro(struct qlcnic_adapter *adapter, + struct qlcnic_host_sds_ring *sds_ring, + int ring, u64 sts_data0, u64 sts_data1) +{ + struct net_device *netdev = adapter->netdev; + struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_rx_buffer *buffer; + struct sk_buff *skb; + struct qlcnic_host_rds_ring *rds_ring; + struct iphdr *iph; + struct tcphdr *th; + bool push, timestamp; + int l2_hdr_offset, l4_hdr_offset; + int index; + u16 lro_length, length, data_offset; + u32 seq_number; + + 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)) + return NULL; + + buffer = &rds_ring->rx_buf_arr[index]; + + timestamp = qlcnic_get_lro_sts_timestamp(sts_data0); + lro_length = qlcnic_get_lro_sts_length(sts_data0); + l2_hdr_offset = qlcnic_get_lro_sts_l2_hdr_offset(sts_data0); + l4_hdr_offset = qlcnic_get_lro_sts_l4_hdr_offset(sts_data0); + push = qlcnic_get_lro_sts_push_flag(sts_data0); + seq_number = qlcnic_get_lro_sts_seq_number(sts_data1); + + skb = qlcnic_process_rxbuf(adapter, rds_ring, index, STATUS_CKSUM_OK); + if (!skb) + return buffer; + + if (timestamp) + data_offset = l4_hdr_offset + QLC_TCP_TS_HDR_SIZE; + else + data_offset = l4_hdr_offset + QLC_TCP_HDR_SIZE; + + skb_put(skb, lro_length + data_offset); + + skb->truesize = skb->len + sizeof(struct sk_buff) + skb_headroom(skb); + + skb_pull(skb, l2_hdr_offset); + skb->protocol = eth_type_trans(skb, netdev); + + iph = (struct iphdr *)skb->data; + th = (struct tcphdr *)(skb->data + (iph->ihl << 2)); + + length = (iph->ihl << 2) + (th->doff << 2) + lro_length; + iph->tot_len = htons(length); + iph->check = 0; + iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); + th->psh = push; + th->seq = htonl(seq_number); + + length = skb->len; + + netif_receive_skb(skb); + + adapter->stats.lro_pkts++; + adapter->stats.rxbytes += length; + + return buffer; +} + +int +qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max) +{ + struct qlcnic_adapter *adapter = sds_ring->adapter; + struct list_head *cur; + struct status_desc *desc; + struct qlcnic_rx_buffer *rxbuf; + u64 sts_data0, sts_data1; + + int count = 0; + int opcode, ring, desc_cnt; + u32 consumer = sds_ring->consumer; + + while (count < max) { + desc = &sds_ring->desc_head[consumer]; + sts_data0 = le64_to_cpu(desc->status_desc_data[0]); + + if (!(sts_data0 & STATUS_OWNER_HOST)) + break; + + desc_cnt = qlcnic_get_sts_desc_cnt(sts_data0); + opcode = qlcnic_get_sts_opcode(sts_data0); + + switch (opcode) { + case QLCNIC_RXPKT_DESC: + case QLCNIC_OLD_RXPKT_DESC: + case QLCNIC_SYN_OFFLOAD: + ring = qlcnic_get_sts_type(sts_data0); + rxbuf = qlcnic_process_rcv(adapter, sds_ring, + ring, sts_data0); + break; + case QLCNIC_LRO_DESC: + ring = qlcnic_get_lro_sts_type(sts_data0); + sts_data1 = le64_to_cpu(desc->status_desc_data[1]); + rxbuf = qlcnic_process_lro(adapter, sds_ring, + ring, sts_data0, sts_data1); + break; + case QLCNIC_RESPONSE_DESC: + qlcnic_handle_fw_message(desc_cnt, consumer, sds_ring); + default: + goto skip; + } + + WARN_ON(desc_cnt > 1); + + if (rxbuf) + list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]); + +skip: + for (; desc_cnt > 0; desc_cnt--) { + desc = &sds_ring->desc_head[consumer]; + desc->status_desc_data[0] = + cpu_to_le64(STATUS_OWNER_PHANTOM); + consumer = get_next_index(consumer, sds_ring->num_desc); + } + count++; + } + + for (ring = 0; ring < adapter->max_rds_rings; ring++) { + struct qlcnic_host_rds_ring *rds_ring = + &adapter->recv_ctx.rds_rings[ring]; + + if (!list_empty(&sds_ring->free_list[ring])) { + list_for_each(cur, &sds_ring->free_list[ring]) { + rxbuf = list_entry(cur, + struct qlcnic_rx_buffer, list); + qlcnic_alloc_rx_skb(adapter, rds_ring, rxbuf); + } + spin_lock(&rds_ring->lock); + list_splice_tail_init(&sds_ring->free_list[ring], + &rds_ring->free_list); + spin_unlock(&rds_ring->lock); + } + + qlcnic_post_rx_buffers_nodb(adapter, rds_ring); + } + + if (count) { + sds_ring->consumer = consumer; + writel(consumer, sds_ring->crb_sts_consumer); + } + + return count; +} + +void +qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, u32 ringid, + struct qlcnic_host_rds_ring *rds_ring) +{ + struct rcv_desc *pdesc; + struct qlcnic_rx_buffer *buffer; + int producer, count = 0; + struct list_head *head; + + producer = rds_ring->producer; + + spin_lock(&rds_ring->lock); + head = &rds_ring->free_list; + while (!list_empty(head)) { + + buffer = list_entry(head->next, struct qlcnic_rx_buffer, list); + + if (!buffer->skb) { + if (qlcnic_alloc_rx_skb(adapter, rds_ring, buffer)) + break; + } + + count++; + list_del(&buffer->list); + + /* make a rcv descriptor */ + pdesc = &rds_ring->desc_head[producer]; + pdesc->addr_buffer = cpu_to_le64(buffer->dma); + pdesc->reference_handle = cpu_to_le16(buffer->ref_handle); + pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size); + + producer = get_next_index(producer, rds_ring->num_desc); + } + spin_unlock(&rds_ring->lock); + + if (count) { + rds_ring->producer = producer; + writel((producer-1) & (rds_ring->num_desc-1), + rds_ring->crb_rcv_producer); + } +} + +static void +qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter, + struct qlcnic_host_rds_ring *rds_ring) +{ + struct rcv_desc *pdesc; + struct qlcnic_rx_buffer *buffer; + int producer, count = 0; + struct list_head *head; + + producer = rds_ring->producer; + if (!spin_trylock(&rds_ring->lock)) + return; + + head = &rds_ring->free_list; + while (!list_empty(head)) { + + buffer = list_entry(head->next, struct qlcnic_rx_buffer, list); + + if (!buffer->skb) { + if (qlcnic_alloc_rx_skb(adapter, rds_ring, buffer)) + break; + } + + count++; + list_del(&buffer->list); + + /* make a rcv descriptor */ + pdesc = &rds_ring->desc_head[producer]; + pdesc->reference_handle = cpu_to_le16(buffer->ref_handle); + pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size); + pdesc->addr_buffer = cpu_to_le64(buffer->dma); + + producer = get_next_index(producer, rds_ring->num_desc); + } + + if (count) { + rds_ring->producer = producer; + writel((producer - 1) & (rds_ring->num_desc - 1), + rds_ring->crb_rcv_producer); + } + spin_unlock(&rds_ring->lock); +} + diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c new file mode 100644 index 00000000000..1698b6a68ed --- /dev/null +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -0,0 +1,2604 @@ +/* + * Copyright (C) 2009 - QLogic Corporation. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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. + * + * The full GNU General Public License is included in this distribution + * in the file called "COPYING". + * + */ + +#include +#include + +#include "qlcnic.h" + +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("QLogic 10 GbE Converged Ethernet Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(QLCNIC_LINUX_VERSIONID); +MODULE_FIRMWARE(QLCNIC_UNIFIED_ROMIMAGE_NAME); + +char qlcnic_driver_name[] = "qlcnic"; +static const char qlcnic_driver_string[] = "QLogic Converged Ethernet Driver v" + QLCNIC_LINUX_VERSIONID; + +static int port_mode = QLCNIC_PORT_MODE_AUTO_NEG; + +/* Default to restricted 1G auto-neg mode */ +static int wol_port_mode = 5; + +static int use_msi = 1; +module_param(use_msi, int, 0644); +MODULE_PARM_DESC(use_msi, "MSI interrupt (0=disabled, 1=enabled"); + +static int use_msi_x = 1; +module_param(use_msi_x, int, 0644); +MODULE_PARM_DESC(use_msi_x, "MSI-X interrupt (0=disabled, 1=enabled"); + +static int auto_fw_reset = AUTO_FW_RESET_ENABLED; +module_param(auto_fw_reset, int, 0644); +MODULE_PARM_DESC(auto_fw_reset, "Auto firmware reset (0=disabled, 1=enabled"); + +static int __devinit qlcnic_probe(struct pci_dev *pdev, + const struct pci_device_id *ent); +static void __devexit qlcnic_remove(struct pci_dev *pdev); +static int qlcnic_open(struct net_device *netdev); +static int qlcnic_close(struct net_device *netdev); +static netdev_tx_t qlcnic_xmit_frame(struct sk_buff *, + struct net_device *); +static void qlcnic_tx_timeout(struct net_device *netdev); +static void qlcnic_tx_timeout_task(struct work_struct *work); +static void qlcnic_attach_work(struct work_struct *work); +static void qlcnic_fwinit_work(struct work_struct *work); +static void qlcnic_fw_poll_work(struct work_struct *work); +static void qlcnic_schedule_work(struct qlcnic_adapter *adapter, + work_func_t func, int delay); +static void qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter); +static int qlcnic_poll(struct napi_struct *napi, int budget); +#ifdef CONFIG_NET_POLL_CONTROLLER +static void qlcnic_poll_controller(struct net_device *netdev); +#endif + +static void qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter); +static void qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter); +static void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter); +static void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter); + +static void qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter); +static int qlcnic_can_start_firmware(struct qlcnic_adapter *adapter); + +static irqreturn_t qlcnic_intr(int irq, void *data); +static irqreturn_t qlcnic_msi_intr(int irq, void *data); +static irqreturn_t qlcnic_msix_intr(int irq, void *data); + +static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev); +static void qlcnic_config_indev_addr(struct net_device *dev, unsigned long); + +/* PCI Device ID Table */ +#define ENTRY(device) \ + {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, (device)), \ + .class = PCI_CLASS_NETWORK_ETHERNET << 8, .class_mask = ~0} + +#define PCI_DEVICE_ID_QLOGIC_QLE824X 0x8020 + +static const struct pci_device_id qlcnic_pci_tbl[] __devinitdata = { + ENTRY(PCI_DEVICE_ID_QLOGIC_QLE824X), + {0,} +}; + +MODULE_DEVICE_TABLE(pci, qlcnic_pci_tbl); + + +void +qlcnic_update_cmd_producer(struct qlcnic_adapter *adapter, + struct qlcnic_host_tx_ring *tx_ring) +{ + writel(tx_ring->producer, tx_ring->crb_cmd_producer); + + if (qlcnic_tx_avail(tx_ring) <= TX_STOP_THRESH) { + netif_stop_queue(adapter->netdev); + smp_mb(); + } +} + +static const u32 msi_tgt_status[8] = { + ISR_INT_TARGET_STATUS, ISR_INT_TARGET_STATUS_F1, + ISR_INT_TARGET_STATUS_F2, ISR_INT_TARGET_STATUS_F3, + ISR_INT_TARGET_STATUS_F4, ISR_INT_TARGET_STATUS_F5, + ISR_INT_TARGET_STATUS_F6, ISR_INT_TARGET_STATUS_F7 +}; + +static const +struct qlcnic_legacy_intr_set legacy_intr[] = QLCNIC_LEGACY_INTR_CONFIG; + +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_int(struct qlcnic_host_sds_ring *sds_ring) +{ + struct qlcnic_adapter *adapter = sds_ring->adapter; + + writel(0x1, sds_ring->crb_intr_mask); + + if (!QLCNIC_IS_MSI_FAMILY(adapter)) + writel(0xfbff, adapter->tgt_mask_reg); +} + +static int +qlcnic_alloc_sds_rings(struct qlcnic_recv_context *recv_ctx, int count) +{ + int size = sizeof(struct qlcnic_host_sds_ring) * count; + + recv_ctx->sds_rings = kzalloc(size, GFP_KERNEL); + + return (recv_ctx->sds_rings == NULL); +} + +static void +qlcnic_free_sds_rings(struct qlcnic_recv_context *recv_ctx) +{ + if (recv_ctx->sds_rings != NULL) + kfree(recv_ctx->sds_rings); + + recv_ctx->sds_rings = NULL; +} + +static int +qlcnic_napi_add(struct qlcnic_adapter *adapter, struct net_device *netdev) +{ + int ring; + struct qlcnic_host_sds_ring *sds_ring; + struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + + if (qlcnic_alloc_sds_rings(recv_ctx, adapter->max_sds_rings)) + return -ENOMEM; + + for (ring = 0; ring < adapter->max_sds_rings; ring++) { + sds_ring = &recv_ctx->sds_rings[ring]; + netif_napi_add(netdev, &sds_ring->napi, + qlcnic_poll, QLCNIC_NETDEV_WEIGHT); + } + + return 0; +} + +static void +qlcnic_napi_del(struct qlcnic_adapter *adapter) +{ + int ring; + struct qlcnic_host_sds_ring *sds_ring; + struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + + for (ring = 0; ring < adapter->max_sds_rings; ring++) { + sds_ring = &recv_ctx->sds_rings[ring]; + netif_napi_del(&sds_ring->napi); + } + + qlcnic_free_sds_rings(&adapter->recv_ctx); +} + +static void +qlcnic_napi_enable(struct qlcnic_adapter *adapter) +{ + int ring; + struct qlcnic_host_sds_ring *sds_ring; + struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + + for (ring = 0; ring < adapter->max_sds_rings; ring++) { + sds_ring = &recv_ctx->sds_rings[ring]; + napi_enable(&sds_ring->napi); + qlcnic_enable_int(sds_ring); + } +} + +static void +qlcnic_napi_disable(struct qlcnic_adapter *adapter) +{ + int ring; + struct qlcnic_host_sds_ring *sds_ring; + struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + + for (ring = 0; ring < adapter->max_sds_rings; ring++) { + sds_ring = &recv_ctx->sds_rings[ring]; + qlcnic_disable_int(sds_ring); + napi_synchronize(&sds_ring->napi); + napi_disable(&sds_ring->napi); + } +} + +static void qlcnic_clear_stats(struct qlcnic_adapter *adapter) +{ + memset(&adapter->stats, 0, sizeof(adapter->stats)); + return; +} + +static int qlcnic_set_dma_mask(struct qlcnic_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + u64 mask, cmask; + + adapter->pci_using_dac = 0; + + mask = DMA_BIT_MASK(39); + cmask = mask; + + if (pci_set_dma_mask(pdev, mask) == 0 && + pci_set_consistent_dma_mask(pdev, cmask) == 0) { + adapter->pci_using_dac = 1; + return 0; + } + + return -EIO; +} + +/* Update addressable range if firmware supports it */ +static int +qlcnic_update_dma_mask(struct qlcnic_adapter *adapter) +{ + int change, shift, err; + u64 mask, old_mask, old_cmask; + struct pci_dev *pdev = adapter->pdev; + + change = 0; + + shift = QLCRD32(adapter, CRB_DMA_SHIFT); + if (shift > 32) + return 0; + + if (shift > 9) + change = 1; + + if (change) { + old_mask = pdev->dma_mask; + old_cmask = pdev->dev.coherent_dma_mask; + + mask = DMA_BIT_MASK(32+shift); + + err = pci_set_dma_mask(pdev, mask); + if (err) + goto err_out; + + err = pci_set_consistent_dma_mask(pdev, mask); + if (err) + goto err_out; + dev_info(&pdev->dev, "using %d-bit dma mask\n", 32+shift); + } + + return 0; + +err_out: + pci_set_dma_mask(pdev, old_mask); + pci_set_consistent_dma_mask(pdev, old_cmask); + return err; +} + +static void qlcnic_set_port_mode(struct qlcnic_adapter *adapter) +{ + u32 val, data; + + val = adapter->ahw.board_type; + if ((val == QLCNIC_BRDTYPE_P3_HMEZ) || + (val == QLCNIC_BRDTYPE_P3_XG_LOM)) { + if (port_mode == QLCNIC_PORT_MODE_802_3_AP) { + data = QLCNIC_PORT_MODE_802_3_AP; + QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data); + } else if (port_mode == QLCNIC_PORT_MODE_XG) { + data = QLCNIC_PORT_MODE_XG; + QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data); + } else if (port_mode == QLCNIC_PORT_MODE_AUTO_NEG_1G) { + data = QLCNIC_PORT_MODE_AUTO_NEG_1G; + QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data); + } else if (port_mode == QLCNIC_PORT_MODE_AUTO_NEG_XG) { + data = QLCNIC_PORT_MODE_AUTO_NEG_XG; + QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data); + } else { + data = QLCNIC_PORT_MODE_AUTO_NEG; + QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data); + } + + if ((wol_port_mode != QLCNIC_PORT_MODE_802_3_AP) && + (wol_port_mode != QLCNIC_PORT_MODE_XG) && + (wol_port_mode != QLCNIC_PORT_MODE_AUTO_NEG_1G) && + (wol_port_mode != QLCNIC_PORT_MODE_AUTO_NEG_XG)) { + wol_port_mode = QLCNIC_PORT_MODE_AUTO_NEG; + } + QLCWR32(adapter, QLCNIC_WOL_PORT_MODE, wol_port_mode); + } +} + +static void qlcnic_set_msix_bit(struct pci_dev *pdev, int enable) +{ + u32 control; + int pos; + + pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX); + if (pos) { + pci_read_config_dword(pdev, pos, &control); + if (enable) + control |= PCI_MSIX_FLAGS_ENABLE; + else + control = 0; + pci_write_config_dword(pdev, pos, control); + } +} + +static void qlcnic_init_msix_entries(struct qlcnic_adapter *adapter, int count) +{ + int i; + + for (i = 0; i < count; i++) + adapter->msix_entries[i].entry = i; +} + +static int +qlcnic_read_mac_addr(struct qlcnic_adapter *adapter) +{ + int i; + unsigned char *p; + u64 mac_addr; + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + + if (qlcnic_get_mac_addr(adapter, &mac_addr) != 0) + return -EIO; + + p = (unsigned char *)&mac_addr; + for (i = 0; i < 6; i++) + netdev->dev_addr[i] = *(p + 5 - i); + + memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len); + memcpy(adapter->mac_addr, netdev->dev_addr, netdev->addr_len); + + /* set station address */ + + if (!is_valid_ether_addr(netdev->perm_addr)) + dev_warn(&pdev->dev, "Bad MAC address %pM.\n", + netdev->dev_addr); + + return 0; +} + +static int qlcnic_set_mac(struct net_device *netdev, void *p) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + struct sockaddr *addr = p; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EINVAL; + + if (netif_running(netdev)) { + netif_device_detach(netdev); + qlcnic_napi_disable(adapter); + } + + memcpy(adapter->mac_addr, addr->sa_data, netdev->addr_len); + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); + qlcnic_set_multi(adapter->netdev); + + if (netif_running(netdev)) { + netif_device_attach(netdev); + qlcnic_napi_enable(adapter); + } + return 0; +} + +static const struct net_device_ops qlcnic_netdev_ops = { + .ndo_open = qlcnic_open, + .ndo_stop = qlcnic_close, + .ndo_start_xmit = qlcnic_xmit_frame, + .ndo_get_stats = qlcnic_get_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = qlcnic_set_multi, + .ndo_set_mac_address = qlcnic_set_mac, + .ndo_change_mtu = qlcnic_change_mtu, + .ndo_tx_timeout = qlcnic_tx_timeout, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = qlcnic_poll_controller, +#endif +}; + +static void +qlcnic_setup_intr(struct qlcnic_adapter *adapter) +{ + const struct qlcnic_legacy_intr_set *legacy_intrp; + struct pci_dev *pdev = adapter->pdev; + int err, num_msix; + + if (adapter->rss_supported) { + num_msix = (num_online_cpus() >= MSIX_ENTRIES_PER_ADAPTER) ? + MSIX_ENTRIES_PER_ADAPTER : 2; + } else + num_msix = 1; + + adapter->max_sds_rings = 1; + + adapter->flags &= ~(QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED); + + legacy_intrp = &legacy_intr[adapter->ahw.pci_func]; + + adapter->int_vec_bit = legacy_intrp->int_vec_bit; + adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter, + legacy_intrp->tgt_status_reg); + adapter->tgt_mask_reg = qlcnic_get_ioaddr(adapter, + legacy_intrp->tgt_mask_reg); + adapter->isr_int_vec = qlcnic_get_ioaddr(adapter, ISR_INT_VECTOR); + + adapter->crb_int_state_reg = qlcnic_get_ioaddr(adapter, + ISR_INT_STATE_REG); + + qlcnic_set_msix_bit(pdev, 0); + + if (adapter->msix_supported) { + + qlcnic_init_msix_entries(adapter, num_msix); + err = pci_enable_msix(pdev, adapter->msix_entries, num_msix); + if (err == 0) { + adapter->flags |= QLCNIC_MSIX_ENABLED; + qlcnic_set_msix_bit(pdev, 1); + + if (adapter->rss_supported) + adapter->max_sds_rings = num_msix; + + dev_info(&pdev->dev, "using msi-x interrupts\n"); + return; + } + + if (err > 0) + pci_disable_msix(pdev); + + /* fall through for msi */ + } + + if (use_msi && !pci_enable_msi(pdev)) { + adapter->flags |= QLCNIC_MSI_ENABLED; + adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter, + msi_tgt_status[adapter->ahw.pci_func]); + dev_info(&pdev->dev, "using msi interrupts\n"); + adapter->msix_entries[0].vector = pdev->irq; + return; + } + + dev_info(&pdev->dev, "using legacy interrupts\n"); + adapter->msix_entries[0].vector = pdev->irq; +} + +static void +qlcnic_teardown_intr(struct qlcnic_adapter *adapter) +{ + if (adapter->flags & QLCNIC_MSIX_ENABLED) + pci_disable_msix(adapter->pdev); + if (adapter->flags & QLCNIC_MSI_ENABLED) + pci_disable_msi(adapter->pdev); +} + +static void +qlcnic_cleanup_pci_map(struct qlcnic_adapter *adapter) +{ + if (adapter->ahw.pci_base0 != NULL) + iounmap(adapter->ahw.pci_base0); +} + +static int +qlcnic_setup_pci_map(struct qlcnic_adapter *adapter) +{ + void __iomem *mem_ptr0 = NULL; + resource_size_t mem_base; + unsigned long mem_len, pci_len0 = 0; + + struct pci_dev *pdev = adapter->pdev; + int pci_func = adapter->ahw.pci_func; + + /* + * Set the CRB window to invalid. If any register in window 0 is + * accessed it should set the window to 0 and then reset it to 1. + */ + adapter->ahw.crb_win = -1; + adapter->ahw.ocm_win = -1; + + /* remap phys address */ + mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */ + mem_len = pci_resource_len(pdev, 0); + + if (mem_len == QLCNIC_PCI_2MB_SIZE) { + + mem_ptr0 = pci_ioremap_bar(pdev, 0); + if (mem_ptr0 == NULL) { + dev_err(&pdev->dev, "failed to map PCI bar 0\n"); + return -EIO; + } + pci_len0 = mem_len; + } else { + return -EIO; + } + + dev_info(&pdev->dev, "%dMB memory map\n", (int)(mem_len>>20)); + + adapter->ahw.pci_base0 = mem_ptr0; + adapter->ahw.pci_len0 = pci_len0; + + adapter->ahw.ocm_win_crb = qlcnic_get_ioaddr(adapter, + QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(pci_func))); + + return 0; +} + +static void get_brd_name(struct qlcnic_adapter *adapter, char *name) +{ + struct pci_dev *pdev = adapter->pdev; + int i, found = 0; + + for (i = 0; i < NUM_SUPPORTED_BOARDS; ++i) { + if (qlcnic_boards[i].vendor == pdev->vendor && + qlcnic_boards[i].device == pdev->device && + qlcnic_boards[i].sub_vendor == pdev->subsystem_vendor && + qlcnic_boards[i].sub_device == pdev->subsystem_device) { + strcpy(name, qlcnic_boards[i].short_name); + found = 1; + break; + } + + } + + if (!found) + name = "Unknown"; +} + +static void +qlcnic_check_options(struct qlcnic_adapter *adapter) +{ + u32 fw_major, fw_minor, fw_build; + char brd_name[QLCNIC_MAX_BOARD_NAME_LEN]; + char serial_num[32]; + int i, offset, val; + int *ptr32; + struct pci_dev *pdev = adapter->pdev; + + adapter->driver_mismatch = 0; + + ptr32 = (int *)&serial_num; + offset = QLCNIC_FW_SERIAL_NUM_OFFSET; + for (i = 0; i < 8; i++) { + if (qlcnic_rom_fast_read(adapter, offset, &val) == -1) { + dev_err(&pdev->dev, "error reading board info\n"); + adapter->driver_mismatch = 1; + return; + } + ptr32[i] = cpu_to_le32(val); + offset += sizeof(u32); + } + + fw_major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR); + fw_minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR); + fw_build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB); + + adapter->fw_version = QLCNIC_VERSION_CODE(fw_major, fw_minor, fw_build); + + if (adapter->portnum == 0) { + get_brd_name(adapter, brd_name); + + pr_info("%s: %s Board Chip rev 0x%x\n", + module_name(THIS_MODULE), + brd_name, adapter->ahw.revision_id); + } + + if (adapter->fw_version < QLCNIC_VERSION_CODE(3, 4, 216)) { + adapter->driver_mismatch = 1; + dev_warn(&pdev->dev, "firmware version %d.%d.%d unsupported\n", + fw_major, fw_minor, fw_build); + return; + } + + i = QLCRD32(adapter, QLCNIC_SRE_MISC); + adapter->ahw.cut_through = (i & 0x8000) ? 1 : 0; + + dev_info(&pdev->dev, "firmware v%d.%d.%d [%s]\n", + fw_major, fw_minor, fw_build, + adapter->ahw.cut_through ? "cut-through" : "legacy"); + + if (adapter->fw_version >= QLCNIC_VERSION_CODE(4, 0, 222)) + adapter->capabilities = QLCRD32(adapter, CRB_FW_CAPABILITIES_1); + + adapter->flags &= ~QLCNIC_LRO_ENABLED; + + if (adapter->ahw.port_type == QLCNIC_XGBE) { + adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_10G; + adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G; + } else if (adapter->ahw.port_type == QLCNIC_GBE) { + adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_1G; + adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G; + } + + adapter->msix_supported = !!use_msi_x; + adapter->rss_supported = !!use_msi_x; + + adapter->num_txd = MAX_CMD_DESCRIPTORS; + + adapter->num_lro_rxd = 0; + adapter->max_rds_rings = 2; +} + +static int +qlcnic_start_firmware(struct qlcnic_adapter *adapter) +{ + int val, err, first_boot; + + err = qlcnic_set_dma_mask(adapter); + if (err) + return err; + + if (!qlcnic_can_start_firmware(adapter)) + goto wait_init; + + first_boot = QLCRD32(adapter, QLCNIC_CAM_RAM(0x1fc)); + if (first_boot == 0x55555555) + /* This is the first boot after power up */ + QLCWR32(adapter, QLCNIC_CAM_RAM(0x1fc), QLCNIC_BDINFO_MAGIC); + + qlcnic_request_firmware(adapter); + + err = qlcnic_need_fw_reset(adapter); + if (err < 0) + goto err_out; + if (err == 0) + goto wait_init; + + if (first_boot != 0x55555555) { + QLCWR32(adapter, CRB_CMDPEG_STATE, 0); + qlcnic_pinit_from_rom(adapter); + msleep(1); + } + + QLCWR32(adapter, CRB_DMA_SHIFT, 0x55555555); + QLCWR32(adapter, QLCNIC_PEG_HALT_STATUS1, 0); + QLCWR32(adapter, QLCNIC_PEG_HALT_STATUS2, 0); + + qlcnic_set_port_mode(adapter); + + err = qlcnic_load_firmware(adapter); + if (err) + goto err_out; + + qlcnic_release_firmware(adapter); + + val = (_QLCNIC_LINUX_MAJOR << 16) + | ((_QLCNIC_LINUX_MINOR << 8)) + | (_QLCNIC_LINUX_SUBVERSION); + QLCWR32(adapter, CRB_DRIVER_VERSION, val); + +wait_init: + /* Handshake with the card before we register the devices. */ + err = qlcnic_phantom_init(adapter); + if (err) + goto err_out; + + QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_READY); + + qlcnic_update_dma_mask(adapter); + + qlcnic_check_options(adapter); + + adapter->need_fw_reset = 0; + + /* fall through and release firmware */ + +err_out: + qlcnic_release_firmware(adapter); + return err; +} + +static int +qlcnic_request_irq(struct qlcnic_adapter *adapter) +{ + irq_handler_t handler; + struct qlcnic_host_sds_ring *sds_ring; + int err, ring; + + unsigned long flags = 0; + struct net_device *netdev = adapter->netdev; + struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + + if (adapter->flags & QLCNIC_MSIX_ENABLED) + handler = qlcnic_msix_intr; + else if (adapter->flags & QLCNIC_MSI_ENABLED) + handler = qlcnic_msi_intr; + else { + flags |= IRQF_SHARED; + handler = qlcnic_intr; + } + adapter->irq = netdev->irq; + + for (ring = 0; ring < adapter->max_sds_rings; ring++) { + sds_ring = &recv_ctx->sds_rings[ring]; + sprintf(sds_ring->name, "%s[%d]", netdev->name, ring); + err = request_irq(sds_ring->irq, handler, + flags, sds_ring->name, sds_ring); + if (err) + return err; + } + + return 0; +} + +static void +qlcnic_free_irq(struct qlcnic_adapter *adapter) +{ + int ring; + struct qlcnic_host_sds_ring *sds_ring; + + struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + + for (ring = 0; ring < adapter->max_sds_rings; ring++) { + sds_ring = &recv_ctx->sds_rings[ring]; + free_irq(sds_ring->irq, sds_ring); + } +} + +static void +qlcnic_init_coalesce_defaults(struct qlcnic_adapter *adapter) +{ + adapter->coal.flags = QLCNIC_INTR_DEFAULT; + adapter->coal.normal.data.rx_time_us = + QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US; + adapter->coal.normal.data.rx_packets = + QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS; + adapter->coal.normal.data.tx_time_us = + QLCNIC_DEFAULT_INTR_COALESCE_TX_TIME_US; + adapter->coal.normal.data.tx_packets = + QLCNIC_DEFAULT_INTR_COALESCE_TX_PACKETS; +} + +static int +__qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev) +{ + if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) + return -EIO; + + qlcnic_set_multi(netdev); + qlcnic_fw_cmd_set_mtu(adapter, netdev->mtu); + + adapter->ahw.linkup = 0; + + if (adapter->max_sds_rings > 1) + qlcnic_config_rss(adapter, 1); + + qlcnic_config_intr_coalesce(adapter); + + if (adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO) + qlcnic_config_hw_lro(adapter, QLCNIC_LRO_ENABLED); + + qlcnic_napi_enable(adapter); + + qlcnic_linkevent_request(adapter, 1); + + set_bit(__QLCNIC_DEV_UP, &adapter->state); + return 0; +} + +/* Usage: During resume and firmware recovery module.*/ + +static int +qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev) +{ + int err = 0; + + rtnl_lock(); + if (netif_running(netdev)) + err = __qlcnic_up(adapter, netdev); + rtnl_unlock(); + + return err; +} + +static void +__qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev) +{ + if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) + return; + + if (!test_and_clear_bit(__QLCNIC_DEV_UP, &adapter->state)) + return; + + smp_mb(); + spin_lock(&adapter->tx_clean_lock); + netif_carrier_off(netdev); + netif_tx_disable(netdev); + + qlcnic_free_mac_list(adapter); + + qlcnic_nic_set_promisc(adapter, QLCNIC_NIU_NON_PROMISC_MODE); + + qlcnic_napi_disable(adapter); + + qlcnic_release_tx_buffers(adapter); + spin_unlock(&adapter->tx_clean_lock); +} + +/* Usage: During suspend and firmware recovery module */ + +static void +qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev) +{ + rtnl_lock(); + if (netif_running(netdev)) + __qlcnic_down(adapter, netdev); + rtnl_unlock(); + +} + +static int +qlcnic_attach(struct qlcnic_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + int err, ring; + struct qlcnic_host_rds_ring *rds_ring; + + if (adapter->is_up == QLCNIC_ADAPTER_UP_MAGIC) + return 0; + + err = qlcnic_init_firmware(adapter); + if (err) + return err; + + err = qlcnic_napi_add(adapter, netdev); + if (err) + return err; + + err = qlcnic_alloc_sw_resources(adapter); + if (err) { + dev_err(&pdev->dev, "Error in setting sw resources\n"); + return err; + } + + err = qlcnic_alloc_hw_resources(adapter); + if (err) { + dev_err(&pdev->dev, "Error in setting hw resources\n"); + goto err_out_free_sw; + } + + + for (ring = 0; ring < adapter->max_rds_rings; ring++) { + rds_ring = &adapter->recv_ctx.rds_rings[ring]; + qlcnic_post_rx_buffers(adapter, ring, rds_ring); + } + + err = qlcnic_request_irq(adapter); + if (err) { + dev_err(&pdev->dev, "failed to setup interrupt\n"); + goto err_out_free_rxbuf; + } + + qlcnic_init_coalesce_defaults(adapter); + + qlcnic_create_sysfs_entries(adapter); + + adapter->is_up = QLCNIC_ADAPTER_UP_MAGIC; + return 0; + +err_out_free_rxbuf: + qlcnic_release_rx_buffers(adapter); + qlcnic_free_hw_resources(adapter); +err_out_free_sw: + qlcnic_free_sw_resources(adapter); + return err; +} + +static void +qlcnic_detach(struct qlcnic_adapter *adapter) +{ + if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) + return; + + qlcnic_remove_sysfs_entries(adapter); + + qlcnic_free_hw_resources(adapter); + qlcnic_release_rx_buffers(adapter); + qlcnic_free_irq(adapter); + qlcnic_napi_del(adapter); + qlcnic_free_sw_resources(adapter); + + adapter->is_up = 0; +} + +int +qlcnic_reset_context(struct qlcnic_adapter *adapter) +{ + int err = 0; + struct net_device *netdev = adapter->netdev; + + if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) + return -EBUSY; + + if (adapter->is_up == QLCNIC_ADAPTER_UP_MAGIC) { + + netif_device_detach(netdev); + + if (netif_running(netdev)) + __qlcnic_down(adapter, netdev); + + qlcnic_detach(adapter); + + if (netif_running(netdev)) { + err = qlcnic_attach(adapter); + if (!err) + err = __qlcnic_up(adapter, netdev); + + if (err) + goto done; + } + + netif_device_attach(netdev); + } + +done: + clear_bit(__QLCNIC_RESETTING, &adapter->state); + return err; +} + +static int +qlcnic_setup_netdev(struct qlcnic_adapter *adapter, + struct net_device *netdev) +{ + int err; + struct pci_dev *pdev = adapter->pdev; + + adapter->rx_csum = 1; + adapter->mc_enabled = 0; + adapter->max_mc_count = 38; + + netdev->netdev_ops = &qlcnic_netdev_ops; + netdev->watchdog_timeo = 2*HZ; + + qlcnic_change_mtu(netdev, netdev->mtu); + + SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_ops); + + netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO); + netdev->features |= (NETIF_F_GRO); + netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO); + + netdev->features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6); + netdev->vlan_features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6); + + if (adapter->pci_using_dac) { + netdev->features |= NETIF_F_HIGHDMA; + netdev->vlan_features |= NETIF_F_HIGHDMA; + } + + if (adapter->capabilities & QLCNIC_FW_CAPABILITY_FVLANTX) + netdev->features |= (NETIF_F_HW_VLAN_TX); + + if (adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO) + netdev->features |= NETIF_F_LRO; + + netdev->irq = adapter->msix_entries[0].vector; + + INIT_WORK(&adapter->tx_timeout_task, qlcnic_tx_timeout_task); + + if (qlcnic_read_mac_addr(adapter)) + dev_warn(&pdev->dev, "failed to read mac addr\n"); + + netif_carrier_off(netdev); + netif_stop_queue(netdev); + + err = register_netdev(netdev); + if (err) { + dev_err(&pdev->dev, "failed to register net device\n"); + return err; + } + + return 0; +} + +static int __devinit +qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct net_device *netdev = NULL; + struct qlcnic_adapter *adapter = NULL; + int err; + int pci_func_id = PCI_FUNC(pdev->devfn); + uint8_t revision_id; + + err = pci_enable_device(pdev); + if (err) + return err; + + if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { + err = -ENODEV; + goto err_out_disable_pdev; + } + + err = pci_request_regions(pdev, qlcnic_driver_name); + if (err) + goto err_out_disable_pdev; + + pci_set_master(pdev); + + netdev = alloc_etherdev(sizeof(struct qlcnic_adapter)); + if (!netdev) { + dev_err(&pdev->dev, "failed to allocate net_device\n"); + err = -ENOMEM; + goto err_out_free_res; + } + + SET_NETDEV_DEV(netdev, &pdev->dev); + + adapter = netdev_priv(netdev); + adapter->netdev = netdev; + adapter->pdev = pdev; + adapter->ahw.pci_func = pci_func_id; + + revision_id = pdev->revision; + adapter->ahw.revision_id = revision_id; + + rwlock_init(&adapter->ahw.crb_lock); + mutex_init(&adapter->ahw.mem_lock); + + spin_lock_init(&adapter->tx_clean_lock); + INIT_LIST_HEAD(&adapter->mac_list); + + err = qlcnic_setup_pci_map(adapter); + if (err) + goto err_out_free_netdev; + + /* This will be reset for mezz cards */ + adapter->portnum = pci_func_id; + + err = qlcnic_get_board_info(adapter); + if (err) { + dev_err(&pdev->dev, "Error getting board config info.\n"); + goto err_out_iounmap; + } + + + err = qlcnic_start_firmware(adapter); + if (err) + goto err_out_decr_ref; + + /* + * See if the firmware gave us a virtual-physical port mapping. + */ + adapter->physical_port = adapter->portnum; + + qlcnic_clear_stats(adapter); + + qlcnic_setup_intr(adapter); + + err = qlcnic_setup_netdev(adapter, netdev); + if (err) + goto err_out_disable_msi; + + pci_set_drvdata(pdev, adapter); + + qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY); + + switch (adapter->ahw.port_type) { + case QLCNIC_GBE: + dev_info(&adapter->pdev->dev, "%s: GbE port initialized\n", + adapter->netdev->name); + break; + case QLCNIC_XGBE: + dev_info(&adapter->pdev->dev, "%s: XGbE port initialized\n", + adapter->netdev->name); + break; + } + + qlcnic_create_diag_entries(adapter); + + return 0; + +err_out_disable_msi: + qlcnic_teardown_intr(adapter); + +err_out_decr_ref: + qlcnic_clr_all_drv_state(adapter); + +err_out_iounmap: + qlcnic_cleanup_pci_map(adapter); + +err_out_free_netdev: + free_netdev(netdev); + +err_out_free_res: + pci_release_regions(pdev); + +err_out_disable_pdev: + pci_set_drvdata(pdev, NULL); + pci_disable_device(pdev); + return err; +} + +static void __devexit qlcnic_remove(struct pci_dev *pdev) +{ + struct qlcnic_adapter *adapter; + struct net_device *netdev; + + adapter = pci_get_drvdata(pdev); + if (adapter == NULL) + return; + + netdev = adapter->netdev; + + qlcnic_cancel_fw_work(adapter); + + unregister_netdev(netdev); + + cancel_work_sync(&adapter->tx_timeout_task); + + qlcnic_detach(adapter); + + qlcnic_clr_all_drv_state(adapter); + + clear_bit(__QLCNIC_RESETTING, &adapter->state); + + qlcnic_teardown_intr(adapter); + + qlcnic_remove_diag_entries(adapter); + + qlcnic_cleanup_pci_map(adapter); + + qlcnic_release_firmware(adapter); + + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + + free_netdev(netdev); +} +static int __qlcnic_shutdown(struct pci_dev *pdev) +{ + struct qlcnic_adapter *adapter = pci_get_drvdata(pdev); + struct net_device *netdev = adapter->netdev; + int retval; + + netif_device_detach(netdev); + + qlcnic_cancel_fw_work(adapter); + + if (netif_running(netdev)) + qlcnic_down(adapter, netdev); + + cancel_work_sync(&adapter->tx_timeout_task); + + qlcnic_detach(adapter); + + qlcnic_clr_all_drv_state(adapter); + + clear_bit(__QLCNIC_RESETTING, &adapter->state); + + retval = pci_save_state(pdev); + if (retval) + return retval; + + if (qlcnic_wol_supported(adapter)) { + pci_enable_wake(pdev, PCI_D3cold, 1); + pci_enable_wake(pdev, PCI_D3hot, 1); + } + + return 0; +} + +static void qlcnic_shutdown(struct pci_dev *pdev) +{ + if (__qlcnic_shutdown(pdev)) + return; + + pci_disable_device(pdev); +} + +#ifdef CONFIG_PM +static int +qlcnic_suspend(struct pci_dev *pdev, pm_message_t state) +{ + int retval; + + retval = __qlcnic_shutdown(pdev); + if (retval) + return retval; + + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + return 0; +} + +static int +qlcnic_resume(struct pci_dev *pdev) +{ + struct qlcnic_adapter *adapter = pci_get_drvdata(pdev); + struct net_device *netdev = adapter->netdev; + int err; + + err = pci_enable_device(pdev); + if (err) + return err; + + pci_set_power_state(pdev, PCI_D0); + pci_set_master(pdev); + pci_restore_state(pdev); + + adapter->ahw.crb_win = -1; + adapter->ahw.ocm_win = -1; + + err = qlcnic_start_firmware(adapter); + if (err) { + dev_err(&pdev->dev, "failed to start firmware\n"); + return err; + } + + if (netif_running(netdev)) { + err = qlcnic_attach(adapter); + if (err) + goto err_out; + + err = qlcnic_up(adapter, netdev); + if (err) + goto err_out_detach; + + + qlcnic_config_indev_addr(netdev, NETDEV_UP); + } + + netif_device_attach(netdev); + qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY); + return 0; + +err_out_detach: + qlcnic_detach(adapter); +err_out: + qlcnic_clr_all_drv_state(adapter); + return err; +} +#endif + +static int qlcnic_open(struct net_device *netdev) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + int err; + + if (adapter->driver_mismatch) + return -EIO; + + err = qlcnic_attach(adapter); + if (err) + return err; + + err = __qlcnic_up(adapter, netdev); + if (err) + goto err_out; + + netif_start_queue(netdev); + + return 0; + +err_out: + qlcnic_detach(adapter); + return err; +} + +/* + * qlcnic_close - Disables a network interface entry point + */ +static int qlcnic_close(struct net_device *netdev) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + + __qlcnic_down(adapter, netdev); + return 0; +} + +static void +qlcnic_tso_check(struct net_device *netdev, + struct qlcnic_host_tx_ring *tx_ring, + struct cmd_desc_type0 *first_desc, + struct sk_buff *skb) +{ + u8 opcode = TX_ETHER_PKT; + __be16 protocol = skb->protocol; + u16 flags = 0, vid = 0; + u32 producer; + int copied, offset, copy_len, hdr_len = 0, tso = 0, vlan_oob = 0; + struct cmd_desc_type0 *hwdesc; + struct vlan_ethhdr *vh; + + if (protocol == cpu_to_be16(ETH_P_8021Q)) { + + vh = (struct vlan_ethhdr *)skb->data; + protocol = vh->h_vlan_encapsulated_proto; + flags = FLAGS_VLAN_TAGGED; + + } else if (vlan_tx_tag_present(skb)) { + + flags = FLAGS_VLAN_OOB; + vid = vlan_tx_tag_get(skb); + qlcnic_set_tx_vlan_tci(first_desc, vid); + vlan_oob = 1; + } + + if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) && + skb_shinfo(skb)->gso_size > 0) { + + 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; + if (vlan_oob) { + first_desc->total_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; + } + + opcode = (protocol == cpu_to_be16(ETH_P_IPV6)) ? + TX_TCP_LSO6 : TX_TCP_LSO; + tso = 1; + + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { + u8 l4proto; + + if (protocol == cpu_to_be16(ETH_P_IP)) { + l4proto = ip_hdr(skb)->protocol; + + if (l4proto == IPPROTO_TCP) + opcode = TX_TCP_PKT; + else if (l4proto == IPPROTO_UDP) + opcode = TX_UDP_PKT; + } else if (protocol == cpu_to_be16(ETH_P_IPV6)) { + l4proto = ipv6_hdr(skb)->nexthdr; + + if (l4proto == IPPROTO_TCP) + opcode = TX_TCPV6_PKT; + else if (l4proto == IPPROTO_UDP) + opcode = TX_UDPV6_PKT; + } + } + + first_desc->tcp_hdr_offset += skb_transport_offset(skb); + first_desc->ip_hdr_offset += skb_network_offset(skb); + qlcnic_set_tx_flags_opcode(first_desc, flags, opcode); + + if (!tso) + return; + + /* For LSO, we need to copy the MAC/IP/TCP headers into + * the descriptor ring + */ + producer = tx_ring->producer; + copied = 0; + offset = 2; + + if (vlan_oob) { + /* Create a TSO vlan header template for firmware */ + + hwdesc = &tx_ring->desc_head[producer]; + tx_ring->cmd_buf_arr[producer].skb = NULL; + + copy_len = min((int)sizeof(struct cmd_desc_type0) - offset, + hdr_len + VLAN_HLEN); + + vh = (struct vlan_ethhdr *)((char *)hwdesc + 2); + skb_copy_from_linear_data(skb, vh, 12); + vh->h_vlan_proto = htons(ETH_P_8021Q); + vh->h_vlan_TCI = htons(vid); + skb_copy_from_linear_data_offset(skb, 12, + (char *)vh + 16, copy_len - 16); + + copied = copy_len - VLAN_HLEN; + offset = 0; + + producer = get_next_index(producer, tx_ring->num_desc); + } + + while (copied < hdr_len) { + + copy_len = min((int)sizeof(struct cmd_desc_type0) - offset, + (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 + offset, copy_len); + + copied += copy_len; + offset = 0; + + producer = get_next_index(producer, tx_ring->num_desc); + } + + tx_ring->producer = producer; + barrier(); +} + +static int +qlcnic_map_tx_skb(struct pci_dev *pdev, + struct sk_buff *skb, struct qlcnic_cmd_buffer *pbuf) +{ + struct qlcnic_skb_frag *nf; + struct skb_frag_struct *frag; + int i, nr_frags; + dma_addr_t map; + + nr_frags = skb_shinfo(skb)->nr_frags; + nf = &pbuf->frag_array[0]; + + map = pci_map_single(pdev, skb->data, + skb_headlen(skb), PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(pdev, map)) + goto out_err; + + nf->dma = map; + nf->length = skb_headlen(skb); + + for (i = 0; i < nr_frags; i++) { + frag = &skb_shinfo(skb)->frags[i]; + nf = &pbuf->frag_array[i+1]; + + map = pci_map_page(pdev, frag->page, frag->page_offset, + frag->size, PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(pdev, map)) + goto unwind; + + nf->dma = map; + nf->length = frag->size; + } + + return 0; + +unwind: + while (--i >= 0) { + nf = &pbuf->frag_array[i+1]; + pci_unmap_page(pdev, nf->dma, nf->length, PCI_DMA_TODEVICE); + } + + nf = &pbuf->frag_array[0]; + pci_unmap_single(pdev, nf->dma, skb_headlen(skb), PCI_DMA_TODEVICE); + +out_err: + return -ENOMEM; +} + +static inline void +qlcnic_clear_cmddesc(u64 *desc) +{ + desc[0] = 0ULL; + desc[2] = 0ULL; +} + +static netdev_tx_t +qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring; + struct qlcnic_cmd_buffer *pbuf; + struct qlcnic_skb_frag *buffrag; + struct cmd_desc_type0 *hwdesc, *first_desc; + struct pci_dev *pdev; + int i, k; + + u32 producer; + int frag_count, no_of_desc; + u32 num_txd = tx_ring->num_desc; + + frag_count = skb_shinfo(skb)->nr_frags + 1; + + /* 4 fragments per cmd des */ + no_of_desc = (frag_count + 3) >> 2; + + if (unlikely(no_of_desc + 2 > qlcnic_tx_avail(tx_ring))) { + netif_stop_queue(netdev); + return NETDEV_TX_BUSY; + } + + producer = tx_ring->producer; + pbuf = &tx_ring->cmd_buf_arr[producer]; + + pdev = adapter->pdev; + + if (qlcnic_map_tx_skb(pdev, skb, pbuf)) + goto drop_packet; + + pbuf->skb = skb; + pbuf->frag_count = frag_count; + + first_desc = hwdesc = &tx_ring->desc_head[producer]; + qlcnic_clear_cmddesc((u64 *)hwdesc); + + qlcnic_set_tx_frags_len(first_desc, frag_count, skb->len); + qlcnic_set_tx_port(first_desc, adapter->portnum); + + for (i = 0; i < frag_count; i++) { + + k = i % 4; + + if ((k == 0) && (i > 0)) { + /* move to next desc.*/ + producer = get_next_index(producer, num_txd); + hwdesc = &tx_ring->desc_head[producer]; + qlcnic_clear_cmddesc((u64 *)hwdesc); + tx_ring->cmd_buf_arr[producer].skb = NULL; + } + + buffrag = &pbuf->frag_array[i]; + + hwdesc->buffer_length[k] = cpu_to_le16(buffrag->length); + switch (k) { + case 0: + hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma); + break; + case 1: + hwdesc->addr_buffer2 = cpu_to_le64(buffrag->dma); + break; + case 2: + hwdesc->addr_buffer3 = cpu_to_le64(buffrag->dma); + break; + case 3: + hwdesc->addr_buffer4 = cpu_to_le64(buffrag->dma); + break; + } + } + + tx_ring->producer = get_next_index(producer, num_txd); + + qlcnic_tso_check(netdev, tx_ring, first_desc, skb); + + qlcnic_update_cmd_producer(adapter, tx_ring); + + adapter->stats.txbytes += skb->len; + adapter->stats.xmitcalled++; + + return NETDEV_TX_OK; + +drop_packet: + adapter->stats.txdropped++; + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; +} + +static int qlcnic_check_temp(struct qlcnic_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + u32 temp, temp_state, temp_val; + int rv = 0; + + temp = QLCRD32(adapter, CRB_TEMP_STATE); + + temp_state = qlcnic_get_temp_state(temp); + temp_val = qlcnic_get_temp_val(temp); + + if (temp_state == QLCNIC_TEMP_PANIC) { + dev_err(&netdev->dev, + "Device temperature %d degrees C exceeds" + " maximum allowed. Hardware has been shut down.\n", + temp_val); + rv = 1; + } else if (temp_state == QLCNIC_TEMP_WARN) { + if (adapter->temp == QLCNIC_TEMP_NORMAL) { + dev_err(&netdev->dev, + "Device temperature %d degrees C " + "exceeds operating range." + " Immediate action needed.\n", + temp_val); + } + } else { + if (adapter->temp == QLCNIC_TEMP_WARN) { + dev_info(&netdev->dev, + "Device temperature is now %d degrees C" + " in normal range.\n", temp_val); + } + } + adapter->temp = temp_state; + return rv; +} + +void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup) +{ + struct net_device *netdev = adapter->netdev; + + if (adapter->ahw.linkup && !linkup) { + dev_info(&netdev->dev, "NIC Link is down\n"); + adapter->ahw.linkup = 0; + if (netif_running(netdev)) { + netif_carrier_off(netdev); + netif_stop_queue(netdev); + } + } else if (!adapter->ahw.linkup && linkup) { + dev_info(&netdev->dev, "NIC Link is up\n"); + adapter->ahw.linkup = 1; + if (netif_running(netdev)) { + netif_carrier_on(netdev); + netif_wake_queue(netdev); + } + } +} + +static void qlcnic_tx_timeout(struct net_device *netdev) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + + if (test_bit(__QLCNIC_RESETTING, &adapter->state)) + return; + + dev_err(&netdev->dev, "transmit timeout, resetting.\n"); + schedule_work(&adapter->tx_timeout_task); +} + +static void qlcnic_tx_timeout_task(struct work_struct *work) +{ + struct qlcnic_adapter *adapter = + container_of(work, struct qlcnic_adapter, tx_timeout_task); + + if (!netif_running(adapter->netdev)) + return; + + if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) + return; + + if (++adapter->tx_timeo_cnt >= QLCNIC_MAX_TX_TIMEOUTS) + goto request_reset; + + clear_bit(__QLCNIC_RESETTING, &adapter->state); + if (!qlcnic_reset_context(adapter)) { + adapter->netdev->trans_start = jiffies; + return; + + /* context reset failed, fall through for fw reset */ + } + +request_reset: + adapter->need_fw_reset = 1; + clear_bit(__QLCNIC_RESETTING, &adapter->state); +} + +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; + + memset(stats, 0, sizeof(*stats)); + + stats->rx_packets = adapter->stats.rx_pkts + adapter->stats.lro_pkts; + stats->tx_packets = adapter->stats.xmitfinished; + stats->rx_bytes = adapter->stats.rxbytes; + stats->tx_bytes = adapter->stats.txbytes; + stats->rx_dropped = adapter->stats.rxdropped; + stats->tx_dropped = adapter->stats.txdropped; + + return stats; +} + +static irqreturn_t qlcnic_intr(int irq, void *data) +{ + struct qlcnic_host_sds_ring *sds_ring = data; + struct qlcnic_adapter *adapter = sds_ring->adapter; + u32 status; + + status = readl(adapter->isr_int_vec); + + if (!(status & adapter->int_vec_bit)) + return IRQ_NONE; + + /* check interrupt state machine, to be sure */ + status = readl(adapter->crb_int_state_reg); + if (!ISR_LEGACY_INT_TRIGGERED(status)) + return IRQ_NONE; + + writel(0xffffffff, adapter->tgt_status_reg); + /* read twice to ensure write is flushed */ + readl(adapter->isr_int_vec); + readl(adapter->isr_int_vec); + + napi_schedule(&sds_ring->napi); + + return IRQ_HANDLED; +} + +static irqreturn_t qlcnic_msi_intr(int irq, void *data) +{ + struct qlcnic_host_sds_ring *sds_ring = data; + struct qlcnic_adapter *adapter = sds_ring->adapter; + + /* clear interrupt */ + writel(0xffffffff, adapter->tgt_status_reg); + + napi_schedule(&sds_ring->napi); + return IRQ_HANDLED; +} + +static irqreturn_t qlcnic_msix_intr(int irq, void *data) +{ + struct qlcnic_host_sds_ring *sds_ring = data; + + napi_schedule(&sds_ring->napi); + return IRQ_HANDLED; +} + +static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter) +{ + u32 sw_consumer, hw_consumer; + int count = 0, i; + struct qlcnic_cmd_buffer *buffer; + struct pci_dev *pdev = adapter->pdev; + struct net_device *netdev = adapter->netdev; + struct qlcnic_skb_frag *frag; + int done; + struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring; + + if (!spin_trylock(&adapter->tx_clean_lock)) + return 1; + + sw_consumer = tx_ring->sw_consumer; + hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer)); + + while (sw_consumer != hw_consumer) { + buffer = &tx_ring->cmd_buf_arr[sw_consumer]; + if (buffer->skb) { + frag = &buffer->frag_array[0]; + pci_unmap_single(pdev, frag->dma, frag->length, + PCI_DMA_TODEVICE); + frag->dma = 0ULL; + for (i = 1; i < buffer->frag_count; i++) { + frag++; + pci_unmap_page(pdev, frag->dma, frag->length, + PCI_DMA_TODEVICE); + frag->dma = 0ULL; + } + + adapter->stats.xmitfinished++; + dev_kfree_skb_any(buffer->skb); + buffer->skb = NULL; + } + + sw_consumer = get_next_index(sw_consumer, tx_ring->num_desc); + if (++count >= MAX_STATUS_HANDLE) + break; + } + + if (count && netif_running(netdev)) { + tx_ring->sw_consumer = sw_consumer; + + smp_mb(); + + if (netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) { + __netif_tx_lock(tx_ring->txq, smp_processor_id()); + if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) { + netif_wake_queue(netdev); + adapter->tx_timeo_cnt = 0; + } + __netif_tx_unlock(tx_ring->txq); + } + } + /* + * If everything is freed up to consumer then check if the ring is full + * If the ring is full then check if more needs to be freed and + * schedule the call back again. + * + * This happens when there are 2 CPUs. One could be freeing and the + * other filling it. If the ring is full when we get out of here and + * the card has already interrupted the host then the host can miss the + * interrupt. + * + * There is still a possible race condition and the host could miss an + * interrupt. The card has to take care of this. + */ + hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer)); + done = (sw_consumer == hw_consumer); + spin_unlock(&adapter->tx_clean_lock); + + return done; +} + +static int qlcnic_poll(struct napi_struct *napi, int budget) +{ + struct qlcnic_host_sds_ring *sds_ring = + container_of(napi, struct qlcnic_host_sds_ring, napi); + + struct qlcnic_adapter *adapter = sds_ring->adapter; + + int tx_complete; + int work_done; + + tx_complete = qlcnic_process_cmd_ring(adapter); + + work_done = qlcnic_process_rcv_ring(sds_ring, 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); + } + + return work_done; +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void qlcnic_poll_controller(struct net_device *netdev) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + disable_irq(adapter->irq); + qlcnic_intr(adapter->irq, adapter); + enable_irq(adapter->irq); +} +#endif + +static void +qlcnic_set_drv_state(struct qlcnic_adapter *adapter, int state) +{ + u32 val; + + WARN_ON(state != QLCNIC_DEV_NEED_RESET && + state != QLCNIC_DEV_NEED_QUISCENT); + + if (qlcnic_api_lock(adapter)) + return ; + + val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE); + + if (state == QLCNIC_DEV_NEED_RESET) + val |= ((u32)0x1 << (adapter->portnum * 4)); + else if (state == QLCNIC_DEV_NEED_QUISCENT) + val |= ((u32)0x1 << ((adapter->portnum * 4) + 1)); + + QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val); + + qlcnic_api_unlock(adapter); +} + +static void +qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter) +{ + u32 val; + + if (qlcnic_api_lock(adapter)) + goto err; + + val = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT); + val &= ~((u32)0x1 << (adapter->portnum * 4)); + QLCWR32(adapter, QLCNIC_CRB_DEV_REF_COUNT, val); + + if (!(val & 0x11111111)) + QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_COLD); + + val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE); + val &= ~((u32)0x3 << (adapter->portnum * 4)); + QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val); + + qlcnic_api_unlock(adapter); +err: + adapter->fw_fail_cnt = 0; + clear_bit(__QLCNIC_START_FW, &adapter->state); + clear_bit(__QLCNIC_RESETTING, &adapter->state); +} + +static int +qlcnic_check_drv_state(struct qlcnic_adapter *adapter) +{ + int act, state; + + state = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE); + act = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT); + + if (((state & 0x11111111) == (act & 0x11111111)) || + ((act & 0x11111111) == ((state >> 1) & 0x11111111))) + return 0; + else + return 1; +} + +static int +qlcnic_can_start_firmware(struct qlcnic_adapter *adapter) +{ + u32 val, prev_state; + int cnt = 0; + int portnum = adapter->portnum; + + if (qlcnic_api_lock(adapter)) + return -1; + + val = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT); + if (!(val & ((int)0x1 << (portnum * 4)))) { + val |= ((u32)0x1 << (portnum * 4)); + QLCWR32(adapter, QLCNIC_CRB_DEV_REF_COUNT, val); + } else if (test_and_clear_bit(__QLCNIC_START_FW, &adapter->state)) { + goto start_fw; + } + + prev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); + + switch (prev_state) { + case QLCNIC_DEV_COLD: +start_fw: + QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITALIZING); + qlcnic_api_unlock(adapter); + return 1; + + case QLCNIC_DEV_READY: + qlcnic_api_unlock(adapter); + return 0; + + case QLCNIC_DEV_NEED_RESET: + val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE); + val |= ((u32)0x1 << (portnum * 4)); + QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val); + break; + + case QLCNIC_DEV_NEED_QUISCENT: + val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE); + val |= ((u32)0x1 << ((portnum * 4) + 1)); + QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val); + break; + + case QLCNIC_DEV_FAILED: + qlcnic_api_unlock(adapter); + return -1; + } + + qlcnic_api_unlock(adapter); + msleep(1000); + while ((QLCRD32(adapter, QLCNIC_CRB_DEV_STATE) != QLCNIC_DEV_READY) && + ++cnt < 20) + msleep(1000); + + if (cnt >= 20) + return -1; + + if (qlcnic_api_lock(adapter)) + return -1; + + val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE); + val &= ~((u32)0x3 << (portnum * 4)); + QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val); + + qlcnic_api_unlock(adapter); + + return 0; +} + +static void +qlcnic_fwinit_work(struct work_struct *work) +{ + struct qlcnic_adapter *adapter = container_of(work, + struct qlcnic_adapter, fw_work.work); + int dev_state; + + if (++adapter->fw_wait_cnt > FW_POLL_THRESH) + goto err_ret; + + if (test_bit(__QLCNIC_START_FW, &adapter->state)) { + + if (qlcnic_check_drv_state(adapter)) { + qlcnic_schedule_work(adapter, + qlcnic_fwinit_work, FW_POLL_DELAY); + return; + } + + if (!qlcnic_start_firmware(adapter)) { + qlcnic_schedule_work(adapter, qlcnic_attach_work, 0); + return; + } + + goto err_ret; + } + + dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); + switch (dev_state) { + case QLCNIC_DEV_READY: + if (!qlcnic_start_firmware(adapter)) { + qlcnic_schedule_work(adapter, qlcnic_attach_work, 0); + return; + } + case QLCNIC_DEV_FAILED: + break; + + default: + qlcnic_schedule_work(adapter, + qlcnic_fwinit_work, 2 * FW_POLL_DELAY); + return; + } + +err_ret: + qlcnic_clr_all_drv_state(adapter); +} + +static void +qlcnic_detach_work(struct work_struct *work) +{ + struct qlcnic_adapter *adapter = container_of(work, + struct qlcnic_adapter, fw_work.work); + struct net_device *netdev = adapter->netdev; + u32 status; + + netif_device_detach(netdev); + + qlcnic_down(adapter, netdev); + + qlcnic_detach(adapter); + + status = QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1); + + if (status & QLCNIC_RCODE_FATAL_ERROR) + goto err_ret; + + if (adapter->temp == QLCNIC_TEMP_PANIC) + goto err_ret; + + qlcnic_set_drv_state(adapter, adapter->dev_state); + + adapter->fw_wait_cnt = 0; + + qlcnic_schedule_work(adapter, qlcnic_fwinit_work, FW_POLL_DELAY); + + return; + +err_ret: + qlcnic_clr_all_drv_state(adapter); + +} + +static void +qlcnic_dev_request_reset(struct qlcnic_adapter *adapter) +{ + u32 state; + + if (qlcnic_api_lock(adapter)) + return; + + state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); + + if (state != QLCNIC_DEV_INITALIZING && state != QLCNIC_DEV_NEED_RESET) { + QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_RESET); + set_bit(__QLCNIC_START_FW, &adapter->state); + } + + qlcnic_api_unlock(adapter); +} + +static void +qlcnic_schedule_work(struct qlcnic_adapter *adapter, + work_func_t func, int delay) +{ + INIT_DELAYED_WORK(&adapter->fw_work, func); + schedule_delayed_work(&adapter->fw_work, round_jiffies_relative(delay)); +} + +static void +qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter) +{ + while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) + msleep(10); + + cancel_delayed_work_sync(&adapter->fw_work); +} + +static void +qlcnic_attach_work(struct work_struct *work) +{ + struct qlcnic_adapter *adapter = container_of(work, + struct qlcnic_adapter, fw_work.work); + struct net_device *netdev = adapter->netdev; + int err; + + if (netif_running(netdev)) { + err = qlcnic_attach(adapter); + if (err) + goto done; + + err = qlcnic_up(adapter, netdev); + if (err) { + qlcnic_detach(adapter); + goto done; + } + + qlcnic_config_indev_addr(netdev, NETDEV_UP); + } + + netif_device_attach(netdev); + +done: + adapter->fw_fail_cnt = 0; + clear_bit(__QLCNIC_RESETTING, &adapter->state); + qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY); +} + +static int +qlcnic_check_health(struct qlcnic_adapter *adapter) +{ + u32 state = 0, heartbit; + struct net_device *netdev = adapter->netdev; + + if (qlcnic_check_temp(adapter)) + goto detach; + + if (adapter->need_fw_reset) { + qlcnic_dev_request_reset(adapter); + goto detach; + } + + state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); + if (state == QLCNIC_DEV_NEED_RESET || state == QLCNIC_DEV_NEED_QUISCENT) + adapter->need_fw_reset = 1; + + heartbit = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER); + if (heartbit != adapter->heartbit) { + adapter->heartbit = heartbit; + adapter->fw_fail_cnt = 0; + if (adapter->need_fw_reset) + goto detach; + return 0; + } + + if (++adapter->fw_fail_cnt < FW_FAIL_THRESH) + return 0; + + qlcnic_dev_request_reset(adapter); + + clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state); + + dev_info(&netdev->dev, "firmware hang detected\n"); + +detach: + adapter->dev_state = (state == QLCNIC_DEV_NEED_QUISCENT) ? state : + QLCNIC_DEV_NEED_RESET; + + if ((auto_fw_reset == AUTO_FW_RESET_ENABLED) && + !test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) + qlcnic_schedule_work(adapter, qlcnic_detach_work, 0); + + return 1; +} + +static void +qlcnic_fw_poll_work(struct work_struct *work) +{ + struct qlcnic_adapter *adapter = container_of(work, + struct qlcnic_adapter, fw_work.work); + + if (test_bit(__QLCNIC_RESETTING, &adapter->state)) + goto reschedule; + + + if (qlcnic_check_health(adapter)) + return; + +reschedule: + qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY); +} + +static ssize_t +qlcnic_store_bridged_mode(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct qlcnic_adapter *adapter = dev_get_drvdata(dev); + unsigned long new; + int ret = -EINVAL; + + if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG)) + goto err_out; + + if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) + goto err_out; + + if (strict_strtoul(buf, 2, &new)) + goto err_out; + + if (!qlcnic_config_bridged_mode(adapter, !!new)) + ret = len; + +err_out: + return ret; +} + +static ssize_t +qlcnic_show_bridged_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct qlcnic_adapter *adapter = dev_get_drvdata(dev); + int bridged_mode = 0; + + if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG) + bridged_mode = !!(adapter->flags & QLCNIC_BRIDGE_ENABLED); + + return sprintf(buf, "%d\n", bridged_mode); +} + +static struct device_attribute dev_attr_bridged_mode = { + .attr = {.name = "bridged_mode", .mode = (S_IRUGO | S_IWUSR)}, + .show = qlcnic_show_bridged_mode, + .store = qlcnic_store_bridged_mode, +}; + +static ssize_t +qlcnic_store_diag_mode(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct qlcnic_adapter *adapter = dev_get_drvdata(dev); + unsigned long new; + + if (strict_strtoul(buf, 2, &new)) + return -EINVAL; + + if (!!new != !!(adapter->flags & QLCNIC_DIAG_ENABLED)) + adapter->flags ^= QLCNIC_DIAG_ENABLED; + + return len; +} + +static ssize_t +qlcnic_show_diag_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct qlcnic_adapter *adapter = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", + !!(adapter->flags & QLCNIC_DIAG_ENABLED)); +} + +static struct device_attribute dev_attr_diag_mode = { + .attr = {.name = "diag_mode", .mode = (S_IRUGO | S_IWUSR)}, + .show = qlcnic_show_diag_mode, + .store = qlcnic_store_diag_mode, +}; + +static int +qlcnic_sysfs_validate_crb(struct qlcnic_adapter *adapter, + loff_t offset, size_t size) +{ + if (!(adapter->flags & QLCNIC_DIAG_ENABLED)) + return -EIO; + + if ((size != 4) || (offset & 0x3)) + return -EINVAL; + + if (offset < QLCNIC_PCI_CRBSPACE) + return -EINVAL; + + return 0; +} + +static ssize_t +qlcnic_sysfs_read_crb(struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t offset, size_t size) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct qlcnic_adapter *adapter = dev_get_drvdata(dev); + u32 data; + int ret; + + ret = qlcnic_sysfs_validate_crb(adapter, offset, size); + if (ret != 0) + return ret; + + data = QLCRD32(adapter, offset); + memcpy(buf, &data, size); + return size; +} + +static ssize_t +qlcnic_sysfs_write_crb(struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t offset, size_t size) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct qlcnic_adapter *adapter = dev_get_drvdata(dev); + u32 data; + int ret; + + ret = qlcnic_sysfs_validate_crb(adapter, offset, size); + if (ret != 0) + return ret; + + memcpy(&data, buf, size); + QLCWR32(adapter, offset, data); + return size; +} + +static int +qlcnic_sysfs_validate_mem(struct qlcnic_adapter *adapter, + loff_t offset, size_t size) +{ + if (!(adapter->flags & QLCNIC_DIAG_ENABLED)) + return -EIO; + + if ((size != 8) || (offset & 0x7)) + return -EIO; + + return 0; +} + +static ssize_t +qlcnic_sysfs_read_mem(struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t offset, size_t size) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct qlcnic_adapter *adapter = dev_get_drvdata(dev); + u64 data; + int ret; + + ret = qlcnic_sysfs_validate_mem(adapter, offset, size); + if (ret != 0) + return ret; + + if (qlcnic_pci_mem_read_2M(adapter, offset, &data)) + return -EIO; + + memcpy(buf, &data, size); + + return size; +} + +static ssize_t +qlcnic_sysfs_write_mem(struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t offset, size_t size) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct qlcnic_adapter *adapter = dev_get_drvdata(dev); + u64 data; + int ret; + + ret = qlcnic_sysfs_validate_mem(adapter, offset, size); + if (ret != 0) + return ret; + + memcpy(&data, buf, size); + + if (qlcnic_pci_mem_write_2M(adapter, offset, data)) + return -EIO; + + return size; +} + + +static struct bin_attribute bin_attr_crb = { + .attr = {.name = "crb", .mode = (S_IRUGO | S_IWUSR)}, + .size = 0, + .read = qlcnic_sysfs_read_crb, + .write = qlcnic_sysfs_write_crb, +}; + +static struct bin_attribute bin_attr_mem = { + .attr = {.name = "mem", .mode = (S_IRUGO | S_IWUSR)}, + .size = 0, + .read = qlcnic_sysfs_read_mem, + .write = qlcnic_sysfs_write_mem, +}; + +static void +qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter) +{ + struct device *dev = &adapter->pdev->dev; + + if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG) + if (device_create_file(dev, &dev_attr_bridged_mode)) + dev_warn(dev, + "failed to create bridged_mode sysfs entry\n"); +} + +static void +qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter) +{ + struct device *dev = &adapter->pdev->dev; + + if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG) + device_remove_file(dev, &dev_attr_bridged_mode); +} + +static void +qlcnic_create_diag_entries(struct qlcnic_adapter *adapter) +{ + struct device *dev = &adapter->pdev->dev; + + if (device_create_file(dev, &dev_attr_diag_mode)) + dev_info(dev, "failed to create diag_mode sysfs entry\n"); + if (device_create_bin_file(dev, &bin_attr_crb)) + dev_info(dev, "failed to create crb sysfs entry\n"); + if (device_create_bin_file(dev, &bin_attr_mem)) + dev_info(dev, "failed to create mem sysfs entry\n"); +} + + +static void +qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter) +{ + struct device *dev = &adapter->pdev->dev; + + device_remove_file(dev, &dev_attr_diag_mode); + device_remove_bin_file(dev, &bin_attr_crb); + device_remove_bin_file(dev, &bin_attr_mem); +} + +#ifdef CONFIG_INET + +#define is_qlcnic_netdev(dev) (dev->netdev_ops == &qlcnic_netdev_ops) + +static int +qlcnic_destip_supported(struct qlcnic_adapter *adapter) +{ + if (adapter->ahw.cut_through) + return 0; + + return 1; +} + +static void +qlcnic_config_indev_addr(struct net_device *dev, unsigned long event) +{ + struct in_device *indev; + struct qlcnic_adapter *adapter = netdev_priv(dev); + + if (!qlcnic_destip_supported(adapter)) + return; + + indev = in_dev_get(dev); + if (!indev) + return; + + for_ifa(indev) { + switch (event) { + case NETDEV_UP: + qlcnic_config_ipaddr(adapter, + ifa->ifa_address, QLCNIC_IP_UP); + break; + case NETDEV_DOWN: + qlcnic_config_ipaddr(adapter, + ifa->ifa_address, QLCNIC_IP_DOWN); + break; + default: + break; + } + } endfor_ifa(indev); + + in_dev_put(indev); + return; +} + +static int qlcnic_netdev_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct qlcnic_adapter *adapter; + struct net_device *dev = (struct net_device *)ptr; + +recheck: + if (dev == NULL) + goto done; + + if (dev->priv_flags & IFF_802_1Q_VLAN) { + dev = vlan_dev_real_dev(dev); + goto recheck; + } + + if (!is_qlcnic_netdev(dev)) + goto done; + + adapter = netdev_priv(dev); + + if (!adapter) + goto done; + + if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) + goto done; + + qlcnic_config_indev_addr(dev, event); +done: + return NOTIFY_DONE; +} + +static int +qlcnic_inetaddr_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct qlcnic_adapter *adapter; + struct net_device *dev; + + struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; + + dev = ifa->ifa_dev ? ifa->ifa_dev->dev : NULL; + +recheck: + if (dev == NULL || !netif_running(dev)) + goto done; + + if (dev->priv_flags & IFF_802_1Q_VLAN) { + dev = vlan_dev_real_dev(dev); + goto recheck; + } + + if (!is_qlcnic_netdev(dev)) + goto done; + + adapter = netdev_priv(dev); + + if (!adapter || !qlcnic_destip_supported(adapter)) + goto done; + + if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) + goto done; + + switch (event) { + case NETDEV_UP: + qlcnic_config_ipaddr(adapter, ifa->ifa_address, QLCNIC_IP_UP); + break; + case NETDEV_DOWN: + qlcnic_config_ipaddr(adapter, ifa->ifa_address, QLCNIC_IP_DOWN); + break; + default: + break; + } + +done: + return NOTIFY_DONE; +} + +static struct notifier_block qlcnic_netdev_cb = { + .notifier_call = qlcnic_netdev_event, +}; + +static struct notifier_block qlcnic_inetaddr_cb = { + .notifier_call = qlcnic_inetaddr_event, +}; +#else +static void +qlcnic_config_indev_addr(struct net_device *dev, unsigned long event) +{ } +#endif + +static struct pci_driver qlcnic_driver = { + .name = qlcnic_driver_name, + .id_table = qlcnic_pci_tbl, + .probe = qlcnic_probe, + .remove = __devexit_p(qlcnic_remove), +#ifdef CONFIG_PM + .suspend = qlcnic_suspend, + .resume = qlcnic_resume, +#endif + .shutdown = qlcnic_shutdown +}; + +static int __init qlcnic_init_module(void) +{ + + printk(KERN_INFO "%s\n", qlcnic_driver_string); + +#ifdef CONFIG_INET + register_netdevice_notifier(&qlcnic_netdev_cb); + register_inetaddr_notifier(&qlcnic_inetaddr_cb); +#endif + + + return pci_register_driver(&qlcnic_driver); +} + +module_init(qlcnic_init_module); + +static void __exit qlcnic_exit_module(void) +{ + + pci_unregister_driver(&qlcnic_driver); + +#ifdef CONFIG_INET + unregister_inetaddr_notifier(&qlcnic_inetaddr_cb); + unregister_netdevice_notifier(&qlcnic_netdev_cb); +#endif +} + +module_exit(qlcnic_exit_module); -- cgit v1.2.3-70-g09d2 From 6a902881cc6993f136906559ca04b6a4c9e260fc Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Mon, 1 Feb 2010 05:24:54 +0000 Subject: qlcnic: use DEFINE_PCI_DEVICE_TABLE Use DEFINE_PCI_DEVICE_TABLE() so we get place PCI ids table into correct section in every case. Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/qlcnic') diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index 1698b6a68ed..05275f2153b 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -102,7 +102,7 @@ static void qlcnic_config_indev_addr(struct net_device *dev, unsigned long); #define PCI_DEVICE_ID_QLOGIC_QLE824X 0x8020 -static const struct pci_device_id qlcnic_pci_tbl[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(qlcnic_pci_tbl) = { ENTRY(PCI_DEVICE_ID_QLOGIC_QLE824X), {0,} }; -- cgit v1.2.3-70-g09d2 From 02420be6fc5fc63526aca43b5bfc571547a1c926 Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Mon, 1 Feb 2010 05:24:55 +0000 Subject: qlcnic: add ethernet identifier in board info Added missing identifier that distinguishes between FCOE/ISCSI/ETHERNET functions. Signed-off-by: Rajesh K Borundia Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/net/qlcnic') diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index abec4684653..9662a37bfc5 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -1068,7 +1068,7 @@ int qlcnic_reset_context(struct qlcnic_adapter *); * QLOGIC Board information */ -#define QLCNIC_MAX_BOARD_NAME_LEN 64 +#define QLCNIC_MAX_BOARD_NAME_LEN 100 struct qlcnic_brdinfo { unsigned short vendor; unsigned short device; @@ -1078,8 +1078,12 @@ struct qlcnic_brdinfo { }; static const struct qlcnic_brdinfo qlcnic_boards[] = { - {0x1077, 0x8020, 0x1077, 0x203, "8200 Series Single Port 10GbE CNA"}, - {0x1077, 0x8020, 0x1077, 0x207, "8200 Series Dual Port 10GbE CNA"}, + {0x1077, 0x8020, 0x1077, 0x203, + "8200 Series Single Port 10GbE Converged Network Adapter \ + (TCP/IP Networking)"}, + {0x1077, 0x8020, 0x1077, 0x207, + "8200 Series Dual Port 10GbE Converged Network Adapter \ + (TCP/IP Networking)"}, {0x1077, 0x8020, 0x1077, 0x20b, "3200 Series Dual Port 10Gb Intelligent Ethernet Adapter"}, {0x1077, 0x8020, 0x1077, 0x20c, -- cgit v1.2.3-70-g09d2 From 1b95a839587f40abab2f9cb3e5254dc821b9829b Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Mon, 1 Feb 2010 05:24:56 +0000 Subject: qlcnic: clear device reset state after fw recovery o After firmware recovery, clear device reset state transition register. Otherwise firmware reload can occur unnecessary. Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic_main.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'drivers/net/qlcnic') diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index 05275f2153b..9a98285ee79 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -1866,6 +1866,23 @@ qlcnic_set_drv_state(struct qlcnic_adapter *adapter, int state) qlcnic_api_unlock(adapter); } +static int +qlcnic_clr_drv_state(struct qlcnic_adapter *adapter) +{ + u32 val; + + if (qlcnic_api_lock(adapter)) + return -EBUSY; + + val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE); + val &= ~((u32)0x3 << (adapter->portnum * 4)); + QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val); + + qlcnic_api_unlock(adapter); + + return 0; +} + static void qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter) { @@ -2119,7 +2136,10 @@ qlcnic_attach_work(struct work_struct *work) done: adapter->fw_fail_cnt = 0; clear_bit(__QLCNIC_RESETTING, &adapter->state); - qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY); + + if (!qlcnic_clr_drv_state(adapter)) + qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, + FW_POLL_DELAY); } static int -- cgit v1.2.3-70-g09d2 From ce6684433fb277406dd861fd8a17133253e7c367 Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Mon, 1 Feb 2010 05:24:57 +0000 Subject: qlcnic: protect resoruce cleanup by rtnl lock o context resources can be in used, while resoruce cleanup is in progress, during fw recover. o Null pointer execption can occur in send_cmd_desc, if fw recovery module frees tx ring without rtnl lock. o Same applies to ethtool register dump and FW health registers should be dump in any case. Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic_ethtool.c | 6 +++--- drivers/net/qlcnic/qlcnic_main.c | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/net/qlcnic') diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c index 65e9620e28f..37df5f6cea0 100644 --- a/drivers/net/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/qlcnic/qlcnic_ethtool.c @@ -326,12 +326,12 @@ qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) regs->version = (1 << 24) | (adapter->ahw.revision_id << 16) | (adapter->pdev)->device; - if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) - return; - for (i = 0; diag_registers[i] != -1; i++) regs_buff[i] = QLCRD32(adapter, diag_registers[i]); + if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) + return; + regs_buff[i++] = 0xFFEFCDAB; /* Marker btw regs and ring count*/ regs_buff[i++] = 1; /* No. of tx ring */ diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index 9a98285ee79..7259adc3263 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -2051,7 +2051,9 @@ qlcnic_detach_work(struct work_struct *work) qlcnic_down(adapter, netdev); + rtnl_lock(); qlcnic_detach(adapter); + rtnl_unlock(); status = QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1); -- cgit v1.2.3-70-g09d2 From 897d3596e0dfc4c25963cff00f1159c79eaf38d3 Mon Sep 17 00:00:00 2001 From: Sucheta Chakraborty Date: Mon, 1 Feb 2010 05:24:58 +0000 Subject: qlcnic: support LED blink for device identification Added support of device identification by blinking LED for specified time. Signed-off-by: Sucheta Chakraborty Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic.h | 1 + drivers/net/qlcnic/qlcnic_ethtool.c | 26 ++++++++++++++++++++++++++ drivers/net/qlcnic/qlcnic_hw.c | 22 ++++++++++++++++++++++ 3 files changed, 49 insertions(+) (limited to 'drivers/net/qlcnic') diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index 9662a37bfc5..514e805f3ab 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -1015,6 +1015,7 @@ void qlcnic_pcie_sem_unlock(struct qlcnic_adapter *, int); int qlcnic_get_board_info(struct qlcnic_adapter *adapter); int qlcnic_wol_supported(struct qlcnic_adapter *adapter); +int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate); /* Functions from qlcnic_init.c */ int qlcnic_phantom_init(struct qlcnic_adapter *adapter); diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c index 37df5f6cea0..7212319760b 100644 --- a/drivers/net/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/qlcnic/qlcnic_ethtool.c @@ -618,6 +618,7 @@ qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test, u64 *data) { memset(data, 0, sizeof(u64) * QLCNIC_TEST_LEN); + data[0] = qlcnic_reg_test(dev); if (data[0]) eth_test->flags |= ETH_TEST_FL_FAILED; @@ -693,6 +694,30 @@ static int qlcnic_set_tso(struct net_device *dev, u32 data) return 0; } +static int qlcnic_blink_led(struct net_device *dev, u32 val) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + int ret; + + ret = qlcnic_config_led(adapter, 1, 0xf); + if (ret) { + dev_err(&adapter->pdev->dev, + "Failed to set LED blink state.\n"); + return ret; + } + + msleep_interruptible(val * 1000); + + ret = qlcnic_config_led(adapter, 0, 0xf); + if (ret) { + dev_err(&adapter->pdev->dev, + "Failed to reset LED blink state.\n"); + return ret; + } + + return 0; +} + static void qlcnic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { @@ -867,4 +892,5 @@ const struct ethtool_ops qlcnic_ethtool_ops = { .set_coalesce = qlcnic_set_intr_coalesce, .get_flags = ethtool_op_get_flags, .set_flags = qlcnic_set_flags, + .phys_id = qlcnic_blink_led, }; diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c index 91234e7b39e..8724e561ed7 100644 --- a/drivers/net/qlcnic/qlcnic_hw.c +++ b/drivers/net/qlcnic/qlcnic_hw.c @@ -1199,3 +1199,25 @@ qlcnic_wol_supported(struct qlcnic_adapter *adapter) return 0; } + +int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate) +{ + struct qlcnic_nic_req req; + int rv; + u64 word; + + memset(&req, 0, sizeof(struct qlcnic_nic_req)); + req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); + + word = QLCNIC_H2C_OPCODE_CONFIG_LED | ((u64)adapter->portnum << 16); + req.req_hdr = cpu_to_le64(word); + + req.words[0] = cpu_to_le64((u64)rate << 32); + req.words[1] = cpu_to_le64(state); + + rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); + if (rv) + dev_err(&adapter->pdev->dev, "LED configuration failed.\n"); + + return rv; +} -- cgit v1.2.3-70-g09d2 From 7eb9855d68faabe0004ed18c2af1f0974d3c2c63 Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Mon, 1 Feb 2010 05:24:59 +0000 Subject: qlcnic: add interrupt diagnostic test Interrupt test (offline) added in ethtool self test. Register a temporary interrupt handler and then send command to fw to raise an interrupt. Signed-off-by: Sucheta Chakraborty Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic.h | 13 ++++- drivers/net/qlcnic/qlcnic_ctx.c | 4 +- drivers/net/qlcnic/qlcnic_ethtool.c | 41 ++++++++++++- drivers/net/qlcnic/qlcnic_main.c | 112 ++++++++++++++++++++++++++++++++---- 4 files changed, 154 insertions(+), 16 deletions(-) (limited to 'drivers/net/qlcnic') diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index 514e805f3ab..a5a67e9b5e1 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -560,6 +560,8 @@ struct qlcnic_recv_context { /* * Context state */ +#define QLCHAL_VERSION 1 + #define QLCNIC_HOST_CTX_STATE_ACTIVE 2 /* @@ -894,6 +896,8 @@ struct qlcnic_mac_req { #define __QLCNIC_RESETTING 2 #define __QLCNIC_START_FW 4 +#define QLCNIC_INTERRUPT_TEST 1 + struct qlcnic_adapter { struct qlcnic_hardware_context ahw; @@ -946,9 +950,10 @@ struct qlcnic_adapter { u32 heartbit; u8 dev_state; + u8 diag_test; + u8 diag_cnt; u8 rsrd1; - u32 rsrd2; - + u16 rsrd2; u8 mac_addr[ETH_ALEN]; @@ -1064,6 +1069,10 @@ int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u64 *mac); /* Functions from qlcnic_main.c */ int qlcnic_reset_context(struct qlcnic_adapter *); +u32 qlcnic_issue_cmd(struct qlcnic_adapter *adapter, + u32 pci_fn, u32 version, u32 arg1, u32 arg2, u32 arg3, u32 cmd); +void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings); +int qlcnic_diag_alloc_res(struct net_device *netdev, int test); /* * QLOGIC Board information diff --git a/drivers/net/qlcnic/qlcnic_ctx.c b/drivers/net/qlcnic/qlcnic_ctx.c index 71c16a18345..0a6a39914ae 100644 --- a/drivers/net/qlcnic/qlcnic_ctx.c +++ b/drivers/net/qlcnic/qlcnic_ctx.c @@ -24,8 +24,6 @@ #include "qlcnic.h" -#define QLCHAL_VERSION 1 - static u32 qlcnic_poll_rsp(struct qlcnic_adapter *adapter) { @@ -45,7 +43,7 @@ qlcnic_poll_rsp(struct qlcnic_adapter *adapter) return rsp; } -static u32 +u32 qlcnic_issue_cmd(struct qlcnic_adapter *adapter, u32 pci_fn, u32 version, u32 arg1, u32 arg2, u32 arg3, u32 cmd) { diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c index 7212319760b..58c50ed791d 100644 --- a/drivers/net/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/qlcnic/qlcnic_ethtool.c @@ -65,7 +65,8 @@ static const struct qlcnic_stats qlcnic_gstrings_stats[] = { static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = { "Register_Test_on_offline", - "Link_Test_on_offline" + "Link_Test_on_offline", + "Interrupt_Test_offline" }; #define QLCNIC_TEST_LEN ARRAY_SIZE(qlcnic_gstrings_test) @@ -613,12 +614,50 @@ static int qlcnic_get_sset_count(struct net_device *dev, int sset) } } +static int qlcnic_irq_test(struct net_device *netdev) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + int max_sds_rings = adapter->max_sds_rings; + int ret; + + if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) + return -EIO; + + ret = qlcnic_diag_alloc_res(netdev, QLCNIC_INTERRUPT_TEST); + if (ret) + goto clear_it; + + adapter->diag_cnt = 0; + ret = qlcnic_issue_cmd(adapter, adapter->ahw.pci_func, + QLCHAL_VERSION, adapter->portnum, 0, 0, 0x00000011); + if (ret) + goto done; + + msleep(10); + + ret = !adapter->diag_cnt; + +done: + qlcnic_diag_free_res(netdev, max_sds_rings); + +clear_it: + adapter->max_sds_rings = max_sds_rings; + clear_bit(__QLCNIC_RESETTING, &adapter->state); + return ret; +} + static void qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test, u64 *data) { memset(data, 0, sizeof(u64) * QLCNIC_TEST_LEN); + if (eth_test->flags == ETH_TEST_FL_OFFLINE) { + data[2] = qlcnic_irq_test(dev); + if (data[2]) + eth_test->flags |= ETH_TEST_FL_FAILED; + } + data[0] = qlcnic_reg_test(dev); if (data[0]) eth_test->flags |= ETH_TEST_FL_FAILED; diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index 7259adc3263..a8b07120d36 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -88,6 +88,7 @@ static void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter); static void qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter); static int qlcnic_can_start_firmware(struct qlcnic_adapter *adapter); +static irqreturn_t qlcnic_tmp_intr(int irq, void *data); static irqreturn_t qlcnic_intr(int irq, void *data); static irqreturn_t qlcnic_msi_intr(int irq, void *data); static irqreturn_t qlcnic_msix_intr(int irq, void *data); @@ -720,13 +721,20 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter) struct net_device *netdev = adapter->netdev; struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; - if (adapter->flags & QLCNIC_MSIX_ENABLED) - handler = qlcnic_msix_intr; - else if (adapter->flags & QLCNIC_MSI_ENABLED) - handler = qlcnic_msi_intr; - else { - flags |= IRQF_SHARED; - handler = qlcnic_intr; + if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) { + handler = qlcnic_tmp_intr; + if (!QLCNIC_IS_MSI_FAMILY(adapter)) + flags |= IRQF_SHARED; + + } else { + if (adapter->flags & QLCNIC_MSIX_ENABLED) + handler = qlcnic_msix_intr; + else if (adapter->flags & QLCNIC_MSI_ENABLED) + handler = qlcnic_msi_intr; + else { + flags |= IRQF_SHARED; + handler = qlcnic_intr; + } } adapter->irq = netdev->irq; @@ -923,6 +931,60 @@ qlcnic_detach(struct qlcnic_adapter *adapter) adapter->is_up = 0; } +void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + struct qlcnic_host_sds_ring *sds_ring; + int ring; + + for (ring = 0; ring < adapter->max_sds_rings; ring++) { + sds_ring = &adapter->recv_ctx.sds_rings[ring]; + qlcnic_disable_int(sds_ring); + } + + qlcnic_detach(adapter); + + adapter->diag_test = 0; + adapter->max_sds_rings = max_sds_rings; + + if (qlcnic_attach(adapter)) + return; + + if (netif_running(netdev)) + __qlcnic_up(adapter, netdev); + + netif_device_attach(netdev); +} + +int qlcnic_diag_alloc_res(struct net_device *netdev, int test) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + struct qlcnic_host_sds_ring *sds_ring; + int ring; + int ret; + + netif_device_detach(netdev); + + if (netif_running(netdev)) + __qlcnic_down(adapter, netdev); + + qlcnic_detach(adapter); + + adapter->max_sds_rings = 1; + adapter->diag_test = test; + + ret = qlcnic_attach(adapter); + if (ret) + return ret; + + for (ring = 0; ring < adapter->max_sds_rings; ring++) { + sds_ring = &adapter->recv_ctx.sds_rings[ring]; + qlcnic_enable_int(sds_ring); + } + + return 0; +} + int qlcnic_reset_context(struct qlcnic_adapter *adapter) { @@ -1689,10 +1751,8 @@ static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev) return stats; } -static irqreturn_t qlcnic_intr(int irq, void *data) +static irqreturn_t qlcnic_clear_legacy_intr(struct qlcnic_adapter *adapter) { - struct qlcnic_host_sds_ring *sds_ring = data; - struct qlcnic_adapter *adapter = sds_ring->adapter; u32 status; status = readl(adapter->isr_int_vec); @@ -1710,6 +1770,38 @@ static irqreturn_t qlcnic_intr(int irq, void *data) readl(adapter->isr_int_vec); readl(adapter->isr_int_vec); + return IRQ_HANDLED; +} + +static irqreturn_t qlcnic_tmp_intr(int irq, void *data) +{ + struct qlcnic_host_sds_ring *sds_ring = data; + struct qlcnic_adapter *adapter = sds_ring->adapter; + + if (adapter->flags & QLCNIC_MSIX_ENABLED) + goto done; + else if (adapter->flags & QLCNIC_MSI_ENABLED) { + writel(0xffffffff, adapter->tgt_status_reg); + goto done; + } + + if (qlcnic_clear_legacy_intr(adapter) == IRQ_NONE) + return IRQ_NONE; + +done: + adapter->diag_cnt++; + qlcnic_enable_int(sds_ring); + return IRQ_HANDLED; +} + +static irqreturn_t qlcnic_intr(int irq, void *data) +{ + struct qlcnic_host_sds_ring *sds_ring = data; + struct qlcnic_adapter *adapter = sds_ring->adapter; + + if (qlcnic_clear_legacy_intr(adapter) == IRQ_NONE) + return IRQ_NONE; + napi_schedule(&sds_ring->napi); return IRQ_HANDLED; -- cgit v1.2.3-70-g09d2 From cdaff1854f32ac9ddb4733530f617d32188665ed Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Mon, 1 Feb 2010 05:25:00 +0000 Subject: qlcnic: add loopback diagnostic test Loopback test (offline) added in ethtool self test. o Set device in loopback mode o Send packets o Process receive packets in qlcnic_process_rcv_ring_diag() o Compare packets o Reset device in normal mode. Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic.h | 6 +++ drivers/net/qlcnic/qlcnic_ethtool.c | 82 ++++++++++++++++++++++++++++++++++++- drivers/net/qlcnic/qlcnic_hw.c | 52 +++++++++++++++++++++++ drivers/net/qlcnic/qlcnic_init.c | 75 +++++++++++++++++++++++++++++++++ drivers/net/qlcnic/qlcnic_main.c | 20 +++++---- 5 files changed, 225 insertions(+), 10 deletions(-) (limited to 'drivers/net/qlcnic') diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index a5a67e9b5e1..b40a851ec7d 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -897,6 +897,7 @@ struct qlcnic_mac_req { #define __QLCNIC_START_FW 4 #define QLCNIC_INTERRUPT_TEST 1 +#define QLCNIC_LOOPBACK_TEST 2 struct qlcnic_adapter { struct qlcnic_hardware_context ahw; @@ -1066,6 +1067,8 @@ int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter); void qlcnic_update_cmd_producer(struct qlcnic_adapter *adapter, struct qlcnic_host_tx_ring *tx_ring); int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u64 *mac); +void qlcnic_clear_ilb_mode(struct qlcnic_adapter *adapter); +int qlcnic_set_ilb_mode(struct qlcnic_adapter *adapter); /* Functions from qlcnic_main.c */ int qlcnic_reset_context(struct qlcnic_adapter *); @@ -1073,6 +1076,9 @@ u32 qlcnic_issue_cmd(struct qlcnic_adapter *adapter, u32 pci_fn, u32 version, u32 arg1, u32 arg2, u32 arg3, u32 cmd); void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings); int qlcnic_diag_alloc_res(struct net_device *netdev, int test); +int qlcnic_check_loopback_buff(unsigned char *data); +netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev); +void qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring); /* * QLOGIC Board information diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c index 58c50ed791d..8da6ec8c13b 100644 --- a/drivers/net/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/qlcnic/qlcnic_ethtool.c @@ -66,7 +66,8 @@ static const struct qlcnic_stats qlcnic_gstrings_stats[] = { static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = { "Register_Test_on_offline", "Link_Test_on_offline", - "Interrupt_Test_offline" + "Interrupt_Test_offline", + "Loopback_Test_offline" }; #define QLCNIC_TEST_LEN ARRAY_SIZE(qlcnic_gstrings_test) @@ -614,6 +615,80 @@ static int qlcnic_get_sset_count(struct net_device *dev, int sset) } } +#define QLC_ILB_PKT_SIZE 64 + +static void qlcnic_create_loopback_buff(unsigned char *data) +{ + unsigned char random_data[] = {0xa8, 0x06, 0x45, 0x00}; + memset(data, 0x4e, QLC_ILB_PKT_SIZE); + memset(data, 0xff, 12); + memcpy(data + 12, random_data, sizeof(random_data)); +} + +int qlcnic_check_loopback_buff(unsigned char *data) +{ + unsigned char buff[QLC_ILB_PKT_SIZE]; + qlcnic_create_loopback_buff(buff); + return memcmp(data, buff, QLC_ILB_PKT_SIZE); +} + +static int qlcnic_do_ilb_test(struct qlcnic_adapter *adapter) +{ + struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_host_sds_ring *sds_ring = &recv_ctx->sds_rings[0]; + struct sk_buff *skb; + int i; + + for (i = 0; i < 16; i++) { + skb = dev_alloc_skb(QLC_ILB_PKT_SIZE); + qlcnic_create_loopback_buff(skb->data); + skb_put(skb, QLC_ILB_PKT_SIZE); + + adapter->diag_cnt = 0; + + qlcnic_xmit_frame(skb, adapter->netdev); + + msleep(5); + + qlcnic_process_rcv_ring_diag(sds_ring); + + dev_kfree_skb_any(skb); + if (!adapter->diag_cnt) + return -1; + } + return 0; +} + +static int qlcnic_loopback_test(struct net_device *netdev) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + int max_sds_rings = adapter->max_sds_rings; + int ret; + + if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) + return -EIO; + + ret = qlcnic_diag_alloc_res(netdev, QLCNIC_LOOPBACK_TEST); + if (ret) + goto clear_it; + + ret = qlcnic_set_ilb_mode(adapter); + if (ret) + goto done; + + ret = qlcnic_do_ilb_test(adapter); + + qlcnic_clear_ilb_mode(adapter); + +done: + qlcnic_diag_free_res(netdev, max_sds_rings); + +clear_it: + adapter->max_sds_rings = max_sds_rings; + clear_bit(__QLCNIC_RESETTING, &adapter->state); + return ret; +} + static int qlcnic_irq_test(struct net_device *netdev) { struct qlcnic_adapter *adapter = netdev_priv(netdev); @@ -656,6 +731,11 @@ qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test, data[2] = qlcnic_irq_test(dev); if (data[2]) eth_test->flags |= ETH_TEST_FL_FAILED; + + data[3] = qlcnic_loopback_test(dev); + if (data[3]) + eth_test->flags |= ETH_TEST_FL_FAILED; + } data[0] = qlcnic_reg_test(dev); diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c index 8724e561ed7..dc6cd69d6d9 100644 --- a/drivers/net/qlcnic/qlcnic_hw.c +++ b/drivers/net/qlcnic/qlcnic_hw.c @@ -1221,3 +1221,55 @@ int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate) return rv; } + +static int qlcnic_set_fw_loopback(struct qlcnic_adapter *adapter, u32 flag) +{ + struct qlcnic_nic_req req; + int rv; + u64 word; + + memset(&req, 0, sizeof(struct qlcnic_nic_req)); + req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); + + word = QLCNIC_H2C_OPCODE_CONFIG_LOOPBACK | + ((u64)adapter->portnum << 16); + req.req_hdr = cpu_to_le64(word); + req.words[0] = cpu_to_le64(flag); + + rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); + if (rv) + dev_err(&adapter->pdev->dev, + "%sting loopback mode failed.\n", + flag ? "Set" : "Reset"); + return rv; +} + +int qlcnic_set_ilb_mode(struct qlcnic_adapter *adapter) +{ + if (qlcnic_set_fw_loopback(adapter, 1)) + return -EIO; + + if (qlcnic_nic_set_promisc(adapter, + VPORT_MISS_MODE_ACCEPT_ALL)) { + qlcnic_set_fw_loopback(adapter, 0); + return -EIO; + } + + msleep(1000); + return 0; +} + +void qlcnic_clear_ilb_mode(struct qlcnic_adapter *adapter) +{ + int mode = VPORT_MISS_MODE_DROP; + struct net_device *netdev = adapter->netdev; + + qlcnic_set_fw_loopback(adapter, 0); + + if (netdev->flags & IFF_PROMISC) + mode = VPORT_MISS_MODE_ACCEPT_ALL; + else if (netdev->flags & IFF_ALLMULTI) + mode = VPORT_MISS_MODE_ACCEPT_MULTI; + + qlcnic_nic_set_promisc(adapter, mode); +} diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c index 7ae8bcc1e43..ea00ab4d4fe 100644 --- a/drivers/net/qlcnic/qlcnic_init.c +++ b/drivers/net/qlcnic/qlcnic_init.c @@ -1464,3 +1464,78 @@ qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter, spin_unlock(&rds_ring->lock); } +static struct qlcnic_rx_buffer * +qlcnic_process_rcv_diag(struct qlcnic_adapter *adapter, + struct qlcnic_host_sds_ring *sds_ring, + int ring, u64 sts_data0) +{ + struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_rx_buffer *buffer; + struct sk_buff *skb; + struct qlcnic_host_rds_ring *rds_ring; + int index, length, cksum, pkt_offset; + + if (unlikely(ring >= adapter->max_rds_rings)) + return NULL; + + rds_ring = &recv_ctx->rds_rings[ring]; + + index = qlcnic_get_sts_refhandle(sts_data0); + if (unlikely(index >= rds_ring->num_desc)) + return NULL; + + buffer = &rds_ring->rx_buf_arr[index]; + + length = qlcnic_get_sts_totallength(sts_data0); + cksum = qlcnic_get_sts_status(sts_data0); + pkt_offset = qlcnic_get_sts_pkt_offset(sts_data0); + + skb = qlcnic_process_rxbuf(adapter, rds_ring, index, cksum); + if (!skb) + return buffer; + + skb_put(skb, rds_ring->skb_size); + + if (pkt_offset) + skb_pull(skb, pkt_offset); + + skb->truesize = skb->len + sizeof(struct sk_buff); + + if (!qlcnic_check_loopback_buff(skb->data)) + adapter->diag_cnt++; + + dev_kfree_skb_any(skb); + + return buffer; +} + +void +qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring) +{ + struct qlcnic_adapter *adapter = sds_ring->adapter; + struct status_desc *desc; + struct qlcnic_rx_buffer *rxbuf; + u64 sts_data0; + + int opcode, ring, desc_cnt; + u32 consumer = sds_ring->consumer; + + desc = &sds_ring->desc_head[consumer]; + sts_data0 = le64_to_cpu(desc->status_desc_data[0]); + + if (!(sts_data0 & STATUS_OWNER_HOST)) + return; + + desc_cnt = qlcnic_get_sts_desc_cnt(sts_data0); + opcode = qlcnic_get_sts_opcode(sts_data0); + + ring = qlcnic_get_sts_type(sts_data0); + rxbuf = qlcnic_process_rcv_diag(adapter, sds_ring, + ring, sts_data0); + + desc->status_desc_data[0] = cpu_to_le64(STATUS_OWNER_PHANTOM); + consumer = get_next_index(consumer, sds_ring->num_desc); + + sds_ring->consumer = consumer; + writel(consumer, sds_ring->crb_sts_consumer); +} diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index a8b07120d36..665e8e56b6a 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -65,8 +65,6 @@ static int __devinit qlcnic_probe(struct pci_dev *pdev, static void __devexit qlcnic_remove(struct pci_dev *pdev); static int qlcnic_open(struct net_device *netdev); static int qlcnic_close(struct net_device *netdev); -static netdev_tx_t qlcnic_xmit_frame(struct sk_buff *, - struct net_device *); static void qlcnic_tx_timeout(struct net_device *netdev); static void qlcnic_tx_timeout_task(struct work_struct *work); static void qlcnic_attach_work(struct work_struct *work); @@ -937,9 +935,11 @@ void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings) struct qlcnic_host_sds_ring *sds_ring; int ring; - for (ring = 0; ring < adapter->max_sds_rings; ring++) { - sds_ring = &adapter->recv_ctx.sds_rings[ring]; - qlcnic_disable_int(sds_ring); + if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) { + for (ring = 0; ring < adapter->max_sds_rings; ring++) { + sds_ring = &adapter->recv_ctx.sds_rings[ring]; + qlcnic_disable_int(sds_ring); + } } qlcnic_detach(adapter); @@ -977,9 +977,11 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test) if (ret) return ret; - for (ring = 0; ring < adapter->max_sds_rings; ring++) { - sds_ring = &adapter->recv_ctx.sds_rings[ring]; - qlcnic_enable_int(sds_ring); + if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) { + for (ring = 0; ring < adapter->max_sds_rings; ring++) { + sds_ring = &adapter->recv_ctx.sds_rings[ring]; + qlcnic_enable_int(sds_ring); + } } return 0; @@ -1549,7 +1551,7 @@ qlcnic_clear_cmddesc(u64 *desc) desc[2] = 0ULL; } -static netdev_tx_t +netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { struct qlcnic_adapter *adapter = netdev_priv(netdev); -- cgit v1.2.3-70-g09d2 From 4cd24eaf0c6ee7f0242e34ee77ec899f255e66b5 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Mon, 8 Feb 2010 04:30:35 +0000 Subject: net: use netdev_mc_count and netdev_mc_empty when appropriate This patch replaces dev->mc_count in all drivers (hopefully I didn't miss anything). Used spatch and did small tweaks and conding style changes when it was suitable. Jirka Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- arch/xtensa/platforms/iss/network.c | 2 +- drivers/infiniband/hw/nes/nes_nic.c | 2 +- drivers/media/dvb/dvb-core/dvb_net.c | 7 +++---- drivers/net/3c505.c | 6 +++--- drivers/net/3c509.c | 10 ++++++---- drivers/net/3c523.c | 4 ++-- drivers/net/3c527.c | 11 ++++++----- drivers/net/7990.c | 2 +- drivers/net/82596.c | 8 ++++---- drivers/net/a2065.c | 2 +- drivers/net/acenic.c | 2 +- drivers/net/amd8111e.c | 7 ++++--- drivers/net/ariadne.c | 2 +- drivers/net/arm/at91_ether.c | 4 ++-- drivers/net/arm/ether3.c | 2 +- drivers/net/arm/ixp4xx_eth.c | 2 +- drivers/net/arm/ks8695net.c | 4 ++-- drivers/net/at1700.c | 6 +++--- drivers/net/atarilance.c | 2 +- drivers/net/atp.c | 7 ++++--- drivers/net/au1000_eth.c | 4 ++-- drivers/net/b44.c | 4 ++-- drivers/net/bcm63xx_enet.c | 4 ++-- drivers/net/benet/be_main.c | 5 +++-- drivers/net/bfin_mac.c | 4 ++-- drivers/net/bmac.c | 8 ++++---- drivers/net/bnx2.c | 2 +- drivers/net/bnx2x_main.c | 7 ++++--- drivers/net/chelsio/common.h | 4 ++-- drivers/net/cpmac.c | 2 +- drivers/net/cris/eth_v10.c | 2 +- drivers/net/davinci_emac.c | 4 ++-- drivers/net/de620.c | 2 +- drivers/net/declance.c | 2 +- drivers/net/defxx.c | 4 ++-- drivers/net/depca.c | 2 +- drivers/net/dl2k.c | 6 +++--- drivers/net/dm9000.c | 2 +- drivers/net/e100.c | 6 +++--- drivers/net/eepro.c | 15 ++++++++------- drivers/net/eexpress.c | 6 +++--- drivers/net/ehea/ehea_main.c | 6 +++--- drivers/net/enc28j60.c | 2 +- drivers/net/enic/enic_main.c | 4 ++-- drivers/net/epic100.c | 6 +++--- drivers/net/eth16i.c | 2 +- drivers/net/ewrk3.c | 2 +- drivers/net/fealnx.c | 4 ++-- drivers/net/fec.c | 2 +- drivers/net/fec_mpc52xx.c | 2 +- drivers/net/fs_enet/mac-fcc.c | 2 +- drivers/net/fs_enet/mac-fec.c | 2 +- drivers/net/fs_enet/mac-scc.c | 2 +- drivers/net/gianfar.c | 2 +- drivers/net/hamachi.c | 6 +++--- drivers/net/hp100.c | 7 ++++--- drivers/net/ibm_newemac/core.c | 6 +++--- drivers/net/ibmveth.c | 5 +++-- drivers/net/igb/igb_main.c | 8 ++++---- drivers/net/igbvf/netdev.c | 6 +++--- drivers/net/ioc3-eth.c | 5 +++-- drivers/net/ipg.c | 4 ++-- drivers/net/isa-skeleton.c | 5 +++-- drivers/net/iseries_veth.c | 4 ++-- drivers/net/ixgb/ixgb_main.c | 6 +++--- drivers/net/ixgbe/ixgbe_main.c | 2 +- drivers/net/ixgbevf/ixgbevf_main.c | 2 +- drivers/net/jme.c | 2 +- drivers/net/korina.c | 6 +++--- drivers/net/ks8851.c | 4 ++-- drivers/net/ks8851_mll.c | 4 ++-- drivers/net/lance.c | 2 +- drivers/net/lib82596.c | 6 +++--- drivers/net/ll_temac_main.c | 6 +++--- drivers/net/lp486e.c | 12 +++++++----- drivers/net/macb.c | 4 ++-- drivers/net/mace.c | 2 +- drivers/net/macmace.c | 2 +- drivers/net/natsemi.c | 4 ++-- drivers/net/netxen/netxen_nic_hw.c | 10 +++++----- drivers/net/ni52.c | 2 +- drivers/net/ni65.c | 2 +- drivers/net/niu.c | 4 ++-- drivers/net/ns83820.c | 2 +- drivers/net/octeon/octeon_mgmt.c | 6 +++--- drivers/net/pci-skeleton.c | 4 ++-- drivers/net/pcmcia/3c574_cs.c | 2 +- drivers/net/pcmcia/3c589_cs.c | 2 +- drivers/net/pcmcia/fmvj18x_cs.c | 6 +++--- drivers/net/pcmcia/nmclan_cs.c | 14 +++++++------- drivers/net/pcmcia/smc91c92_cs.c | 4 ++-- drivers/net/pcmcia/xirc2ps_cs.c | 8 ++++---- drivers/net/pcnet32.c | 2 +- drivers/net/ps3_gelic_net.c | 2 +- drivers/net/qlcnic/qlcnic_hw.c | 4 ++-- drivers/net/qlge/qlge_main.c | 4 ++-- drivers/net/r6040.c | 11 ++++++----- drivers/net/r8169.c | 4 ++-- drivers/net/s2io.c | 8 ++++---- drivers/net/sc92031.c | 2 +- drivers/net/sfc/efx.c | 2 +- drivers/net/sgiseeq.c | 2 +- drivers/net/sis190.c | 4 ++-- drivers/net/sis900.c | 4 ++-- drivers/net/skfp/skfddi.c | 6 +++--- drivers/net/skge.c | 6 +++--- drivers/net/sky2.c | 4 ++-- drivers/net/smc911x.c | 6 +++--- drivers/net/smc9194.c | 4 ++-- drivers/net/smc91x.c | 6 +++--- drivers/net/smsc911x.c | 4 ++-- drivers/net/smsc9420.c | 2 +- drivers/net/sonic.c | 8 +++++--- drivers/net/starfire.c | 8 ++++---- drivers/net/stmmac/dwmac100.c | 6 +++--- drivers/net/stmmac/dwmac1000_core.c | 8 ++++---- drivers/net/sun3_82586.c | 2 +- drivers/net/sun3lance.c | 2 +- drivers/net/sunbmac.c | 4 ++-- drivers/net/sundance.c | 6 +++--- drivers/net/sungem.c | 4 ++-- drivers/net/sunhme.c | 8 ++++---- drivers/net/sunlance.c | 2 +- drivers/net/sunqe.c | 4 ++-- drivers/net/tc35815.c | 6 +++--- drivers/net/tehuti.c | 4 ++-- drivers/net/tg3.c | 4 ++-- drivers/net/tlan.c | 2 +- drivers/net/tokenring/3c359.c | 2 +- drivers/net/tokenring/ibmtr.c | 2 +- drivers/net/tokenring/lanstreamer.c | 2 +- drivers/net/tokenring/olympic.c | 2 +- drivers/net/tokenring/tms380tr.c | 2 +- drivers/net/tsi108_eth.c | 2 +- drivers/net/tulip/de2104x.c | 8 ++++---- drivers/net/tulip/de4x5.c | 6 +++--- drivers/net/tulip/dmfe.c | 15 ++++++++------- drivers/net/tulip/tulip_core.c | 18 +++++++++++------- drivers/net/tulip/uli526x.c | 12 +++++++----- drivers/net/tulip/winbond-840.c | 7 ++++--- drivers/net/typhoon.c | 9 +++++---- drivers/net/ucc_geth.c | 3 ++- drivers/net/usb/asix.c | 12 ++++++------ drivers/net/usb/catc.c | 4 +++- drivers/net/usb/int51x1.c | 2 +- drivers/net/usb/kaweth.c | 2 +- drivers/net/usb/mcs7830.c | 6 +++--- drivers/net/usb/pegasus.c | 2 +- drivers/net/usb/rtl8150.c | 2 +- drivers/net/usb/smsc95xx.c | 4 ++-- drivers/net/via-rhine.c | 5 +++-- drivers/net/via-velocity.c | 6 ++++-- drivers/net/virtio_net.c | 13 ++++++++----- drivers/net/vmxnet3/vmxnet3_drv.c | 8 ++++---- drivers/net/vxge/vxge-main.c | 6 +++--- drivers/net/wireless/airo.c | 2 +- drivers/net/wireless/orinoco/main.c | 4 ++-- drivers/net/wireless/ray_cs.c | 2 +- drivers/net/wireless/rndis_wlan.c | 6 +++--- drivers/net/wireless/zd1201.c | 7 +++---- drivers/net/yellowfin.c | 7 ++++--- drivers/staging/et131x/et131x_netdev.c | 10 +++++----- drivers/staging/netwave/netwave_cs.c | 8 ++++---- drivers/staging/slicoss/slicoss.c | 2 +- drivers/staging/vt6655/device_main.c | 4 ++-- drivers/staging/vt6656/main_usb.c | 5 +++-- drivers/staging/wavelan/wavelan.c | 8 ++++---- drivers/staging/wavelan/wavelan_cs.c | 11 ++++++----- drivers/staging/wlags49_h2/wl_netdev.c | 12 ++++++------ net/bluetooth/bnep/netdev.c | 6 ++++-- net/core/dev.c | 2 +- net/irda/irlan/irlan_eth.c | 5 +++-- net/mac80211/iface.c | 2 +- 173 files changed, 440 insertions(+), 401 deletions(-) (limited to 'drivers/net/qlcnic') diff --git a/arch/xtensa/platforms/iss/network.c b/arch/xtensa/platforms/iss/network.c index 2f0b86b37cf..87e218f98ef 100644 --- a/arch/xtensa/platforms/iss/network.c +++ b/arch/xtensa/platforms/iss/network.c @@ -560,7 +560,7 @@ static void iss_net_set_multicast_list(struct net_device *dev) #if 0 if (dev->flags & IFF_PROMISC) return; - else if (dev->mc_count) + else if (!netdev_mc_empty(dev)) dev->flags |= IFF_ALLMULTI; else dev->flags &= ~IFF_ALLMULTI; diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c index ab110278018..c04f8fc6fc2 100644 --- a/drivers/infiniband/hw/nes/nes_nic.c +++ b/drivers/infiniband/hw/nes/nes_nic.c @@ -862,7 +862,7 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev) } nes_debug(NES_DBG_NIC_RX, "Number of MC entries = %d, Promiscous = %d, All Multicast = %d.\n", - netdev->mc_count, !!(netdev->flags & IFF_PROMISC), + netdev_mc_count(netdev), !!(netdev->flags & IFF_PROMISC), !!(netdev->flags & IFF_ALLMULTI)); if (!mc_all_on) { multicast_addr = netdev->mc_list; diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index da6552d32cf..37d8579fc7a 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -1138,18 +1138,18 @@ static void wq_set_multicast_list (struct work_struct *work) } else if ((dev->flags & IFF_ALLMULTI)) { dprintk("%s: allmulti mode\n", dev->name); priv->rx_mode = RX_MODE_ALL_MULTI; - } else if (dev->mc_count) { + } else if (!netdev_mc_empty(dev)) { int mci; struct dev_mc_list *mc; dprintk("%s: set_mc_list, %d entries\n", - dev->name, dev->mc_count); + dev->name, netdev_mc_count(dev)); priv->rx_mode = RX_MODE_MULTI; priv->multi_num = 0; for (mci = 0, mc=dev->mc_list; - mci < dev->mc_count; + mci < netdev_mc_count(dev); mc = mc->next, mci++) { dvb_set_mc_filter(dev, mc); } @@ -1236,7 +1236,6 @@ static void dvb_net_setup(struct net_device *dev) dev->header_ops = &dvb_header_ops; dev->netdev_ops = &dvb_netdev_ops; dev->mtu = 4096; - dev->mc_count = 0; dev->flags |= IFF_NOARP; } diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c index 9257d7ce037..dadb46a8833 100644 --- a/drivers/net/3c505.c +++ b/drivers/net/3c505.c @@ -1229,8 +1229,8 @@ static void elp_set_mc_list(struct net_device *dev) /* send a "load multicast list" command to the board, max 10 addrs/cmd */ /* if num_addrs==0 the list will be cleared */ adapter->tx_pcb.command = CMD_LOAD_MULTICAST_LIST; - adapter->tx_pcb.length = 6 * dev->mc_count; - for (i = 0; i < dev->mc_count; i++) { + adapter->tx_pcb.length = 6 * netdev_mc_count(dev); + for (i = 0; i < netdev_mc_count(dev); i++) { memcpy(adapter->tx_pcb.data.multicast[i], dmi->dmi_addr, 6); dmi = dmi->next; } @@ -1244,7 +1244,7 @@ static void elp_set_mc_list(struct net_device *dev) TIMEOUT_MSG(__LINE__); } } - if (dev->mc_count) + if (!netdev_mc_empty(dev)) adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD | RECV_MULTI; else /* num_addrs == 0 */ adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD; diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index 9d85efce591..902435a7646 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -1111,12 +1111,14 @@ set_multicast_list(struct net_device *dev) unsigned long flags; struct el3_private *lp = netdev_priv(dev); int ioaddr = dev->base_addr; + int mc_count = netdev_mc_count(dev); if (el3_debug > 1) { static int old; - if (old != dev->mc_count) { - old = dev->mc_count; - pr_debug("%s: Setting Rx mode to %d addresses.\n", dev->name, dev->mc_count); + if (old != mc_count) { + old = mc_count; + pr_debug("%s: Setting Rx mode to %d addresses.\n", + dev->name, mc_count); } } spin_lock_irqsave(&lp->lock, flags); @@ -1124,7 +1126,7 @@ set_multicast_list(struct net_device *dev) outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm, ioaddr + EL3_CMD); } - else if (dev->mc_count || (dev->flags&IFF_ALLMULTI)) { + else if (mc_count || (dev->flags&IFF_ALLMULTI)) { outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast, ioaddr + EL3_CMD); } else diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c index 27d80ca5e4c..6948d667fc5 100644 --- a/drivers/net/3c523.c +++ b/drivers/net/3c523.c @@ -626,7 +626,7 @@ static int init586(struct net_device *dev) volatile struct tdr_cmd_struct *tdr_cmd; volatile struct mcsetup_cmd_struct *mc_cmd; struct dev_mc_list *dmi = dev->mc_list; - int num_addrs = dev->mc_count; + int num_addrs = netdev_mc_count(dev); ptr = (void *) ((char *) p->scb + sizeof(struct scb_struct)); @@ -771,7 +771,7 @@ static int init586(struct net_device *dev) * Multicast setup */ - if (dev->mc_count) { + if (num_addrs) { /* I don't understand this: do we really need memory after the init? */ int len = ((char *) p->iscp - (char *) ptr - 8) / 6; if (len <= 0) { diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c index 36c4191e7bc..ce982698051 100644 --- a/drivers/net/3c527.c +++ b/drivers/net/3c527.c @@ -1526,10 +1526,10 @@ static void do_mc32_set_multicast_list(struct net_device *dev, int retry) if ((dev->flags&IFF_PROMISC) || (dev->flags&IFF_ALLMULTI) || - dev->mc_count > 10) + netdev_mc_count(dev) > 10) /* Enable promiscuous mode */ filt |= 1; - else if(dev->mc_count) + else if (!netdev_mc_empty(dev)) { unsigned char block[62]; unsigned char *bp; @@ -1542,16 +1542,17 @@ static void do_mc32_set_multicast_list(struct net_device *dev, int retry) if(!lp->mc_list_valid) { block[1]=0; - block[0]=dev->mc_count; + block[0]=netdev_mc_count(dev); bp=block+2; - for(i=0;imc_count;i++) + for(i=0;idmi_addr, 6); bp+=6; dmc=dmc->next; } - if(mc32_command_nowait(dev, 2, block, 2+6*dev->mc_count)==-1) + if(mc32_command_nowait(dev, 2, block, + 2+6*netdev_mc_count(dev))==-1) { lp->mc_reload_wait = 1; return; diff --git a/drivers/net/7990.c b/drivers/net/7990.c index b1e5764628c..079d0be3782 100644 --- a/drivers/net/7990.c +++ b/drivers/net/7990.c @@ -611,7 +611,7 @@ static void lance_load_multicast (struct net_device *dev) ib->filter [1] = 0; /* Add addresses */ - for (i = 0; i < dev->mc_count; i++){ + for (i = 0; i < netdev_mc_count(dev); i++){ addrs = dmi->dmi_addr; dmi = dmi->next; diff --git a/drivers/net/82596.c b/drivers/net/82596.c index 1663bc9e45d..638ce3b2985 100644 --- a/drivers/net/82596.c +++ b/drivers/net/82596.c @@ -1505,7 +1505,7 @@ static void set_multicast_list(struct net_device *dev) int config = 0, cnt; DEB(DEB_MULTI,printk(KERN_DEBUG "%s: set multicast list, %d entries, promisc %s, allmulti %s\n", - dev->name, dev->mc_count, + dev->name, netdev_mc_count(dev), dev->flags & IFF_PROMISC ? "ON" : "OFF", dev->flags & IFF_ALLMULTI ? "ON" : "OFF")); @@ -1533,7 +1533,7 @@ static void set_multicast_list(struct net_device *dev) i596_add_cmd(dev, &lp->cf_cmd.cmd); } - cnt = dev->mc_count; + cnt = netdev_mc_count(dev); if (cnt > MAX_MC_CNT) { cnt = MAX_MC_CNT; @@ -1541,7 +1541,7 @@ static void set_multicast_list(struct net_device *dev) dev->name, cnt); } - if (dev->mc_count > 0) { + if (!netdev_mc_empty(dev)) { struct dev_mc_list *dmi; unsigned char *cp; struct mc_cmd *cmd; @@ -1550,7 +1550,7 @@ static void set_multicast_list(struct net_device *dev) return; cmd = &lp->mc_cmd; cmd->cmd.command = CmdMulticastList; - cmd->mc_cnt = dev->mc_count * 6; + cmd->mc_cnt = netdev_mc_count(dev) * 6; cp = cmd->mc_addrs; for (dmi = dev->mc_list; cnt && dmi != NULL; dmi = dmi->next, cnt--, cp += 6) { memcpy(cp, dmi->dmi_addr, 6); diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index b7ec0368d7e..6a65f660c19 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -619,7 +619,7 @@ static void lance_load_multicast (struct net_device *dev) ib->filter [1] = 0; /* Add addresses */ - for (i = 0; i < dev->mc_count; i++){ + for (i = 0; i < netdev_mc_count(dev); i++){ addrs = dmi->dmi_addr; dmi = dmi->next; diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index ec624ab03e8..4ae750ef1e1 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -2845,7 +2845,7 @@ static void ace_set_multicast_list(struct net_device *dev) * set the entire multicast list at a time and keeping track of * it here is going to be messy. */ - if ((dev->mc_count) && !(ap->mcast_all)) { + if (!netdev_mc_empty(dev) && !ap->mcast_all) { cmd.evt = C_SET_MULTICAST_MODE; cmd.code = C_C_MCAST_ENABLE; cmd.idx = 0; diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index bb27b27d967..bdffdfb4c88 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -1387,7 +1387,8 @@ static void amd8111e_set_multicast_list(struct net_device *dev) } else writel( PROM, lp->mmio + CMD2); - if(dev->flags & IFF_ALLMULTI || dev->mc_count > MAX_FILTER_SIZE){ + if (dev->flags & IFF_ALLMULTI || + netdev_mc_count(dev) > MAX_FILTER_SIZE) { /* get all multicast packet */ mc_filter[1] = mc_filter[0] = 0xffffffff; lp->mc_list = dev->mc_list; @@ -1395,7 +1396,7 @@ static void amd8111e_set_multicast_list(struct net_device *dev) amd8111e_writeq(*(u64*)mc_filter,lp->mmio + LADRF); return; } - if( dev->mc_count == 0 ){ + if (netdev_mc_empty(dev)) { /* get only own packets */ mc_filter[1] = mc_filter[0] = 0; lp->mc_list = NULL; @@ -1409,7 +1410,7 @@ static void amd8111e_set_multicast_list(struct net_device *dev) lp->options |= OPTION_MULTICAST_ENABLE; lp->mc_list = dev->mc_list; mc_filter[1] = mc_filter[0] = 0; - for (i = 0, mc_ptr = dev->mc_list; mc_ptr && i < dev->mc_count; + for (i = 0, mc_ptr = dev->mc_list; mc_ptr && i < netdev_mc_count(dev); i++, mc_ptr = mc_ptr->next) { bit_num = (ether_crc_le(ETH_ALEN, mc_ptr->dmi_addr) >> 26) & 0x3f; mc_filter[bit_num >> 5] |= 1 << (bit_num & 31); diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c index e2c202493fa..08d8be47dae 100644 --- a/drivers/net/ariadne.c +++ b/drivers/net/ariadne.c @@ -819,7 +819,7 @@ static void set_multicast_list(struct net_device *dev) lance->RDP = PROM; /* Set promiscuous mode */ } else { short multicast_table[4]; - int num_addrs = dev->mc_count; + int num_addrs = netdev_mc_count(dev); int i; /* We don't use the multicast table, but rely on upper-layer filtering. */ memset(multicast_table, (num_addrs == 0) ? 0 : -1, diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c index c8bc60a7040..17d85d98987 100644 --- a/drivers/net/arm/at91_ether.c +++ b/drivers/net/arm/at91_ether.c @@ -563,7 +563,7 @@ static void at91ether_sethashtable(struct net_device *dev) mc_filter[0] = mc_filter[1] = 0; curr = dev->mc_list; - for (i = 0; i < dev->mc_count; i++, curr = curr->next) { + for (i = 0; i < netdev_mc_count(dev); i++, curr = curr->next) { if (!curr) break; /* unexpected end of list */ bitnr = hash_get_index(curr->dmi_addr); @@ -592,7 +592,7 @@ static void at91ether_set_multicast_list(struct net_device *dev) at91_emac_write(AT91_EMAC_HSH, -1); at91_emac_write(AT91_EMAC_HSL, -1); cfg |= AT91_EMAC_MTI; - } else if (dev->mc_count > 0) { /* Enable specific multicasts */ + } else if (!netdev_mc_empty(dev)) { /* Enable specific multicasts */ at91ether_sethashtable(dev); cfg |= AT91_EMAC_MTI; } else if (dev->flags & (~IFF_ALLMULTI)) { /* Disable all multicast mode */ diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c index 1f7a69c929a..d9de9bce239 100644 --- a/drivers/net/arm/ether3.c +++ b/drivers/net/arm/ether3.c @@ -463,7 +463,7 @@ static void ether3_setmulticastlist(struct net_device *dev) if (dev->flags & IFF_PROMISC) { /* promiscuous mode */ priv(dev)->regs.config1 |= CFG1_RECVPROMISC; - } else if (dev->flags & IFF_ALLMULTI || dev->mc_count) { + } else if (dev->flags & IFF_ALLMULTI || !netdev_mc_empty(dev)) { priv(dev)->regs.config1 |= CFG1_RECVSPECBRMULTI; } else priv(dev)->regs.config1 |= CFG1_RECVSPECBROAD; diff --git a/drivers/net/arm/ixp4xx_eth.c b/drivers/net/arm/ixp4xx_eth.c index c3dfbdd2cdc..1a5f78b160f 100644 --- a/drivers/net/arm/ixp4xx_eth.c +++ b/drivers/net/arm/ixp4xx_eth.c @@ -737,7 +737,7 @@ static void eth_set_mcast_list(struct net_device *dev) struct port *port = netdev_priv(dev); struct dev_mc_list *mclist = dev->mc_list; u8 diffs[ETH_ALEN], *addr; - int cnt = dev->mc_count, i; + int cnt = netdev_mc_count(dev), i; if ((dev->flags & IFF_PROMISC) || !mclist || !cnt) { __raw_writel(DEFAULT_RX_CNTRL0 & ~RX_CNTRL0_ADDR_FLTR_EN, diff --git a/drivers/net/arm/ks8695net.c b/drivers/net/arm/ks8695net.c index be256b34cea..1dc181a9fbc 100644 --- a/drivers/net/arm/ks8695net.c +++ b/drivers/net/arm/ks8695net.c @@ -1207,7 +1207,7 @@ ks8695_set_multicast(struct net_device *ndev) if (ndev->flags & IFF_ALLMULTI) { /* enable all multicast mode */ ctrl |= DRXC_RM; - } else if (ndev->mc_count > KS8695_NR_ADDRESSES) { + } else if (netdev_mc_count(ndev) > KS8695_NR_ADDRESSES) { /* more specific multicast addresses than can be * handled in hardware */ @@ -1216,7 +1216,7 @@ ks8695_set_multicast(struct net_device *ndev) /* enable specific multicasts */ ctrl &= ~DRXC_RM; ks8695_init_partial_multicast(ksp, ndev->mc_list, - ndev->mc_count); + netdev_mc_count(ndev)); } ks8695_writereg(ksp, KS8695_DRXC, ctrl); diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c index b14f4799d5d..fe60cd02c86 100644 --- a/drivers/net/at1700.c +++ b/drivers/net/at1700.c @@ -839,12 +839,12 @@ set_rx_mode(struct net_device *dev) if (dev->flags & IFF_PROMISC) { memset(mc_filter, 0xff, sizeof(mc_filter)); outb(3, ioaddr + RX_MODE); /* Enable promiscuous mode */ - } else if (dev->mc_count > MC_FILTERBREAK || + } else if (netdev_mc_count(dev) > MC_FILTERBREAK || (dev->flags & IFF_ALLMULTI)) { /* Too many to filter perfectly -- accept all multicasts. */ memset(mc_filter, 0xff, sizeof(mc_filter)); outb(2, ioaddr + RX_MODE); /* Use normal mode. */ - } else if (dev->mc_count == 0) { + } else if (netdev_mc_empty(dev)) { memset(mc_filter, 0x00, sizeof(mc_filter)); outb(1, ioaddr + RX_MODE); /* Ignore almost all multicasts. */ } else { @@ -852,7 +852,7 @@ set_rx_mode(struct net_device *dev) int i; memset(mc_filter, 0, sizeof(mc_filter)); - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { unsigned int bit = ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 26; diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index cc9ed864391..280cfff48b4 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -1097,7 +1097,7 @@ static void set_multicast_list( struct net_device *dev ) REGA( CSR15 ) = 0x8000; /* Set promiscuous mode */ } else { short multicast_table[4]; - int num_addrs = dev->mc_count; + int num_addrs = netdev_mc_count(dev); int i; /* We don't use the multicast table, but rely on upper-layer * filtering. */ diff --git a/drivers/net/atp.c b/drivers/net/atp.c index 2f8261c9614..a841feb5df2 100644 --- a/drivers/net/atp.c +++ b/drivers/net/atp.c @@ -861,7 +861,7 @@ static void set_rx_mode_8002(struct net_device *dev) struct net_local *lp = netdev_priv(dev); long ioaddr = dev->base_addr; - if (dev->mc_count > 0 || (dev->flags & (IFF_ALLMULTI|IFF_PROMISC))) + if (!netdev_mc_empty(dev) || (dev->flags & (IFF_ALLMULTI|IFF_PROMISC))) lp->addr_mode = CMR2h_PROMISC; else lp->addr_mode = CMR2h_Normal; @@ -877,7 +877,8 @@ static void set_rx_mode_8012(struct net_device *dev) if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ new_mode = CMR2h_PROMISC; - } else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) { + } else if ((netdev_mc_count(dev) > 1000) || + (dev->flags & IFF_ALLMULTI)) { /* Too many to filter perfectly -- accept all multicasts. */ memset(mc_filter, 0xff, sizeof(mc_filter)); new_mode = CMR2h_Normal; @@ -885,7 +886,7 @@ static void set_rx_mode_8012(struct net_device *dev) struct dev_mc_list *mclist; memset(mc_filter, 0, sizeof(mc_filter)); - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { int filterbit = ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f; diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index 6bac04603a8..9337d023919 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -1013,7 +1013,7 @@ static void au1000_multicast_list(struct net_device *dev) if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ aup->mac->control |= MAC_PROMISCUOUS; } else if ((dev->flags & IFF_ALLMULTI) || - dev->mc_count > MULTICAST_FILTER_LIMIT) { + netdev_mc_count(dev) > MULTICAST_FILTER_LIMIT) { aup->mac->control |= MAC_PASS_ALL_MULTI; aup->mac->control &= ~MAC_PROMISCUOUS; printk(KERN_INFO "%s: Pass all multicast\n", dev->name); @@ -1023,7 +1023,7 @@ static void au1000_multicast_list(struct net_device *dev) u32 mc_filter[2]; /* Multicast hash filter */ mc_filter[1] = mc_filter[0] = 0; - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26, (long *)mc_filter); diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 44b66be3813..9091c6574b1 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -1691,7 +1691,7 @@ static int __b44_load_mcast(struct b44 *bp, struct net_device *dev) struct dev_mc_list *mclist; int i, num_ents; - num_ents = min_t(int, dev->mc_count, B44_MCAST_TABLE_SIZE); + num_ents = min_t(int, netdev_mc_count(dev), B44_MCAST_TABLE_SIZE); mclist = dev->mc_list; for (i = 0; mclist && i < num_ents; i++, mclist = mclist->next) { __b44_cam_write(bp, mclist->dmi_addr, i + 1); @@ -1716,7 +1716,7 @@ static void __b44_set_rx_mode(struct net_device *dev) __b44_set_mac_addr(bp); if ((dev->flags & IFF_ALLMULTI) || - (dev->mc_count > B44_MCAST_TABLE_SIZE)) + (netdev_mc_count(dev) > B44_MCAST_TABLE_SIZE)) val |= RXCONFIG_ALLMULTI; else i = __b44_load_mcast(bp, dev); diff --git a/drivers/net/bcm63xx_enet.c b/drivers/net/bcm63xx_enet.c index 0bd47d32ec4..0927ffa0d75 100644 --- a/drivers/net/bcm63xx_enet.c +++ b/drivers/net/bcm63xx_enet.c @@ -619,7 +619,7 @@ static void bcm_enet_set_multicast_list(struct net_device *dev) /* only 3 perfect match registers left, first one is used for * own mac address */ - if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > 3) + if ((dev->flags & IFF_ALLMULTI) || netdev_mc_count(dev) > 3) val |= ENET_RXCFG_ALLMCAST_MASK; else val &= ~ENET_RXCFG_ALLMCAST_MASK; @@ -632,7 +632,7 @@ static void bcm_enet_set_multicast_list(struct net_device *dev) } for (i = 0, mc_list = dev->mc_list; - (mc_list != NULL) && (i < dev->mc_count) && (i < 3); + (mc_list != NULL) && (i < netdev_mc_count(dev)) && (i < 3); i++, mc_list = mc_list->next) { u8 *dmi_addr; u32 tmp; diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 626b76c0ebc..0014a4e8644 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -565,14 +565,15 @@ static void be_set_multicast_list(struct net_device *netdev) } /* Enable multicast promisc if num configured exceeds what we support */ - if (netdev->flags & IFF_ALLMULTI || netdev->mc_count > BE_MAX_MC) { + if (netdev->flags & IFF_ALLMULTI || + netdev_mc_count(netdev) > BE_MAX_MC) { be_cmd_multicast_set(adapter, adapter->if_handle, NULL, 0, &adapter->mc_cmd_mem); goto done; } be_cmd_multicast_set(adapter, adapter->if_handle, netdev->mc_list, - netdev->mc_count, &adapter->mc_cmd_mem); + netdev_mc_count(netdev), &adapter->mc_cmd_mem); done: return; } diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index 0b23bc4f56c..ef7f77113e2 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -819,7 +819,7 @@ static void bfin_mac_multicast_hash(struct net_device *dev) emac_hashhi = emac_hashlo = 0; - for (i = 0; i < dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(dev); i++) { addrs = dmi->dmi_addr; dmi = dmi->next; @@ -862,7 +862,7 @@ static void bfin_mac_set_multicast_list(struct net_device *dev) sysctl = bfin_read_EMAC_OPMODE(); sysctl |= PAM; bfin_write_EMAC_OPMODE(sysctl); - } else if (dev->mc_count) { + } else if (!netdev_mc_empty(dev)) { /* set up multicast hash table */ sysctl = bfin_read_EMAC_OPMODE(); sysctl |= HM; diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c index 9b587c34419..189fa69c209 100644 --- a/drivers/net/bmac.c +++ b/drivers/net/bmac.c @@ -973,7 +973,7 @@ static void bmac_set_multicast(struct net_device *dev) { struct dev_mc_list *dmi; struct bmac_data *bp = netdev_priv(dev); - int num_addrs = dev->mc_count; + int num_addrs = netdev_mc_count(dev); unsigned short rx_cfg; int i; @@ -982,7 +982,7 @@ static void bmac_set_multicast(struct net_device *dev) XXDEBUG(("bmac: enter bmac_set_multicast, n_addrs=%d\n", num_addrs)); - if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) { + if((dev->flags & IFF_ALLMULTI) || (netdev_mc_count(dev) > 64)) { for (i=0; i<4; i++) bp->hash_table_mask[i] = 0xffff; bmac_update_hash_table_mask(dev, bp); rx_cfg = bmac_rx_on(dev, 1, 0); @@ -1021,7 +1021,7 @@ static void bmac_set_multicast(struct net_device *dev) unsigned short rx_cfg; u32 crc; - if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) { + if((dev->flags & IFF_ALLMULTI) || (netdev_mc_count(dev) > 64)) { bmwrite(dev, BHASH0, 0xffff); bmwrite(dev, BHASH1, 0xffff); bmwrite(dev, BHASH2, 0xffff); @@ -1039,7 +1039,7 @@ static void bmac_set_multicast(struct net_device *dev) for(i = 0; i < 4; i++) hash_table[i] = 0; - for(i = 0; i < dev->mc_count; i++) { + for(i = 0; i < netdev_mc_count(dev); i++) { addrs = dmi->dmi_addr; dmi = dmi->next; diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 5917b941aca..c7f5515ddaa 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -3560,7 +3560,7 @@ bnx2_set_rx_mode(struct net_device *dev) memset(mc_filter, 0, 4 * NUM_MC_HASH_REGISTERS); - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { crc = ether_crc_le(ETH_ALEN, mclist->dmi_addr); diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index ffc7381969a..6d8559052ee 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -11471,7 +11471,8 @@ static void bnx2x_set_rx_mode(struct net_device *dev) rx_mode = BNX2X_RX_MODE_PROMISC; else if ((dev->flags & IFF_ALLMULTI) || - ((dev->mc_count > BNX2X_MAX_MULTICAST) && CHIP_IS_E1(bp))) + ((netdev_mc_count(dev) > BNX2X_MAX_MULTICAST) && + CHIP_IS_E1(bp))) rx_mode = BNX2X_RX_MODE_ALLMULTI; else { /* some multicasts */ @@ -11482,7 +11483,7 @@ static void bnx2x_set_rx_mode(struct net_device *dev) bnx2x_sp(bp, mcast_config); for (i = 0, mclist = dev->mc_list; - mclist && (i < dev->mc_count); + mclist && (i < netdev_mc_count(dev)); i++, mclist = mclist->next) { config->config_table[i]. @@ -11554,7 +11555,7 @@ static void bnx2x_set_rx_mode(struct net_device *dev) memset(mc_filter, 0, 4 * MC_HASH_SIZE); for (i = 0, mclist = dev->mc_list; - mclist && (i < dev->mc_count); + mclist && (i < netdev_mc_count(dev)); i++, mclist = mclist->next) { DP(NETIF_MSG_IFUP, "Adding mcast MAC: %pM\n", diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h index f6462b54f82..bb159d9603b 100644 --- a/drivers/net/chelsio/common.h +++ b/drivers/net/chelsio/common.h @@ -97,13 +97,13 @@ struct t1_rx_mode { #define t1_rx_mode_promisc(rm) (rm->dev->flags & IFF_PROMISC) #define t1_rx_mode_allmulti(rm) (rm->dev->flags & IFF_ALLMULTI) -#define t1_rx_mode_mc_cnt(rm) (rm->dev->mc_count) +#define t1_rx_mode_mc_cnt(rm) (netdev_mc_count(rm->dev)) static inline u8 *t1_get_next_mcaddr(struct t1_rx_mode *rm) { u8 *addr = NULL; - if (rm->idx++ < rm->dev->mc_count) { + if (rm->idx++ < t1_rx_mode_mc_cnt(rm)) { addr = rm->list->dmi_addr; rm->list = rm->list->next; } diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index 8d0be26f94e..c9c537be4ab 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c @@ -340,7 +340,7 @@ static void cpmac_set_multicast_list(struct net_device *dev) * cpmac uses some strange mac address hashing * (not crc32) */ - for (i = 0, iter = dev->mc_list; i < dev->mc_count; + for (i = 0, iter = dev->mc_list; i < netdev_mc_count(dev); i++, iter = iter->next) { bit = 0; tmp = iter->dmi_addr[0]; diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c index a24be34a3f7..c9309eadebc 100644 --- a/drivers/net/cris/eth_v10.c +++ b/drivers/net/cris/eth_v10.c @@ -1564,7 +1564,7 @@ static void set_multicast_list(struct net_device *dev) { struct net_local *lp = netdev_priv(dev); - int num_addr = dev->mc_count; + int num_addr = netdev_mc_count(dev); unsigned long int lo_bits; unsigned long int hi_bits; diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c index faffad40998..d1e03b5984c 100644 --- a/drivers/net/davinci_emac.c +++ b/drivers/net/davinci_emac.c @@ -956,11 +956,11 @@ static void emac_dev_mcast_set(struct net_device *ndev) } else { mbp_enable = (mbp_enable & ~EMAC_MBP_RXPROMISC); if ((ndev->flags & IFF_ALLMULTI) || - (ndev->mc_count > EMAC_DEF_MAX_MULTICAST_ADDRESSES)) { + netdev_mc_count(ndev) > EMAC_DEF_MAX_MULTICAST_ADDRESSES) { mbp_enable = (mbp_enable | EMAC_MBP_RXMCAST); emac_add_mcast(priv, EMAC_ALL_MULTI_SET, NULL); } - if (ndev->mc_count > 0) { + if (!netdev_mc_empty(ndev)) { struct dev_mc_list *mc_ptr; mbp_enable = (mbp_enable | EMAC_MBP_RXMCAST); emac_add_mcast(priv, EMAC_ALL_MULTI_CLR, NULL); diff --git a/drivers/net/de620.c b/drivers/net/de620.c index 45794f6cb0f..a0a6830b5e6 100644 --- a/drivers/net/de620.c +++ b/drivers/net/de620.c @@ -464,7 +464,7 @@ static int de620_close(struct net_device *dev) static void de620_set_multicast_list(struct net_device *dev) { - if (dev->mc_count || dev->flags&(IFF_ALLMULTI|IFF_PROMISC)) + if (!netdev_mc_empty(dev) || dev->flags&(IFF_ALLMULTI|IFF_PROMISC)) { /* Enable promiscuous mode */ de620_set_register(dev, W_TCR, (TCR_DEF & ~RXPBM) | RXALL); } diff --git a/drivers/net/declance.c b/drivers/net/declance.c index be9590253aa..76e0de6a426 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -960,7 +960,7 @@ static void lance_load_multicast(struct net_device *dev) *lib_ptr(ib, filter[3], lp->type) = 0; /* Add addresses */ - for (i = 0; i < dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(dev); i++) { addrs = dmi->dmi_addr; dmi = dmi->next; diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c index 98da085445e..5adb1e03956 100644 --- a/drivers/net/defxx.c +++ b/drivers/net/defxx.c @@ -2227,7 +2227,7 @@ static void dfx_ctl_set_multicast_list(struct net_device *dev) * perfect filtering will be used. */ - if (dev->mc_count > (PI_CMD_ADDR_FILTER_K_SIZE - bp->uc_count)) + if (netdev_mc_count(dev) > (PI_CMD_ADDR_FILTER_K_SIZE - bp->uc_count)) { bp->group_prom = PI_FSTATE_K_PASS; /* Enable LLC group prom mode */ bp->mc_count = 0; /* Don't add mc addrs to CAM */ @@ -2235,7 +2235,7 @@ static void dfx_ctl_set_multicast_list(struct net_device *dev) else { bp->group_prom = PI_FSTATE_K_BLOCK; /* Disable LLC group prom mode */ - bp->mc_count = dev->mc_count; /* Add mc addrs to CAM */ + bp->mc_count = netdev_mc_count(dev); /* Add mc addrs to CAM */ } /* Copy addresses to multicast address table, then update adapter CAM */ diff --git a/drivers/net/depca.c b/drivers/net/depca.c index 0c1f491d20b..314bc96689f 100644 --- a/drivers/net/depca.c +++ b/drivers/net/depca.c @@ -1287,7 +1287,7 @@ static void SetMulticastFilter(struct net_device *dev) lp->init_block.mcast_table[i] = 0; } /* Add multicast addresses */ - for (i = 0; i < dev->mc_count; i++) { /* for each address in the list */ + for (i = 0; i < netdev_mc_count(dev); i++) { /* for each address in the list */ addrs = dmi->dmi_addr; dmi = dmi->next; if ((*addrs & 0x01) == 1) { /* multicast address? */ diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index 2a8b6a7c0b8..dea40953ed1 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -1128,17 +1128,17 @@ set_multicast (struct net_device *dev) /* Receive all frames promiscuously. */ rx_mode = ReceiveAllFrames; } else if ((dev->flags & IFF_ALLMULTI) || - (dev->mc_count > multicast_filter_limit)) { + (netdev_mc_count(dev) > multicast_filter_limit)) { /* Receive broadcast and multicast frames */ rx_mode = ReceiveBroadcast | ReceiveMulticast | ReceiveUnicast; - } else if (dev->mc_count > 0) { + } else if (!netdev_mc_empty(dev)) { int i; struct dev_mc_list *mclist; /* Receive broadcast frames and multicast frames filtering by Hashtable */ rx_mode = ReceiveBroadcast | ReceiveMulticastHash | ReceiveUnicast; - for (i=0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i=0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist=mclist->next) { int bit, index = 0; diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index b3773006568..da0985a7a87 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -725,7 +725,7 @@ dm9000_hash_table(struct net_device *dev) { board_info_t *db = netdev_priv(dev); struct dev_mc_list *mcptr = dev->mc_list; - int mc_cnt = dev->mc_count; + int mc_cnt = netdev_mc_count(dev); int i, oft; u32 hash_val; u16 hash_table[4]; diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 5c7a155e849..e8c0e823a06 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -1538,7 +1538,7 @@ static void e100_multi(struct nic *nic, struct cb *cb, struct sk_buff *skb) { struct net_device *netdev = nic->netdev; struct dev_mc_list *list = netdev->mc_list; - u16 i, count = min(netdev->mc_count, E100_MAX_MULTICAST_ADDRS); + u16 i, count = min(netdev_mc_count(netdev), E100_MAX_MULTICAST_ADDRS); cb->command = cpu_to_le16(cb_multi); cb->u.multi.count = cpu_to_le16(count * ETH_ALEN); @@ -1552,7 +1552,7 @@ static void e100_set_multicast_list(struct net_device *netdev) struct nic *nic = netdev_priv(netdev); DPRINTK(HW, DEBUG, "mc_count=%d, flags=0x%04X\n", - netdev->mc_count, netdev->flags); + netdev_mc_count(netdev), netdev->flags); if (netdev->flags & IFF_PROMISC) nic->flags |= promiscuous; @@ -1560,7 +1560,7 @@ static void e100_set_multicast_list(struct net_device *netdev) nic->flags &= ~promiscuous; if (netdev->flags & IFF_ALLMULTI || - netdev->mc_count > E100_MAX_MULTICAST_ADDRS) + netdev_mc_count(netdev) > E100_MAX_MULTICAST_ADDRS) nic->flags |= multicast_all; else nic->flags &= ~multicast_all; diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index 94c59498cdb..488bc13cc7e 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -1288,8 +1288,9 @@ set_multicast_list(struct net_device *dev) short ioaddr = dev->base_addr; unsigned short mode; struct dev_mc_list *dmi=dev->mc_list; + int mc_count = mc_count; - if (dev->flags&(IFF_ALLMULTI|IFF_PROMISC) || dev->mc_count > 63) + if (dev->flags&(IFF_ALLMULTI|IFF_PROMISC) || mc_count > 63) { eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */ mode = inb(ioaddr + REG2); @@ -1299,7 +1300,7 @@ set_multicast_list(struct net_device *dev) eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */ } - else if (dev->mc_count==0 ) + else if (mc_count == 0) { eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */ mode = inb(ioaddr + REG2); @@ -1329,9 +1330,9 @@ set_multicast_list(struct net_device *dev) outw(MC_SETUP, ioaddr + IO_PORT); outw(0, ioaddr + IO_PORT); outw(0, ioaddr + IO_PORT); - outw(6*(dev->mc_count + 1), ioaddr + IO_PORT); + outw(6 * (mc_count + 1), ioaddr + IO_PORT); - for (i = 0; i < dev->mc_count; i++) + for (i = 0; i < mc_count; i++) { eaddrs=(unsigned short *)dmi->dmi_addr; dmi=dmi->next; @@ -1348,7 +1349,7 @@ set_multicast_list(struct net_device *dev) outb(MC_SETUP, ioaddr); /* Update the transmit queue */ - i = lp->tx_end + XMT_HEADER + 6*(dev->mc_count + 1); + i = lp->tx_end + XMT_HEADER + 6 * (mc_count + 1); if (lp->tx_start != lp->tx_end) { @@ -1380,8 +1381,8 @@ set_multicast_list(struct net_device *dev) break; } else if ((i & 0x0f) == 0x03) { /* MC-Done */ printk(KERN_DEBUG "%s: set Rx mode to %d address%s.\n", - dev->name, dev->mc_count, - dev->mc_count > 1 ? "es":""); + dev->name, mc_count, + mc_count > 1 ? "es":""); break; } } diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index 6fbfc8eee63..d804ff18eda 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c @@ -1578,7 +1578,7 @@ static void eexp_setup_filter(struct net_device *dev) { struct dev_mc_list *dmi; unsigned short ioaddr = dev->base_addr; - int count = dev->mc_count; + int count = netdev_mc_count(dev); int i; if (count > 8) { printk(KERN_INFO "%s: too many multicast addresses (%d)\n", @@ -1627,9 +1627,9 @@ eexp_set_multicast(struct net_device *dev) } if (!(dev->flags & IFF_PROMISC)) { eexp_setup_filter(dev); - if (lp->old_mc_count != dev->mc_count) { + if (lp->old_mc_count != netdev_mc_count(dev)) { kick = 1; - lp->old_mc_count = dev->mc_count; + lp->old_mc_count = netdev_mc_count(dev); } } if (kick) { diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 7b62336e673..99e4f8360d2 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -1981,7 +1981,7 @@ static void ehea_set_multicast_list(struct net_device *dev) } ehea_allmulti(dev, 0); - if (dev->mc_count) { + if (!netdev_mc_empty(dev)) { ret = ehea_drop_multicast_list(dev); if (ret) { /* Dropping the current multicast list failed. @@ -1990,14 +1990,14 @@ static void ehea_set_multicast_list(struct net_device *dev) ehea_allmulti(dev, 1); } - if (dev->mc_count > port->adapter->max_mc_mac) { + if (netdev_mc_count(dev) > port->adapter->max_mc_mac) { ehea_info("Mcast registration limit reached (0x%llx). " "Use ALLMULTI!", port->adapter->max_mc_mac); goto out; } - for (i = 0, k_mcl_entry = dev->mc_list; i < dev->mc_count; i++, + for (i = 0, k_mcl_entry = dev->mc_list; i < netdev_mc_count(dev); i++, k_mcl_entry = k_mcl_entry->next) ehea_add_multicast_entry(port, k_mcl_entry->dmi_addr); diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c index 66813c91a72..3ee32e58c7e 100644 --- a/drivers/net/enc28j60.c +++ b/drivers/net/enc28j60.c @@ -1413,7 +1413,7 @@ static void enc28j60_set_multicast_list(struct net_device *dev) if (netif_msg_link(priv)) dev_info(&dev->dev, "promiscuous mode\n"); priv->rxfilter = RXFILTER_PROMISC; - } else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count) { + } else if ((dev->flags & IFF_ALLMULTI) || !netdev_mc_empty(dev)) { if (netif_msg_link(priv)) dev_info(&dev->dev, "%smulticast mode\n", (dev->flags & IFF_ALLMULTI) ? "all-" : ""); diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index c81bc4b1816..94749ebaaea 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -827,11 +827,11 @@ static void enic_set_multicast_list(struct net_device *netdev) int multicast = (netdev->flags & IFF_MULTICAST) ? 1 : 0; int broadcast = (netdev->flags & IFF_BROADCAST) ? 1 : 0; int promisc = (netdev->flags & IFF_PROMISC) ? 1 : 0; + unsigned int mc_count = netdev_mc_count(netdev); int allmulti = (netdev->flags & IFF_ALLMULTI) || - (netdev->mc_count > ENIC_MULTICAST_PERFECT_FILTERS); + mc_count > ENIC_MULTICAST_PERFECT_FILTERS; unsigned int flags = netdev->flags | (allmulti ? IFF_ALLMULTI : 0); u8 mc_addr[ENIC_MULTICAST_PERFECT_FILTERS][ETH_ALEN]; - unsigned int mc_count = netdev->mc_count; unsigned int i, j; if (mc_count > ENIC_MULTICAST_PERFECT_FILTERS) diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index 1f8b11449fa..31a3adb6556 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -1390,20 +1390,20 @@ static void set_rx_mode(struct net_device *dev) outl(0x002C, ioaddr + RxCtrl); /* Unconditionally log net taps. */ memset(mc_filter, 0xff, sizeof(mc_filter)); - } else if ((dev->mc_count > 0) || (dev->flags & IFF_ALLMULTI)) { + } else if ((!netdev_mc_empty(dev)) || (dev->flags & IFF_ALLMULTI)) { /* There is apparently a chip bug, so the multicast filter is never enabled. */ /* Too many to filter perfectly -- accept all multicasts. */ memset(mc_filter, 0xff, sizeof(mc_filter)); outl(0x000C, ioaddr + RxCtrl); - } else if (dev->mc_count == 0) { + } else if (netdev_mc_empty(dev)) { outl(0x0004, ioaddr + RxCtrl); return; } else { /* Never executed, for now. */ struct dev_mc_list *mclist; memset(mc_filter, 0, sizeof(mc_filter)); - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { unsigned int bit_nr = ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f; diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c index 71bfeec33a0..d3abeee3f11 100644 --- a/drivers/net/eth16i.c +++ b/drivers/net/eth16i.c @@ -1359,7 +1359,7 @@ static void eth16i_multicast(struct net_device *dev) { int ioaddr = dev->base_addr; - if(dev->mc_count || dev->flags&(IFF_ALLMULTI|IFF_PROMISC)) + if (!netdev_mc_empty(dev) || dev->flags&(IFF_ALLMULTI|IFF_PROMISC)) { outb(3, ioaddr + RECEIVE_MODE_REG); } else { diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c index dd4ba01fd92..96817a872f4 100644 --- a/drivers/net/ewrk3.c +++ b/drivers/net/ewrk3.c @@ -1213,7 +1213,7 @@ static void SetMulticastFilter(struct net_device *dev) } /* Update table */ - for (i = 0; i < dev->mc_count; i++) { /* for each address in the list */ + for (i = 0; i < netdev_mc_count(dev); i++) { /* for each address in the list */ addrs = dmi->dmi_addr; dmi = dmi->next; if ((*addrs & 0x01) == 1) { /* multicast address? */ diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index e6a98129d78..f95b5ff0587 100644 --- a/drivers/net/fealnx.c +++ b/drivers/net/fealnx.c @@ -1786,7 +1786,7 @@ static void __set_rx_mode(struct net_device *dev) if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ memset(mc_filter, 0xff, sizeof(mc_filter)); rx_mode = CR_W_PROM | CR_W_AB | CR_W_AM; - } else if ((dev->mc_count > multicast_filter_limit) || + } else if ((netdev_mc_count(dev) > multicast_filter_limit) || (dev->flags & IFF_ALLMULTI)) { /* Too many to match, or accept all multicasts. */ memset(mc_filter, 0xff, sizeof(mc_filter)); @@ -1796,7 +1796,7 @@ static void __set_rx_mode(struct net_device *dev) int i; memset(mc_filter, 0, sizeof(mc_filter)); - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { unsigned int bit; bit = (ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26) ^ 0x3F; diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 5d0d3326815..d9d14c83f51 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -1606,7 +1606,7 @@ static void set_multicast_list(struct net_device *dev) dmi = dev->mc_list; - for (j = 0; j < dev->mc_count; j++, dmi = dmi->next) { + for (j = 0; j < netdev_mc_count(dev); j++, dmi = dmi->next) { /* Only support group multicast for now */ if (!(dmi->dmi_addr[0] & 1)) continue; diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c index 848e8407ea8..10903b75802 100644 --- a/drivers/net/fec_mpc52xx.c +++ b/drivers/net/fec_mpc52xx.c @@ -581,7 +581,7 @@ static void mpc52xx_fec_set_multicast_list(struct net_device *dev) u32 gaddr2 = 0x00000000; dmi = dev->mc_list; - for (i=0; imc_count; i++) { + for (i=0; idmi_addr) >> 26; if (crc >= 32) gaddr1 |= 1 << (crc-32); diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c index 22e5a847a58..482f27d5f7d 100644 --- a/drivers/net/fs_enet/mac-fcc.c +++ b/drivers/net/fs_enet/mac-fcc.c @@ -218,7 +218,7 @@ static void set_multicast_finish(struct net_device *dev) /* if all multi or too many multicasts; just enable all */ if ((dev->flags & IFF_ALLMULTI) != 0 || - dev->mc_count > FCC_MAX_MULTICAST_ADDRS) { + netdev_mc_count(dev) > FCC_MAX_MULTICAST_ADDRS) { W32(ep, fen_gaddrh, 0xffffffff); W32(ep, fen_gaddrl, 0xffffffff); diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c index ca7bcb8ab3a..ddf13ef8ac8 100644 --- a/drivers/net/fs_enet/mac-fec.c +++ b/drivers/net/fs_enet/mac-fec.c @@ -220,7 +220,7 @@ static void set_multicast_finish(struct net_device *dev) /* if all multi or too many multicasts; just enable all */ if ((dev->flags & IFF_ALLMULTI) != 0 || - dev->mc_count > FEC_MAX_MULTICAST_ADDRS) { + netdev_mc_count(dev) > FEC_MAX_MULTICAST_ADDRS) { fep->fec.hthi = 0xffffffffU; fep->fec.htlo = 0xffffffffU; } diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c index 008cdd9cc53..141dbc91e5e 100644 --- a/drivers/net/fs_enet/mac-scc.c +++ b/drivers/net/fs_enet/mac-scc.c @@ -213,7 +213,7 @@ static void set_multicast_finish(struct net_device *dev) /* if all multi or too many multicasts; just enable all */ if ((dev->flags & IFF_ALLMULTI) != 0 || - dev->mc_count > SCC_MAX_MULTICAST_ADDRS) { + netdev_mc_count(dev) > SCC_MAX_MULTICAST_ADDRS) { W16(ep, sen_gaddr1, 0xffff); W16(ep, sen_gaddr2, 0xffff); diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 8bd3c9f1753..c9be090485d 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -2863,7 +2863,7 @@ static void gfar_set_multi(struct net_device *dev) em_num = 0; } - if (dev->mc_count == 0) + if (netdev_mc_empty(dev)) return; /* Parse the list, and set the appropriate bits */ diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index dd72c5025e6..c70b147b4fe 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -1854,13 +1854,13 @@ static void set_rx_mode(struct net_device *dev) if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ writew(0x000F, ioaddr + AddrMode); - } else if ((dev->mc_count > 63) || (dev->flags & IFF_ALLMULTI)) { + } else if ((netdev_mc_count(dev) > 63) || (dev->flags & IFF_ALLMULTI)) { /* Too many to match, or accept all multicasts. */ writew(0x000B, ioaddr + AddrMode); - } else if (dev->mc_count > 0) { /* Must use the CAM filter. */ + } else if (!netdev_mc_empty(dev)) { /* Must use the CAM filter. */ struct dev_mc_list *mclist; int i; - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { writel(*(u32*)(mclist->dmi_addr), ioaddr + 0x100 + i*8); writel(0x20000 | (*(u16*)&mclist->dmi_addr[4]), diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index 0c2f2e8b1c4..debac1bc679 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -2090,7 +2090,7 @@ static void hp100_set_multicast_list(struct net_device *dev) lp->mac2_mode = HP100_MAC2MODE6; /* promiscuous mode = get all good */ lp->mac1_mode = HP100_MAC1MODE6; /* packets on the net */ memset(&lp->hash_bytes, 0xff, 8); - } else if (dev->mc_count || (dev->flags & IFF_ALLMULTI)) { + } else if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI)) { lp->mac2_mode = HP100_MAC2MODE5; /* multicast mode = get packets for */ lp->mac1_mode = HP100_MAC1MODE5; /* me, broadcasts and all multicasts */ #ifdef HP100_MULTICAST_FILTER /* doesn't work!!! */ @@ -2104,9 +2104,10 @@ static void hp100_set_multicast_list(struct net_device *dev) memset(&lp->hash_bytes, 0x00, 8); #ifdef HP100_DEBUG - printk("hp100: %s: computing hash filter - mc_count = %i\n", dev->name, dev->mc_count); + printk("hp100: %s: computing hash filter - mc_count = %i\n", + dev->name, netdev_mc_count(dev)); #endif - for (i = 0, dmi = dev->mc_list; i < dev->mc_count; i++, dmi = dmi->next) { + for (i = 0, dmi = dev->mc_list; i < netdev_mc_count(dev); i++, dmi = dmi->next) { addrs = dmi->dmi_addr; if ((*addrs & 0x01) == 0x01) { /* multicast address? */ #ifdef HP100_DEBUG diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index fb5e019169e..b75d27e82a3 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -391,7 +391,7 @@ static void emac_hash_mc(struct emac_instance *dev) struct dev_mc_list *dmi; int i; - DBG(dev, "hash_mc %d" NL, dev->ndev->mc_count); + DBG(dev, "hash_mc %d" NL, netdev_mc_count(dev->ndev)); memset(gaht_temp, 0, sizeof (gaht_temp)); @@ -425,9 +425,9 @@ static inline u32 emac_iff2rmr(struct net_device *ndev) if (ndev->flags & IFF_PROMISC) r |= EMAC_RMR_PME; else if (ndev->flags & IFF_ALLMULTI || - (ndev->mc_count > EMAC_XAHT_SLOTS(dev))) + (netdev_mc_count(ndev) > EMAC_XAHT_SLOTS(dev))) r |= EMAC_RMR_PMME; - else if (ndev->mc_count > 0) + else if (!netdev_mc_empty(ndev)) r |= EMAC_RMR_MAE; return r; diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index a86693906ac..41b9c0efcbd 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -1062,7 +1062,8 @@ static void ibmveth_set_multicast_list(struct net_device *netdev) struct ibmveth_adapter *adapter = netdev_priv(netdev); unsigned long lpar_rc; - if((netdev->flags & IFF_PROMISC) || (netdev->mc_count > adapter->mcastFilterSize)) { + if ((netdev->flags & IFF_PROMISC) || + (netdev_mc_count(netdev) > adapter->mcastFilterSize)) { lpar_rc = h_multicast_ctrl(adapter->vdev->unit_address, IbmVethMcastEnableRecv | IbmVethMcastDisableFiltering, @@ -1083,7 +1084,7 @@ static void ibmveth_set_multicast_list(struct net_device *netdev) ibmveth_error_printk("h_multicast_ctrl rc=%ld when attempting to clear filter table\n", lpar_rc); } /* add the addresses to the filter table */ - for(i = 0; i < netdev->mc_count; ++i, mclist = mclist->next) { + for(i = 0; i < netdev_mc_count(netdev); ++i, mclist = mclist->next) { // add the multicast address to the filter table unsigned long mcast_addr = 0; memcpy(((char *)&mcast_addr)+2, mclist->dmi_addr, 6); diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 83cd0d7417d..28371d64820 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -2848,14 +2848,14 @@ static int igb_write_mc_addr_list(struct net_device *netdev) u32 vmolr = 0; int i; - if (!netdev->mc_count) { + if (netdev_mc_empty(netdev)) { /* nothing to program, so clear mc list */ igb_update_mc_addr_list(hw, NULL, 0); igb_restore_vf_multicasts(adapter); return 0; } - mta_list = kzalloc(netdev->mc_count * 6, GFP_ATOMIC); + mta_list = kzalloc(netdev_mc_count(netdev) * 6, GFP_ATOMIC); if (!mta_list) return -ENOMEM; @@ -2865,7 +2865,7 @@ static int igb_write_mc_addr_list(struct net_device *netdev) /* The shared function expects a packed array of only addresses. */ mc_ptr = netdev->mc_list; - for (i = 0; i < netdev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(netdev); i++) { if (!mc_ptr) break; memcpy(mta_list + (i*ETH_ALEN), mc_ptr->dmi_addr, ETH_ALEN); @@ -2874,7 +2874,7 @@ static int igb_write_mc_addr_list(struct net_device *netdev) igb_update_mc_addr_list(hw, mta_list, i); kfree(mta_list); - return netdev->mc_count; + return netdev_mc_count(netdev); } /** diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c index 23ce07d3de0..6029c400f2b 100644 --- a/drivers/net/igbvf/netdev.c +++ b/drivers/net/igbvf/netdev.c @@ -1403,8 +1403,8 @@ static void igbvf_set_multi(struct net_device *netdev) u8 *mta_list = NULL; int i; - if (netdev->mc_count) { - mta_list = kmalloc(netdev->mc_count * 6, GFP_ATOMIC); + if (!netdev_mc_empty(netdev)) { + mta_list = kmalloc(netdev_mc_count(netdev) * 6, GFP_ATOMIC); if (!mta_list) { dev_err(&adapter->pdev->dev, "failed to allocate multicast filter list\n"); @@ -1415,7 +1415,7 @@ static void igbvf_set_multi(struct net_device *netdev) /* prepare a packed array of only addresses. */ mc_ptr = netdev->mc_list; - for (i = 0; i < netdev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(netdev); i++) { if (!mc_ptr) break; memcpy(mta_list + (i*ETH_ALEN), mc_ptr->dmi_addr, diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index 81a4c5d3073..0bd5fef22d4 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -1681,14 +1681,15 @@ static void ioc3_set_multicast_list(struct net_device *dev) ioc3_w_emcr(ip->emcr); /* Clear promiscuous. */ (void) ioc3_r_emcr(); - if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) { + if ((dev->flags & IFF_ALLMULTI) || + (netdev_mc_count(dev) > 64)) { /* Too many for hashing to make sense or we want all multicast packets anyway, so skip computing all the hashes and just accept all packets. */ ip->ehar_h = 0xffffffff; ip->ehar_l = 0xffffffff; } else { - for (i = 0; i < dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(dev); i++) { char *addr = dmi->dmi_addr; dmi = dmi->next; diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c index 49f35e2ed19..dbdebd5efe8 100644 --- a/drivers/net/ipg.c +++ b/drivers/net/ipg.c @@ -585,11 +585,11 @@ static void ipg_nic_set_multicast_list(struct net_device *dev) receivemode = IPG_RM_RECEIVEALLFRAMES; } else if ((dev->flags & IFF_ALLMULTI) || ((dev->flags & IFF_MULTICAST) && - (dev->mc_count > IPG_MULTICAST_HASHTABLE_SIZE))) { + (netdev_mc_count(dev) > IPG_MULTICAST_HASHTABLE_SIZE))) { /* NIC to be configured to receive all multicast * frames. */ receivemode |= IPG_RM_RECEIVEMULTICAST; - } else if ((dev->flags & IFF_MULTICAST) && (dev->mc_count > 0)) { + } else if ((dev->flags & IFF_MULTICAST) && !netdev_mc_empty(dev)) { /* NIC to be configured to receive selected * multicast addresses. */ receivemode |= IPG_RM_RECEIVEMULTICASTHASH; diff --git a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c index 04d0502726c..bb4a3cda6e4 100644 --- a/drivers/net/isa-skeleton.c +++ b/drivers/net/isa-skeleton.c @@ -655,14 +655,15 @@ set_multicast_list(struct net_device *dev) /* Enable promiscuous mode */ outw(MULTICAST|PROMISC, ioaddr); } - else if((dev->flags&IFF_ALLMULTI) || dev->mc_count > HW_MAX_ADDRS) + else if ((dev->flags&IFF_ALLMULTI) || + netdev_mc_count(dev) > HW_MAX_ADDRS) { /* Disable promiscuous mode, use normal mode. */ hardware_set_filter(NULL); outw(MULTICAST, ioaddr); } - else if(dev->mc_count) + else if (!netdev_mc_empty(dev)) { /* Walk the address list, and load the filter */ hardware_set_filter(dev->mc_list); diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index 16c91910d6c..ff015e15f5d 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c @@ -958,7 +958,7 @@ static void veth_set_multicast_list(struct net_device *dev) write_lock_irqsave(&port->mcast_gate, flags); if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) || - (dev->mc_count > VETH_MAX_MCAST)) { + (netdev_mc_count(dev) > VETH_MAX_MCAST)) { port->promiscuous = 1; } else { struct dev_mc_list *dmi = dev->mc_list; @@ -969,7 +969,7 @@ static void veth_set_multicast_list(struct net_device *dev) /* Update table */ port->num_mcast = 0; - for (i = 0; i < dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(dev); i++) { u8 *addr = dmi->dmi_addr; u64 xaddr = 0; diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index c56ea69762c..6a7b2ccef72 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -1077,7 +1077,7 @@ ixgb_set_multi(struct net_device *netdev) rctl |= IXGB_RCTL_VFE; } - if (netdev->mc_count > IXGB_MAX_NUM_MULTICAST_ADDRESSES) { + if (netdev_mc_count(netdev) > IXGB_MAX_NUM_MULTICAST_ADDRESSES) { rctl |= IXGB_RCTL_MPE; IXGB_WRITE_REG(hw, RCTL, rctl); } else { @@ -1092,7 +1092,7 @@ ixgb_set_multi(struct net_device *netdev) memcpy(&mta[i * IXGB_ETH_LENGTH_OF_ADDRESS], mc_ptr->dmi_addr, IXGB_ETH_LENGTH_OF_ADDRESS); - ixgb_mc_addr_list_update(hw, mta, netdev->mc_count, 0); + ixgb_mc_addr_list_update(hw, mta, netdev_mc_count(netdev), 0); } } @@ -1616,7 +1616,7 @@ ixgb_update_stats(struct ixgb_adapter *adapter) return; if ((netdev->flags & IFF_PROMISC) || (netdev->flags & IFF_ALLMULTI) || - (netdev->mc_count > IXGB_MAX_NUM_MULTICAST_ADDRESSES)) { + (netdev_mc_count(netdev) > IXGB_MAX_NUM_MULTICAST_ADDRESSES)) { u64 multi = IXGB_READ_REG(&adapter->hw, MPRCL); u32 bcast_l = IXGB_READ_REG(&adapter->hw, BPRCL); u32 bcast_h = IXGB_READ_REG(&adapter->hw, BPRCH); diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 382bf8945d1..0792f151de9 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -2571,7 +2571,7 @@ void ixgbe_set_rx_mode(struct net_device *netdev) hw->mac.ops.update_uc_addr_list(hw, netdev); /* reprogram multicast list */ - addr_count = netdev->mc_count; + addr_count = netdev_mc_count(netdev); if (addr_count) addr_list = netdev->mc_list->dmi_addr; hw->mac.ops.update_mc_addr_list(hw, addr_list, addr_count, diff --git a/drivers/net/ixgbevf/ixgbevf_main.c b/drivers/net/ixgbevf/ixgbevf_main.c index b9f10d05049..235b5fd4b8d 100644 --- a/drivers/net/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ixgbevf/ixgbevf_main.c @@ -1527,7 +1527,7 @@ static void ixgbevf_set_rx_mode(struct net_device *netdev) int addr_count = 0; /* reprogram multicast list */ - addr_count = netdev->mc_count; + addr_count = netdev_mc_count(netdev); if (addr_count) addr_list = netdev->mc_list->dmi_addr; if (hw->mac.ops.update_mc_addr_list) diff --git a/drivers/net/jme.c b/drivers/net/jme.c index 26eed49d320..d44c39dfbef 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -2013,7 +2013,7 @@ jme_set_multi(struct net_device *netdev) jme->reg_rxmcs |= RXMCS_MULFRAME | RXMCS_MULFILTERED; for (i = 0, mclist = netdev->mc_list; - mclist && i < netdev->mc_count; + mclist && i < netdev_mc_count(netdev); ++i, mclist = mclist->next) { bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) & 0x3F; diff --git a/drivers/net/korina.c b/drivers/net/korina.c index 25e2af6997e..af0c764130e 100644 --- a/drivers/net/korina.c +++ b/drivers/net/korina.c @@ -490,19 +490,19 @@ static void korina_multicast_list(struct net_device *dev) if (dev->flags & IFF_PROMISC) recognise |= ETH_ARC_PRO; - else if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 4)) + else if ((dev->flags & IFF_ALLMULTI) || (netdev_mc_count(dev) > 4)) /* All multicast and broadcast */ recognise |= ETH_ARC_AM; /* Build the hash table */ - if (dev->mc_count > 4) { + if (netdev_mc_count(dev) > 4) { u16 hash_table[4]; u32 crc; for (i = 0; i < 4; i++) hash_table[i] = 0; - for (i = 0; i < dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(dev); i++) { char *addrs = dmi->dmi_addr; dmi = dmi->next; diff --git a/drivers/net/ks8851.c b/drivers/net/ks8851.c index 6d3ac65bc35..9845ab1e557 100644 --- a/drivers/net/ks8851.c +++ b/drivers/net/ks8851.c @@ -965,14 +965,14 @@ static void ks8851_set_rx_mode(struct net_device *dev) rxctrl.rxcr1 = (RXCR1_RXME | RXCR1_RXAE | RXCR1_RXPAFMA | RXCR1_RXMAFMA); - } else if (dev->flags & IFF_MULTICAST && dev->mc_count > 0) { + } else if (dev->flags & IFF_MULTICAST && !netdev_mc_empty(dev)) { struct dev_mc_list *mcptr = dev->mc_list; u32 crc; int i; /* accept some multicast */ - for (i = dev->mc_count; i > 0; i--) { + for (i = netdev_mc_count(dev); i > 0; i--) { crc = ether_crc(ETH_ALEN, mcptr->dmi_addr); crc >>= (32 - 6); /* get top six bits */ diff --git a/drivers/net/ks8851_mll.c b/drivers/net/ks8851_mll.c index c0ceebccaa4..ffffb388970 100644 --- a/drivers/net/ks8851_mll.c +++ b/drivers/net/ks8851_mll.c @@ -1193,8 +1193,8 @@ static void ks_set_rx_mode(struct net_device *netdev) else ks_set_promis(ks, false); - if ((netdev->flags & IFF_MULTICAST) && netdev->mc_count) { - if (netdev->mc_count <= MAX_MCAST_LST) { + if ((netdev->flags & IFF_MULTICAST) && netdev_mc_count(netdev)) { + if (netdev_mc_count(netdev) <= MAX_MCAST_LST) { int i = 0; for (ptr = netdev->mc_list; ptr; ptr = ptr->next) { if (!(*ptr->dmi_addr & 1)) diff --git a/drivers/net/lance.c b/drivers/net/lance.c index 8d7d3d4625f..7b9447646f8 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -1288,7 +1288,7 @@ static void set_multicast_list(struct net_device *dev) } else { short multicast_table[4]; int i; - int num_addrs=dev->mc_count; + int num_addrs=netdev_mc_count(dev); if(dev->flags&IFF_ALLMULTI) num_addrs=1; /* FIXIT: We don't use the multicast table, but rely on upper-layer filtering. */ diff --git a/drivers/net/lib82596.c b/drivers/net/lib82596.c index b60efd4bd01..371b58b1d15 100644 --- a/drivers/net/lib82596.c +++ b/drivers/net/lib82596.c @@ -1380,21 +1380,21 @@ static void set_multicast_list(struct net_device *dev) } } - cnt = dev->mc_count; + cnt = netdev_mc_count(dev); if (cnt > MAX_MC_CNT) { cnt = MAX_MC_CNT; printk(KERN_NOTICE "%s: Only %d multicast addresses supported", dev->name, cnt); } - if (dev->mc_count > 0) { + if (!netdev_mc_empty(dev)) { struct dev_mc_list *dmi; unsigned char *cp; struct mc_cmd *cmd; cmd = &dma->mc_cmd; cmd->cmd.command = SWAP16(CmdMulticastList); - cmd->mc_cnt = SWAP16(dev->mc_count * 6); + cmd->mc_cnt = SWAP16(netdev_mc_count(dev) * 6); cp = cmd->mc_addrs; for (dmi = dev->mc_list; cnt && dmi != NULL; diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c index a8522bd73ae..8442c47e93e 100644 --- a/drivers/net/ll_temac_main.c +++ b/drivers/net/ll_temac_main.c @@ -232,7 +232,7 @@ static void temac_set_multicast_list(struct net_device *ndev) mutex_lock(&lp->indirect_mutex); if (ndev->flags & (IFF_ALLMULTI | IFF_PROMISC) || - ndev->mc_count > MULTICAST_CAM_TABLE_NUM) { + netdev_mc_count(ndev) > MULTICAST_CAM_TABLE_NUM) { /* * We must make the kernel realise we had to move * into promisc mode or we start all out war on @@ -242,9 +242,9 @@ static void temac_set_multicast_list(struct net_device *ndev) ndev->flags |= IFF_PROMISC; temac_indirect_out32(lp, XTE_AFM_OFFSET, XTE_AFM_EPPRM_MASK); dev_info(&ndev->dev, "Promiscuous mode enabled.\n"); - } else if (ndev->mc_count) { + } else if (!netdev_mc_empty(ndev)) { struct dev_mc_list *mclist = ndev->mc_list; - for (i = 0; mclist && i < ndev->mc_count; i++) { + for (i = 0; mclist && i < netdev_mc_count(ndev); i++) { if (i >= MULTICAST_CAM_TABLE_NUM) break; diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c index e20fefc73c8..b1f5d79af61 100644 --- a/drivers/net/lp486e.c +++ b/drivers/net/lp486e.c @@ -1253,18 +1253,19 @@ static void set_multicast_list(struct net_device *dev) { if (i596_debug > 1) printk ("%s: set multicast list %d\n", - dev->name, dev->mc_count); + dev->name, netdev_mc_count(dev)); - if (dev->mc_count > 0) { + if (!netdev_mc_empty(dev)) { struct dev_mc_list *dmi; char *cp; - cmd = kmalloc(sizeof(struct i596_cmd)+2+dev->mc_count*6, GFP_ATOMIC); + cmd = kmalloc(sizeof(struct i596_cmd) + 2 + + netdev_mc_count(dev) * 6, GFP_ATOMIC); if (cmd == NULL) { printk (KERN_ERR "%s: set_multicast Memory squeeze.\n", dev->name); return; } cmd->command = CmdMulticastList; - *((unsigned short *) (cmd + 1)) = dev->mc_count * 6; + *((unsigned short *) (cmd + 1)) = netdev_mc_count(dev) * 6; cp = ((char *)(cmd + 1))+2; for (dmi = dev->mc_list; dmi != NULL; dmi = dmi->next) { memcpy(cp, dmi,6); @@ -1277,7 +1278,8 @@ static void set_multicast_list(struct net_device *dev) { if (lp->set_conf.pa_next != I596_NULL) { return; } - if (dev->mc_count == 0 && !(dev->flags & (IFF_PROMISC | IFF_ALLMULTI))) { + if (netdev_mc_empty(dev) && + !(dev->flags & (IFF_PROMISC | IFF_ALLMULTI))) { lp->i596_config[8] &= ~0x01; } else { lp->i596_config[8] |= 0x01; diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 1d0d4d9ab62..fbc371fa19b 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -901,7 +901,7 @@ static void macb_sethashtable(struct net_device *dev) mc_filter[0] = mc_filter[1] = 0; curr = dev->mc_list; - for (i = 0; i < dev->mc_count; i++, curr = curr->next) { + for (i = 0; i < netdev_mc_count(dev); i++, curr = curr->next) { if (!curr) break; /* unexpected end of list */ bitnr = hash_get_index(curr->dmi_addr); @@ -934,7 +934,7 @@ static void macb_set_rx_mode(struct net_device *dev) macb_writel(bp, HRB, -1); macb_writel(bp, HRT, -1); cfg |= MACB_BIT(NCFGR_MTI); - } else if (dev->mc_count > 0) { + } else if (!netdev_mc_empty(dev)) { /* Enable specific multicasts */ macb_sethashtable(dev); cfg |= MACB_BIT(NCFGR_MTI); diff --git a/drivers/net/mace.c b/drivers/net/mace.c index d9fbad38638..fdb0bbdd678 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -606,7 +606,7 @@ static void mace_set_multicast(struct net_device *dev) } else { for (i = 0; i < 8; i++) multicast_filter[i] = 0; - for (i = 0; i < dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(dev); i++) { crc = ether_crc_le(6, dmi->dmi_addr); j = crc >> 26; /* bit number in multicast_filter */ multicast_filter[j >> 3] |= 1 << (j & 7); diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c index 44f3c2896f2..740accbf080 100644 --- a/drivers/net/macmace.c +++ b/drivers/net/macmace.c @@ -518,7 +518,7 @@ static void mace_set_multicast(struct net_device *dev) } else { for (i = 0; i < 8; i++) multicast_filter[i] = 0; - for (i = 0; i < dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(dev); i++) { crc = ether_crc_le(6, dmi->dmi_addr); j = crc >> 26; /* bit number in multicast_filter */ multicast_filter[j >> 3] |= 1 << (j & 7); diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 2d7b3bbfed0..c64e5b0d359 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -2488,7 +2488,7 @@ static void __set_rx_mode(struct net_device *dev) if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ rx_mode = RxFilterEnable | AcceptBroadcast | AcceptAllMulticast | AcceptAllPhys | AcceptMyPhys; - } else if ((dev->mc_count > multicast_filter_limit) || + } else if ((netdev_mc_count(dev) > multicast_filter_limit) || (dev->flags & IFF_ALLMULTI)) { rx_mode = RxFilterEnable | AcceptBroadcast | AcceptAllMulticast | AcceptMyPhys; @@ -2496,7 +2496,7 @@ static void __set_rx_mode(struct net_device *dev) struct dev_mc_list *mclist; int i; memset(mc_filter, 0, sizeof(mc_filter)); - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { int b = (ether_crc(ETH_ALEN, mclist->dmi_addr) >> 23) & 0x1ff; mc_filter[b/8] |= (1 << (b & 0x07)); diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index dd45c7a9122..25f4414cc33 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -554,7 +554,7 @@ void netxen_p2_nic_set_multi(struct net_device *netdev) return; } - if (netdev->mc_count == 0) { + if (netdev_mc_empty(netdev)) { adapter->set_promisc(adapter, NETXEN_NIU_NON_PROMISC_MODE); netxen_nic_disable_mcast_filter(adapter); @@ -563,7 +563,7 @@ void netxen_p2_nic_set_multi(struct net_device *netdev) adapter->set_promisc(adapter, NETXEN_NIU_ALLMULTI_MODE); if (netdev->flags & IFF_ALLMULTI || - netdev->mc_count > adapter->max_mc_count) { + netdev_mc_count(netdev) > adapter->max_mc_count) { netxen_nic_disable_mcast_filter(adapter); return; } @@ -573,7 +573,7 @@ void netxen_p2_nic_set_multi(struct net_device *netdev) for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next, index++) netxen_nic_set_mcast_addr(adapter, index, mc_ptr->dmi_addr); - if (index != netdev->mc_count) + if (index != netdev_mc_count(netdev)) printk(KERN_WARNING "%s: %s multicast address count mismatch\n", netxen_nic_driver_name, netdev->name); @@ -704,12 +704,12 @@ void netxen_p3_nic_set_multi(struct net_device *netdev) } if ((netdev->flags & IFF_ALLMULTI) || - (netdev->mc_count > adapter->max_mc_count)) { + (netdev_mc_count(netdev) > adapter->max_mc_count)) { mode = VPORT_MISS_MODE_ACCEPT_MULTI; goto send_fw_cmd; } - if (netdev->mc_count > 0) { + if (!netdev_mc_empty(netdev)) { for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) { nx_p3_nic_add_mac(adapter, mc_ptr->dmi_addr, &del_list); diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c index b42f5e522f9..497c6d514a6 100644 --- a/drivers/net/ni52.c +++ b/drivers/net/ni52.c @@ -597,7 +597,7 @@ static int init586(struct net_device *dev) struct tdr_cmd_struct __iomem *tdr_cmd; struct mcsetup_cmd_struct __iomem *mc_cmd; struct dev_mc_list *dmi = dev->mc_list; - int num_addrs = dev->mc_count; + int num_addrs = netdev_mc_count(dev); ptr = p->scb + 1; diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c index ae19aafd2c7..9225c76cac4 100644 --- a/drivers/net/ni65.c +++ b/drivers/net/ni65.c @@ -849,7 +849,7 @@ static int ni65_lance_reinit(struct net_device *dev) if(dev->flags & IFF_PROMISC) ni65_init_lance(p,dev->dev_addr,0x00,M_PROM); - else if(dev->mc_count || dev->flags & IFF_ALLMULTI) + else if (netdev_mc_count(dev) || dev->flags & IFF_ALLMULTI) ni65_init_lance(p,dev->dev_addr,0xff,0x0); else ni65_init_lance(p,dev->dev_addr,0x00,0x00); diff --git a/drivers/net/niu.c b/drivers/net/niu.c index af9a8647c7e..7b52d9762b0 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -6369,7 +6369,7 @@ static void niu_set_rx_mode(struct net_device *dev) np->flags &= ~(NIU_FLAGS_MCAST | NIU_FLAGS_PROMISC); if (dev->flags & IFF_PROMISC) np->flags |= NIU_FLAGS_PROMISC; - if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 0)) + if ((dev->flags & IFF_ALLMULTI) || (!netdev_mc_empty(dev))) np->flags |= NIU_FLAGS_MCAST; alt_cnt = netdev_uc_count(dev); @@ -6412,7 +6412,7 @@ static void niu_set_rx_mode(struct net_device *dev) if (dev->flags & IFF_ALLMULTI) { for (i = 0; i < 16; i++) hash[i] = 0xffff; - } else if (dev->mc_count > 0) { + } else if (!netdev_mc_empty(dev)) { for (addr = dev->mc_list; addr; addr = addr->next) { u32 crc = ether_crc_le(ETH_ALEN, addr->da_addr); diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index a3b6aa0f375..8dd509c09bc 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -1719,7 +1719,7 @@ static void ns83820_set_multicast(struct net_device *ndev) else and_mask &= ~(RFCR_AAU | RFCR_AAM); - if (ndev->flags & IFF_ALLMULTI || ndev->mc_count) + if (ndev->flags & IFF_ALLMULTI || netdev_mc_count(ndev)) or_mask |= RFCR_AAM; else and_mask &= ~RFCR_AAM; diff --git a/drivers/net/octeon/octeon_mgmt.c b/drivers/net/octeon/octeon_mgmt.c index 6fd8789ef48..3a0f910924a 100644 --- a/drivers/net/octeon/octeon_mgmt.c +++ b/drivers/net/octeon/octeon_mgmt.c @@ -493,8 +493,8 @@ static void octeon_mgmt_set_rx_filtering(struct net_device *netdev) } if (netdev->flags & IFF_MULTICAST) { - if (cam_mode == 0 || (netdev->flags & IFF_ALLMULTI) - || netdev->mc_count > available_cam_entries) + if (cam_mode == 0 || (netdev->flags & IFF_ALLMULTI) || + netdev_mc_count(netdev) > available_cam_entries) multicast_mode = 2; /* 1 - Accept all multicast. */ else multicast_mode = 0; /* 0 - Use CAM. */ @@ -511,7 +511,7 @@ static void octeon_mgmt_set_rx_filtering(struct net_device *netdev) } } if (multicast_mode == 0) { - i = netdev->mc_count; + i = netdev_mc_count(netdev); list = netdev->mc_list; while (i--) { octeon_mgmt_cam_state_add(&cam_state, list->da_addr); diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c index 20273832bfc..bbdf0398c93 100644 --- a/drivers/net/pci-skeleton.c +++ b/drivers/net/pci-skeleton.c @@ -1820,7 +1820,7 @@ static void netdrv_set_rx_mode (struct net_device *dev) AcceptBroadcast | AcceptMulticast | AcceptMyPhys | AcceptAllPhys; mc_filter[1] = mc_filter[0] = 0xffffffff; - } else if ((dev->mc_count > multicast_filter_limit) || + } else if ((netdev_mc_count(dev) > multicast_filter_limit) || (dev->flags & IFF_ALLMULTI)) { /* Too many to filter perfectly -- accept all multicasts. */ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; @@ -1829,7 +1829,7 @@ static void netdrv_set_rx_mode (struct net_device *dev) struct dev_mc_list *mclist; rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; mc_filter[1] = mc_filter[0] = 0; - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index 98938ea9e0b..3d1d3a7b7ed 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -1148,7 +1148,7 @@ static void set_rx_mode(struct net_device *dev) if (dev->flags & IFF_PROMISC) outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm, ioaddr + EL3_CMD); - else if (dev->mc_count || (dev->flags & IFF_ALLMULTI)) + else if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI)) outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD); else outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD); diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index 322e11df009..091e0b00043 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -886,7 +886,7 @@ static void set_rx_mode(struct net_device *dev) if (dev->flags & IFF_PROMISC) opts |= RxMulticast | RxProm; - else if (dev->mc_count || (dev->flags & IFF_ALLMULTI)) + else if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI)) opts |= RxMulticast; outw(opts, ioaddr + EL3_CMD); } diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 7b17404d085..3d573ed5f7c 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -1187,19 +1187,19 @@ static void set_rx_mode(struct net_device *dev) if (dev->flags & IFF_PROMISC) { memset(mc_filter, 0xff, sizeof(mc_filter)); outb(3, ioaddr + RX_MODE); /* Enable promiscuous mode */ - } else if (dev->mc_count > MC_FILTERBREAK || + } else if (netdev_mc_count(dev) > MC_FILTERBREAK || (dev->flags & IFF_ALLMULTI)) { /* Too many to filter perfectly -- accept all multicasts. */ memset(mc_filter, 0xff, sizeof(mc_filter)); outb(2, ioaddr + RX_MODE); /* Use normal mode. */ - } else if (dev->mc_count == 0) { + } else if (netdev_mc_empty(dev)) { memset(mc_filter, 0x00, sizeof(mc_filter)); outb(1, ioaddr + RX_MODE); /* Ignore almost all multicasts. */ } else { struct dev_mc_list *mclist; memset(mc_filter, 0, sizeof(mc_filter)); - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { unsigned int bit = ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 26; diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c index 12e3233868e..c42a31a97fa 100644 --- a/drivers/net/pcmcia/nmclan_cs.c +++ b/drivers/net/pcmcia/nmclan_cs.c @@ -1481,8 +1481,8 @@ static void set_multicast_list(struct net_device *dev) #ifdef PCMCIA_DEBUG { static int old; - if (dev->mc_count != old) { - old = dev->mc_count; + if (netdev_mc_count(dev) != old) { + old = netdev_mc_count(dev); pr_debug("%s: setting Rx mode to %d addresses.\n", dev->name, old); } @@ -1490,13 +1490,13 @@ static void set_multicast_list(struct net_device *dev) #endif /* Set multicast_num_addrs. */ - lp->multicast_num_addrs = dev->mc_count; + lp->multicast_num_addrs = netdev_mc_count(dev); /* Set multicast_ladrf. */ if (num_addrs > 0) { /* Calculate multicast logical address filter */ memset(lp->multicast_ladrf, 0, MACE_LADRF_LEN); - for (i = 0; i < dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(dev); i++) { memcpy(adr, dmi->dmi_addr, ETHER_ADDR_LEN); dmi = dmi->next; BuildLAF(lp->multicast_ladrf, adr); @@ -1537,15 +1537,15 @@ static void set_multicast_list(struct net_device *dev) #ifdef PCMCIA_DEBUG { static int old; - if (dev->mc_count != old) { - old = dev->mc_count; + if (netdev_mc_count(dev) != old) { + old = netdev_mc_count(dev); pr_debug("%s: setting Rx mode to %d addresses.\n", dev->name, old); } } #endif - lp->multicast_num_addrs = dev->mc_count; + lp->multicast_num_addrs = netdev_mc_count(dev); restore_multicast_list(dev); } /* set_multicast_list */ diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 6dd486d2977..d2e86b8887c 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -1638,8 +1638,8 @@ static void set_rx_mode(struct net_device *dev) } else if (dev->flags & IFF_ALLMULTI) rx_cfg_setting = RxStripCRC | RxEnable | RxAllMulti; else { - if (dev->mc_count) { - fill_multicast_tbl(dev->mc_count, dev->mc_list, + if (!netdev_mc_empty(dev)) { + fill_multicast_tbl(netdev_mc_count(dev), dev->mc_list, (u_char *)multicast_table); } rx_cfg_setting = RxStripCRC | RxEnable; diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index 466fc72698c..4ace18a7115 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -1384,7 +1384,7 @@ set_addresses(struct net_device *dev) if (++n > 9) break; i = 0; - if (n > 1 && n <= dev->mc_count && dmi) { + if (n > 1 && n <= netdev_mc_count(dev) && dmi) { dmi = dmi->next; } } @@ -1394,7 +1394,7 @@ set_addresses(struct net_device *dev) SelectPage(k); } - if (n && n <= dev->mc_count && dmi) + if (n && n <= netdev_mc_count(dev) && dmi) addr = dmi->dmi_addr; else addr = dev->dev_addr; @@ -1424,9 +1424,9 @@ set_multicast_list(struct net_device *dev) if (dev->flags & IFF_PROMISC) { /* snoop */ PutByte(XIRCREG42_SWC1, value | 0x06); /* set MPE and PME */ - } else if (dev->mc_count > 9 || (dev->flags & IFF_ALLMULTI)) { + } else if (netdev_mc_count(dev) > 9 || (dev->flags & IFF_ALLMULTI)) { PutByte(XIRCREG42_SWC1, value | 0x02); /* set MPE */ - } else if (dev->mc_count) { + } else if (!netdev_mc_empty(dev)) { /* the chip can filter 9 addresses perfectly */ PutByte(XIRCREG42_SWC1, value | 0x01); SelectPage(0x40); diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 0dc7ff896ee..3522794550d 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -2698,7 +2698,7 @@ static void pcnet32_load_multicast(struct net_device *dev) ib->filter[1] = 0; /* Add addresses */ - for (i = 0; i < dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(dev); i++) { addrs = dmi->dmi_addr; dmi = dmi->next; diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index 0c768593aad..c19dd4a6cd7 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -568,7 +568,7 @@ void gelic_net_set_multi(struct net_device *netdev) status); if ((netdev->flags & IFF_ALLMULTI) || - (netdev->mc_count > GELIC_NET_MC_COUNT_MAX)) { + (netdev_mc_count(netdev) > GELIC_NET_MC_COUNT_MAX)) { status = lv1_net_add_multicast_address(bus_id(card), dev_id(card), 0, 1); diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c index dc6cd69d6d9..8ea7f869e29 100644 --- a/drivers/net/qlcnic/qlcnic_hw.c +++ b/drivers/net/qlcnic/qlcnic_hw.c @@ -447,12 +447,12 @@ void qlcnic_set_multi(struct net_device *netdev) } if ((netdev->flags & IFF_ALLMULTI) || - (netdev->mc_count > adapter->max_mc_count)) { + (netdev_mc_count(netdev) > adapter->max_mc_count)) { mode = VPORT_MISS_MODE_ACCEPT_MULTI; goto send_fw_cmd; } - if (netdev->mc_count > 0) { + if (!netdev_mc_empty(netdev)) { for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) { qlcnic_nic_add_mac(adapter, mc_ptr->dmi_addr, diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 3cb60e10d45..dd3e0f1b296 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -4221,7 +4221,7 @@ static void qlge_set_multicast_list(struct net_device *ndev) * transition is taking place. */ if ((ndev->flags & IFF_ALLMULTI) || - (ndev->mc_count > MAX_MULTICAST_ENTRIES)) { + (netdev_mc_count(ndev) > MAX_MULTICAST_ENTRIES)) { if (!test_bit(QL_ALLMULTI, &qdev->flags)) { if (ql_set_routing_reg (qdev, RT_IDX_ALLMULTI_SLOT, RT_IDX_MCAST, 1)) { @@ -4243,7 +4243,7 @@ static void qlge_set_multicast_list(struct net_device *ndev) } } - if (ndev->mc_count) { + if (!netdev_mc_empty(ndev)) { status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK); if (status) goto exit; diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index d68ba7a5863..b8103425fac 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -958,21 +958,22 @@ static void r6040_multicast_list(struct net_device *dev) } /* Too many multicast addresses * accept all traffic */ - else if ((dev->mc_count > MCAST_MAX) || (dev->flags & IFF_ALLMULTI)) + else if ((netdev_mc_count(dev) > MCAST_MAX) || + (dev->flags & IFF_ALLMULTI)) reg |= 0x0020; iowrite16(reg, ioaddr); spin_unlock_irqrestore(&lp->lock, flags); /* Build the hash table */ - if (dev->mc_count > MCAST_MAX) { + if (netdev_mc_count(dev) > MCAST_MAX) { u16 hash_table[4]; u32 crc; for (i = 0; i < 4; i++) hash_table[i] = 0; - for (i = 0; i < dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(dev); i++) { char *addrs = dmi->dmi_addr; dmi = dmi->next; @@ -994,14 +995,14 @@ static void r6040_multicast_list(struct net_device *dev) iowrite16(hash_table[3], ioaddr + MAR3); } /* Multicast Address 1~4 case */ - for (i = 0, dmi; (i < dev->mc_count) && (i < MCAST_MAX); i++) { + for (i = 0, dmi; (i < netdev_mc_count(dev)) && (i < MCAST_MAX); i++) { adrp = (u16 *)dmi->dmi_addr; iowrite16(adrp[0], ioaddr + MID_1L + 8*i); iowrite16(adrp[1], ioaddr + MID_1M + 8*i); iowrite16(adrp[2], ioaddr + MID_1H + 8*i); dmi = dmi->next; } - for (i = dev->mc_count; i < MCAST_MAX; i++) { + for (i = netdev_mc_count(dev); i < MCAST_MAX; i++) { iowrite16(0xffff, ioaddr + MID_0L + 8*i); iowrite16(0xffff, ioaddr + MID_0M + 8*i); iowrite16(0xffff, ioaddr + MID_0H + 8*i); diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index c1bb24cf079..85c635f354b 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -4758,7 +4758,7 @@ static void rtl_set_rx_mode(struct net_device *dev) AcceptBroadcast | AcceptMulticast | AcceptMyPhys | AcceptAllPhys; mc_filter[1] = mc_filter[0] = 0xffffffff; - } else if ((dev->mc_count > multicast_filter_limit) || + } else if ((netdev_mc_count(dev) > multicast_filter_limit) || (dev->flags & IFF_ALLMULTI)) { /* Too many to filter perfectly -- accept all multicasts. */ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; @@ -4769,7 +4769,7 @@ static void rtl_set_rx_mode(struct net_device *dev) rx_mode = AcceptBroadcast | AcceptMyPhys; mc_filter[1] = mc_filter[0] = 0; - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index d1664586e8f..102be16e9b5 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -5055,8 +5055,8 @@ static void s2io_set_multicast(struct net_device *dev) } /* Update individual M_CAST address list */ - if ((!sp->m_cast_flg) && dev->mc_count) { - if (dev->mc_count > + if ((!sp->m_cast_flg) && netdev_mc_count(dev)) { + if (netdev_mc_count(dev) > (config->max_mc_addr - config->max_mac_addr)) { DBG_PRINT(ERR_DBG, "%s: No more Rx filters can be added - " @@ -5066,7 +5066,7 @@ static void s2io_set_multicast(struct net_device *dev) } prev_cnt = sp->mc_addr_count; - sp->mc_addr_count = dev->mc_count; + sp->mc_addr_count = netdev_mc_count(dev); /* Clear out the previous list of Mc in the H/W. */ for (i = 0; i < prev_cnt; i++) { @@ -5092,7 +5092,7 @@ static void s2io_set_multicast(struct net_device *dev) } /* Create the new Rx filter list and update the same in H/W. */ - for (i = 0, mclist = dev->mc_list; i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; i < netdev_mc_count(dev); i++, mclist = mclist->next) { memcpy(sp->usr_addrs[i].addr, mclist->dmi_addr, ETH_ALEN); diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c index fd8cb506a2b..00ff8995ad6 100644 --- a/drivers/net/sc92031.c +++ b/drivers/net/sc92031.c @@ -429,7 +429,7 @@ static void _sc92031_set_mar(struct net_device *dev) u32 mar0 = 0, mar1 = 0; if ((dev->flags & IFF_PROMISC) || - dev->mc_count > multicast_filter_limit || + netdev_mc_count(dev) > multicast_filter_limit || (dev->flags & IFF_ALLMULTI)) mar0 = mar1 = 0xffffffff; else if (dev->flags & IFF_MULTICAST) { diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 62d5cd51a9d..fafaf30ecd9 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1615,7 +1615,7 @@ static void efx_set_multicast_list(struct net_device *net_dev) memset(mc_hash, 0xff, sizeof(*mc_hash)); } else { memset(mc_hash, 0x00, sizeof(*mc_hash)); - for (i = 0; i < net_dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(net_dev); i++) { crc = ether_crc_le(ETH_ALEN, mc_list->dmi_addr); bit = crc & (EFX_MCAST_HASH_ENTRIES - 1); set_bit_le(bit, mc_hash->byte); diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index 6b364a6c6c6..ed999d31f1f 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c @@ -660,7 +660,7 @@ static void sgiseeq_set_multicast(struct net_device *dev) if(dev->flags & IFF_PROMISC) sp->mode = SEEQ_RCMD_RANY; - else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count) + else if ((dev->flags & IFF_ALLMULTI) || !netdev_mc_empty(dev)) sp->mode = SEEQ_RCMD_RBMCAST; else sp->mode = SEEQ_RCMD_RBCAST; diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index 626de766443..8c4e38f9ebf 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -841,7 +841,7 @@ static void sis190_set_rx_mode(struct net_device *dev) AcceptBroadcast | AcceptMulticast | AcceptMyPhys | AcceptAllPhys; mc_filter[1] = mc_filter[0] = 0xffffffff; - } else if ((dev->mc_count > multicast_filter_limit) || + } else if ((netdev_mc_count(dev) > multicast_filter_limit) || (dev->flags & IFF_ALLMULTI)) { /* Too many to filter perfectly -- accept all multicasts. */ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; @@ -852,7 +852,7 @@ static void sis190_set_rx_mode(struct net_device *dev) rx_mode = AcceptBroadcast | AcceptMyPhys; mc_filter[1] = mc_filter[0] = 0; - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) & 0x3f; diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index 20c5ce47489..32ae87c09f5 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -2288,7 +2288,7 @@ static void set_rx_mode(struct net_device *net_dev) rx_mode = RFPromiscuous; for (i = 0; i < table_entries; i++) mc_filter[i] = 0xffff; - } else if ((net_dev->mc_count > multicast_filter_limit) || + } else if ((netdev_mc_count(net_dev) > multicast_filter_limit) || (net_dev->flags & IFF_ALLMULTI)) { /* too many multicast addresses or accept all multicast packet */ rx_mode = RFAAB | RFAAM; @@ -2301,7 +2301,7 @@ static void set_rx_mode(struct net_device *net_dev) struct dev_mc_list *mclist; rx_mode = RFAAB; for (i = 0, mclist = net_dev->mc_list; - mclist && i < net_dev->mc_count; + mclist && i < netdev_mc_count(net_dev); i++, mclist = mclist->next) { unsigned int bit_nr = sis900_mcast_bitnr(mclist->dmi_addr, sis_priv->chipset_rev); diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c index 6b955a4f19b..346adfae986 100644 --- a/drivers/net/skfp/skfddi.c +++ b/drivers/net/skfp/skfddi.c @@ -872,14 +872,14 @@ static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev) if (dev->flags & IFF_ALLMULTI) { mac_drv_rx_mode(smc, RX_ENABLE_ALLMULTI); pr_debug(KERN_INFO "ENABLE ALL MC ADDRESSES\n"); - } else if (dev->mc_count > 0) { - if (dev->mc_count <= FPMAX_MULTICAST) { + } else if (!netdev_mc_empty(dev)) { + if (netdev_mc_count(dev) <= FPMAX_MULTICAST) { /* use exact filtering */ // point to first multicast addr dmi = dev->mc_list; - for (i = 0; i < dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(dev); i++) { mac_add_multicast(smc, (struct fddi_addr *)dmi->dmi_addr, 1); diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 5ff46eb18d0..36ead52dea7 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -2932,7 +2932,7 @@ static void genesis_set_multicast(struct net_device *dev) struct skge_port *skge = netdev_priv(dev); struct skge_hw *hw = skge->hw; int port = skge->port; - int i, count = dev->mc_count; + int i, count = netdev_mc_count(dev); struct dev_mc_list *list = dev->mc_list; u32 mode; u8 filter[8]; @@ -2987,7 +2987,7 @@ static void yukon_set_multicast(struct net_device *dev) reg &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA); else if (dev->flags & IFF_ALLMULTI) /* all multicast */ memset(filter, 0xff, sizeof(filter)); - else if (dev->mc_count == 0 && !rx_pause)/* no multicast */ + else if (netdev_mc_empty(dev) && !rx_pause)/* no multicast */ reg &= ~GM_RXCR_MCF_ENA; else { int i; @@ -2996,7 +2996,7 @@ static void yukon_set_multicast(struct net_device *dev) if (rx_pause) yukon_add_filter(filter, pause_mc_addr); - for (i = 0; list && i < dev->mc_count; i++, list = list->next) + for (i = 0; list && i < netdev_mc_count(dev); i++, list = list->next) yukon_add_filter(filter, list->dmi_addr); } diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 478288b8bc2..45299d66349 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3626,7 +3626,7 @@ static void sky2_set_multicast(struct net_device *dev) reg &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA); else if (dev->flags & IFF_ALLMULTI) memset(filter, 0xff, sizeof(filter)); - else if (dev->mc_count == 0 && !rx_pause) + else if (netdev_mc_empty(dev) && !rx_pause) reg &= ~GM_RXCR_MCF_ENA; else { int i; @@ -3635,7 +3635,7 @@ static void sky2_set_multicast(struct net_device *dev) if (rx_pause) sky2_add_filter(filter, pause_mc_addr); - for (i = 0; list && i < dev->mc_count; i++, list = list->next) + for (i = 0; list && i < netdev_mc_count(dev); i++, list = list->next) sky2_add_filter(filter, list->dmi_addr); } diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 3c5a4f52345..ef9674c6713 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -1323,7 +1323,7 @@ static void smc911x_set_multicast_list(struct net_device *dev) * I don't need to zero the multicast table, because the flag is * checked before the table is */ - else if (dev->flags & IFF_ALLMULTI || dev->mc_count > 16) { + else if (dev->flags & IFF_ALLMULTI || netdev_mc_count(dev) > 16) { DBG(SMC_DEBUG_MISC, "%s: RCR_ALMUL\n", dev->name); mcr |= MAC_CR_MCPAS_; } @@ -1340,7 +1340,7 @@ static void smc911x_set_multicast_list(struct net_device *dev) * the number of the 32 bit register, while the low 5 bits are the bit * within that register. */ - else if (dev->mc_count) { + else if (!netdev_mc_empty(dev)) { int i; struct dev_mc_list *cur_addr; @@ -1351,7 +1351,7 @@ static void smc911x_set_multicast_list(struct net_device *dev) memset(multicast_table, 0, sizeof(multicast_table)); cur_addr = dev->mc_list; - for (i = 0; i < dev->mc_count; i++, cur_addr = cur_addr->next) { + for (i = 0; i < netdev_mc_count(dev); i++, cur_addr = cur_addr->next) { u32 position; /* do we have a pointer here? */ diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c index 8371b82323a..41c3dddeab5 100644 --- a/drivers/net/smc9194.c +++ b/drivers/net/smc9194.c @@ -1542,7 +1542,7 @@ static void smc_set_multicast_list(struct net_device *dev) /* We just get all multicast packets even if we only want them . from one source. This will be changed at some future . point. */ - else if (dev->mc_count ) { + else if (!netdev_mc_empty(dev)) { /* support hardware multicasting */ /* be sure I get rid of flags I might have set */ @@ -1550,7 +1550,7 @@ static void smc_set_multicast_list(struct net_device *dev) ioaddr + RCR ); /* NOTE: this has to set the bank, so make sure it is the last thing called. The bank is set to zero at the top */ - smc_setmulticast( ioaddr, dev->mc_count, dev->mc_list ); + smc_setmulticast(ioaddr, netdev_mc_count(dev), dev->mc_list); } else { outw( inw( ioaddr + RCR ) & ~(RCR_PROMISC | RCR_ALMUL), diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index ea4fae79d6e..66450127c5a 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -1395,7 +1395,7 @@ static void smc_set_multicast_list(struct net_device *dev) * I don't need to zero the multicast table, because the flag is * checked before the table is */ - else if (dev->flags & IFF_ALLMULTI || dev->mc_count > 16) { + else if (dev->flags & IFF_ALLMULTI || netdev_mc_count(dev) > 16) { DBG(2, "%s: RCR_ALMUL\n", dev->name); lp->rcr_cur_mode |= RCR_ALMUL; } @@ -1412,7 +1412,7 @@ static void smc_set_multicast_list(struct net_device *dev) * the number of the 8 bit register, while the low 3 bits are the bit * within that register. */ - else if (dev->mc_count) { + else if (!netdev_mc_empty(dev)) { int i; struct dev_mc_list *cur_addr; @@ -1423,7 +1423,7 @@ static void smc_set_multicast_list(struct net_device *dev) memset(multicast_table, 0, sizeof(multicast_table)); cur_addr = dev->mc_list; - for (i = 0; i < dev->mc_count; i++, cur_addr = cur_addr->next) { + for (i = 0; i < netdev_mc_count(dev); i++, cur_addr = cur_addr->next) { int position; /* do we have a pointer here? */ diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c index 494cd91ea39..3c1f9aa84cf 100644 --- a/drivers/net/smsc911x.c +++ b/drivers/net/smsc911x.c @@ -1383,7 +1383,7 @@ static void smsc911x_set_multicast_list(struct net_device *dev) pdata->clear_bits_mask = (MAC_CR_PRMS_ | MAC_CR_HPFILT_); pdata->hashhi = 0; pdata->hashlo = 0; - } else if (dev->mc_count > 0) { + } else if (!netdev_mc_empty(dev)) { /* Enabling specific multicast addresses */ unsigned int hash_high = 0; unsigned int hash_low = 0; @@ -1408,7 +1408,7 @@ static void smsc911x_set_multicast_list(struct net_device *dev) } mc_list = mc_list->next; } - if (count != (unsigned int)dev->mc_count) + if (count != (unsigned int)netdev_mc_count(dev)) SMSC_WARNING(DRV, "mc_count != dev->mc_count"); pdata->hashhi = hash_high; diff --git a/drivers/net/smsc9420.c b/drivers/net/smsc9420.c index 1495a5dd4b4..2bd3c986559 100644 --- a/drivers/net/smsc9420.c +++ b/drivers/net/smsc9420.c @@ -1062,7 +1062,7 @@ static void smsc9420_set_multicast_list(struct net_device *dev) mac_cr &= (~MAC_CR_PRMS_); mac_cr |= MAC_CR_MCPAS_; mac_cr &= (~MAC_CR_HPFILT_); - } else if (dev->mc_count > 0) { + } else if (!netdev_mc_empty(dev)) { struct dev_mc_list *mc_list = dev->mc_list; u32 hash_lo = 0, hash_hi = 0; diff --git a/drivers/net/sonic.c b/drivers/net/sonic.c index 9599ce77ef8..bd8bc66f2e0 100644 --- a/drivers/net/sonic.c +++ b/drivers/net/sonic.c @@ -541,13 +541,15 @@ static void sonic_multicast_list(struct net_device *dev) if (dev->flags & IFF_PROMISC) { /* set promiscuous mode */ rcr |= SONIC_RCR_PRO; } else { - if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 15)) { + if ((dev->flags & IFF_ALLMULTI) || + (netdev_mc_count(dev) > 15)) { rcr |= SONIC_RCR_AMC; } else { if (sonic_debug > 2) - printk("sonic_multicast_list: mc_count %d\n", dev->mc_count); + printk("sonic_multicast_list: mc_count %d\n", + netdev_mc_count(dev)); sonic_set_cam_enable(dev, 1); /* always enable our own address */ - for (i = 1; i <= dev->mc_count; i++) { + for (i = 1; i <= netdev_mc_count(dev); i++) { addr = dmi->dmi_addr; dmi = dmi->next; sonic_cda_put(dev, i, SONIC_CD_CAP0, addr[1] << 8 | addr[0]); diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index d0556a9b456..58bc7ac086c 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -1796,15 +1796,15 @@ static void set_rx_mode(struct net_device *dev) if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ rx_mode |= AcceptAll; - } else if ((dev->mc_count > multicast_filter_limit) || + } else if ((netdev_mc_count(dev) > multicast_filter_limit) || (dev->flags & IFF_ALLMULTI)) { /* Too many to match, or accept all multicasts. */ rx_mode |= AcceptBroadcast|AcceptAllMulticast|PerfectFilter; - } else if (dev->mc_count <= 14) { + } else if (netdev_mc_count(dev) <= 14) { /* Use the 16 element perfect filter, skip first two entries. */ void __iomem *filter_addr = ioaddr + PerfFilterTable + 2 * 16; __be16 *eaddrs; - for (i = 2, mclist = dev->mc_list; mclist && i < dev->mc_count + 2; + for (i = 2, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev) + 2; i++, mclist = mclist->next) { eaddrs = (__be16 *)mclist->dmi_addr; writew(be16_to_cpu(eaddrs[2]), filter_addr); filter_addr += 4; @@ -1825,7 +1825,7 @@ static void set_rx_mode(struct net_device *dev) __le16 mc_filter[32] __attribute__ ((aligned(sizeof(long)))); /* Multicast hash filter */ memset(mc_filter, 0, sizeof(mc_filter)); - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { /* The chip uses the upper 9 CRC bits as index into the hash table */ diff --git a/drivers/net/stmmac/dwmac100.c b/drivers/net/stmmac/dwmac100.c index ac48ed78704..576b256ee38 100644 --- a/drivers/net/stmmac/dwmac100.c +++ b/drivers/net/stmmac/dwmac100.c @@ -305,13 +305,13 @@ static void dwmac100_set_filter(struct net_device *dev) value |= MAC_CONTROL_PR; value &= ~(MAC_CONTROL_PM | MAC_CONTROL_IF | MAC_CONTROL_HO | MAC_CONTROL_HP); - } else if ((dev->mc_count > HASH_TABLE_SIZE) + } else if ((netdev_mc_count(dev) > HASH_TABLE_SIZE) || (dev->flags & IFF_ALLMULTI)) { value |= MAC_CONTROL_PM; value &= ~(MAC_CONTROL_PR | MAC_CONTROL_IF | MAC_CONTROL_HO); writel(0xffffffff, ioaddr + MAC_HASH_HIGH); writel(0xffffffff, ioaddr + MAC_HASH_LOW); - } else if (dev->mc_count == 0) { /* no multicast */ + } else if (netdev_mc_empty(dev)) { /* no multicast */ value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR | MAC_CONTROL_IF | MAC_CONTROL_HO | MAC_CONTROL_HP); } else { @@ -327,7 +327,7 @@ static void dwmac100_set_filter(struct net_device *dev) memset(mc_filter, 0, sizeof(mc_filter)); for (i = 0, mclist = dev->mc_list; - mclist && i < dev->mc_count; i++, mclist = mclist->next) { + mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { /* The upper 6 bits of the calculated CRC are used to * index the contens of the hash table */ int bit_nr = diff --git a/drivers/net/stmmac/dwmac1000_core.c b/drivers/net/stmmac/dwmac1000_core.c index d812e9cdb3d..90dbb4f41ef 100644 --- a/drivers/net/stmmac/dwmac1000_core.c +++ b/drivers/net/stmmac/dwmac1000_core.c @@ -83,16 +83,16 @@ static void dwmac1000_set_filter(struct net_device *dev) unsigned int value = 0; DBG(KERN_INFO "%s: # mcasts %d, # unicast %d\n", - __func__, dev->mc_count, netdev_uc_count(dev)); + __func__, netdev_mc_count(dev), netdev_uc_count(dev)); if (dev->flags & IFF_PROMISC) value = GMAC_FRAME_FILTER_PR; - else if ((dev->mc_count > HASH_TABLE_SIZE) + else if ((netdev_mc_count(dev) > HASH_TABLE_SIZE) || (dev->flags & IFF_ALLMULTI)) { value = GMAC_FRAME_FILTER_PM; /* pass all multi */ writel(0xffffffff, ioaddr + GMAC_HASH_HIGH); writel(0xffffffff, ioaddr + GMAC_HASH_LOW); - } else if (dev->mc_count > 0) { + } else if (!netdev_mc_empty(dev)) { int i; u32 mc_filter[2]; struct dev_mc_list *mclist; @@ -102,7 +102,7 @@ static void dwmac1000_set_filter(struct net_device *dev) memset(mc_filter, 0, sizeof(mc_filter)); for (i = 0, mclist = dev->mc_list; - mclist && i < dev->mc_count; i++, mclist = mclist->next) { + mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { /* The upper 6 bits of the calculated CRC are used to index the contens of the hash table */ int bit_nr = diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c index b447a871942..efedc252e4b 100644 --- a/drivers/net/sun3_82586.c +++ b/drivers/net/sun3_82586.c @@ -414,7 +414,7 @@ static int init586(struct net_device *dev) volatile struct tdr_cmd_struct *tdr_cmd; volatile struct mcsetup_cmd_struct *mc_cmd; struct dev_mc_list *dmi=dev->mc_list; - int num_addrs=dev->mc_count; + int num_addrs=netdev_mc_count(dev); ptr = (void *) ((char *)p->scb + sizeof(struct scb_struct)); diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c index 0ca4241b4f6..99998862c22 100644 --- a/drivers/net/sun3lance.c +++ b/drivers/net/sun3lance.c @@ -917,7 +917,7 @@ static void set_multicast_list( struct net_device *dev ) REGA( CSR15 ) = 0x8000; /* Set promiscuous mode */ } else { short multicast_table[4]; - int num_addrs = dev->mc_count; + int num_addrs = netdev_mc_count(dev); int i; /* We don't use the multicast table, but rely on upper-layer * filtering. */ diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c index 25e81ebd9cd..dfea56fa39e 100644 --- a/drivers/net/sunbmac.c +++ b/drivers/net/sunbmac.c @@ -1013,7 +1013,7 @@ static void bigmac_set_multicast(struct net_device *dev) while ((sbus_readl(bregs + BMAC_RXCFG) & BIGMAC_RXCFG_ENABLE) != 0) udelay(20); - if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) { + if ((dev->flags & IFF_ALLMULTI) || (netdev_mc_count(dev) > 64)) { sbus_writel(0xffff, bregs + BMAC_HTABLE0); sbus_writel(0xffff, bregs + BMAC_HTABLE1); sbus_writel(0xffff, bregs + BMAC_HTABLE2); @@ -1028,7 +1028,7 @@ static void bigmac_set_multicast(struct net_device *dev) for (i = 0; i < 4; i++) hash_table[i] = 0; - for (i = 0; i < dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(dev); i++) { addrs = dmi->dmi_addr; dmi = dmi->next; diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index 0c972e560cf..4171259590b 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -1517,18 +1517,18 @@ static void set_rx_mode(struct net_device *dev) if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ memset(mc_filter, 0xff, sizeof(mc_filter)); rx_mode = AcceptBroadcast | AcceptMulticast | AcceptAll | AcceptMyPhys; - } else if ((dev->mc_count > multicast_filter_limit) || + } else if ((netdev_mc_count(dev) > multicast_filter_limit) || (dev->flags & IFF_ALLMULTI)) { /* Too many to match, or accept all multicasts. */ memset(mc_filter, 0xff, sizeof(mc_filter)); rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; - } else if (dev->mc_count) { + } else if (!netdev_mc_empty(dev)) { struct dev_mc_list *mclist; int bit; int index; int crc; memset (mc_filter, 0, sizeof (mc_filter)); - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { crc = ether_crc_le (ETH_ALEN, mclist->dmi_addr); for (index=0, bit=0; bit < 6; bit++, crc <<= 1) diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index b55ceb88d93..d497ec05395 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -1837,7 +1837,7 @@ static u32 gem_setup_multicast(struct gem *gp) int i; if ((gp->dev->flags & IFF_ALLMULTI) || - (gp->dev->mc_count > 256)) { + (netdev_mc_count(gp->dev) > 256)) { for (i=0; i<16; i++) writel(0xffff, gp->regs + MAC_HASH0 + (i << 2)); rxcfg |= MAC_RXCFG_HFE; @@ -1852,7 +1852,7 @@ static u32 gem_setup_multicast(struct gem *gp) for (i = 0; i < 16; i++) hash_table[i] = 0; - for (i = 0; i < gp->dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(gp->dev); i++) { char *addrs = dmi->dmi_addr; dmi = dmi->next; diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 76ccd31cbf5..905df35ff78 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -1516,7 +1516,7 @@ static int happy_meal_init(struct happy_meal *hp) HMD(("htable, ")); if ((hp->dev->flags & IFF_ALLMULTI) || - (hp->dev->mc_count > 64)) { + (netdev_mc_count(hp->dev) > 64)) { hme_write32(hp, bregs + BMAC_HTABLE0, 0xffff); hme_write32(hp, bregs + BMAC_HTABLE1, 0xffff); hme_write32(hp, bregs + BMAC_HTABLE2, 0xffff); @@ -1531,7 +1531,7 @@ static int happy_meal_init(struct happy_meal *hp) for (i = 0; i < 4; i++) hash_table[i] = 0; - for (i = 0; i < hp->dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(hp->dev); i++) { addrs = dmi->dmi_addr; dmi = dmi->next; @@ -2373,7 +2373,7 @@ static void happy_meal_set_multicast(struct net_device *dev) spin_lock_irq(&hp->happy_lock); - if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) { + if ((dev->flags & IFF_ALLMULTI) || (netdev_mc_count(dev) > 64)) { hme_write32(hp, bregs + BMAC_HTABLE0, 0xffff); hme_write32(hp, bregs + BMAC_HTABLE1, 0xffff); hme_write32(hp, bregs + BMAC_HTABLE2, 0xffff); @@ -2387,7 +2387,7 @@ static void happy_meal_set_multicast(struct net_device *dev) for (i = 0; i < 4; i++) hash_table[i] = 0; - for (i = 0; i < dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(dev); i++) { addrs = dmi->dmi_addr; dmi = dmi->next; diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index 64e7d08c878..cf9d5bb9e1e 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -1196,7 +1196,7 @@ static void lance_load_multicast(struct net_device *dev) return; /* Add addresses */ - for (i = 0; i < dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(dev); i++) { addrs = dmi->dmi_addr; dmi = dmi->next; diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c index 45c383f285e..3bc35d86ed6 100644 --- a/drivers/net/sunqe.c +++ b/drivers/net/sunqe.c @@ -636,7 +636,7 @@ static void qe_set_multicast(struct net_device *dev) /* Lock out others. */ netif_stop_queue(dev); - if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) { + if ((dev->flags & IFF_ALLMULTI) || (netdev_mc_count(dev) > 64)) { sbus_writeb(MREGS_IACONFIG_ACHNGE | MREGS_IACONFIG_LARESET, qep->mregs + MREGS_IACONFIG); while ((sbus_readb(qep->mregs + MREGS_IACONFIG) & MREGS_IACONFIG_ACHNGE) != 0) @@ -653,7 +653,7 @@ static void qe_set_multicast(struct net_device *dev) for (i = 0; i < 4; i++) hash_table[i] = 0; - for (i = 0; i < dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(dev); i++) { addrs = dmi->dmi_addr; dmi = dmi->next; diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index 033408f589f..d838d4015c6 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -1941,18 +1941,18 @@ tc35815_set_multicast_list(struct net_device *dev) /* Enable promiscuous mode */ tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc | CAM_StationAcc, &tr->CAM_Ctl); } else if ((dev->flags & IFF_ALLMULTI) || - dev->mc_count > CAM_ENTRY_MAX - 3) { + netdev_mc_count(dev) > CAM_ENTRY_MAX - 3) { /* CAM 0, 1, 20 are reserved. */ /* Disable promiscuous mode, use normal mode. */ tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc, &tr->CAM_Ctl); - } else if (dev->mc_count) { + } else if (!netdev_mc_empty(dev)) { struct dev_mc_list *cur_addr = dev->mc_list; int i; int ena_bits = CAM_Ena_Bit(CAM_ENTRY_SOURCE); tc_writel(0, &tr->CAM_Ctl); /* Walk the address list, and load the filter */ - for (i = 0; i < dev->mc_count; i++, cur_addr = cur_addr->next) { + for (i = 0; i < netdev_mc_count(dev); i++, cur_addr = cur_addr->next) { if (!cur_addr) break; /* entry 0,1 is reserved. */ diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c index b907bee31fd..ab9b0280317 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c @@ -808,7 +808,7 @@ static void bdx_setmulti(struct net_device *ndev) /* set IMF to accept all multicast frmaes */ for (i = 0; i < MAC_MCST_HASH_NUM; i++) WRITE_REG(priv, regRX_MCST_HASH0 + i * 4, ~0); - } else if (ndev->mc_count) { + } else if (!netdev_mc_empty(ndev)) { u8 hash; struct dev_mc_list *mclist; u32 reg, val; @@ -840,7 +840,7 @@ static void bdx_setmulti(struct net_device *ndev) } } else { - DBG("only own mac %d\n", ndev->mc_count); + DBG("only own mac %d\n", netdev_mc_count(ndev)); rxf_val |= GMAC_RX_FILTER_AB; } WRITE_REG(priv, regGMAC_RXF_A, rxf_val); diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 7195bdec17f..d29282f01c2 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -9430,7 +9430,7 @@ static void __tg3_set_rx_mode(struct net_device *dev) } else if (dev->flags & IFF_ALLMULTI) { /* Accept all multicast. */ tg3_set_multi (tp, 1); - } else if (dev->mc_count < 1) { + } else if (netdev_mc_empty(dev)) { /* Reject all multicast. */ tg3_set_multi (tp, 0); } else { @@ -9442,7 +9442,7 @@ static void __tg3_set_rx_mode(struct net_device *dev) u32 bit; u32 crc; - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { crc = calc_crc (mclist->dmi_addr, ETH_ALEN); diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index 3ec31dce99f..e44d5a074c6 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -1335,7 +1335,7 @@ static void TLan_SetMulticastList( struct net_device *dev ) TLan_DioWrite32( dev->base_addr, TLAN_HASH_1, 0xFFFFFFFF ); TLan_DioWrite32( dev->base_addr, TLAN_HASH_2, 0xFFFFFFFF ); } else { - for ( i = 0; i < dev->mc_count; i++ ) { + for ( i = 0; i < netdev_mc_count(dev); i++ ) { if ( i < 3 ) { TLan_SetMac( dev, i + 1, (char *) &dmi->dmi_addr ); diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c index b0d7db9d8bb..eff68e1d107 100644 --- a/drivers/net/tokenring/3c359.c +++ b/drivers/net/tokenring/3c359.c @@ -1408,7 +1408,7 @@ static void xl_set_rx_mode(struct net_device *dev) dev_mc_address[0] = dev_mc_address[1] = dev_mc_address[2] = dev_mc_address[3] = 0 ; - for (i=0,dmi=dev->mc_list;i < dev->mc_count; i++,dmi = dmi->next) { + for (i=0,dmi=dev->mc_list;i < netdev_mc_count(dev); i++,dmi = dmi->next) { dev_mc_address[0] |= dmi->dmi_addr[2] ; dev_mc_address[1] |= dmi->dmi_addr[3] ; dev_mc_address[2] |= dmi->dmi_addr[4] ; diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c index 66272f2a075..1ce8f85a89a 100644 --- a/drivers/net/tokenring/ibmtr.c +++ b/drivers/net/tokenring/ibmtr.c @@ -996,7 +996,7 @@ static void tok_set_multicast_list(struct net_device *dev) if (/*BMSHELPdev->start == 0 ||*/ ti->open_status != OPEN) return; address[0] = address[1] = address[2] = address[3] = 0; mclist = dev->mc_list; - for (i = 0; i < dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(dev); i++) { address[0] |= mclist->dmi_addr[2]; address[1] |= mclist->dmi_addr[3]; address[2] |= mclist->dmi_addr[4]; diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index 3f9d5a25562..26d84daf660 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -1303,7 +1303,7 @@ static void streamer_set_rx_mode(struct net_device *dev) writel(streamer_priv->srb,streamer_mmio+LAPA); dev_mc_address[0] = dev_mc_address[1] = dev_mc_address[2] = dev_mc_address[3] = 0 ; - for (i=0,dmi=dev->mc_list;i < dev->mc_count; i++,dmi = dmi->next) + for (i=0,dmi=dev->mc_list;i < netdev_mc_count(dev); i++,dmi = dmi->next) { dev_mc_address[0] |= dmi->dmi_addr[2] ; dev_mc_address[1] |= dmi->dmi_addr[3] ; diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index f010a4dc5f1..a242d125b34 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -1178,7 +1178,7 @@ static void olympic_set_rx_mode(struct net_device *dev) dev_mc_address[0] = dev_mc_address[1] = dev_mc_address[2] = dev_mc_address[3] = 0 ; - for (i=0,dmi=dev->mc_list;i < dev->mc_count; i++,dmi = dmi->next) { + for (i=0,dmi=dev->mc_list;i < netdev_mc_count(dev); i++,dmi = dmi->next) { dev_mc_address[0] |= dmi->dmi_addr[2] ; dev_mc_address[1] |= dmi->dmi_addr[3] ; dev_mc_address[2] |= dmi->dmi_addr[4] ; diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c index e3c42f5ac4a..6b8868959b8 100644 --- a/drivers/net/tokenring/tms380tr.c +++ b/drivers/net/tokenring/tms380tr.c @@ -1214,7 +1214,7 @@ static void tms380tr_set_multicast_list(struct net_device *dev) { int i; struct dev_mc_list *mclist = dev->mc_list; - for (i=0; i< dev->mc_count; i++) + for (i=0; i< netdev_mc_count(dev); i++) { ((char *)(&tp->ocpl.FunctAddr))[0] |= mclist->dmi_addr[2]; diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c index a69c4a48bab..f4b30c4826f 100644 --- a/drivers/net/tsi108_eth.c +++ b/drivers/net/tsi108_eth.c @@ -1184,7 +1184,7 @@ static void tsi108_set_rx_mode(struct net_device *dev) rxcfg &= ~(TSI108_EC_RXCFG_UFE | TSI108_EC_RXCFG_MFE); - if (dev->flags & IFF_ALLMULTI || dev->mc_count) { + if (dev->flags & IFF_ALLMULTI || !netdev_mc_empty(dev)) { int i; struct dev_mc_list *mc = dev->mc_list; rxcfg |= TSI108_EC_RXCFG_MFE | TSI108_EC_RXCFG_MC_HASH; diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index 29330209ad8..a4cff23dcdf 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -677,7 +677,7 @@ static void build_setup_frame_hash(u16 *setup_frm, struct net_device *dev) memset(hash_table, 0, sizeof(hash_table)); set_bit_le(255, hash_table); /* Broadcast entry */ /* This should work on big-endian machines as well. */ - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { int index = ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff; @@ -706,7 +706,7 @@ static void build_setup_frame_perfect(u16 *setup_frm, struct net_device *dev) /* We have <= 14 addresses so we can use the wonderful 16 address perfect filtering of the Tulip. */ - for (i = 0, mclist = dev->mc_list; i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; i < netdev_mc_count(dev); i++, mclist = mclist->next) { eaddrs = (u16 *)mclist->dmi_addr; *setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++; @@ -741,7 +741,7 @@ static void __de_set_rx_mode (struct net_device *dev) goto out; } - if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) { + if ((netdev_mc_count(dev) > 1000) || (dev->flags & IFF_ALLMULTI)) { /* Too many to filter well -- accept all multicasts. */ macmode |= AcceptAllMulticast; goto out; @@ -749,7 +749,7 @@ static void __de_set_rx_mode (struct net_device *dev) /* Note that only the low-address shortword of setup_frame is valid! The values are doubled for big-endian architectures. */ - if (dev->mc_count > 14) /* Must use a multicast hash table. */ + if (netdev_mc_count(dev) > 14) /* Must use a multicast hash table. */ build_setup_frame_hash (de->setup_frame, dev); else build_setup_frame_perfect (de->setup_frame, dev); diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index a8349b7200b..0b6a9731091 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -1963,10 +1963,10 @@ SetMulticastFilter(struct net_device *dev) omr &= ~(OMR_PR | OMR_PM); pa = build_setup_frame(dev, ALL); /* Build the basic frame */ - if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 14)) { + if ((dev->flags & IFF_ALLMULTI) || (netdev_mc_count(dev) > 14)) { omr |= OMR_PM; /* Pass all multicasts */ } else if (lp->setup_f == HASH_PERF) { /* Hash Filtering */ - for (i=0;imc_count;i++) { /* for each address in the list */ + for (i = 0; i < netdev_mc_count(dev) ;i++) { addrs=dmi->dmi_addr; dmi=dmi->next; if ((*addrs & 0x01) == 1) { /* multicast address? */ @@ -1984,7 +1984,7 @@ SetMulticastFilter(struct net_device *dev) } } } else { /* Perfect filtering */ - for (j=0; jmc_count; j++) { + for (j=0; jdmi_addr; dmi=dmi->next; for (i=0; ichip_id == PCI_DM9132_ID) - dm9132_id_table(dev, dev->mc_count); /* DM9132 */ + dm9132_id_table(dev, netdev_mc_count(dev)); /* DM9132 */ else - send_filter_frame(dev, dev->mc_count); /* DM9102/DM9102A */ + send_filter_frame(dev, netdev_mc_count(dev)); /* DM9102/DM9102A */ /* Init CR7, interrupt active bit */ db->cr7_data = CR7_DEFAULT; @@ -1052,6 +1052,7 @@ static void dmfe_set_filter_mode(struct DEVICE * dev) { struct dmfe_board_info *db = netdev_priv(dev); unsigned long flags; + int mc_count = netdev_mc_count(dev); DMFE_DBUG(0, "dmfe_set_filter_mode()", 0); spin_lock_irqsave(&db->lock, flags); @@ -1064,19 +1065,19 @@ static void dmfe_set_filter_mode(struct DEVICE * dev) return; } - if (dev->flags & IFF_ALLMULTI || dev->mc_count > DMFE_MAX_MULTICAST) { - DMFE_DBUG(0, "Pass all multicast address", dev->mc_count); + if (dev->flags & IFF_ALLMULTI || mc_count > DMFE_MAX_MULTICAST) { + DMFE_DBUG(0, "Pass all multicast address", mc_count); db->cr6_data &= ~(CR6_PM | CR6_PBF); db->cr6_data |= CR6_PAM; spin_unlock_irqrestore(&db->lock, flags); return; } - DMFE_DBUG(0, "Set multicast address", dev->mc_count); + DMFE_DBUG(0, "Set multicast address", mc_count); if (db->chip_id == PCI_DM9132_ID) - dm9132_id_table(dev, dev->mc_count); /* DM9132 */ + dm9132_id_table(dev, mc_count); /* DM9132 */ else - send_filter_frame(dev, dev->mc_count); /* DM9102/DM9102A */ + send_filter_frame(dev, mc_count); /* DM9102/DM9102A */ spin_unlock_irqrestore(&db->lock, flags); } diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index e1a5f03a49c..cce2ada0795 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -997,7 +997,7 @@ static void build_setup_frame_hash(u16 *setup_frm, struct net_device *dev) memset(hash_table, 0, sizeof(hash_table)); set_bit_le(255, hash_table); /* Broadcast entry */ /* This should work on big-endian machines as well. */ - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { int index = ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff; @@ -1026,7 +1026,7 @@ static void build_setup_frame_perfect(u16 *setup_frm, struct net_device *dev) /* We have <= 14 addresses so we can use the wonderful 16 address perfect filtering of the Tulip. */ - for (i = 0, mclist = dev->mc_list; i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; i < netdev_mc_count(dev); i++, mclist = mclist->next) { eaddrs = (u16 *)mclist->dmi_addr; *setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++; @@ -1057,7 +1057,8 @@ static void set_rx_mode(struct net_device *dev) if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ tp->csr6 |= AcceptAllMulticast | AcceptAllPhys; csr6 |= AcceptAllMulticast | AcceptAllPhys; - } else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) { + } else if ((netdev_mc_count(dev) > 1000) || + (dev->flags & IFF_ALLMULTI)) { /* Too many to filter well -- accept all multicasts. */ tp->csr6 |= AcceptAllMulticast; csr6 |= AcceptAllMulticast; @@ -1066,14 +1067,16 @@ static void set_rx_mode(struct net_device *dev) /* Should verify correctness on big-endian/__powerpc__ */ struct dev_mc_list *mclist; int i; - if (dev->mc_count > 64) { /* Arbitrary non-effective limit. */ + if (netdev_mc_count(dev) > 64) { + /* Arbitrary non-effective limit. */ tp->csr6 |= AcceptAllMulticast; csr6 |= AcceptAllMulticast; } else { u32 mc_filter[2] = {0, 0}; /* Multicast hash filter */ int filterbit; - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; - i++, mclist = mclist->next) { + for (i = 0, mclist = dev->mc_list; + mclist && i < netdev_mc_count(dev); + i++, mclist = mclist->next) { if (tp->flags & COMET_MAC_ADDR) filterbit = ether_crc_le(ETH_ALEN, mclist->dmi_addr); else @@ -1107,7 +1110,8 @@ static void set_rx_mode(struct net_device *dev) /* Note that only the low-address shortword of setup_frame is valid! The values are doubled for big-endian architectures. */ - if (dev->mc_count > 14) { /* Must use a multicast hash table. */ + if (netdev_mc_count(dev) > 14) { + /* Must use a multicast hash table. */ build_setup_frame_hash(tp->setup_frame, dev); tx_flags = 0x08400000 | 192; } else { diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index dc3335d906f..216ceb322ed 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -557,7 +557,7 @@ static void uli526x_init(struct net_device *dev) update_cr6(db->cr6_data, ioaddr); /* Send setup frame */ - send_filter_frame(dev, dev->mc_count); /* M5261/M5263 */ + send_filter_frame(dev, netdev_mc_count(dev)); /* M5261/M5263 */ /* Init CR7, interrupt active bit */ db->cr7_data = CR7_DEFAULT; @@ -906,16 +906,18 @@ static void uli526x_set_filter_mode(struct net_device * dev) return; } - if (dev->flags & IFF_ALLMULTI || dev->mc_count > ULI5261_MAX_MULTICAST) { - ULI526X_DBUG(0, "Pass all multicast address", dev->mc_count); + if (dev->flags & IFF_ALLMULTI || + netdev_mc_count(dev) > ULI5261_MAX_MULTICAST) { + ULI526X_DBUG(0, "Pass all multicast address", + netdev_mc_count(dev)); db->cr6_data &= ~(CR6_PM | CR6_PBF); db->cr6_data |= CR6_PAM; spin_unlock_irqrestore(&db->lock, flags); return; } - ULI526X_DBUG(0, "Set multicast address", dev->mc_count); - send_filter_frame(dev, dev->mc_count); /* M5261/M5263 */ + ULI526X_DBUG(0, "Set multicast address", netdev_mc_count(dev)); + send_filter_frame(dev, netdev_mc_count(dev)); /* M5261/M5263 */ spin_unlock_irqrestore(&db->lock, flags); } diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index 9fb89afccf7..98711a9f35a 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -1361,7 +1361,7 @@ static u32 __set_rx_mode(struct net_device *dev) memset(mc_filter, 0xff, sizeof(mc_filter)); rx_mode = RxAcceptBroadcast | AcceptMulticast | RxAcceptAllPhys | AcceptMyPhys; - } else if ((dev->mc_count > multicast_filter_limit) || + } else if ((netdev_mc_count(dev) > multicast_filter_limit) || (dev->flags & IFF_ALLMULTI)) { /* Too many to match, or accept all multicasts. */ memset(mc_filter, 0xff, sizeof(mc_filter)); @@ -1370,8 +1370,9 @@ static u32 __set_rx_mode(struct net_device *dev) struct dev_mc_list *mclist; int i; memset(mc_filter, 0, sizeof(mc_filter)); - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; - i++, mclist = mclist->next) { + for (i = 0, mclist = dev->mc_list; + mclist && i < netdev_mc_count(dev); + i++, mclist = mclist->next) { int filterbit = (ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26) ^ 0x3F; filterbit &= 0x3f; mc_filter[filterbit >> 5] |= 1 << (filterbit & 31); diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 6e4f754c4ba..edabc49a49b 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -924,17 +924,18 @@ typhoon_set_rx_mode(struct net_device *dev) filter = TYPHOON_RX_FILTER_DIRECTED | TYPHOON_RX_FILTER_BROADCAST; if(dev->flags & IFF_PROMISC) { filter |= TYPHOON_RX_FILTER_PROMISCOUS; - } else if((dev->mc_count > multicast_filter_limit) || + } else if ((netdev_mc_count(dev) > multicast_filter_limit) || (dev->flags & IFF_ALLMULTI)) { /* Too many to match, or accept all multicasts. */ filter |= TYPHOON_RX_FILTER_ALL_MCAST; - } else if(dev->mc_count) { + } else if (!netdev_mc_empty(dev)) { struct dev_mc_list *mclist; int i; memset(mc_filter, 0, sizeof(mc_filter)); - for(i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; - i++, mclist = mclist->next) { + for (i = 0, mclist = dev->mc_list; + mclist && i < netdev_mc_count(dev); + i++, mclist = mclist->next) { int bit = ether_crc(ETH_ALEN, mclist->dmi_addr) & 0x3f; mc_filter[bit >> 5] |= 1 << (bit & 0x1f); } diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 225f65812f2..a05720289c7 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -2031,7 +2031,8 @@ static void ucc_geth_set_multi(struct net_device *dev) dmi = dev->mc_list; - for (i = 0; i < dev->mc_count; i++, dmi = dmi->next) { + for (i = 0; i < netdev_mc_count(dev); + i++, dmi = dmi->next) { /* Only support group multicast for now. */ diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c index a516185cbc9..f02551713b1 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix.c @@ -542,9 +542,9 @@ static void asix_set_multicast(struct net_device *net) if (net->flags & IFF_PROMISC) { rx_ctl |= AX_RX_CTL_PRO; } else if (net->flags & IFF_ALLMULTI || - net->mc_count > AX_MAX_MCAST) { + netdev_mc_count(net) > AX_MAX_MCAST) { rx_ctl |= AX_RX_CTL_AMALL; - } else if (net->mc_count == 0) { + } else if (netdev_mc_empty(net)) { /* just broadcast and directed */ } else { /* We use the 20 byte dev->data @@ -558,7 +558,7 @@ static void asix_set_multicast(struct net_device *net) memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); /* Build the multicast hash filter. */ - for (i = 0; i < net->mc_count; i++) { + for (i = 0; i < netdev_mc_count(net); i++) { crc_bits = ether_crc(ETH_ALEN, mc_list->dmi_addr) >> 26; @@ -754,9 +754,9 @@ static void ax88172_set_multicast(struct net_device *net) if (net->flags & IFF_PROMISC) { rx_ctl |= 0x01; } else if (net->flags & IFF_ALLMULTI || - net->mc_count > AX_MAX_MCAST) { + netdev_mc_count(net) > AX_MAX_MCAST) { rx_ctl |= 0x02; - } else if (net->mc_count == 0) { + } else if (netdev_mc_empty(net)) { /* just broadcast and directed */ } else { /* We use the 20 byte dev->data @@ -770,7 +770,7 @@ static void ax88172_set_multicast(struct net_device *net) memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); /* Build the multicast hash filter. */ - for (i = 0; i < net->mc_count; i++) { + for (i = 0; i < netdev_mc_count(net); i++) { crc_bits = ether_crc(ETH_ALEN, mc_list->dmi_addr) >> 26; diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c index 7d3fa06980c..5a13660ebd1 100644 --- a/drivers/net/usb/catc.c +++ b/drivers/net/usb/catc.c @@ -648,7 +648,9 @@ static void catc_set_multicast_list(struct net_device *netdev) if (netdev->flags & IFF_ALLMULTI) { memset(catc->multicast, 0xff, 64); } else { - for (i = 0, mc = netdev->mc_list; mc && i < netdev->mc_count; i++, mc = mc->next) { + for (i = 0, mc = netdev->mc_list; + mc && i < netdev_mc_count(netdev); + i++, mc = mc->next) { u32 crc = ether_crc_le(6, mc->dmi_addr); if (!catc->is_f5u011) { catc->multicast[(crc >> 3) & 0x3f] |= 1 << (crc & 7); diff --git a/drivers/net/usb/int51x1.c b/drivers/net/usb/int51x1.c index 55cf7081de1..9ab5c1983a7 100644 --- a/drivers/net/usb/int51x1.c +++ b/drivers/net/usb/int51x1.c @@ -139,7 +139,7 @@ static void int51x1_set_multicast(struct net_device *netdev) /* do not expect to see traffic of other PLCs */ filter |= PACKET_TYPE_PROMISCUOUS; devinfo(dev, "promiscuous mode enabled"); - } else if (netdev->mc_count || + } else if (!netdev_mc_empty(netdev) || (netdev->flags & IFF_ALLMULTI)) { filter |= PACKET_TYPE_ALL_MULTICAST; devdbg(dev, "receive all multicast enabled"); diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index f1d64ef67ef..52671ea043a 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -881,7 +881,7 @@ static void kaweth_set_rx_mode(struct net_device *net) if (net->flags & IFF_PROMISC) { packet_filter_bitmap |= KAWETH_PACKET_FILTER_PROMISCUOUS; } - else if ((net->mc_count) || (net->flags & IFF_ALLMULTI)) { + else if (!netdev_mc_empty(net) || (net->flags & IFF_ALLMULTI)) { packet_filter_bitmap |= KAWETH_PACKET_FILTER_ALL_MULTICAST; } diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c index 6fc098fe9ff..34665137f2c 100644 --- a/drivers/net/usb/mcs7830.c +++ b/drivers/net/usb/mcs7830.c @@ -443,9 +443,9 @@ static void mcs7830_data_set_multicast(struct net_device *net) if (net->flags & IFF_PROMISC) { data->config |= HIF_REG_CONFIG_PROMISCUOUS; } else if (net->flags & IFF_ALLMULTI || - net->mc_count > MCS7830_MAX_MCAST) { + netdev_mc_count(net) > MCS7830_MAX_MCAST) { data->config |= HIF_REG_CONFIG_ALLMULTICAST; - } else if (net->mc_count == 0) { + } else if (netdev_mc_empty(net)) { /* just broadcast and directed */ } else { /* We use the 20 byte dev->data @@ -457,7 +457,7 @@ static void mcs7830_data_set_multicast(struct net_device *net) int i; /* Build the multicast hash filter. */ - for (i = 0; i < net->mc_count; i++) { + for (i = 0; i < netdev_mc_count(net); i++) { crc_bits = ether_crc(ETH_ALEN, mc_list->dmi_addr) >> 26; data->multi_filter[crc_bits >> 3] |= 1 << (crc_bits & 7); mc_list = mc_list->next; diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index ed4a508ef26..44ae8f6d313 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -1232,7 +1232,7 @@ static void pegasus_set_multicast(struct net_device *net) pegasus->eth_regs[EthCtrl2] |= RX_PROMISCUOUS; if (netif_msg_link(pegasus)) pr_info("%s: Promiscuous mode enabled.\n", net->name); - } else if (net->mc_count || (net->flags & IFF_ALLMULTI)) { + } else if (!netdev_mc_empty(net) || (net->flags & IFF_ALLMULTI)) { pegasus->eth_regs[EthCtrl0] |= RX_MULTICAST; pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS; if (netif_msg_link(pegasus)) diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index 21ac103fbb7..e85c89c6706 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -711,7 +711,7 @@ static void rtl8150_set_multicast(struct net_device *netdev) if (netdev->flags & IFF_PROMISC) { dev->rx_creg |= cpu_to_le16(0x0001); dev_info(&netdev->dev, "%s: promiscuous mode\n", netdev->name); - } else if (netdev->mc_count || + } else if (!netdev_mc_empty(netdev) || (netdev->flags & IFF_ALLMULTI)) { dev->rx_creg &= cpu_to_le16(0xfffe); dev->rx_creg |= cpu_to_le16(0x0002); diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 0c3c738d741..48555d0e374 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -384,7 +384,7 @@ static void smsc95xx_set_multicast(struct net_device *netdev) devdbg(dev, "receive all multicast enabled"); pdata->mac_cr |= MAC_CR_MCPAS_; pdata->mac_cr &= ~(MAC_CR_PRMS_ | MAC_CR_HPFILT_); - } else if (dev->net->mc_count > 0) { + } else if (!netdev_mc_empty(dev->net)) { struct dev_mc_list *mc_list = dev->net->mc_list; int count = 0; @@ -406,7 +406,7 @@ static void smsc95xx_set_multicast(struct net_device *netdev) mc_list = mc_list->next; } - if (count != ((u32)dev->net->mc_count)) + if (count != ((u32) netdev_mc_count(dev->net))) devwarn(dev, "mc_count != dev->mc_count"); if (netif_msg_drv(dev)) diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index a7e0c84426e..85df7ac636b 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -1697,7 +1697,7 @@ static void rhine_set_rx_mode(struct net_device *dev) rx_mode = 0x1C; iowrite32(0xffffffff, ioaddr + MulticastFilter0); iowrite32(0xffffffff, ioaddr + MulticastFilter1); - } else if ((dev->mc_count > multicast_filter_limit) || + } else if ((netdev_mc_count(dev) > multicast_filter_limit) || (dev->flags & IFF_ALLMULTI)) { /* Too many to match, or accept all multicasts. */ iowrite32(0xffffffff, ioaddr + MulticastFilter0); @@ -1707,7 +1707,8 @@ static void rhine_set_rx_mode(struct net_device *dev) struct dev_mc_list *mclist; int i; memset(mc_filter, 0, sizeof(mc_filter)); - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; + mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index f15485efe40..bdb19c3d656 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -1132,7 +1132,7 @@ static void velocity_set_multi(struct net_device *dev) writel(0xffffffff, ®s->MARCAM[0]); writel(0xffffffff, ®s->MARCAM[4]); rx_mode = (RCR_AM | RCR_AB | RCR_PROM); - } else if ((dev->mc_count > vptr->multicast_limit) || + } else if ((netdev_mc_count(dev) > vptr->multicast_limit) || (dev->flags & IFF_ALLMULTI)) { writel(0xffffffff, ®s->MARCAM[0]); writel(0xffffffff, ®s->MARCAM[4]); @@ -1141,7 +1141,9 @@ static void velocity_set_multi(struct net_device *dev) int offset = MCAM_SIZE - vptr->multicast_limit; mac_get_cam_mask(regs, vptr->mCAMmask); - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) { + for (i = 0, mclist = dev->mc_list; + mclist && i < netdev_mc_count(dev); + i++, mclist = mclist->next) { mac_set_cam(regs, i + offset, mclist->dmi_addr); vptr->mCAMmask[(offset + i) / 8] |= 1 << ((offset + i) & 7); } diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 9d8984a3741..4c347a3df65 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -735,6 +735,7 @@ static void virtnet_set_rx_mode(struct net_device *dev) struct dev_addr_list *addr; struct netdev_hw_addr *ha; int uc_count; + int mc_count; void *buf; int i; @@ -762,9 +763,11 @@ static void virtnet_set_rx_mode(struct net_device *dev) allmulti ? "en" : "dis"); uc_count = netdev_uc_count(dev); + mc_count = netdev_mc_count(dev); /* MAC filter - use one buffer for both lists */ - mac_data = buf = kzalloc(((uc_count + dev->mc_count) * ETH_ALEN) + - (2 * sizeof(mac_data->entries)), GFP_ATOMIC); + buf = kzalloc(((uc_count + mc_count) * ETH_ALEN) + + (2 * sizeof(mac_data->entries)), GFP_ATOMIC); + mac_data = buf; if (!buf) { dev_warn(&dev->dev, "No memory for MAC address buffer\n"); return; @@ -784,13 +787,13 @@ static void virtnet_set_rx_mode(struct net_device *dev) /* multicast list and count fill the end */ mac_data = (void *)&mac_data->macs[uc_count][0]; - mac_data->entries = dev->mc_count; + mac_data->entries = mc_count; addr = dev->mc_list; - for (i = 0; i < dev->mc_count; i++, addr = addr->next) + for (i = 0; i < mc_count; i++, addr = addr->next) memcpy(&mac_data->macs[i][0], addr->da_addr, ETH_ALEN); sg_set_buf(&sg[1], mac_data, - sizeof(mac_data->entries) + (dev->mc_count * ETH_ALEN)); + sizeof(mac_data->entries) + (mc_count * ETH_ALEN)); if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MAC, VIRTIO_NET_CTRL_MAC_TABLE_SET, diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index b896f938611..ee1b397417f 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -1668,7 +1668,7 @@ static u8 * vmxnet3_copy_mc(struct net_device *netdev) { u8 *buf = NULL; - u32 sz = netdev->mc_count * ETH_ALEN; + u32 sz = netdev_mc_count(netdev) * ETH_ALEN; /* struct Vmxnet3_RxFilterConf.mfTableLen is u16. */ if (sz <= 0xffff) { @@ -1678,7 +1678,7 @@ vmxnet3_copy_mc(struct net_device *netdev) int i; struct dev_mc_list *mc = netdev->mc_list; - for (i = 0; i < netdev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(netdev); i++) { BUG_ON(!mc); memcpy(buf + i * ETH_ALEN, mc->dmi_addr, ETH_ALEN); @@ -1708,12 +1708,12 @@ vmxnet3_set_mc(struct net_device *netdev) if (netdev->flags & IFF_ALLMULTI) new_mode |= VMXNET3_RXM_ALL_MULTI; else - if (netdev->mc_count > 0) { + if (!netdev_mc_empty(netdev)) { new_table = vmxnet3_copy_mc(netdev); if (new_table) { new_mode |= VMXNET3_RXM_MCAST; rxConf->mfTableLen = cpu_to_le16( - netdev->mc_count * ETH_ALEN); + netdev_mc_count(netdev) * ETH_ALEN); rxConf->mfTablePA = cpu_to_le64(virt_to_phys( new_table)); } else { diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index a6606b8948e..c248b01218a 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -1178,11 +1178,11 @@ static void vxge_set_multicast(struct net_device *dev) memset(&mac_info, 0, sizeof(struct macInfo)); /* Update individual M_CAST address list */ - if ((!vdev->all_multi_flg) && dev->mc_count) { + if ((!vdev->all_multi_flg) && netdev_mc_count(dev)) { mcast_cnt = vdev->vpaths[0].mcast_addr_cnt; list_head = &vdev->vpaths[0].mac_addr_list; - if ((dev->mc_count + + if ((netdev_mc_count(dev) + (vdev->vpaths[0].mac_addr_cnt - mcast_cnt)) > vdev->vpaths[0].max_mac_addr_cnt) goto _set_all_mcast; @@ -1217,7 +1217,7 @@ static void vxge_set_multicast(struct net_device *dev) } /* Add new ones */ - for (i = 0, mclist = dev->mc_list; i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; i < netdev_mc_count(dev); i++, mclist = mclist->next) { memcpy(mac_info.macaddr, mclist->dmi_addr, ETH_ALEN); diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index ef6b78da370..c22a34c7639 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -2310,7 +2310,7 @@ static void airo_set_multicast_list(struct net_device *dev) { airo_set_promisc(ai); } - if ((dev->flags&IFF_ALLMULTI)||dev->mc_count>0) { + if ((dev->flags&IFF_ALLMULTI) || !netdev_mc_empty(dev)) { /* Turn on multicast. (Should be already setup...) */ } } diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index 753a1804eee..a9e9cea2d76 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -1668,12 +1668,12 @@ __orinoco_set_multicast_list(struct net_device *dev) /* The Hermes doesn't seem to have an allmulti mode, so we go * into promiscuous mode and let the upper levels deal. */ if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) || - (dev->mc_count > MAX_MULTICAST(priv))) { + (netdev_mc_count(dev) > MAX_MULTICAST(priv))) { promisc = 1; mc_count = 0; } else { promisc = 0; - mc_count = dev->mc_count; + mc_count = netdev_mc_count(dev); } err = __orinoco_hw_set_multicast_list(priv, dev->mc_list, mc_count, diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 88e1e4e32b2..85905cab4f1 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -1950,7 +1950,7 @@ static void set_multicast_list(struct net_device *dev) if (dev->flags & IFF_ALLMULTI) ray_update_multi_list(dev, 1); else { - if (local->num_multi != dev->mc_count) + if (local->num_multi != netdev_mc_count(dev)) ray_update_multi_list(dev, 0); } } /* end set_multicast_list */ diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 305c106fdc1..14692bc51b5 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -1492,10 +1492,10 @@ static void set_multicast_list(struct usbnet *usbdev) filter |= RNDIS_PACKET_TYPE_PROMISCUOUS | RNDIS_PACKET_TYPE_ALL_LOCAL; } else if (usbdev->net->flags & IFF_ALLMULTI || - usbdev->net->mc_count > priv->multicast_size) { + netdev_mc_count(usbdev->net) > priv->multicast_size) { filter |= RNDIS_PACKET_TYPE_ALL_MULTICAST; - } else if (usbdev->net->mc_count > 0) { - size = min(priv->multicast_size, usbdev->net->mc_count); + } else if (!netdev_mc_empty(usbdev->net)) { + size = min(priv->multicast_size, netdev_mc_count(usbdev->net)); buf = kmalloc(size * ETH_ALEN, GFP_KERNEL); if (!buf) { devwarn(usbdev, diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c index 33c8be7ec8e..5d2b52f4717 100644 --- a/drivers/net/wireless/zd1201.c +++ b/drivers/net/wireless/zd1201.c @@ -879,16 +879,15 @@ static void zd1201_set_multicast(struct net_device *dev) unsigned char reqbuf[ETH_ALEN*ZD1201_MAXMULTI]; int i; - if (dev->mc_count > ZD1201_MAXMULTI) + if (netdev_mc_count(dev) > ZD1201_MAXMULTI) return; - for (i=0; imc_count; i++) { + for (i=0; idmi_addr, ETH_ALEN); mc = mc->next; } zd1201_setconfig(zd, ZD1201_RID_CNFGROUPADDRESS, reqbuf, - dev->mc_count*ETH_ALEN, 0); - + netdev_mc_count(dev) * ETH_ALEN, 0); } static int zd1201_config_commit(struct net_device *dev, diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 8b231b30fd1..5c880240a64 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -1301,15 +1301,16 @@ static void set_rx_mode(struct net_device *dev) iowrite16(cfg_value & ~0x1000, ioaddr + Cnfg); if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ iowrite16(0x000F, ioaddr + AddrMode); - } else if ((dev->mc_count > 64) || (dev->flags & IFF_ALLMULTI)) { + } else if ((netdev_mc_count(dev) > 64) || + (dev->flags & IFF_ALLMULTI)) { /* Too many to filter well, or accept all multicasts. */ iowrite16(0x000B, ioaddr + AddrMode); - } else if (dev->mc_count > 0) { /* Must use the multicast hash table. */ + } else if (!netdev_mc_empty(dev)) { /* Must use the multicast hash table. */ struct dev_mc_list *mclist; u16 hash_table[4]; int i; memset(hash_table, 0, sizeof(hash_table)); - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { unsigned int bit; diff --git a/drivers/staging/et131x/et131x_netdev.c b/drivers/staging/et131x/et131x_netdev.c index 24d97b4fa6f..bc1fad24895 100644 --- a/drivers/staging/et131x/et131x_netdev.c +++ b/drivers/staging/et131x/et131x_netdev.c @@ -444,11 +444,11 @@ void et131x_multicast(struct net_device *netdev) adapter->PacketFilter |= ET131X_PACKET_TYPE_ALL_MULTICAST; } - if (netdev->mc_count > NIC_MAX_MCAST_LIST) { + if (netdev_mc_count(netdev) > NIC_MAX_MCAST_LIST) { adapter->PacketFilter |= ET131X_PACKET_TYPE_ALL_MULTICAST; } - if (netdev->mc_count < 1) { + if (netdev_mc_count(netdev) < 1) { adapter->PacketFilter &= ~ET131X_PACKET_TYPE_ALL_MULTICAST; adapter->PacketFilter &= ~ET131X_PACKET_TYPE_MULTICAST; } else { @@ -456,10 +456,10 @@ void et131x_multicast(struct net_device *netdev) } /* Set values in the private adapter struct */ - adapter->MCAddressCount = netdev->mc_count; + adapter->MCAddressCount = netdev_mc_count(netdev); - if (netdev->mc_count) { - count = netdev->mc_count - 1; + if (!netdev_mc_empty(netdev)) { + count = netdev_mc_count(netdev) - 1; memcpy(adapter->MCList[count], mclist->dmi_addr, ETH_ALEN); } diff --git a/drivers/staging/netwave/netwave_cs.c b/drivers/staging/netwave/netwave_cs.c index e61e6b9440a..e936717d1f4 100644 --- a/drivers/staging/netwave/netwave_cs.c +++ b/drivers/staging/netwave/netwave_cs.c @@ -1341,15 +1341,15 @@ static void set_multicast_list(struct net_device *dev) #ifdef PCMCIA_DEBUG { xstatic int old; - if (old != dev->mc_count) { - old = dev->mc_count; + if (old != netdev_mc_count(dev)) { + old = netdev_mc_count(dev); pr_debug("%s: setting Rx mode to %d addresses.\n", - dev->name, dev->mc_count); + dev->name, netdev_mc_count(dev)); } } #endif - if (dev->mc_count || (dev->flags & IFF_ALLMULTI)) { + if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI)) { /* Multicast Mode */ rcvMode = rxConfRxEna + rxConfAMP + rxConfBcast; } else if (dev->flags & IFF_PROMISC) { diff --git a/drivers/staging/slicoss/slicoss.c b/drivers/staging/slicoss/slicoss.c index 5b191afc144..8c9d5e5c770 100644 --- a/drivers/staging/slicoss/slicoss.c +++ b/drivers/staging/slicoss/slicoss.c @@ -1365,7 +1365,7 @@ static void slic_mcast_set_list(struct net_device *dev) int i; char *addresses; struct dev_mc_list *mc_list = dev->mc_list; - int mc_count = dev->mc_count; + int mc_count = netdev_mc_count(dev); ASSERT(adapter); diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index 0db8d7b6e79..82b3a6e0b15 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -3093,7 +3093,7 @@ static void device_set_multi(struct net_device *dev) { /* Unconditionally log net taps. */ pDevice->byRxMode |= (RCR_MULTICAST|RCR_BROADCAST|RCR_UNICAST); } - else if ((dev->mc_count > pDevice->multicast_limit) + else if ((netdev_mc_count(dev) > pDevice->multicast_limit) || (dev->flags & IFF_ALLMULTI)) { MACvSelectPage1(pDevice->PortOffset); VNSvOutPortD(pDevice->PortOffset + MAC_REG_MAR0, 0xffffffff); @@ -3103,7 +3103,7 @@ static void device_set_multi(struct net_device *dev) { } else { memset(mc_filter, 0, sizeof(mc_filter)); - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; mc_filter[bit_nr >> 5] |= cpu_to_le32(1 << (bit_nr & 31)); diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c index ef17c4958c6..2c6a5350547 100644 --- a/drivers/staging/vt6656/main_usb.c +++ b/drivers/staging/vt6656/main_usb.c @@ -1619,7 +1619,8 @@ static void device_set_multi(struct net_device *dev) { // Unconditionally log net taps. pDevice->byRxMode |= (RCR_MULTICAST|RCR_BROADCAST|RCR_UNICAST); } - else if ((dev->mc_count > pDevice->multicast_limit) || (dev->flags & IFF_ALLMULTI)) { + else if ((netdev_mc_count(dev) > pDevice->multicast_limit) || + (dev->flags & IFF_ALLMULTI)) { CONTROLnsRequestOut(pDevice, MESSAGE_TYPE_WRITE, MAC_REG_MAR0, @@ -1631,7 +1632,7 @@ static void device_set_multi(struct net_device *dev) { } else { memset(mc_filter, 0, sizeof(mc_filter)); - for (ii = 0, mclist = dev->mc_list; mclist && ii < dev->mc_count; + for (ii = 0, mclist = dev->mc_list; mclist && ii < netdev_mc_count(dev); ii++, mclist = mclist->next) { int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; mc_filter[bit_nr >> 5] |= cpu_to_le32(1 << (bit_nr & 31)); diff --git a/drivers/staging/wavelan/wavelan.c b/drivers/staging/wavelan/wavelan.c index d634b2da3b8..961f1417fb5 100644 --- a/drivers/staging/wavelan/wavelan.c +++ b/drivers/staging/wavelan/wavelan.c @@ -1367,7 +1367,7 @@ static void wavelan_set_multicast_list(struct net_device * dev) #ifdef DEBUG_IOCTL_INFO printk(KERN_DEBUG "%s: wavelan_set_multicast_list(): setting Rx mode %02X to %d addresses.\n", - dev->name, dev->flags, dev->mc_count); + dev->name, dev->flags, netdev_mc_count(dev)); #endif /* Are we asking for promiscuous mode, @@ -1375,7 +1375,7 @@ static void wavelan_set_multicast_list(struct net_device * dev) * or too many multicast addresses for the hardware filter? */ if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) || - (dev->mc_count > I82586_MAX_MULTICAST_ADDRESSES)) { + (netdev_mc_count(dev) > I82586_MAX_MULTICAST_ADDRESSES)) { /* * Enable promiscuous mode: receive all packets. */ @@ -1393,11 +1393,11 @@ static void wavelan_set_multicast_list(struct net_device * dev) * in multicast list */ #ifdef MULTICAST_AVOID - if (lp->promiscuous || (dev->mc_count != lp->mc_count)) + if (lp->promiscuous || (netdev_mc_count(dev) != lp->mc_count)) #endif { lp->promiscuous = 0; - lp->mc_count = dev->mc_count; + lp->mc_count = netdev_mc_count(dev); wv_82586_reconfig(dev); } diff --git a/drivers/staging/wavelan/wavelan_cs.c b/drivers/staging/wavelan/wavelan_cs.c index 10c702b5be4..08fcb226d7d 100644 --- a/drivers/staging/wavelan/wavelan_cs.c +++ b/drivers/staging/wavelan/wavelan_cs.c @@ -1373,7 +1373,7 @@ wavelan_set_multicast_list(struct net_device * dev) #ifdef DEBUG_IOCTL_INFO printk(KERN_DEBUG "%s: wavelan_set_multicast_list(): setting Rx mode %02X to %d addresses.\n", - dev->name, dev->flags, dev->mc_count); + dev->name, dev->flags, netdev_mc_count(dev)); #endif if(dev->flags & IFF_PROMISC) @@ -1394,7 +1394,7 @@ wavelan_set_multicast_list(struct net_device * dev) /* If all multicast addresses * or too much multicast addresses for the hardware filter */ if((dev->flags & IFF_ALLMULTI) || - (dev->mc_count > I82593_MAX_MULTICAST_ADDRESSES)) + (netdev_mc_count(dev) > I82593_MAX_MULTICAST_ADDRESSES)) { /* * Disable promiscuous mode, but active the all multicast mode @@ -1418,12 +1418,12 @@ wavelan_set_multicast_list(struct net_device * dev) */ #ifdef MULTICAST_AVOID if(lp->promiscuous || lp->allmulticast || - (dev->mc_count != lp->mc_count)) + (netdev_mc_count(dev) != lp->mc_count)) #endif { lp->promiscuous = 0; lp->allmulticast = 0; - lp->mc_count = dev->mc_count; + lp->mc_count = netdev_mc_count(dev); wv_82593_reconfig(dev); } @@ -3622,7 +3622,8 @@ wv_82593_config(struct net_device * dev) if(!wv_82593_cmd(dev, "wv_82593_config(): mc-setup", OP0_MC_SETUP, SR0_MC_SETUP_DONE)) ret = FALSE; - lp->mc_count = dev->mc_count; /* remember to avoid repeated reset */ + /* remember to avoid repeated reset */ + lp->mc_count = netdev_mc_count(dev); } /* Job done, clear the flag */ diff --git a/drivers/staging/wlags49_h2/wl_netdev.c b/drivers/staging/wlags49_h2/wl_netdev.c index 0d22e3692fe..a95ebf881fc 100644 --- a/drivers/staging/wlags49_h2/wl_netdev.c +++ b/drivers/staging/wlags49_h2/wl_netdev.c @@ -1070,9 +1070,9 @@ void wl_multicast( struct net_device *dev ) ( dev->flags & IFF_MULTICAST ) ? "Multicast " : "", ( dev->flags & IFF_ALLMULTI ) ? "All-Multicast" : "" ); - DBG_PRINT( " mc_count: %d\n", dev->mc_count ); + DBG_PRINT( " mc_count: %d\n", netdev_mc_count(dev)); - for( x = 0, mclist = dev->mc_list; mclist && x < dev->mc_count; + for( x = 0, mclist = dev->mc_list; mclist && x < netdev_mc_count(dev); x++, mclist = mclist->next ) { DBG_PRINT( " %s (%d)\n", DbgHwAddr(mclist->dmi_addr), mclist->dmi_addrlen ); @@ -1103,7 +1103,7 @@ void wl_multicast( struct net_device *dev ) DBG_PRINT( "Enabling Promiscuous mode (IFF_PROMISC)\n" ); hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord )); } - else if(( dev->mc_count > HCF_MAX_MULTICAST ) || + else if ((netdev_mc_count(dev) > HCF_MAX_MULTICAST) || ( dev->flags & IFF_ALLMULTI )) { /* Shutting off this filter will enable all multicast frames to be sent up from the device; however, this is a static RID, so @@ -1115,13 +1115,13 @@ void wl_multicast( struct net_device *dev ) hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord )); wl_apply( lp ); } - else if( dev->mc_count != 0 ) { + else if (!netdev_mc_empty(dev)) { /* Set the multicast addresses */ - lp->ltvRecord.len = ( dev->mc_count * 3 ) + 1; + lp->ltvRecord.len = ( netdev_mc_count(dev) * 3 ) + 1; lp->ltvRecord.typ = CFG_GROUP_ADDR; for( x = 0, mclist = dev->mc_list; - ( x < dev->mc_count ) && ( mclist != NULL ); + ( x < netdev_mc_count(dev)) && ( mclist != NULL ); x++, mclist = mclist->next ) { memcpy( &( lp->ltvRecord.u.u8[x * ETH_ALEN] ), mclist->dmi_addr, ETH_ALEN ); diff --git a/net/bluetooth/bnep/netdev.c b/net/bluetooth/bnep/netdev.c index 26fb831ef7e..b6234b73c4c 100644 --- a/net/bluetooth/bnep/netdev.c +++ b/net/bluetooth/bnep/netdev.c @@ -64,7 +64,7 @@ static void bnep_net_set_mc_list(struct net_device *dev) struct sk_buff *skb; int size; - BT_DBG("%s mc_count %d", dev->name, dev->mc_count); + BT_DBG("%s mc_count %d", dev->name, netdev_mc_count(dev)); size = sizeof(*r) + (BNEP_MAX_MULTICAST_FILTERS + 1) * ETH_ALEN * 2; skb = alloc_skb(size, GFP_ATOMIC); @@ -97,7 +97,9 @@ static void bnep_net_set_mc_list(struct net_device *dev) /* FIXME: We should group addresses here. */ - for (i = 0; i < dev->mc_count && i < BNEP_MAX_MULTICAST_FILTERS; i++) { + for (i = 0; + i < netdev_mc_count(dev) && i < BNEP_MAX_MULTICAST_FILTERS; + i++) { memcpy(__skb_put(skb, ETH_ALEN), dmi->dmi_addr, ETH_ALEN); memcpy(__skb_put(skb, ETH_ALEN), dmi->dmi_addr, ETH_ALEN); dmi = dmi->next; diff --git a/net/core/dev.c b/net/core/dev.c index ae75f25ac0a..d1cf53d0d59 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4263,7 +4263,7 @@ static void dev_addr_discard(struct net_device *dev) netif_addr_lock_bh(dev); __dev_addr_discard(&dev->mc_list); - dev->mc_count = 0; + netdev_mc_count(dev) = 0; netif_addr_unlock_bh(dev); } diff --git a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c index d340110f5c0..9616c32d107 100644 --- a/net/irda/irlan/irlan_eth.c +++ b/net/irda/irlan/irlan_eth.c @@ -321,14 +321,15 @@ static void irlan_eth_set_multicast_list(struct net_device *dev) /* Enable promiscuous mode */ IRDA_WARNING("Promiscuous mode not implemented by IrLAN!\n"); } - else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > HW_MAX_ADDRS) { + else if ((dev->flags & IFF_ALLMULTI) || + netdev_mc_count(dev) > HW_MAX_ADDRS) { /* Disable promiscuous mode, use normal mode. */ IRDA_DEBUG(4, "%s(), Setting multicast filter\n", __func__ ); /* hardware_set_filter(NULL); */ irlan_set_multicast_filter(self, TRUE); } - else if (dev->mc_count) { + else if (!netdev_mc_empty(dev)) { IRDA_DEBUG(4, "%s(), Setting multicast filter\n", __func__ ); /* Walk the address list, and load the filter */ /* hardware_set_filter(dev->mc_list); */ diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 09fff4662e8..f943f5fa728 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -413,7 +413,7 @@ static int ieee80211_stop(struct net_device *dev) netif_addr_lock_bh(dev); spin_lock_bh(&local->filter_lock); __dev_addr_unsync(&local->mc_list, &local->mc_count, - &dev->mc_list, &dev->mc_count); + &dev->mc_list, dev->mc_count); spin_unlock_bh(&local->filter_lock); netif_addr_unlock_bh(dev); -- cgit v1.2.3-70-g09d2 From f9dcbcc9e338d08c0f7de7eba4eaafbbb7f81249 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 23 Feb 2010 09:19:49 +0000 Subject: net: convert multiple drivers to use netdev_for_each_mc_addr, part5 V2 removed some needless checks and also corrected bug in lp486e (dmi was passed instead of dmi->dmi_addr) Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/jme.c | 6 +----- drivers/net/korina.c | 6 ++---- drivers/net/ks8851.c | 5 ++--- drivers/net/ks8851_mll.c | 3 ++- drivers/net/ksz884x.c | 4 ++-- drivers/net/lib82596.c | 7 ++++--- drivers/net/lib8390.c | 15 ++++----------- drivers/net/ll_temac_main.c | 7 ++++--- drivers/net/lp486e.c | 4 ++-- drivers/net/mac89x0.c | 4 +--- drivers/net/macb.c | 7 ++----- drivers/net/mace.c | 11 +++++------ drivers/net/macmace.c | 12 ++++++------ drivers/net/mv643xx_eth.c | 2 +- drivers/net/myri10ge/myri10ge.c | 2 +- drivers/net/natsemi.c | 4 ++-- drivers/net/netxen/netxen_nic_hw.c | 19 +++++++------------ drivers/net/ni5010.c | 3 ++- drivers/net/ni52.c | 8 ++++---- drivers/net/niu.c | 2 +- drivers/net/pci-skeleton.c | 6 +++--- drivers/net/pcnet32.c | 5 ++--- drivers/net/ps3_gelic_net.c | 2 +- drivers/net/qlcnic/qlcnic_hw.c | 3 +-- drivers/net/qlge/qlge_main.c | 6 ++++-- drivers/net/r6040.c | 30 +++++++++++++++--------------- drivers/net/r8169.c | 4 +--- 27 files changed, 82 insertions(+), 105 deletions(-) (limited to 'drivers/net/qlcnic') diff --git a/drivers/net/jme.c b/drivers/net/jme.c index 558b6a0b15f..0f31497833d 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -1997,7 +1997,6 @@ jme_set_multi(struct net_device *netdev) { struct jme_adapter *jme = netdev_priv(netdev); u32 mc_hash[2] = {}; - int i; spin_lock_bh(&jme->rxmcs_lock); @@ -2012,10 +2011,7 @@ jme_set_multi(struct net_device *netdev) int bit_nr; jme->reg_rxmcs |= RXMCS_MULFRAME | RXMCS_MULFILTERED; - for (i = 0, mclist = netdev->mc_list; - mclist && i < netdev_mc_count(netdev); - ++i, mclist = mclist->next) { - + netdev_for_each_mc_addr(mclist, netdev) { bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) & 0x3F; mc_hash[bit_nr >> 5] |= 1 << (bit_nr & 0x1F); } diff --git a/drivers/net/korina.c b/drivers/net/korina.c index af0c764130e..300c2249812 100644 --- a/drivers/net/korina.c +++ b/drivers/net/korina.c @@ -482,7 +482,7 @@ static void korina_multicast_list(struct net_device *dev) { struct korina_private *lp = netdev_priv(dev); unsigned long flags; - struct dev_mc_list *dmi = dev->mc_list; + struct dev_mc_list *dmi; u32 recognise = ETH_ARC_AB; /* always accept broadcasts */ int i; @@ -502,11 +502,9 @@ static void korina_multicast_list(struct net_device *dev) for (i = 0; i < 4; i++) hash_table[i] = 0; - for (i = 0; i < netdev_mc_count(dev); i++) { + netdev_for_each_mc_addr(dmi, dev) { char *addrs = dmi->dmi_addr; - dmi = dmi->next; - if (!(*addrs & 1)) continue; diff --git a/drivers/net/ks8851.c b/drivers/net/ks8851.c index 9845ab1e557..b5219cce12e 100644 --- a/drivers/net/ks8851.c +++ b/drivers/net/ks8851.c @@ -966,13 +966,12 @@ static void ks8851_set_rx_mode(struct net_device *dev) rxctrl.rxcr1 = (RXCR1_RXME | RXCR1_RXAE | RXCR1_RXPAFMA | RXCR1_RXMAFMA); } else if (dev->flags & IFF_MULTICAST && !netdev_mc_empty(dev)) { - struct dev_mc_list *mcptr = dev->mc_list; + struct dev_mc_list *mcptr; u32 crc; - int i; /* accept some multicast */ - for (i = netdev_mc_count(dev); i > 0; i--) { + netdev_for_each_mc_addr(mcptr, dev) { crc = ether_crc(ETH_ALEN, mcptr->dmi_addr); crc >>= (32 - 6); /* get top six bits */ diff --git a/drivers/net/ks8851_mll.c b/drivers/net/ks8851_mll.c index ffffb388970..84b0e15831f 100644 --- a/drivers/net/ks8851_mll.c +++ b/drivers/net/ks8851_mll.c @@ -1196,7 +1196,8 @@ static void ks_set_rx_mode(struct net_device *netdev) if ((netdev->flags & IFF_MULTICAST) && netdev_mc_count(netdev)) { if (netdev_mc_count(netdev) <= MAX_MCAST_LST) { int i = 0; - for (ptr = netdev->mc_list; ptr; ptr = ptr->next) { + + netdev_for_each_mc_addr(ptr, netdev) { if (!(*ptr->dmi_addr & 1)) continue; if (i >= MAX_MCAST_LST) diff --git a/drivers/net/ksz884x.c b/drivers/net/ksz884x.c index 6f187c7e61f..7264a3e5c2c 100644 --- a/drivers/net/ksz884x.c +++ b/drivers/net/ksz884x.c @@ -5777,7 +5777,7 @@ static void netdev_set_rx_mode(struct net_device *dev) if (hw_priv->hw.dev_count > 1) return; - if ((dev->flags & IFF_MULTICAST) && dev->mc_count) { + if ((dev->flags & IFF_MULTICAST) && !netdev_mc_empty(dev)) { int i = 0; /* List too big to support so turn on all multicast mode. */ @@ -5790,7 +5790,7 @@ static void netdev_set_rx_mode(struct net_device *dev) return; } - for (mc_ptr = dev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) { + netdev_for_each_mc_addr(mc_ptr, dev) { if (!(*mc_ptr->dmi_addr & 1)) continue; if (i >= MAX_MULTICAST_LIST) diff --git a/drivers/net/lib82596.c b/drivers/net/lib82596.c index 371b58b1d15..443c39a3732 100644 --- a/drivers/net/lib82596.c +++ b/drivers/net/lib82596.c @@ -1396,15 +1396,16 @@ static void set_multicast_list(struct net_device *dev) cmd->cmd.command = SWAP16(CmdMulticastList); cmd->mc_cnt = SWAP16(netdev_mc_count(dev) * 6); cp = cmd->mc_addrs; - for (dmi = dev->mc_list; - cnt && dmi != NULL; - dmi = dmi->next, cnt--, cp += 6) { + netdev_for_each_mc_addr(dmi, dev) { + if (!cnt--) + break; memcpy(cp, dmi->dmi_addr, 6); if (i596_debug > 1) DEB(DEB_MULTI, printk(KERN_DEBUG "%s: Adding address %pM\n", dev->name, cp)); + cp += 6; } DMA_WBACK_INV(dev, &dma->mc_cmd, sizeof(struct mc_cmd)); i596_add_cmd(dev, &cmd->cmd); diff --git a/drivers/net/lib8390.c b/drivers/net/lib8390.c index 57f25848fe8..56f66f48540 100644 --- a/drivers/net/lib8390.c +++ b/drivers/net/lib8390.c @@ -907,15 +907,8 @@ static inline void make_mc_bits(u8 *bits, struct net_device *dev) { struct dev_mc_list *dmi; - for (dmi=dev->mc_list; dmi; dmi=dmi->next) - { - u32 crc; - if (dmi->dmi_addrlen != ETH_ALEN) - { - printk(KERN_INFO "%s: invalid multicast address length given.\n", dev->name); - continue; - } - crc = ether_crc(ETH_ALEN, dmi->dmi_addr); + netdev_for_each_mc_addr(dmi, dev) { + u32 crc = ether_crc(ETH_ALEN, dmi->dmi_addr); /* * The 8390 uses the 6 most significant bits of the * CRC to index the multicast table. @@ -941,7 +934,7 @@ static void do_set_multicast_list(struct net_device *dev) if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))) { memset(ei_local->mcfilter, 0, 8); - if (dev->mc_list) + if (!netdev_mc_empty(dev)) make_mc_bits(ei_local->mcfilter, dev); } else @@ -975,7 +968,7 @@ static void do_set_multicast_list(struct net_device *dev) if(dev->flags&IFF_PROMISC) ei_outb_p(E8390_RXCONFIG | 0x18, e8390_base + EN0_RXCR); - else if(dev->flags&IFF_ALLMULTI || dev->mc_list) + else if (dev->flags & IFF_ALLMULTI || !netdev_mc_empty(dev)) ei_outb_p(E8390_RXCONFIG | 0x08, e8390_base + EN0_RXCR); else ei_outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c index e5344025374..a18e3485476 100644 --- a/drivers/net/ll_temac_main.c +++ b/drivers/net/ll_temac_main.c @@ -250,9 +250,10 @@ static void temac_set_multicast_list(struct net_device *ndev) temac_indirect_out32(lp, XTE_AFM_OFFSET, XTE_AFM_EPPRM_MASK); dev_info(&ndev->dev, "Promiscuous mode enabled.\n"); } else if (!netdev_mc_empty(ndev)) { - struct dev_mc_list *mclist = ndev->mc_list; - for (i = 0; mclist && i < netdev_mc_count(ndev); i++) { + struct dev_mc_list *mclist; + i = 0; + netdev_for_each_mc_addr(mclist, ndev) { if (i >= MULTICAST_CAM_TABLE_NUM) break; multi_addr_msw = ((mclist->dmi_addr[3] << 24) | @@ -265,7 +266,7 @@ static void temac_set_multicast_list(struct net_device *ndev) (mclist->dmi_addr[4]) | (i << 16)); temac_indirect_out32(lp, XTE_MAW1_OFFSET, multi_addr_lsw); - mclist = mclist->next; + i++; } } else { val = temac_indirect_in32(lp, XTE_AFM_OFFSET); diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c index b1f5d79af61..3e3cc04defd 100644 --- a/drivers/net/lp486e.c +++ b/drivers/net/lp486e.c @@ -1267,8 +1267,8 @@ static void set_multicast_list(struct net_device *dev) { cmd->command = CmdMulticastList; *((unsigned short *) (cmd + 1)) = netdev_mc_count(dev) * 6; cp = ((char *)(cmd + 1))+2; - for (dmi = dev->mc_list; dmi != NULL; dmi = dmi->next) { - memcpy(cp, dmi,6); + netdev_for_each_mc_addr(dmi, dev) { + memcpy(cp, dmi->dmi_addr, 6); cp += 6; } if (i596_debug & LOG_SRCDST) diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c index 23b633e2ac4..c292a608f9a 100644 --- a/drivers/net/mac89x0.c +++ b/drivers/net/mac89x0.c @@ -568,9 +568,7 @@ static void set_multicast_list(struct net_device *dev) if(dev->flags&IFF_PROMISC) { lp->rx_mode = RX_ALL_ACCEPT; - } - else if((dev->flags&IFF_ALLMULTI)||dev->mc_list) - { + } else if ((dev->flags & IFF_ALLMULTI) || !netdev_mc_empty(dev)) { /* The multicast-accept list is initialized to accept-all, and we rely on higher-level filtering for now. */ lp->rx_mode = RX_MULTCAST_ACCEPT; diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 7a5f89728a8..c8a18a6203c 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -884,15 +884,12 @@ static void macb_sethashtable(struct net_device *dev) { struct dev_mc_list *curr; unsigned long mc_filter[2]; - unsigned int i, bitnr; + unsigned int bitnr; struct macb *bp = netdev_priv(dev); mc_filter[0] = mc_filter[1] = 0; - curr = dev->mc_list; - for (i = 0; i < netdev_mc_count(dev); i++, curr = curr->next) { - if (!curr) break; /* unexpected end of list */ - + netdev_for_each_mc_addr(curr, dev) { bitnr = hash_get_index(curr->dmi_addr); mc_filter[bitnr >> 5] |= 1 << (bitnr & 31); } diff --git a/drivers/net/mace.c b/drivers/net/mace.c index fdb0bbdd678..57534f0e906 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -588,7 +588,7 @@ static void mace_set_multicast(struct net_device *dev) { struct mace_data *mp = netdev_priv(dev); volatile struct mace __iomem *mb = mp->mace; - int i, j; + int i; u32 crc; unsigned long flags; @@ -598,7 +598,7 @@ static void mace_set_multicast(struct net_device *dev) mp->maccc |= PROM; } else { unsigned char multicast_filter[8]; - struct dev_mc_list *dmi = dev->mc_list; + struct dev_mc_list *dmi; if (dev->flags & IFF_ALLMULTI) { for (i = 0; i < 8; i++) @@ -606,11 +606,10 @@ static void mace_set_multicast(struct net_device *dev) } else { for (i = 0; i < 8; i++) multicast_filter[i] = 0; - for (i = 0; i < netdev_mc_count(dev); i++) { + netdev_for_each_mc_addr(dmi, dev) { crc = ether_crc_le(6, dmi->dmi_addr); - j = crc >> 26; /* bit number in multicast_filter */ - multicast_filter[j >> 3] |= 1 << (j & 7); - dmi = dmi->next; + i = crc >> 26; /* bit number in multicast_filter */ + multicast_filter[i >> 3] |= 1 << (i & 7); } } #if 0 diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c index 740accbf080..4e4eac0ba17 100644 --- a/drivers/net/macmace.c +++ b/drivers/net/macmace.c @@ -496,7 +496,7 @@ static void mace_set_multicast(struct net_device *dev) { struct mace_data *mp = netdev_priv(dev); volatile struct mace *mb = mp->mace; - int i, j; + int i; u32 crc; u8 maccc; unsigned long flags; @@ -509,7 +509,7 @@ static void mace_set_multicast(struct net_device *dev) mb->maccc |= PROM; } else { unsigned char multicast_filter[8]; - struct dev_mc_list *dmi = dev->mc_list; + struct dev_mc_list *dmi; if (dev->flags & IFF_ALLMULTI) { for (i = 0; i < 8; i++) { @@ -518,11 +518,11 @@ static void mace_set_multicast(struct net_device *dev) } else { for (i = 0; i < 8; i++) multicast_filter[i] = 0; - for (i = 0; i < netdev_mc_count(dev); i++) { + netdev_for_each_mc_addr(dmi, dev) { crc = ether_crc_le(6, dmi->dmi_addr); - j = crc >> 26; /* bit number in multicast_filter */ - multicast_filter[j >> 3] |= 1 << (j & 7); - dmi = dmi->next; + /* bit number in multicast_filter */ + i = crc >> 26; + multicast_filter[i >> 3] |= 1 << (i & 7); } } diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 2733b0a3b70..c97b6e4365a 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -1794,7 +1794,7 @@ oom: memset(mc_spec, 0, 0x100); memset(mc_other, 0, 0x100); - for (addr = dev->mc_list; addr != NULL; addr = addr->next) { + netdev_for_each_mc_addr(addr, dev) { u8 *a = addr->da_addr; u32 *table; int entry; diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 1d14a8b05fa..aae2ddb5d82 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -3035,7 +3035,7 @@ static void myri10ge_set_multicast_list(struct net_device *dev) } /* Walk the multicast list, and add each address */ - for (mc_list = dev->mc_list; mc_list != NULL; mc_list = mc_list->next) { + netdev_for_each_mc_addr(mc_list, dev) { memcpy(data, &mc_list->dmi_addr, 6); cmd.data0 = ntohl(data[0]); cmd.data1 = ntohl(data[1]); diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index c64e5b0d359..e5203878324 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -2495,9 +2495,9 @@ static void __set_rx_mode(struct net_device *dev) } else { struct dev_mc_list *mclist; int i; + memset(mc_filter, 0, sizeof(mc_filter)); - for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); - i++, mclist = mclist->next) { + netdev_for_each_mc_addr(mclist, dev) { int b = (ether_crc(ETH_ALEN, mclist->dmi_addr) >> 23) & 0x1ff; mc_filter[b/8] |= (1 << (b & 0x07)); } diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 25f4414cc33..a945591298a 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -539,7 +539,7 @@ void netxen_p2_nic_set_multi(struct net_device *netdev) struct netxen_adapter *adapter = netdev_priv(netdev); struct dev_mc_list *mc_ptr; u8 null_addr[6]; - int index = 0; + int i; memset(null_addr, 0, 6); @@ -570,16 +570,13 @@ void netxen_p2_nic_set_multi(struct net_device *netdev) netxen_nic_enable_mcast_filter(adapter); - for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next, index++) - netxen_nic_set_mcast_addr(adapter, index, mc_ptr->dmi_addr); - - if (index != netdev_mc_count(netdev)) - printk(KERN_WARNING "%s: %s multicast address count mismatch\n", - netxen_nic_driver_name, netdev->name); + i = 0; + netdev_for_each_mc_addr(mc_ptr, netdev) + netxen_nic_set_mcast_addr(adapter, i++, mc_ptr->dmi_addr); /* Clear out remaining addresses */ - for (; index < adapter->max_mc_count; index++) - netxen_nic_set_mcast_addr(adapter, index, null_addr); + while (i < adapter->max_mc_count) + netxen_nic_set_mcast_addr(adapter, i++, null_addr); } static int @@ -710,10 +707,8 @@ void netxen_p3_nic_set_multi(struct net_device *netdev) } if (!netdev_mc_empty(netdev)) { - for (mc_ptr = netdev->mc_list; mc_ptr; - mc_ptr = mc_ptr->next) { + netdev_for_each_mc_addr(mc_ptr, netdev) nx_p3_nic_add_mac(adapter, mc_ptr->dmi_addr, &del_list); - } } send_fw_cmd: diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c index 6a87d810e59..c16cbfb4061 100644 --- a/drivers/net/ni5010.c +++ b/drivers/net/ni5010.c @@ -651,7 +651,8 @@ static void ni5010_set_multicast_list(struct net_device *dev) PRINTK2((KERN_DEBUG "%s: entering set_multicast_list\n", dev->name)); - if (dev->flags&IFF_PROMISC || dev->flags&IFF_ALLMULTI || dev->mc_list) { + if (dev->flags & IFF_PROMISC || dev->flags & IFF_ALLMULTI || + !netdev_mc_empty(dev)) { outb(RMD_PROMISC, EDLC_RMODE); /* Enable promiscuous mode */ PRINTK((KERN_DEBUG "%s: Entering promiscuous mode\n", dev->name)); } else { diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c index 497c6d514a6..05c29c2cef2 100644 --- a/drivers/net/ni52.c +++ b/drivers/net/ni52.c @@ -596,7 +596,7 @@ static int init586(struct net_device *dev) struct iasetup_cmd_struct __iomem *ias_cmd; struct tdr_cmd_struct __iomem *tdr_cmd; struct mcsetup_cmd_struct __iomem *mc_cmd; - struct dev_mc_list *dmi = dev->mc_list; + struct dev_mc_list *dmi; int num_addrs = netdev_mc_count(dev); ptr = p->scb + 1; @@ -724,9 +724,9 @@ static int init586(struct net_device *dev) writew(0xffff, &mc_cmd->cmd_link); writew(num_addrs * 6, &mc_cmd->mc_cnt); - for (i = 0; i < num_addrs; i++, dmi = dmi->next) - memcpy_toio(mc_cmd->mc_list[i], - dmi->dmi_addr, 6); + i = 0; + netdev_for_each_mc_addr(dmi, dev) + memcpy_toio(mc_cmd->mc_list[i++], dmi->dmi_addr, 6); writew(make16(mc_cmd), &p->scb->cbl_offset); writeb(CUC_START, &p->scb->cmd_cuc); diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 5e604e305d9..0678f3106cb 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -6365,7 +6365,7 @@ static void niu_set_rx_mode(struct net_device *dev) for (i = 0; i < 16; i++) hash[i] = 0xffff; } else if (!netdev_mc_empty(dev)) { - for (addr = dev->mc_list; addr; addr = addr->next) { + netdev_for_each_mc_addr(addr, dev) { u32 crc = ether_crc_le(ETH_ALEN, addr->da_addr); crc >>= 24; diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c index 11d4398eac9..36785853a14 100644 --- a/drivers/net/pci-skeleton.c +++ b/drivers/net/pci-skeleton.c @@ -1793,7 +1793,7 @@ static void netdrv_set_rx_mode(struct net_device *dev) struct netdrv_private *tp = netdev_priv(dev); void *ioaddr = tp->mmio_addr; u32 mc_filter[2]; /* Multicast hash filter */ - int i, rx_mode; + int rx_mode; u32 tmp; DPRINTK("ENTER\n"); @@ -1814,10 +1814,10 @@ static void netdrv_set_rx_mode(struct net_device *dev) mc_filter[1] = mc_filter[0] = 0xffffffff; } else { struct dev_mc_list *mclist; + rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; mc_filter[1] = mc_filter[0] = 0; - for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); - i++, mclist = mclist->next) { + netdev_for_each_mc_addr(mclist, dev) { int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 63e03159daf..084d78dd163 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -2590,7 +2590,7 @@ static void pcnet32_load_multicast(struct net_device *dev) struct pcnet32_private *lp = netdev_priv(dev); volatile struct pcnet32_init_block *ib = lp->init_block; volatile __le16 *mcast_table = (__le16 *)ib->filter; - struct dev_mc_list *dmi = dev->mc_list; + struct dev_mc_list *dmi; unsigned long ioaddr = dev->base_addr; char *addrs; int i; @@ -2611,9 +2611,8 @@ static void pcnet32_load_multicast(struct net_device *dev) ib->filter[1] = 0; /* Add addresses */ - for (i = 0; i < netdev_mc_count(dev); i++) { + netdev_for_each_mc_addr(dmi, dev) { addrs = dmi->dmi_addr; - dmi = dmi->next; /* multicast address? */ if (!(*addrs & 1)) diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index c19dd4a6cd7..a849f6f23a1 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -580,7 +580,7 @@ void gelic_net_set_multi(struct net_device *netdev) } /* set multicast addresses */ - for (mc = netdev->mc_list; mc; mc = mc->next) { + netdev_for_each_mc_addr(mc, netdev) { addr = 0; p = mc->dmi_addr; for (i = 0; i < ETH_ALEN; i++) { diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c index 8ea7f869e29..99a4d1379d0 100644 --- a/drivers/net/qlcnic/qlcnic_hw.c +++ b/drivers/net/qlcnic/qlcnic_hw.c @@ -453,8 +453,7 @@ void qlcnic_set_multi(struct net_device *netdev) } if (!netdev_mc_empty(netdev)) { - for (mc_ptr = netdev->mc_list; mc_ptr; - mc_ptr = mc_ptr->next) { + netdev_for_each_mc_addr(mc_ptr, netdev) { qlcnic_nic_add_mac(adapter, mc_ptr->dmi_addr, &del_list); } diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index c170349717c..c26ec5d740f 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -4270,8 +4270,8 @@ static void qlge_set_multicast_list(struct net_device *ndev) status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK); if (status) goto exit; - for (i = 0, mc_ptr = ndev->mc_list; mc_ptr; - i++, mc_ptr = mc_ptr->next) + i = 0; + netdev_for_each_mc_addr(mc_ptr, ndev) { if (ql_set_mac_addr_reg(qdev, (u8 *) mc_ptr->dmi_addr, MAC_ADDR_TYPE_MULTI_MAC, i)) { netif_err(qdev, hw, qdev->ndev, @@ -4279,6 +4279,8 @@ static void qlge_set_multicast_list(struct net_device *ndev) ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK); goto exit; } + i++; + } ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK); if (ql_set_routing_reg (qdev, RT_IDX_MCAST_MATCH_SLOT, RT_IDX_MCAST_MATCH, 1)) { diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index b8103425fac..15d5373dc8f 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -938,7 +938,7 @@ static void r6040_multicast_list(struct net_device *dev) u16 *adrp; u16 reg; unsigned long flags; - struct dev_mc_list *dmi = dev->mc_list; + struct dev_mc_list *dmi; int i; /* MAC Address */ @@ -973,11 +973,9 @@ static void r6040_multicast_list(struct net_device *dev) for (i = 0; i < 4; i++) hash_table[i] = 0; - for (i = 0; i < netdev_mc_count(dev); i++) { + netdev_for_each_mc_addr(dmi, dev) { char *addrs = dmi->dmi_addr; - dmi = dmi->next; - if (!(*addrs & 1)) continue; @@ -995,17 +993,19 @@ static void r6040_multicast_list(struct net_device *dev) iowrite16(hash_table[3], ioaddr + MAR3); } /* Multicast Address 1~4 case */ - for (i = 0, dmi; (i < netdev_mc_count(dev)) && (i < MCAST_MAX); i++) { - adrp = (u16 *)dmi->dmi_addr; - iowrite16(adrp[0], ioaddr + MID_1L + 8*i); - iowrite16(adrp[1], ioaddr + MID_1M + 8*i); - iowrite16(adrp[2], ioaddr + MID_1H + 8*i); - dmi = dmi->next; - } - for (i = netdev_mc_count(dev); i < MCAST_MAX; i++) { - iowrite16(0xffff, ioaddr + MID_0L + 8*i); - iowrite16(0xffff, ioaddr + MID_0M + 8*i); - iowrite16(0xffff, ioaddr + MID_0H + 8*i); + i = 0; + netdev_for_each_mc_addr(dmi, dev) { + if (i < MCAST_MAX) { + adrp = (u16 *) dmi->dmi_addr; + iowrite16(adrp[0], ioaddr + MID_1L + 8 * i); + iowrite16(adrp[1], ioaddr + MID_1M + 8 * i); + iowrite16(adrp[2], ioaddr + MID_1H + 8 * i); + } else { + iowrite16(0xffff, ioaddr + MID_0L + 8 * i); + iowrite16(0xffff, ioaddr + MID_0M + 8 * i); + iowrite16(0xffff, ioaddr + MID_0H + 8 * i); + } + i++; } } diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 83965eeba45..dfc3573c91b 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -4732,12 +4732,10 @@ static void rtl_set_rx_mode(struct net_device *dev) mc_filter[1] = mc_filter[0] = 0xffffffff; } else { struct dev_mc_list *mclist; - unsigned int i; rx_mode = AcceptBroadcast | AcceptMyPhys; mc_filter[1] = mc_filter[0] = 0; - for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); - i++, mclist = mclist->next) { + netdev_for_each_mc_addr(mclist, dev) { int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); rx_mode |= AcceptMulticast; -- cgit v1.2.3-70-g09d2